Flow of the program and tutorial 7

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
RobinvK
Posts: 12
Joined: Thu Mar 10, 2011 1:22 pm

Flow of the program and tutorial 7

Post by RobinvK »

Hello everyone, I've been going through the tutorials on Irrlicht and I've read through what is currently there in the wiki. I've just gone through tutorial 7 for the third time, but I don't understand some of the parts in that tutorial. I also have some questions about how irrlicht goes through the code in general.

for my first question I'll use parts of the code of the very first tutorial:
startup

Code: Select all

#include <irrLicht/irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#pragma comment(lib, "Irrlicht.lib")

int main()
{

	IrrlichtDevice *device =
		createDevice( video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16,
			false, false, false, 0);

	if (!device)
		return 1;

	device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");

	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
From what I understand so far the following piece of code just connect a mesh to the pointer called 'mesh'. Nothing will actually be created yet. Is this correct?

Code: Select all

	IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
	if (!mesh)
	{
		device->drop();
		return 1;
	}

But I'm not really sure that I understand what happens in the following bit of code. I've tried to explain it in my own words, is the following correct?L

So 'node' is a pointer of the class IAnimatedMeshSceneNode. And when node gets created a function is called (addAnimatedMeshSceneNode). The node itself just holds information, but the function addAnimatedMeshSceneNode() is what actually puts the sydney mesh on the scene. from that function onward the mesh exists on the scene. You can't see it just yet because there is no camera and because the drawAll() function has not been called yet by smgr.

Code: Select all

	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
and I understand the following

Code: Select all

	if (node)
	{
		node->setMaterialFlag(EMF_LIGHTING, false);
		node->setMD2Animation(scene::EMAT_STAND);
		node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
	}

	smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));

	while(device->run())
	{

		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();
		guienv->drawAll();

		driver->endScene();
	}

	device->drop();

	return 0;
}

So the full version of my question would really be if the following is true:
- the pointer 'node' holds information
- the function addAnimatedMeshSceneNode adds the mesh to the scene, after that point the mesh exists but is not visible yet. node now points to that mesh
- letting node call functions like node->setMaterialFlag changes properties of the mesh was created on the scene
- However, if I would put the following line after the if(node){ ...} part:
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"));
then I would not be able to change the properties of the first mesh anymore (the sydney one) because node points to a different mesh now.
If I would want two meshes on the screen that I could keep changing the properties of I would need two seperate nodes.
-after the camera is created the user still doesn't see anything on the screen. Only after smgr->drawAll(); is called the user will be able to see something.



My other questions are related to tutorial 7. ( I won't put the entire code here, its very long, it is found here:http://irrlicht.sourceforge.net/docu/example007.html)

My first question is about the Triangleselector. In the comments in the code it says
"After we created the triangle selector, we attach
it to the q3node. This is not necessary, but in this way, we do not
need to care for the selector, for example dropping it after we do not
need it anymore."
This is done here:

Code: Select all

	
		selector = smgr->createOctreeTriangleSelector(q3node->getMesh(), q3node, 128);
		q3node->setTriangleSelector(selector);
But at the end the comment reads: "We're not done with this selector yet, so don't drop it."
But just before they said it did not matter. And later on in the code the selector gets dropped anyway. Why is this?
I'm also not quite sure what these lines of code really do. The first one creates an OcrtreeTriangleSelector and lets selector point to that TrianglSelector.
createOctreeTriangleSelector is like addAnimatedMeshSceneNode, it makes something. but they are two different things and in the case of createOctreeTriangleSelector you must not forget to drop it afterwards.

I don't understand the second line of code either. In the first line you already created a triangle selector that affects a certain mesh of node q3node. So what does the second line do?


Then a bit down there is the following code:

Code: Select all

	if (selector)
	{
		scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
			selector, camera, core::vector3df(30,50,30),
			core::vector3df(0,-10,0), core::vector3df(0,30,0));
		selector->drop(); // As soon as we're done with the selector, drop it.
		camera->addAnimator(anim);
		anim->drop();  // And likewise, drop the animator when we're done referring to it.
	}
