need help with some code based off the BezierPatch example

Problems building or running the engine, queries about how to use features etc.
Post Reply

How important is it to have alot of experience with a 3D api like DX before using Ogre?

Not important.
3
17%
somewhat usefull.
13
72%
nessicary
1
6%
crucial!
1
6%
 
Total votes: 18

TwistedMatrix
Gnoblar
Posts: 20
Joined: Tue Mar 04, 2003 5:15 am

need help with some code based off the BezierPatch example

Post by TwistedMatrix »

Hi, i'm still an extreme newbie but I'm trying to make some dynamic water based off of the BezierPatch example. My idea is to write a class that will encapsulate this dynamic water entity. I want to be able to define its size at initialization and change with its control points during runtime to create animated water/lava/whatever.

THe trouble is, I dont think I am understanding how the Geometry data is handled by the engine. My init routine just produces shards of polygons. Am I even going about this the right way?
thanks for the help.

Code: Select all

#include "ExampleApplication.h"



/*********************************************************************/
class WaterMesh
{
public:
	SceneNode* pNode;
	Entity* patchEntity;
	PatchSurface ps;

protected:
	GeometryData patchCtlPoints;

    struct PatchVertex {
        Real x, y, z;
        Real nx, ny, nz;
        Real u, v;
    };

public:
	WaterMesh(int numVertices) 
	{ 
		patchCtlPoints.pVertices = 0; 
		init(numVertices);
	}
	~WaterMesh() 
	{
        if (patchCtlPoints.pVertices)
            delete [] patchCtlPoints.pVertices;
    }
	
	/* numVertices must be a square number which is >=9
	   and a multiple of 3 (since polygons come in multiples of 3)
	*/
	void init( int numVertices )
	{
        // Create patch
        patchCtlPoints.hasColours = false;
        patchCtlPoints.hasNormals = true;
        patchCtlPoints.numTexCoords = 1;
        patchCtlPoints.numTexCoordDimensions[0] = 2;
        // Packed data
        patchCtlPoints.vertexStride = sizeof(Real) * 5;
        patchCtlPoints.normalStride = sizeof(Real) * 5;
        patchCtlPoints.texCoordStride[0] = sizeof(Real) * 6;
        
        patchCtlPoints.pVertices = (Real*)( new PatchVertex[numVertices] );
        patchCtlPoints.numVertices = numVertices;
        patchCtlPoints.pNormals = patchCtlPoints.pVertices + 3;
        patchCtlPoints.pTexCoords[0] = patchCtlPoints.pVertices + 6;

        /*** Space out x/z coordinates of Vertex control points ***/
        PatchVertex *pVert = (PatchVertex*)patchCtlPoints.pVertices;
		
		int side = (sqrt(numVertices)-1)/2;
		for (int z = -side; z < side; z++)
		{
			for (int x = -side; x < side; x++)
			{
				pVert->x = x*100; pVert->y = 0.0; pVert->z = z*100;
				pVert++;
			}
		}


		/*** Set up the face data ***/
		pVert = (PatchVertex*)patchCtlPoints.pVertices;

		for (int faces = 0; faces < (numVertices/3); faces++)
		{
			pVert->nx = -0.5; pVert->ny = 0.5; pVert->nz = 0.0;
			pVert->u = 0.0; pVert->v = 0.0;
			pVert++;
			pVert->nx = 0.0; pVert->ny = 0.5; pVert->nz = 0.0;
			pVert->u = 0.5; pVert->v = 0.0;
			pVert++;
			pVert->nx = 0.5; pVert->ny = 0.5; pVert->nz = 0.0;
			pVert->u = 1.0; pVert->v = 0.0;
			pVert++;
		}

        ps.defineSurface("Bezier1", patchCtlPoints, 3, PatchSurface::PST_BEZIER, 0, PatchSurface::VS_BOTH);
        ps.build();
	}

};



/*********************************************************************/

static WaterMesh* mWaterMesh;


// Listener class for frame updates
class myFrameListener : public ExampleFrameListener
{
public:
    myFrameListener(RenderWindow* win, Camera* cam)
        : ExampleFrameListener(win, cam) { }

    bool frameStarted(const FrameEvent& evt)
    {

        // Call superclass
        return ExampleFrameListener::frameStarted(evt);
    }
};



