Dynamic ManualObject - Performance Issue

Problems building or running the engine, queries about how to use features etc.
Post Reply
noche
Kobold
Posts: 29
Joined: Sun Apr 15, 2007 1:35 am

Dynamic ManualObject - Performance Issue

Post by noche »

Hello,

I'm using PhysX with Ogre.
PhysX comes with a nice debug renderering system.
One function call, and all the physical actors are renderer in wireframe.
But I need to implement a rendering interface. I use a ManualObject.

Code: Select all

DebugRenderer::DebugRenderer()
{
   ...
   _manualObject = sceneManager->createManualObject("ManualObject");
   _manualObject->setDynamic(true);
   _manualObject->estimateVertexCount(1000);
   _sceneNode->attachObject(_manualObject);
}
I clear and set the vertices position at every frame. The number of vertices is not static (physic actors can be added). So i cannot use beginUpdate.

Code: Select all

// the rendering method

void DebugRenderer::renderData(const NxDebugRenderable& data) const
{
  _manualObject->clear();

  NxU32 NbLines = data.getNbLines();
  const NxDebugLine* Lines = data.getLines();
  while(NbLines--)
  {
    _manualObject->begin("ManualObjectMaterial", RenderOperation::OT_LINE_LIST); 
    _manualObject->position(Lines->p0.x, Lines->p0.y, Lines->p0.z);
    _manualObject->position(Lines->p1.x, Lines->p1.y, Lines->p1.z);
    _manualObject->end();
     Lines++;
  }
}
It seems to be very expensive.
In debug the FPS pass from 160 to 8, with only 90 lines to render.

Is there any faster way to do this ?
User avatar
HexiDave
OGRE Expert User
OGRE Expert User
Posts: 1538
Joined: Sat Jan 14, 2006 8:00 pm
x 1

Post by HexiDave »

Since it's attached to a SceneNode, don't re-render all the vertices, just move the ManualObject with it as you transform. If you MUST re-do the vertices every frame, then, ya, your frame rate WILL die. It's just how the render system works. Ogre likes batches, so you generally don't want to feed it tons of little bits of lines every single frame.

You shouldn't be adjusting the vertices unless the vertices of your physics object changes. Just do all the transforms for your physics object (say if it rotates and translates) to your SceneNode containing each physics object's ManualObject.
noche
Kobold
Posts: 29
Joined: Sun Apr 15, 2007 1:35 am

Post by noche »

You shouldn't be adjusting the vertices unless the vertices of your physics object changes. Just do all the transforms for your physics object (say if it rotates and translates) to your SceneNode containing each physics object's ManualObject.
I'm not sure you understood the issue. I'll try to re-explain.

PhysX (Novodex) provide a way to render the physic scene and internal data. Its very usefull, since you can visualize all the physical actor shapes, the actor axis, the collision contact points, ect. They provide something independant from the rendering system (which could be OpengGL, DirectX, Ogre, ...)

So they only provide a list of Point, Lines, and Triangles (in a NxDebugRenderable strucutre). The physic engine fill this structure according to the present actor, the collisions, etc. It's the job of the application to tell how to render this structure.

For exemple, using OpenGL it would look like this :

Code: Select all

void DebugRenderer::renderData(const NxDebugRenderable& data) const
{
    glLineWidth(1.0f);
    glPushMatrix();
    glDisable(GL_LIGHTING);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Render lines
    NxU32 NbLines = data.getNbLines();
    if(NbLines)
    {
        const NxDebugLine* Lines = data.getLines();

        glBegin(GL_LINES);
        while(NbLines--)
        {
            setupColor(Lines->color);
            glVertex3fv(&Lines->p0.x);
            glVertex3fv(&Lines->p1.x);
            Lines++;
        }
        glEnd();
    }
This code is a lot faster than a Ogre ManualObject version (in my post).
Is there anyway to get the same performances ?

I dont know what the ManualObject is excalty doing during clear() and begin() end(). (I will check)
Maybe he is building vertex indices, optimizing the structure for a fast rendering. Mayve they considered that vertices will not be cleared every frame. But I think it would be nice to have a mode which would consume very little processing during the vertices building (as OpenGL) and would cost a little more during the rendering.
P
OGRE Expert User
OGRE Expert User
Posts: 421
Joined: Fri Jan 07, 2005 9:49 pm
Location: UK
x 2
Contact:

Post by P »

You could create a Mesh directly, it would be faster.
noche
Kobold
Posts: 29
Joined: Sun Apr 15, 2007 1:35 am

Post by noche »

I'll try that.
Thanks.
JeDi
Gnome
Posts: 351
Joined: Thu Oct 21, 2004 1:34 pm
Location: Diepenbeek, Belgium
x 3
Contact:

Post by JeDi »

Actually, it works pretty good with manual objects, you just have to use them correctly. Ogre creates a render operation for each begin/end pair, and you are creating one for each line. That's really expensive.

And you can grow/shrink the number of vertices while updating dynamic manual objects, you just can't change the render operations. That works perfectly here, as you should create three manual object segments: one for the points, one for the lines and one for the triangles.

So at initialization of you debug renderer class, you should do something like this (m_pObject is your manual object):

Code: Select all

	// Create the 3 render types (will be filled in each frame)
	m_pObject->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_POINT_LIST);
	m_pObject->end();
	m_pObject->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST);
	m_pObject->end();
	m_pObject->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST);
	m_pObject->end();