in this bit of code the selector gets dropped. But according to the comments in the code that shouldn't be necessary. so why does it get dropped?
And what does the line camera->addAnimator(anim); really do? the createCollisionResponseAnimator already has 'selector' and 'camera' defined for its first 2 parameters, so what does addAnimator do that hasn't already been defined yet?


Later on in the code a md2 node gets made (called node) after that there is this bit of code:
video::SMaterial material;
material.Lighting = true;
node->getMaterial(0) = material;

would that be any different from:?
node->setMaterialFlag(EMF_LIGHTING, true);

I don't see anything change when I replace that part of the code. So is it the same or is there some other difference I can't see here?


in the game loop is the following bit of code:

Code: Select all

		core::line3d<f32> ray;
		ray.start = camera->getPosition();
		ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f;
So what is ray.end exactly? it is not the position of the closest scene node the camera is looking at, right? Because that is gotten from the getSceneNodeAndCollisionPointFromRay() function later on.



Then in if(selectedSceneNode) it says:

Code: Select all

			// We need to reset the transform before doing our own rendering.
			driver->setTransform(video::ETS_WORLD, core::matrix4());
			driver->setMaterial(material);
			driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0));
I don't understand the first line at all. And I'm not entirely sure about the second and third, does the second one overwrite the default parameters of the function setMaterial so that when the triangle is drawn in the following line it uses these new parameters as default?



Phew, that took me a while to write! I hope someone is willing to help me with some of this. Any help is very much appreciated! :D
CuteAlien
Admin
Posts: 9933
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Flow of the program and tutorial 7

Post by CuteAlien »

Phew, lots of text ^_^

First make sure you know what a node and a mesh, etc are. Best read this page: http://www.irrlicht3d.org/wiki/index.ph ... ommonTerms
This should probably already answer most of your questions.
RobinvK wrote: From what I understand so far the following piece of code just connect a mesh to the pointer called 'mesh'. Nothing will actually be created yet. Is this correct?

Code: Select all

	IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
	if (!mesh)
	{
		device->drop();
		return 1;
	}
This will load the mesh into memory and return a pointer to that memory. So a mesh is created.
RobinvK wrote: <snip>
So the full version of my question would really be if the following is true:
- the pointer 'node' holds information
Well, every c++ object holds some information. The most important part of a MeshSceneNode is that it has a position, rotations, size and a pointer to the mesh which had been created in getMesh.
RobinvK wrote: - the function addAnimatedMeshSceneNode adds the mesh to the scene, after that point the mesh exists but is not visible yet. node now points to that mesh
It does 2 things. First it creates the node-object. Second it does add it to the scenegraph so if that scene is rendered the scenenode will be rendered as well (which will draw the mesh).
RobinvK wrote: - letting node call functions like node->setMaterialFlag changes properties of the mesh was created on the scene
Actually the mesh-materials are copied for each SceneNode unless you call setReadOnlyMaterials(false). Which means although you can have several scenenodes for the same mesh you can still change the material for each scenenode independently.
RobinvK wrote: - However, if I would put the following line after the if(node){ ...} part:
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"));
then I would not be able to change the properties of the first mesh anymore (the sydney one) because node points to a different mesh now.
It would point to a different node as it 's a node-pointer not a mesh-pointer. Although as it's given a different mesh as well this node will also contain a pointer to another mesh.
RobinvK wrote: If I would want two meshes on the screen that I could keep changing the properties of I would need two seperate nodes.
Right, you need one scenenode for each object on the screen. What's confusing you seem mostly do be meshes and nodes. Think of meshes containing the geometry-data (the edges of each polygon for example) and nodes contain just a pointer to the mesh + position, rotation, scale. So you can have a single mesh several times on screen, but you still need one SceneNode for each.
RobinvK wrote: -after the camera is created the user still doesn't see anything on the screen. Only after smgr->drawAll(); is called the user will be able to see something.
Yes, drawAll will do the rendering. Before that you have only geometry data in your computer memory. Rendering will use that geometry data to create an image. Usually by sending the geometry-data (and textures) to the graphic-card.
RobinvK wrote: My first question is about the Triangleselector.
This is a lot about reference-counting. Irrlicht uses reference-counting for memory control. This is to ensure that as long as one object is still needed somewhere it won't be deleted from memory, but when it is no longer needed it is removed. Check the documentation here: http://irrlicht.sourceforge.net/docu/cl ... unted.html
RobinvK wrote: But at the end the comment reads: "We're not done with this selector yet, so don't drop it."
But just before they said it did not matter. And later on in the code the selector gets dropped anyway. Why is this?
It's just as it says. Usually you can drop a selector after you add it to the scenenode as that will increase it's reference-count and make sure the selector will not be deleted anymore before you remove the node itself. But in this case here we still need the selector and even though it wouldn't be deleted anymore with drop() it is very bad style doing so when the variable is still used. So it is only dropped when everything we wanted to do with this variable has been done. That is general the safest way to work with reference counting - never drop as long as you use the variable, but drop when you are finished with it so the object can be deleted later on.

And triangle-selectors are for collision. Sometimes you use the same triangles as for rendering, but sometimes you don't. And even if you have the same polygons for rendering and colliding it is often still useful to have them in different structures as those tasks need different optimizations (for example you still want to collide against objects which are behind your back, while you do not want to draw them). So a triangleselector is a structure which allows you to access the meshes for collision - whatever it does internally. An octree is an optimization to access those triangles faster in certain cases (works good for static geometry, but bad for animated meshes).
RobinvK wrote: And what does the line camera->addAnimator(anim); really do? the createCollisionResponseAnimator already has 'selector' and 'camera' defined for its first 2 parameters, so what does addAnimator do that hasn't already been defined yet?
A collision response animator makes sure an object does not move through the polygons it gets from the triangle-selector. The triangle-selector in this case contains your world-map - so it makes sure you don't move through walls or the the floor.
Adding it to the camera-node means therefore that the camera now no longer can move through walls. Just experiment and outcomment the line - you will see the difference.
RobinvK wrote: Later on in the code a md2 node gets made (called node) after that there is this bit of code:
video::SMaterial material;
material.Lighting = true;
node->getMaterial(0) = material;

would that be any different from:?
node->setMaterialFlag(EMF_LIGHTING, true);
That depends if the model has only a single material or not. getMaterial(0) will only access the first material while setMaterialFlag will affect all materials in the node. Could be it's the same here.
RobinvK wrote: in the game loop is the following bit of code:

Code: Select all

		core::line3d<f32> ray;
		ray.start = camera->getPosition();
		ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f;
So what is ray.end exactly? it is not the position of the closest scene node the camera is looking at, right? Because that is gotten from the getSceneNodeAndCollisionPointFromRay() function later on.
It is a line starting at the camera and going 1000 units in the direction of it. So anything within 1000 units can be hit. The 1000 is an arbitrary number (using the maximal clipping distance instead is often better as then you are guaranteed to hit everything you can see).
RobinvK wrote: Then in if(selectedSceneNode) it says:

Code: Select all

			// We need to reset the transform before doing our own rendering.
			driver->setTransform(video::ETS_WORLD, core::matrix4());
			driver->setMaterial(material);
			driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0));
I don't understand the first line at all. And I'm not entirely sure about the second and third, does the second one overwrite the default parameters of the function setMaterial so that when the triangle is drawn in the following line it uses these new parameters as default?
Hm, I don't think I can explain transformations in a few quick words. Basically they define the way your geometry is rendered. If someone tells you to draw a cube you have different possibilities how you want to do that. You can draw from front, you can draw like architects do so you would only see a rectangle or you can draw with some way that it looks 3d or you can draw from the side, etc. That is the transformation. The driver always has the transformation and the material which was used last. So you wouldn't really know which transformation that is right now (depends on which node was rendered last). That is why you have to set one before you draw anything. So we set just a the standard transformation (no rotation, scaling or anything) and standard material (without textures for example) before we draw the triangle there.
RobinvK wrote: Phew, that took me a while to write! I hope someone is willing to help me with some of this. Any help is very much appreciated! :D
I hope it helps. But please try to ask less questions at one time, this took me a little too long too answer ;-)
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
RobinvK
Posts: 12
Joined: Thu Mar 10, 2011 1:22 pm

Post by RobinvK »

Thanks for your post CuteAlien! That cleared a lot of things up for me! Sorry I asked so many things at once, but I'm glad you took the time to answer them, it helped me a lot! :D

I made the following based on http://www.irrlicht3d.org/wiki/index.ph ... ommonTerms and your explanations:
Image
So this is basically how it all works, right?


