glateur
02-11-2009 17:19:34
Hi all,
I've been trying to make a class that can render lines in Ogre. There are 2 interesting tutorials about this on the wiki:
http://www.ogre3d.org/wiki/index.php/DynamicGrowingBuffers
http://www.ogre3d.org/wiki/index.php/DynamicLineDrawing
These appear to provide a solution to my problem, but they're in C++. I've been trying to 'translate' these into C#, but I can't seem to get it to work. Well, it compiles and it runs, but nothing gets rendered.
Two classes need to be definded: DynamicRenderable (extends SimpleRenderable) and DynamicLines (extends DynamicRenderable). This what I have so far:
Part 1/2: DynamicRenderable:
Questions/remarks about Part 1/2: DynamicRenderable:
1. About class DynamicRenderable : SimpleRenderable
It seems a bit strange that I have to keep my own RenderOperation property. I don't quite understand how SimpleRenderable.GetRenderOperation(RenderOperation op) is supposed to work. Or does it copy it's values to the RenderOperation argument?
2. About DynamicRenderable(string name) constructor
This is a hack I found in this post:
http://www.ogre3d.org/addonforums/viewtopic.php?f=8&t=11345
Unfortunately, I could not really translate this to the SimpleRenderable case. I've tried using smi.Current.CreateMovableObject(), but this requires a second type argument, which I couldn't get right (tried "SimpleRenderable" and such). This code is very likely to be wrong, so if anyone can comment on this, that would be great.
Part 2/2: DynamicLines:
Questions/remarks about 2/2: DynamicLines:
1. About DynamicLines() constructor
I had to uncomment SetMaterial(matname), as it crashed the application (nothing in Ogre.log). I'm sure the material by the given name exists. Maybe my not being able to assign a material could explain a lot towards nothing being visible on the screen, I don't know (my axes are visible, though).
2. About fillHardwareBuffers()
The code to copy the vertex data to the buffer was kindly provided by this post:
http://www.ogre3d.org/addonforums/viewtopic.php?f=8&t=8354&p=48568&hilit=HardwareBufferManager#p48568
I've hardcoded the size of float to be 4 (I'm on a 32-bit machine).
The usage of this class can be summarized as follows:
Like I said, everything seems to be working, but nothing gets rendered on the screen.
If anybody has any experience with this, or any ideas what could be wrong/improved in this code, I'd be very happy to hear from you.
Cheers,
g
I've been trying to make a class that can render lines in Ogre. There are 2 interesting tutorials about this on the wiki:
http://www.ogre3d.org/wiki/index.php/DynamicGrowingBuffers
http://www.ogre3d.org/wiki/index.php/DynamicLineDrawing
These appear to provide a solution to my problem, but they're in C++. I've been trying to 'translate' these into C#, but I can't seem to get it to work. Well, it compiles and it runs, but nothing gets rendered.
Two classes need to be definded: DynamicRenderable (extends SimpleRenderable) and DynamicLines (extends DynamicRenderable). This what I have so far:
Part 1/2: DynamicRenderable:
public partial class DynamicRenderable : SimpleRenderable
{
public RenderOperation rop;
protected uint mVertexBufferCapacity;
protected uint mIndexBufferCapacity;
public RenderOperation RenderOperation { get { return rop; } set { rop = value; } }
public virtual void createVertexDeclaration() { }
public unsafe DynamicRenderable(string name)
: base(null)
{
using (SceneManagerEnumerator.SceneManagerIterator smi = Root.Singleton.GetSceneManagerIterator())
{
smi.MoveNext();
ManualObject dummyObject = smi.Current.CreateManualObject(name);
typeof(SimpleRenderable).GetField("_native", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, (IntPtr)dummyObject.NativePtr);
}
}
public void initialize(RenderOperation.OperationTypes rtype, bool useIndices)
{
rop = new RenderOperation();
SetRenderOperation(rop);
rop.operationType = rtype;
rop.useIndexes = useIndices;
rop.vertexData = new VertexData();
if (useIndices) rop.indexData = new IndexData();
mVertexBufferCapacity = 0;
mIndexBufferCapacity = 0;
createVertexDeclaration();
}
public void prepareHardwareBuffers(uint vertexCount, uint indexCount)
{
// Prepare vertex buffer
uint newVertCapacity = mVertexBufferCapacity;
if ((vertexCount > mVertexBufferCapacity) ||
(mVertexBufferCapacity == 0))
{
// vertexCount exceeds current capacity!
// It is necessary to reallocate the buffer.
// Check if this is the first call
if (newVertCapacity == 0)
newVertCapacity = 1;
// Make capacity the next power of two
while (newVertCapacity < vertexCount)
newVertCapacity <<= 1;
}
else if (vertexCount < mVertexBufferCapacity >> 1)
{
// Make capacity the previous power of two
while (vertexCount < newVertCapacity >> 1)
newVertCapacity >>= 1;
}
if (newVertCapacity != mVertexBufferCapacity)
{
mVertexBufferCapacity = newVertCapacity;
// Create new vertex buffer
HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager.Singleton.CreateVertexBuffer
(rop.vertexData.vertexDeclaration.GetVertexSize(0), mVertexBufferCapacity,
HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); // TODO: Custom HBU_?
// Bind buffer
rop.vertexData.vertexBufferBinding.SetBinding(0, vbuf);
}
// Update vertex count in the render operation
rop.vertexData.vertexCount = vertexCount;
if (rop.useIndexes)
{
//OgreAssert(indexCount <= std::numeric_limits<unsigned short>::max(), "indexCount exceeds 16 bit");
uint newIndexCapacity = mIndexBufferCapacity;
// Prepare index buffer
if ((indexCount > newIndexCapacity) ||
(newIndexCapacity == 0))
{
// indexCount exceeds current capacity!
// It is necessary to reallocate the buffer.
// Check if this is the first call
if (newIndexCapacity == 0)
newIndexCapacity = 1;
// Make capacity the next power of two
while (newIndexCapacity < indexCount)
newIndexCapacity <<= 1;
}
else if (indexCount < newIndexCapacity >> 1)
{
// Make capacity the previous power of two
while (indexCount < newIndexCapacity >> 1)
newIndexCapacity >>= 1;
}
if (newIndexCapacity != mIndexBufferCapacity)
{
mIndexBufferCapacity = newIndexCapacity;
// Create new index buffer
rop.indexData.indexBuffer = HardwareBufferManager.Singleton.CreateIndexBuffer(HardwareIndexBuffer.IndexType.IT_16BIT, mIndexBufferCapacity, HardwareBuffer.Usage.HBU_DYNAMIC_WRITE_ONLY);
}
// Update index count in the render operation
rop.indexData.indexCount = indexCount;
}
}
public float getBoundingRadius()
{
float sl = BoundingBox.Maximum.SquaredLength;
if (sl < BoundingBox.Minimum.SquaredLength) sl = BoundingBox.Minimum.SquaredLength;
return Mogre.Math.Sqrt(sl);
}
public float getSquaredViewDepth(Camera cam)
{
Vector3 vMin, vMax, vMid, vDist;
vMin = BoundingBox.Minimum;
vMax = BoundingBox.Maximum;
vMid = ((vMax - vMin) * 0.5f) + vMin;
vDist = cam.DerivedPosition - vMid;
return vDist.SquaredLength;
}
}
Questions/remarks about Part 1/2: DynamicRenderable:
1. About class DynamicRenderable : SimpleRenderable
It seems a bit strange that I have to keep my own RenderOperation property. I don't quite understand how SimpleRenderable.GetRenderOperation(RenderOperation op) is supposed to work. Or does it copy it's values to the RenderOperation argument?
2. About DynamicRenderable(string name) constructor
This is a hack I found in this post:
http://www.ogre3d.org/addonforums/viewtopic.php?f=8&t=11345
Unfortunately, I could not really translate this to the SimpleRenderable case. I've tried using smi.Current.CreateMovableObject(), but this requires a second type argument, which I couldn't get right (tried "SimpleRenderable" and such). This code is very likely to be wrong, so if anyone can comment on this, that would be great.
Part 2/2: DynamicLines:
public partial class DynamicLines : DynamicRenderable
{
public bool mDirty;
public ArrayList ALPoints;
public DynamicLines(RenderOperation.OperationTypes rtype, string matname, string name)
: base(name)
{
initialize(rtype, false);
//SetMaterial(matname);
mDirty = true;
ALPoints = new ArrayList();
}
public void addPoint(Vector3 p)
{
ALPoints.Add(p);
mDirty = true;
}
public void addPoint(float x, float y, float z)
{
ALPoints.Add(new Vector3(x, y, z));
mDirty = true;
}
public void Clear()
{
ALPoints = new ArrayList();
mDirty = true;
}
public void Update()
{
if (mDirty) fillHardwareBuffers();
}
public override void createVertexDeclaration()
{
rop.vertexData.vertexDeclaration.AddElement(0, 0, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION);
}
public float[] FloatArray
{
get
{
float[] rvfa = new float[3 * ALPoints.Count];
Vector3 cv3;
int i3;
for (int i = 0; i < ALPoints.Count; i++)
{
cv3 = (Vector3)ALPoints[i];
i3 = 3*i;
rvfa[i3] = cv3.x;
rvfa[i3+1] = cv3.y;
rvfa[i3+2] = cv3.z;
}
return rvfa;
}
}
public void fillHardwareBuffers()
{
uint size = (uint)ALPoints.Count;
prepareHardwareBuffers(size, 0);
if (size == 0)
{
BoundingBox.SetExtents(Vector3.ZERO, Vector3.ZERO);
mDirty = false;
return;
}
Vector3 vaabMin = (Vector3)ALPoints[0];
Vector3 vaabMax = (Vector3)ALPoints[0];
HardwareVertexBufferSharedPtr vbuf =
RenderOperation.vertexData.vertexBufferBinding.GetBuffer(0);
float[] vertices = FloatArray;
unsafe
{
void* voidPtr;
fixed (float* floatPtr = vertices)
{
voidPtr = floatPtr;
vbuf.WriteData(0, (uint)vertices.Length*4, voidPtr, true);
}
}
Vector3 cv3;
for (int i = 0; i < size; i++)
{
cv3 = (Vector3)ALPoints[i];
if (cv3.x < vaabMin.x) vaabMin.x = cv3.x;
if (cv3.y < vaabMin.y) vaabMin.y = cv3.y;
if (cv3.z < vaabMin.z) vaabMin.z = cv3.z;
if (cv3.x > vaabMax.x) vaabMax.x = cv3.x;
if (cv3.y > vaabMax.y) vaabMax.y = cv3.y;
if (cv3.z > vaabMax.z) vaabMax.z = cv3.z;
}
BoundingBox.SetExtents(vaabMin, vaabMax);
mDirty = false;
}
}
Questions/remarks about 2/2: DynamicLines:
1. About DynamicLines() constructor
I had to uncomment SetMaterial(matname), as it crashed the application (nothing in Ogre.log). I'm sure the material by the given name exists. Maybe my not being able to assign a material could explain a lot towards nothing being visible on the screen, I don't know (my axes are visible, though).
2. About fillHardwareBuffers()
The code to copy the vertex data to the buffer was kindly provided by this post:
http://www.ogre3d.org/addonforums/viewtopic.php?f=8&t=8354&p=48568&hilit=HardwareBufferManager#p48568
I've hardcoded the size of float to be 4 (I'm on a 32-bit machine).
The usage of this class can be summarized as follows:
DynamicLines lines = new DynamicLines(RenderOperation.OperationTypes.OT_LINE_LIST, matname, entname);
foreach (Vector3 v3 in someArrayList) lines.addPoint(v3);
scenenode.AttachObject(lines);
lines.Update();
Like I said, everything seems to be working, but nothing gets rendered on the screen.
If anybody has any experience with this, or any ideas what could be wrong/improved in this code, I'd be very happy to hear from you.
Cheers,
g