Then your renderData function:

Code: Select all

void DebugRenderer::renderData(const NxDebugRenderable &data) const
{
	// Calculate the total number of vertices
	unsigned int numVertices = data.getNbPoints();
	numVertices += data.getNbLines() * 2;
	numVertices += data.getNbTriangles() * 3;
	m_pObject->estimateVertexCount(numVertices);

	// Debug points
	m_pObject->beginUpdate(0);
	for(unsigned int i = 0; i < data.getNbPoints(); ++i)
	{
		const NxVec3 &pos = data.getPoints()[i].p;
		m_pObject->position(pos[0], pos[1], pos[2]);

		float r,g,b;
		convertColor(data.getPoints()[i].color, r,g,b);
		m_pObject->colour(r,g,b);
	}
	m_pObject->end();

	// Debug lines
	m_pObject->beginUpdate(1);
	for(unsigned int i = 0; i < data.getNbLines(); ++i)
	{
		// Get the line color (same for both vertices)
		float r,g,b;
		convertColor(data.getLines()[i].color, r,g,b);

		const NxVec3 &pos1 = data.getLines()[i].p0;
		m_pObject->position(pos1[0], pos1[1], pos1[2]);
		m_pObject->colour(r,g,b);

		const NxVec3 &pos2 = data.getLines()[i].p1;
		m_pObject->position(pos2[0], pos2[1], pos2[2]);
		m_pObject->colour(r,g,b);
	}
	m_pObject->end();

	// Debug triangles
	m_pObject->beginUpdate(2);
	for(unsigned int i = 0; i < data.getNbTriangles(); ++i)
	{
		// Get the triangle color (same for all three vertices)
		float r,g,b;
		convertColor(data.getTriangles()[i].color, r,g,b);

		const NxVec3 &pos1 = data.getTriangles()[i].p0;
		m_pObject->position(pos1[0], pos1[1], pos1[2]);
		m_pObject->colour(r,g,b);

		const NxVec3 &pos2 = data.getTriangles()[i].p1;
		m_pObject->position(pos2[0], pos2[1], pos2[2]);
		m_pObject->colour(r,g,b);

		const NxVec3 &pos3 = data.getTriangles()[i].p2;
		m_pObject->position(pos3[0], pos3[1], pos3[2]);
		m_pObject->colour(r,g,b);
	}
	m_pObject->end();
}
As you can see, this only generates three batches, which is a whole lot more efficient than what you were doing. I'm not sure about the estimateVertexCount though, it could be that that belongs inside each batch (so for points, lines and triangles seperate and inside the beginUpdate/end parts).

Good luck!

Greetz,
JeDi
JeDi
Gnome
Posts: 351
Joined: Thu Oct 21, 2004 1:34 pm
Location: Diepenbeek, Belgium
x 3
Contact:

Post by JeDi »

Actually, I just tried this, and it doesn't work because we can't create empty manual object sections like we do. So you use a hack such as inserting one random element in the initialization. Or you could hold a boolean whether it is the first time you are in the renderData function.
noche
Kobold
Posts: 29
Joined: Sun Apr 15, 2007 1:35 am

Post by noche »

Thanks a lot, its working fine this way :). At least for performance.
I dont get any colors on my lines.
Do you have any idea ?

Thanks again and sorry for the delay.
JeDi
Gnome
Posts: 351
Joined: Thu Oct 21, 2004 1:34 pm
Location: Diepenbeek, Belgium
x 3
Contact:

Post by JeDi »

Well, with the code above you should have colors, if you are using the same material. BaseWhiteNoLighting has no lighting enabled, so the vertex colours are used. Otherwise, I have no idea. I don't have much experience in lighting issues.

Greetz, and good luck!
JeDi
Post Reply