I want to make sure I get the difference between the following two bits of code:

Code: Select all

IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
IAnimatedMeshSceneNode node = smgr->addAnimatedMeshSceneNode( mesh );

Code: Select all

IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/sydney.md2"));
The first line in the first piece of code creates a pointer to a mesh. The second piece of code does the same, right? With the only difference being that we actually gave the pointer the name 'mesh' in the first bit.
However when I put this line:
mesh = smgr->getMesh("../../media/ninja.b3d");
at the end of the first bit of code the displayed model doesn't change. So based on this I assume that in the first bit of code addAnimatedMeshSceneNode() creates a new pointer to a mesh (which copies information from 'mesh'). So node doesn't contain a pointer to 'mesh' but to a copy of that pointer. Changing 'mesh' doesn't change anything about 'node' anymore, because 'node' contains a pointer to a mesh which is the same as what 'mesh' was at the point addAnimatedMeshSceneNode() was called.

And if the above is true then it would work the same for a triangleselector, right? So in the following line
node->setTriangleSelector(selector);
the Scenenode 'node' will create a pointer to a triangleselector, that pointer will copy all the information from 'selector'. After this line 'node' contains a pointer to a triangleselector and 'selector' can be changed without changing anything to 'node'. Just like meshes and materials, scenenodes can also contain pointers of the type triangleselector or animator. (this also explains why 'selector' was not dropped early on in tutorial 7)


Anyway, I think I now understand much better how irrLicht works. Thanks! :D
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Post by serengeor »

RobinvK wrote: I want to make sure I get the difference between the following two bits of code:

Code: Select all

IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
IAnimatedMeshSceneNode node = smgr->addAnimatedMeshSceneNode( mesh );

Code: Select all

IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/sydney.md2"));
The first line in the first piece of code creates a pointer to a mesh. The second piece of code does the same, right? With the only difference being that we actually gave the pointer the name 'mesh' in the first bit.
However when I put this line:
mesh = smgr->getMesh("../../media/ninja.b3d");
at the end of the first bit of code the displayed model doesn't change. So based on this I assume that in the first bit of code addAnimatedMeshSceneNode() creates a new pointer to a mesh (which copies information from 'mesh'). So node doesn't contain a pointer to 'mesh' but to a copy of that pointer. Changing 'mesh' doesn't change anything about 'node' anymore, because 'node' contains a pointer to a mesh which is the same as what 'mesh' was at the point addAnimatedMeshSceneNode() was called.

And if the above is true then it would work the same for a triangleselector, right? So in the following line
node->setTriangleSelector(selector);
the Scenenode 'node' will create a pointer to a triangleselector, that pointer will copy all the information from 'selector'. After this line 'node' contains a pointer to a triangleselector and 'selector' can be changed without changing anything to 'node'. Just like meshes and materials, scenenodes can also contain pointers of the type triangleselector or animator. (this also explains why 'selector' was not dropped early on in tutorial 7)


Anyway, I think I now understand much better how irrLicht works. Thanks! :D
This is just plain c++ stuff, nothing irrlicht specific(I mean the pointer stuff) you should study more c++ and I'm pretty sure you will understand most if not all of the things in irrlicht.
Working on game: Marrbles (Currently stopped).
CuteAlien
Admin
Posts: 9933
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Your diagram is approximately correct. It might be tricky to tell who does the rendering (each node rendered in a frame is registered and then tells the driver how it wants to be rendered). And materials are originally in meshes and nodes copy them from there when you set the mesh (to allow having a mesh just once in memory and still displaying it with different materials). Also Nodes contain material objects not just pointers to materials, but that's internal stuff and doesn't really matter as you only care about the node interfaces when using the engine.

I've also the feeling you should try a little more understanding pointers and the difference between a pointers and objects and variables in general. It's something you will need all the time.
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
RobinvK
Posts: 12
Joined: Thu Mar 10, 2011 1:22 pm

Post by RobinvK »

Yeah I noticed I'm not very comfortable with pointers yet. I understand online tutorials on pointers, classes and objects. But it's more difficult when they are used in a more complex engine.
But I think I understand things enough to at least continue with the tutorials. Thanks for all the help! :D
Post Reply