Custom Meshes: completely confused

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Custom Meshes: completely confused

Post by primem0ver »

Hello everyone,
When I first decided to use Irrlicht for my project I used the information in the "Custom SceneNode" tutorial to design some basic meshes to be used by the engine I am developing. Now it seems I was barking up the wrong tree because this tutorial doesn't seem to be consistent with creating meshes using IMeshSceneNode. Furthermore, I am rather confused by some of the features of IMeshSceneNodes and my inability to alter the material for a mesh. So I am going to explain a bit about myself and my project, then present some examples of what I have so far for feedback on my misconceptions and what I am doing wrong so that I can fix it.

First: I am new to working with graphics engines so please forgive my ignorance in what are probably commonplace approaches to doing things. In all my previous work (which isn't small) I have dealt with DirectX directly using primitives and rendering things by hand. So some of these features seem counter intuitive to what I am used to.

Second: My project is completely plugin based. It is a platform designed so that plugins can be built by authoring software. Everything that is drawn by the engine is defined using XML (and files pointed to in the XML). All components. This includes meshes, textures, materials, lights, cameras, billboards, panels, ui components, custom colors, as well as the objects and scenes that use all these pieces.

Now that you know a bit about the project, lets get into my confusion. I have 3 types of meshes defined in xml:
  1. Static Meshes - meshes and/or animated meshes that are defined in a file created in a 3D authoring tool (such as Blender, 3D Max, Maya, etc...). They are "static" because they do not change according to XML parameters.
    Coded Meshes - meshes that are completely customized using code; they are unique to a specific plugin and intentionally hard-coded (for whatever reason) by the plugin developer.
    Dynamic Meshes - meshes that are familiar and generic in nature (such as a sphere, box, pyramid, etc...) and can be defined using a consistent set of parameters.
Coded and Dynamic meshes are "custom" meshes. These meshes must support dynamic material assignments; including the changing of those materials once they are in the scene. I could do this when I was using DirectX. In addition, the custom scene node tutorial (using ISceneNode to create a few basic meshes) seems to suggest that arbitrarily assigning materials is fine because that assignment can be done during the override of the Render method.

However, IMeshSceneNode seems incompatible with this approach. My biggest problem with the IMeshSceneNode is that it does not seem that I can arbitrarily change the materials. Furthermore, the IMesh on which this class seems to be based has mesh buffers that are dependent on a material... Example:

Code: Select all

virtual IMeshBuffer * getMeshBuffer (const video::SMaterial &material) const =0
I am lost with this concept. I thought materials were applied to meshes not the other way around. Why would only one mesh buffer (assumed to be a set of triangles to be drawn) "fit" a material when texture coordinates are arbitrary? Or is this simply to find the buffer that has been assigned to a specific material? What if more than one buffer is assigned to that material? (For example, the four tires on a car).

Those are my basic questions I would like to start with. Next comes turning the classes I created using the tutorial into the classes that are compatible with the IMeshSceneNode class.

Here is an example of a "dynamic mesh" that I created based on the "Custom Scene Node" tutorial and the set of classes it relies on. I will work to figure this out myself once I understand the things above but just in case anyone will offer advice... how would I change this setup so that it is consistent with the IMeshSceneNode structure/interface?

First.. by basic "mesh" (node) class:

Code: Select all

class VRMesh : public ISceneNode
{
enum VRMeshType { TwoDimensional, Planar, ThreeDimensional };
public:
    VRMesh(ISceneManager* manager, ISceneNode* parent = 0, int id = -1);
    virtual ~VRMesh();
 
public /*virtual*/:
    virtual const core::aabbox3d<f32>& getBoundingBox() const override;
 
public /*abstract*/:
    virtual VRMeshType vrMeshType() = 0;
 
protected:
    core::aabbox3d<f32> mBox;
 
};
My class used for 3 dimensional meshes (as opposed to 2 dimensional/planar objects such as circles, squares, etc...)

Code: Select all

class _3DMesh : public VRMesh
{
public:
    _3DMesh(ISceneManager* manager, ISceneNode* parent = 0, int id = -1);
    virtual ~_3DMesh();
 
    void resposition(vector3df* vertexArray, const int vertexCount, PositioningFlags3D alignmentPolicy);
    void resposition(video::S3DVertex* vertexArray, const int vertexCount, PositioningFlags3D alignmentPolicy);
 
public /*override*/:
    inline VRMeshType vrMeshType() override; 
};
inline VRMeshType _3DMesh::vrMeshType() { return VRMeshType::ThreeDimensional; }
My 3D mesh using the standard vertex type

Code: Select all

class Standard3DMesh : public _3DMesh
{
public:
    Standard3DMesh(ObjectInfo* info, ISceneManager* manager, ISceneNode* parent = 0, int id = -1);
    virtual ~Standard3DMesh();
 
    SMaterial* material() const;
    void setMaterial(SMaterial* material);
 
protected:
    video::S3DVertex* mVertexArray;
    SMaterial* mMaterial;
};
Now for my example mesh. Here is the class header:

Code: Select all

class SingleTexturedSphere : public Standard3DMesh
{
public:
    SingleTexturedSphere(ObjectInfo* info, ISceneManager* manager, ISceneNode* parent = NULL, int id = -1, const vector3df& position = vector3df(0.0f, 0.0f, 0.0f), 
        PositioningFlags3D alignmentPolicy = PositioningFlags3D(PositioningPolicy3D::centered, PositioningPolicy3D::centered, PositioningPolicy3D::centered));
    virtual ~SingleTexturedSphere();
 
public /*overrides*/:
    virtual void OnRegisterSceneNode() override;
    virtual void render() override;
 
private /*fields*/:
    unsigned short* mIndices;
    int mSlices;
    int mWedges;
    int mVertexCount;
    int mIndexCount;
    S3DVertex mCenterVertex;
    float mRadius;
    void createSphereVertices(ObjectInfo* info, PositioningFlags3D alignmentPolicy);
    inline vector2df getTextureCoordinates(ObjectInfo* info, int faceIndex);
}; 
Here is the code file to give you a basic idea of how the xml is used to create the objects. This method is called from a method in the ObjectInfo class used to create the node. This ObjectInfo class method then sets the material and texture based on the XML stored in the a private class that handles that aspect of the object. Materials on dynamic meshes must be changeable in order for certain effects to be allowable (including the user picking a different texture for the object)

Code: Select all

SingleTexturedSphere::SingleTexturedSphere(ObjectInfo* info, ISceneManager* manager, ISceneNode* parent, int id, const vector3df& position, PositioningFlags3D alignmentPolicy) :
    Standard3DMesh(info, manager, parent, id),
    mSlices(8),
    mWedges(8),
    mRadius(1.0f)
    //mMaterial(info->
{
    DynamicMesh* meshInfo = static_cast<DynamicMesh*>(info->getMesh());
 
    if (meshInfo)
    {
        mRadius = meshInfo->getFloatParameter("radius");
        if (mRadius == FLT_MAX)
            mRadius = 1.0f;
 
        mWedges = meshInfo->getIntParameter("wedges");
        if (mWedges == INT_MAX)
            mWedges = 8;
        
        mSlices = meshInfo->getIntParameter("slices");
        if (mSlices == INT_MAX)
            mSlices = 8;
    }
 
    createSphereVertices(info, alignmentPolicy);
}
 
SingleTexturedSphere::~SingleTexturedSphere()
{
    delete [] mVertexArray;
    delete [] mIndices;
}
 
void SingleTexturedSphere::createSphereVertices(ObjectInfo* info, PositioningFlags3D alignmentPolicy)
{
    mCenterVertex.Pos.set(mRadius, mRadius, mRadius);
    vector3df northpole(mRadius, 2 * mRadius, mRadius);
    vector3df southpole(mRadius, 0.0f, mRadius);
    //float uYDelta = PI / (float)mSlices;
    //float uYOffset = 1.0f;
    float tDelta = PI / (float)mSlices;
    float theta;
    float omega = 0.0f;
    float oDelta = 2 * PI / mWedges;
 
    mVertexCount = (mSlices + 1) * (mWedges + 1);
    mVertexArray = new S3DVertex[mVertexCount];
    mIndexCount = 6 * (mSlices - 1) * mWedges;
    mIndices = new unsigned short[mIndexCount];
    
    int vIndex = 0;
    int iIndex = 0;
    int verticesPerWedgeLine = mSlices + 1;
    float tFactorY = 1.0f / mWedges;
    //int slicePos = mSlices - 1;
 
    // ALL WEDGES EXCEPT LAST ONE
    for (int i = 0; i < mWedges; ++i)
    {
        theta = 0.0f;
 
        for (int j = 0; j <= mSlices; ++j)
        {
            // determine coordinates and texture coordinates
            if (j == 0)
            {
                mVertexArray[vIndex].Pos.set(northpole);
                mVertexArray[vIndex].TCoords.set(mWedges * i, 0.0f);
            }
            else if (j == mSlices)
            {
                mVertexArray[vIndex].Pos.set(southpole);
                mVertexArray[vIndex].TCoords.set(mWedges * i, 1.0f);
            }
            else
            {
                mVertexArray[vIndex].Pos.set(
                    mRadius * sinf(theta) * cosf(omega),
                    mRadius * cosf(theta),
                    mRadius * sinf(theta) * sinf(omega));
                mVertexArray[vIndex].TCoords.set(mWedges * i, 0.5f - (0.5f * cosf(theta))); // attempts equal area grid
            }
 
            // figure out next index set
            if (i > 0)
            {
                if (j == 1)
                {
                    mIndices[iIndex] = vIndex - 1;
                    mIndices[iIndex + 1] = vIndex;
                    mIndices[iIndex + 2] = vIndex - verticesPerWedgeLine;
                    iIndex += 3;
                }
                else if (j == mSlices)
                {
                    mIndices[iIndex] = vIndex - verticesPerWedgeLine - 1;
                    mIndices[iIndex + 1] = vIndex - 1;
                    mIndices[iIndex + 2] = vIndex;
                    iIndex += 3;
                }
                else
                {
                    mIndices[iIndex] = vIndex - verticesPerWedgeLine - 1;
                    mIndices[iIndex + 1] = vIndex;
                    mIndices[iIndex + 2] = vIndex - verticesPerWedgeLine;
                    mIndices[iIndex + 3] = vIndex - verticesPerWedgeLine - 1;;
                    mIndices[iIndex + 4] = vIndex - 1;
                    mIndices[iIndex + 5] = vIndex;
                    iIndex += 6;
                }
            }
 
            mVertexArray[vIndex].Normal.set(mVertexArray[vIndex].Pos.normalize());
            ++vIndex;
            theta += tDelta;
        }
        omega += oDelta;
    }
 
    // figure out last wedge
    theta = 0.0f;
 
    for (int j = 0; j <= mSlices; ++j)
    {
        mVertexArray[vIndex].Pos.set(mVertexArray[j].Pos);
 
        if (j == 1)
        {
            mIndices[iIndex] = vIndex - 1;
            mIndices[iIndex + 1] = vIndex;
            mIndices[iIndex + 2] = vIndex - verticesPerWedgeLine;
            iIndex += 3;
        }
        else if (j == mSlices)
        {
            mIndices[iIndex] = vIndex - verticesPerWedgeLine - 1;
            mIndices[iIndex + 1] = vIndex - 1;
            mIndices[iIndex + 2] = vIndex;
            iIndex += 3;
        }
        else
        {
            mIndices[iIndex] = vIndex - verticesPerWedgeLine - 1;
            mIndices[iIndex + 1] = vIndex;
            mIndices[iIndex + 2] = vIndex - verticesPerWedgeLine;
            mIndices[iIndex + 3] = vIndex - verticesPerWedgeLine - 1;;
            mIndices[iIndex + 4] = vIndex - 1;
            mIndices[iIndex + 5] = vIndex;
            iIndex += 6;
        }
 
        mVertexArray[vIndex].Normal.set(mVertexArray[vIndex].Pos.normalize());
        ++vIndex;
        theta += tDelta;
    }
 
    // apply the alignment policy
    this->resposition(mVertexArray, mVertexCount, alignmentPolicy);
 
    // create bounding box
    mBox.reset(mCenterVertex.Pos);
    for (int i = 0; i < mVertexCount; ++i)
        mBox.addInternalPoint(mVertexArray[i].Pos);
}
 
void SingleTexturedSphere::OnRegisterSceneNode()
{
    if (IsVisible)
        SceneManager->registerNodeForRendering(this);
 
    ISceneNode::OnRegisterSceneNode();
}
 
void SingleTexturedSphere::render()
{
    video::IVideoDriver* driver = SceneManager->getVideoDriver();
    driver->setMaterial(*mMaterial);
    driver->drawIndexedTriangleList(mVertexArray, mVertexCount, mIndices, mIndexCount / 3);
}
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Meshes: completely confused

Post by CuteAlien »

First maybe do a quick check about terminology in Irrlicht, see here: http://irrlicht3d.org/wiki/index.php?n= ... ommonTerms
I just mention it because if you derive a "mesh" from a scenenode - that's somewhat mixing the terminology and probably just adds to the confusion.

You are right that each meshbuffer has one material. But think of that material as the default material. When you create a node that materials is by copied and so each node has it's own material-copies which you can modify. So the same mesh can have new materials for each node. You can also disabled that copying of materials and always use the default-mesh by settting IMeshSceneNode::setReadOnlyMaterials(true). Then the nodes no longer have material copies and instead use the meshbuffer materials directly. Depending on which solution you decide on you have to either change scenenode-materials or mesh-materials to see a change.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: Custom Meshes: completely confused

Post by primem0ver »

So basically if I want to create my own custom IMeshSceneNode I would need to create a custom IMesh that makes use of at least one custom IMeshBuffer? And override all of the pure virtual functions?
I still don't see a way to set the material of either one of these objects. How does the SMaterial get defined? How do I assign a material to a mesh, or at least a part of a mesh?

Another thing I don't understand is why is the included sphere mesh an IAnimatedMesh when it doesn't have any moving parts? Is revolving an object considered an "animation"? Is there any starting point to understanding the conceptual framework/design of the classes?

Since all materials are defined in XML and those materials can change dynamically depending on plugin settings, sliders, and choices made by users, I need all objects that use a material to point to the original copy of the material.

Here is an example of why it must be done this way. In the advanced help section I posted this topic on custom lights and scene rendering. I used a sun as an example as a "custom light type". This is used in a basic plugin I am creating as a proof of concept (for what I am building). The user can change the temperature of the sun. This changes the size, mass, and the color of the star. In the XML, a color used in a plugin can be set as dynamic. In this particular case, the color object whose name is SUN_COLOR is set as dynamic. This means that every material that uses SUN_COLOR must be updated with the new color when the color changes. All material objects that use this material MUST make use of a pointer to the original material. Otherwise it becomes a nightmare for both the developer and the user to deal with objects that require "dynamic" colors.

I know you spoke of the method of IMeshSceneNode::setReadOnlyMaterials(true). Would this ensure the above situation? Is there a way to manually assign the sun material (which is used to create an SMaterial) to a mesh?
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Custom Meshes: completely confused

Post by mongoose7 »

Why are you trying to add the colour of a light to a material? Suppose an object has the material "wood'. The light shines on the object, and the (diffuse) colour is

Code: Select all

wood*light-colour*factor
(where factor depends on the angle of incidence of the light on the object). So, 'wood' is stored in the material of the mesh buffer and 'light-colour' is stored in the light's properties.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Meshes: completely confused

Post by CuteAlien »

Maybe start by taking a look at the draw functions in IVideoDriver. Those are the lowest level in the engine and you can see they only need the S3DVertex structures (and a few parameters for the indices to those and sizes). If you render a scenegraph (aka IScenemanager::drawAll() it expects that the ISceneNode's it calls will send their data in some way to those IVideoDriver functions. In Irrlicht there are several scenenodes which don't work with meshes or meshbuffers at all, for example the skybox. But working with meshes and meshbuffers makes things generally easier.
primem0ver wrote:So basically if I want to create my own custom IMeshSceneNode I would need to create a custom IMesh that makes use of at least one custom IMeshBuffer? And override all of the pure virtual functions?
You probably don't need to create your own IMesh or IMeshBuffer. I suppose you can use SMesh directly in your case. So you only create your own ISceneNode. Or maybe even just a function to create a IMeshSceneNode where you fill in the mesh at creation (both solutions can be useful depending on the situation, custom scenenode adds some flexibility, but you don't always need them).
primem0ver wrote: I still don't see a way to set the material of either one of these objects. How does the SMaterial get defined? How do I assign a material to a mesh, or at least a part of a mesh?
For scenes you use ISceneNode::getMaterial(material_index) which returns a reference which you can then modify. For meshbuffers you use IMesh::getMeshBuffer(material_index)::getMaterial to access the material.
primem0ver wrote: Another thing I don't understand is why is the included sphere mesh an IAnimatedMesh when it doesn't have any moving parts? Is revolving an object considered an "animation"? Is there any starting point to understanding the conceptual framework/design of the classes?
I don't see that. CSphereSceneNode is derived from IMeshSceneNode and IGeometryCreator::createSphereMesh returns an IMesh*. What are you referring to exactly?
primem0ver wrote: Since all materials are defined in XML and those materials can change dynamically depending on plugin settings, sliders, and choices made by users, I need all objects that use a material to point to the original copy of the material.
<snip>
I know you spoke of the method of IMeshSceneNode::setReadOnlyMaterials(true). Would this ensure the above situation?
Yes - setReadOnlyMaterials would do that. But notice that in this case you will need a copy of the mesh for every scenenode in your scene which doesn't have the same material. That's why scenenodes generally override materials. So they can share the same geometry and just put different materials on them. Both are valid solutions - really depends on your application which one makes more sense. Note that if you override materials always in scenenodes then the SMaterial inside the meshbuffer wouldn't really be needed and just wastes some memory (but not that much so we don't care and it's an untypical case).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: Custom Meshes: completely confused

Post by primem0ver »

mongoose7 wrote:Why are you trying to add the colour of a light to a material? Suppose an object has the material "wood'. The light shines on the object, and the (diffuse) colour is

Code: Select all

wood*light-colour*factor
(where factor depends on the angle of incidence of the light on the object). So, 'wood' is stored in the material of the mesh buffer and 'light-colour' is stored in the light's properties.
Keep in mind that this is just an example. I originally wrote the plugin I am trying to create as an application with everything hard coded. It has been a number of years since that time but it just seemed to work better at the time. I wanted to make sure that it was easy to see the suns color being reflected off the planet. Regardless, the point is the same which is that the things that the user will do in plugins can affect the material in a number of different ways so the settings of those materials need to be easily accessed and changed.

CuteAlien wrote:Maybe start by taking a look at the draw functions in IVideoDriver. Those are the lowest level in the engine and you can see they only need the S3DVertex structures (and a few parameters for the indices to those and sizes). If you render a scenegraph (aka IScenemanager::drawAll() it expects that the ISceneNode's it calls will send their data in some way to those IVideoDriver functions. In Irrlicht there are several scenenodes which don't work with meshes or meshbuffers at all, for example the skybox. But working with meshes and meshbuffers makes things generally easier.
I realize that technically speaking the classes I currently have should work provided that I set things up correctly. However, I would still like to take advantage of the common model as much as possible so that I can take advantage of what Irrlicht has to offer and change things when I need too. I wish there was some sort of documentation on not only the purpose of each class/structure, but its relationship to other class/structures that work together to accomplish the task of creating a scene. I suppose that most people who use this engine already have experience with graphics engines and making use of them.

CuteAlien wrote: For scenes you use ISceneNode::getMaterial(material_index) which returns a reference which you can then modify. For meshbuffers you use IMesh::getMeshBuffer(material_index)::getMaterial to access the material.
I don't want to modify the material. I want to set it directly.

CuteAlien wrote:
primem0ver wrote: Another thing I don't understand is why is the included sphere mesh an IAnimatedMesh when it doesn't have any moving parts? Is revolving an object considered an "animation"? Is there any starting point to understanding the conceptual framework/design of the classes?
I don't see that. CSphereSceneNode is derived from IMeshSceneNode and IGeometryCreator::createSphereMesh returns an IMesh*. What are you referring to exactly?
I am talking about this function:

Code: Select all

virtual IAnimatedMesh* irr::scene::ISceneManager::addSphereMesh(...)
CuteAlien wrote:
primem0ver wrote:I know you spoke of the method of IMeshSceneNode::setReadOnlyMaterials(true). Would this ensure the above situation?
Yes - setReadOnlyMaterials would do that. But notice that in this case you will need a copy of the mesh for every scenenode in your scene which doesn't have the same material. That's why scenenodes generally override materials. So they can share the same geometry and just put different materials on them. Both are valid solutions - really depends on your application which one makes more sense. Note that if you override materials always in scenenodes then the SMaterial inside the meshbuffer wouldn't really be needed and just wastes some memory (but not that much so we don't care and it's an untypical case).
Ok. well I can work with both situations then. However, this brings up another question. I often add nodes that use the same exact mesh. When I did this in Direct X, I would simply draw the same mesh at each location (without making copies of the mesh). Does it work like this in Irrlicht?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Custom Meshes: completely confused

Post by CuteAlien »

primem0ver wrote:
CuteAlien wrote: For scenes you use ISceneNode::getMaterial(material_index) which returns a reference which you can then modify. For meshbuffers you use IMesh::getMeshBuffer(material_index)::getMaterial to access the material.
I don't want to modify the material. I want to set it directly.
I fail to see the difference between modifying and setting a material. Do something like "myNode()->getMaterial(0) = myOwnMaterial;" and you set it (and modify it... it's really the same).
primem0ver wrote:I am talking about this function:

Code: Select all

virtual IAnimatedMesh* irr::scene::ISceneManager::addSphereMesh(...)
Sorry, I didn't know that function existed. Basically a design decision - all named meshes (aka those in the mesh-cache) are animated meshes. Static meshes are just animated meshes with 1 frame. I guess the advantage was to simplify handling. That way a call to getMesh() just works - people don't have to care what kind of mesh the format really has. Also if I remember correctly the animated mesh wasn't derived from the non-animated meshes a few years ago and that was just changed later on. But guessing here - that design was made years before I joined the engine. Disadvantage is that as soon as you want named meshes you have to create an animated mesh (but not complicated - just look at that implementation).
primem0ver wrote:Ok. well I can work with both situations then. However, this brings up another question. I often add nodes that use the same exact mesh. When I did this in Direct X, I would simply draw the same mesh at each location (without making copies of the mesh). Does it work like this in Irrlicht?
That's what meshes are. And drawing them then in different locations is what nodes are about. That is why nodes have that material copy by default so you can draw the exact same mesh in different locations without having to make copies.

You have to think about the difference between a mesh-format and a scene-format. If you only have meshes (and no positions etc) then you have geometry + 1 material set. Typical formats doing that are .X and .OBJ and a few more. Things like having the same mesh twice don't even make sense in that context as you have no positions yet.

That stuff only comes into play when you have a scene. In which case you can decide between sharing mesh-materials on different nodes or each node having it's own material. Irrlicht allows both with the mentioned readonlymaterial flag setting. Formats of that type are for example collada or .irr from irrEdit. In that case the mesh-material wouldn't really be needed, thought you still need the different meshbuffers as each material needs it's own meshbuffer. But for a pure scene-format you wouldn't need the SMaterial inside a meshbuffer. And from your posts so far I guess that is what you want. Meaning - you want to have a sceneformat. So ignore the materials inside the meshbuffer (keep them uninitialized, they have sane defaults which bascially do nothing special) and overwrite them as soon as you create your scenenodes. And what you serialize is the scene in your case. Maybe you can even use the .irr format directly (I haven't worked with that yet, so I'm not too familiar, but it probably does exactly what you need - serializing the whole scene in xml and you can modify each attribute anytime and send the new serialization data to your nodes).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply