Making my Manualobjects look good..

Autumn

29-07-2012 11:36:27

Hi community,

I'm using Mogre in windows form and I'm creating manualobjects from STL-Files, but I am not happy with the way they look.

Here is a minimal example:

What my cube looks like:



What i want my cube to look like: (edited with paint..)



I create my cube like this: (I create my manualobjects from STL-Files in a similar way using a Streamreader..)

ManObjTest = mgr.CreateManualObject("ManObjTestTriangle");
ManObjTest.Begin("Blue", RenderOperation.OperationTypes.OT_TRIANGLE_LIST);

ManObjTest.Position(0, 0, 0);
ManObjTest.Position(100, 0, 0);
ManObjTest.Position(100, 100, 0);
ManObjTest.Position(0, 100, 0);

ManObjTest.Position(0, 0, 100);
ManObjTest.Position(100, 0, 100);
ManObjTest.Position(100, 100, 100);
ManObjTest.Position(0, 100, 100);

//bottom side
ManObjTest.Index(0);
ManObjTest.Index(2);
ManObjTest.Index(1);

ManObjTest.Index(0);
ManObjTest.Index(3);
ManObjTest.Index(2);
//end bottom

//left side
ManObjTest.Index(0);
ManObjTest.Index(4);
ManObjTest.Index(7);

ManObjTest.Index(0);
ManObjTest.Index(7);
ManObjTest.Index(3);
//end left

//front side
ManObjTest.Index(3);
ManObjTest.Index(7);
ManObjTest.Index(6);

ManObjTest.Index(3);
ManObjTest.Index(6);
ManObjTest.Index(2);
//end front

//back side
ManObjTest.Index(0);
ManObjTest.Index(1);
ManObjTest.Index(4);

ManObjTest.Index(1);
ManObjTest.Index(5);
ManObjTest.Index(4);
//end back

//right side
ManObjTest.Index(1);
ManObjTest.Index(6);
ManObjTest.Index(5);

ManObjTest.Index(1);
ManObjTest.Index(2);
ManObjTest.Index(6);
//end right

//up side
ManObjTest.Index(7);
ManObjTest.Index(4);
ManObjTest.Index(5);

ManObjTest.Index(5);
ManObjTest.Index(6);
ManObjTest.Index(7);
//end up

ManObjTest.End();

MeshPtr ManObjTestMes = ManObjTest.ConvertToMesh("MeshiQuad");
ManObjTestMes.BuildEdgeList();

MeshEnti = mgr.CreateEntity("MeshEntity", "MeshiQuad");
MeshEnti.CastShadows = true;

ManObjTestNode = mgr.RootSceneNode.CreateChildSceneNode("ManObjTestNodi");
ManObjTestNode.SetPosition(0, 0, 0);
ManObjTestNode.AttachObject(MeshEnti);



I create a spotLight, pointLight and a directionalLight.
I create a plane with a texture for casting shadows on.

I am using STENCIL_ADDITIVE shadows.

My Material:

material Blue
{
technique
{
pass
{
lighting off

texture_unit
{
texture blue.png
}
}
}
}


How can i make my objects look like the cube in the 2. picture?
They don't have to cast shadows. I just want the parts of my objects which are hit by light to be shiny and the parts which are not hit by light to be dark..
I don't know if I have to work on my lights, my material, the shadowtype i am using or the way I create my manualobjects... :(

Thanks
Autumn

tafkag

01-08-2012 10:42:52

I think you need to define some normals for the vertices and activate lighting in your material
lighting on

zarfius

01-08-2012 11:51:24

When you want to display a cube with "face normals" like you have drawn in your example, I think you'll need to define the vertices for each of the sides separately.

This means that even though you only have 8 vertices in your cube, you'll actually need to define 24 vertices in total (6 sides * 4 vertices). One way to manage this is to actually store the positions of your vertices in your own data structure. For example:


Vector3[] vertices = new Vector3[8];
vertices[0] = new Vector3(0, 0, 0);
vertices[1] = new Vector3(100, 0, 0);
vertices[2] = new Vector3(100, 100, 0);
vertices[3] = new Vector3(0, 100, 0);

vertices[4] = new Vector3(0, 0, 100);
vertices[5] = new Vector3(100, 0, 100);
vertices[6] = new Vector3(100, 100, 100);
vertices[7] = new Vector3(0, 100, 100);

CreateVertices(ManObjTest, vertices, 0, 1, 2, 3, Vector3.NEGATIVE_UNIT_Y); // bottom vertices
CreateVertices(ManObjTest, vertices, 0, 4, 7, 3, Vector3.NEGATIVE_UNIT_X); // left vertices


And define a method that helps create the vertices in the manual object.


void CreateVertices(ManualObject manualObject, Vector3[] vertices, uint index0, uint index1, uint index2, uint index3, Vector3 normal)
{
manualObject.Position(vertices[index0]);
manualObject.Normal(normal);
manualObject.Position(vertices[index1]);
manualObject.Normal(normal);
manualObject.Position(vertices[index2]);
manualObject.Normal(normal);
manualObject.Position(vertices[index3]);
manualObject.Normal(normal);
}


And finally you can use the Quad method instead of calling Index a whole bunch of times. For example:


ManObjTest.Quad(0, 1, 2, 3); // top side
ManObjTest.Quad(4, 5, 6, 7); // left side


Disclaimer: I wrote this code off the top of my head without testing it. The logic should work (I've done it a bunch of times, but it may have some bugs).

Autumn

01-08-2012 13:54:38

I think you need to define some normals for the vertices and activate lighting in your material
lighting on


Defining normals didn't help. But "lighting on" together with this:

When you want to display a cube with "face normals" like you have drawn in your example, I think you'll need to define the vertices for each of the sides separately.

This means that even though you only have 8 vertices in your cube, you'll actually need to define 24 vertices in total (6 sides * 4 vertices). One way to manage this is to actually store the positions of your vertices in your own data structure. For example:


Vector3[] vertices = new Vector3[8];
vertices[0] = new Vector3(0, 0, 0);
vertices[1] = new Vector3(100, 0, 0);
vertices[2] = new Vector3(100, 100, 0);
vertices[3] = new Vector3(0, 100, 0);

vertices[4] = new Vector3(0, 0, 100);
vertices[5] = new Vector3(100, 0, 100);
vertices[6] = new Vector3(100, 100, 100);
vertices[7] = new Vector3(0, 100, 100);

CreateVertices(ManObjTest, vertices, 0, 1, 2, 3, Vector3.NEGATIVE_UNIT_Y); // bottom vertices
CreateVertices(ManObjTest, vertices, 0, 4, 7, 3, Vector3.NEGATIVE_UNIT_X); // left vertices


And define a method that helps create the vertices in the manual object.


void CreateVertices(ManualObject manualObject, Vector3[] vertices, uint index0, uint index1, uint index2, uint index3, Vector3 normal)
{
manualObject.Position(vertices[index0]);
manualObject.Normal(normal);
manualObject.Position(vertices[index1]);
manualObject.Normal(normal);
manualObject.Position(vertices[index2]);
manualObject.Normal(normal);
manualObject.Position(vertices[index3]);
manualObject.Normal(normal);
}


And finally you can use the Quad method instead of calling Index a whole bunch of times. For example:


ManObjTest.Quad(0, 1, 2, 3); // top side
ManObjTest.Quad(4, 5, 6, 7); // left side


Disclaimer: I wrote this code off the top of my head without testing it. The logic should work (I've done it a bunch of times, but it may have some bugs).


helped!!!

Thanks to both of you! :)

Now my cube looks like this:



:)

tafkag

01-08-2012 15:34:08

Nice cube! :D
And kudos to zarfius for his very detailed answer!

mstoyke

01-08-2012 17:07:14

The cube looks a bit strange, could you make it less blue and maybe with fewer edges? :p

Ok, back to topic. Remember to set lighting on if you use fixed function pipeline. It won't be necessary if you use shaders for the object.

zarfius

02-08-2012 07:49:34

It won't be necessary if you use shaders for the object.
Do you know of any good tutorials on how to use shaders instead?

Autumn

02-08-2012 10:18:08

Kudos were given to zarfius :)
His code is also working when calling Index a whole bunch of times instead of using the Quad method, btw.

My cube problem is solved! Though I don't know, how I can apply this new information to my STL - Problem..

My ASCII-STL-File looks like this:
solid CATIA STL
facet normal -1.000000e+000 0.000000e+000 -0.000000e+000
outer loop
vertex -2.111549e+002 -3.151697e+002 -0.467555e-010
vertex -2.079062e+002 -3.142919e+002 -0.467555e-010
vertex -2.054985e+002 -3.166429e+002 -0.467555e-010
endloop
endfacet
facet normal -0.000000e+000 2.000000e+000 -0.000000e+000
outer loop
vertex -2.136567e+002 -3.132454e+002 -0.467555e-010
vertex -2.107850e+002 -3.137882e+002 -0.467555e-010
vertex -2.111549e+002 -3.151697e+002 -0.467555e-010
endloop
endfacet
facet normal -1.000000e+000 0.000000e+000 -0.000000e+000
outer loop
vertex -2.136567e+002 -3.132454e+002 -0.467555e-010
vertex -2.111549e+002 -3.151697e+002 -0.467555e-010
vertex -2.167907e+002 -3.136196e+002 -0.467555e-010
endloop
endfacet
[...]
endsolid CATIA STL


How I create my Entity (Pseudocode):


Vector3 pos = new Vector3(0, 0, 0);
Vector3 norm = new Vector3(0, 0, 0);

ManObj = mgr.CreateManualObject("triangle");
ManObj.Begin("Blue", RenderOperation.OperationTypes.OT_TRIANGLE_LIST);

Now I'm reading out the lines with a Streamreader.

- saving the first Normal: norm = new Vector3(-1, 0, 0);
- saving the first Position: pos = new Vector3(-211,1549f, -315,1697f, 0f);
- call ManObj.Position(pos);
- call ManObj.Normal(norm);
- saving the next Position: pos = new Vector3(-207,9062f, -314,2919f, 0);
- call ManObj.Position(pos);
- call ManObj.Normal(norm);
- saving the next Position: pos = new Vector3(-205,4985f, -316,6429f, 0);
- call ManObj.Position(pos);
- call ManObj.Normal(norm);

- saving the new Normal: norm = new Vector3(0, 2, 0);
- saving the Position: pos = new Vector3(-213,6567f, -313,2454f, 0);
- call ManObj.Position(pos);
- call ManObj.Normal(norm);
[and so on...]

after I've called ManObj.Position() and ManObj.Normal() like 100.000 times I do:
for (uint j = 0; j < numberOfPositions; j++)
{
ManObj.Index(j);
}

ManObj.End();

MeshPtr ManObjMes = ManObj.ConvertToMesh("MeshObj");
ManObjMes.BuildEdgeList();

ManObjEnt = mgr.CreateEntity("MeshObj");
ManObjEnt.CastShadows = true;

NodeEnt = mgr.RootSceneNode.CreateChildSceneNode("NodeEnti");
NodeEnt.SetPosition(0, 0, 0);
NodeEnt.AttachObject(ManObjEnt);


Some models cast shadows in a very odd way.. some models crash once I create a light.. (AccessViolationException..)
Any ideas what I can do different? :(
Do you know any other way how to create a Manualobject/Entity?
Shall I use shaders??!

Beauty

13-11-2012 19:39:51

When you want to display a cube with "face normals" like you have drawn in your example, I think you'll need to define the vertices for each of the sides separately.
This means that even though you only have 8 vertices in your cube, you'll actually need to define 24 vertices in total

Is it possible to use redundant indices instead of redundant vertices?

If it's possible by index definitions, there would be
8 vertices, 24 indices and 24 normals instead of
24 vertices and 24 normals.
Advantage: Less memory usage (and possibly more speed??) for objects complex objects (or a huge amount of ManualObjects).


MeshPtr ManObjMes = ManObj.ConvertToMesh("MeshObj");
ManObjMes.BuildEdgeList();

ManObjEnt = mgr.CreateEntity("MeshObj");
ManObjEnt.CastShadows = true;

NodeEnt = mgr.RootSceneNode.CreateChildSceneNode("NodeEnti");
NodeEnt.SetPosition(0, 0, 0);
NodeEnt.AttachObject(ManObjEnt);


In most cases you don't need to convert a ManualObject to a mesh.
Just attach it to a SceneNode:

ManObj.CastShadows = true;
NodeEnt = mgr.RootSceneNode.CreateChildSceneNode("NodeEnti");
// NodeEnt.SetPosition(0, 0, 0);
// --> I suppose this isn't needed, because 0/0/0 should be the default.
NodeEnt.AttachObject(ManObj);


For quick tests (with unmovable objects) you also can attach a ManualObject directly to the RootSceneNode:
mgr.RootSceneNode.AttachObject(ManObj);

I'm not shure about ManObjMes.BuildEdgeList().
Maybe you can use other options instead. (e.g. getEdgeList, )
There are also class members, which contains "stencilShadows" in its name.
Have a look to the class description of ManualObject.


some models crash once I create a light.. (AccessViolationException..)
Some years ago I had crashes in scenes with complex objects. The crashed just happened, when I enabled shadows. (I don't remember the shadow type.)
I had discussions about the shadow problems.
Have a look to this post and the next below.
Maybe it helps to increase the ShadowIndexBufferSize of the SceneManager.

Beauty

13-11-2012 19:41:29

There is useful information in this topic.
It could be added to the wiki page about ManualObject.