/*********************************************************************/
class myApplication : public ExampleApplication
{
public:
    myApplication() {}
	~myApplication() { delete mWaterMesh; }

protected:
    // Just override the mandatory create scene method
    void createScene(void)
    {
        // Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(1, 1, 1));

        // Create a light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setPosition(20,80,50);

/*		// and an entity (ogre cube)
        Entity *ent = mSceneMgr->createEntity("cube", "cube.mesh");
		ent->setMaterialName("Examples/OgreLogo");

		// Create a new node, attach the cube entity
		mCubeNode = static_cast<SceneNode*>(mSceneMgr->getRootSceneNode()->createChild());
		mCubeNode->attachObject(ent);
*/
		// Create a new Watermesh with 81 controll points	
		mWaterMesh= new WaterMesh( 81 );

        // Create entity based on patch
        mWaterMesh->patchEntity = mSceneMgr->createEntity("Entity1", "Bezier1");

        Material *pMat = (Material*)MaterialManager::getSingleton().create( "TextMat" );
        pMat->addTextureLayer( "Water02.jpg" );
        mWaterMesh->patchEntity->setMaterialName("TextMat");

        // Attach the entity to the root of the scene
		mWaterMesh->pNode = static_cast<SceneNode*>(mSceneMgr->getRootSceneNode()->createChild());
		mWaterMesh->pNode->attachObject(mWaterMesh->patchEntity);

        mCamera->setPosition(500,500, 1500);
        mCamera->lookAt(0,200,-300);
    }


    void createFrameListener(void)
    {
		// This is where we instantiate our own frame listener
        mFrameListener= new myFrameListener(mWindow, mCamera);
        mRoot->addFrameListener(mFrameListener);

    }

};
~ Twisted Matrix ~
User avatar
eru
Gnoblar
Posts: 13
Joined: Wed Jan 15, 2003 1:40 pm
Location: Amsterdam, NL

Post by eru »

The first problem I see is here:

Code: Select all

    int side = (sqrt(numVertices)-1)/2;
    for (int z = -side; z < side; z++)
    {
      for (int x = -side; x < side; x++)
      {
        pVert->x = x*100; pVert->y = 0.0; pVert->z = z*100;
        pVert++;
      }
    }
For numvertices=81, side is 4
Your loop doesn't exactly do what you want it to do - it traverses z and x in range -4..3, not -4..4. Hence, your 9x9 mesh looks really strange - first 64 vertices are set, while the others are random. Try using <= instead of <.

Another thing is:

Code: Select all

    ps.defineSurface("Bezier1", patchCtlPoints, 3, PatchSurface::PST_BEZIER, 0, PatchSurface::VS_BOTH);
    ps.build();
The #3 argument should be 9, as it is mesh width.

Other remarks:
- your texture will look really bad, as each tile will use the same texture coords - try to set U,V coordinates so the texture spans over whole mesh. Also, note that you don't set V coordinate.
- for water, you have to remember to define normals properly, if you don't do it, it will look really crappy
- using bezier algorithm for water calculation doesn't really make sense, since bezier calculation will take more time than most of the simple water algorithms (I don't know which one you want to choose). Moreover, using PatchSurface::build each frame may be painful, since it creates new Mesh each time you call it - big waste of time.
- your algorithm (after fixes) will not work properly for numVertices that are not the square of an odd number. It really makes more sense to define width/height of mesh than number of used points, as the latter may be misleading.
- WaterMesh class name is copyrighted by eru and used in Water sample :lol:

Remark - All my comments are based on watching the code, I don't have ogre here, so I couldn't test it.
TwistedMatrix
Gnoblar
Posts: 20
Joined: Tue Mar 04, 2003 5:15 am

Post by TwistedMatrix »

I bezier patches are not practical for this kind of thing what would be?

Is there a easy way I could just subdivide a plane and be able to play with the controll points?
~ Twisted Matrix ~
User avatar
eru
Gnoblar
Posts: 13
Joined: Wed Jan 15, 2003 1:40 pm
Location: Amsterdam, NL

Post by eru »

TwistedMatrix wrote:I bezier patches are not practical for this kind of thing what would be?

Is there a easy way I could just subdivide a plane and be able to play with the controll points?
I don't see a point of creating bezier patch for a thing like Water.
If you want to do per-vertex calculations anyway, why not doing water-algorithm calculation for it? it will be more accurate, and, depending on the water algorithm, may be even faster.

Besides, Bezier is control-points driven, and it's far from intuitive. Splines would do better (though possibly a bit slower) here.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

Just a warning: as previously advised GeometryData is going to change or be phased out in the next version in favour of structures using hardware vertex buffers, so don't get too attached to it :)
TwistedMatrix
Gnoblar
Posts: 20
Joined: Tue Mar 04, 2003 5:15 am

Post by TwistedMatrix »

ok thanks...
~ Twisted Matrix ~
User avatar
Antiarc
Greenskin
Posts: 120
Joined: Thu Jan 23, 2003 8:40 am
Contact:

Post by Antiarc »

I've hit a similar snag in my own work. I'm working on a bezier/bspline (I'm working on implementations for both) terrain scene manager, but I'm having trouble actually understanding how to build the geometry. I have zero experience with D3D/OGL, so I'm kinda flying by the seat of my pants. I'm trying to learn what I can from the existing scene managers, but it's not going as smoothly as I might like.

Can anyone post a quick hit-the-highlights summary of what needs to be done in terms of creating geometry dynamically? I can load a bezier data file and create a field of mathematical points easily enough, but I'm really having a difficult time translating them into visible geometry. Can anyone help me out?
User avatar
eru
Gnoblar
Posts: 13
Joined: Wed Jan 15, 2003 1:40 pm
Location: Amsterdam, NL

Post by eru »

Antiarc, I'll give it a shot. After all, both CubicMapping and Water samples do exactly that - dynamic mesh updating.

First remark - all things described below are basing on the old geometry interface. When the new one (HardwareVertexBuffers) comes, it will have to be changed.

First thing one has to know - there are three levels of defining geometry.

The lowest level is GeometryData - it describes the vertices. For each of the numVertices it stores its 3D position (in pVertices), normal vector (in pNormals), colour(in pColour) and texture coordinates(in pTexCoords - note here, a mesh can define multiple texture coordinates if one uses multiple texture layers). It is possible to use *stride fields, to pack full information about a single vertex into a handy structure (look at BezierPatch demo). Also, not all data has to be filled - look at has* fields. All of the (used) data arrays have to be manually allocated by the user.

The middle level is SubMesh - it describes faces. There are two important choices here.
The faces are described using GeometryData - here is the first choice one can make. If useSharedGeometry is false, the SubMesh uses vertices from its own geometry field. If it is true, the SubMesh uses a sharedGeometry defined in its parent Mesh class.
Knowing, which GeometryData we use, we define number of faces in numFaces field. Now we have to make the second choice.
If useTriStrips is not set, in faceVertexIndices we store 3*numFaces integers. Each three values describe one face. A single integer in this array is a number of vertex in used GeometryData.
If useTriStrips is set, in faceVertexIndices we store numFaces+2 integers. They describe numFaces faces, in such a way that indices 0..2 describe the first face, 1..3 - second, numFaces-1..numFaces+1 - the last one.
Remember about vertex orientation. In a default configuration anti-clockwise faces are visible, and clockwise are invisible (it may be changed in Material properties).
Note, that on SubMesh level we also can define materials (either directly here or via SubEntity that uses this SubMesh).

The top-most level is a Mesh. It is simply a collection of SubMeshes. Its additional function is that it may store GeometryData that is shared by multiple child SubMesh objects. Note, that some of the SubMeshes may use this geometry, and some not (yet there maybe only one shared geometry in a Mesh).

Note, that there is a direct relation between Entities and Meshes. When one compose an Entity based on a Mesh, it will have the same number of SubEntities as Mesh has SubMeshes.

Now, about often meshes updates.
First thing one has to think about is 'what do we want to change frequently?'. Various items may change:
- vertex positions - it is most often case
- vertex normals - when we change positions, it is often a very good idea to recalculate normals, if we don't do it, it will not look good
- texture coordinates - very often we may leave it
- colour values - we may also leave that unchanged
- face definitions - most of the time, it is also constant.

Calculating vertex positions is completely application-dependent. Normals can be either manually set or calculated basing on vertex positions. The first may be more accurate, the latter is automatic. An example of automatic calculation may be found at http://www.mimuw.edu.pl/~eru/ogre/perli ... eMapping.h. It is a bit improved version of the CubeMapping sample currently in CVS. Function calculateMeshNormals should work for all types of Mesh objects (yet it has to be tested).

For the details, look into BezierPatch, CubeMapping or Water code.

Note that in Ogre, before we go to HardwareVertexBuffers, it is very simple - changes done to a Mesh are seen immediately. With HVB some locking mechanism will be used, so it may get a bit more complicated.

[EDIT]One more thing - the visibility of an Entity is checked using its underyling Mesh's bounding box. If one creates/updates geometry, should call Mesh::_updateBounds() at the end. If one is sure, it's not necessary (like in Water demo - it doesn't make much difference), it may be omitted[/EDIT]
User avatar
Antiarc
Greenskin
Posts: 120
Joined: Thu Jan 23, 2003 8:40 am
Contact:

Post by Antiarc »

Awesome, eru, that was exactly what I needed. I had all the pieces - I just wasn't sure how they fit together. That has helped a TON.

Hopefully I can get this knocked out, now :D
Post Reply