Jump to content
  • Advertisement
Sign in to follow this  
Talyrond

Gouraud shading

This topic is 4450 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I am working on a 3D CAD system and am playing around with rendering some models. I am importing a file format called STL, this is basically a load of triangles with a surface normal for each. I can read this in and display OK, at the moment a have not created a mesh I am just using a vertex buffer and then drawing with DrawPrimitives using PrimitiveType.TriangleList (I am used managed DirectX 9.0 by the way). As expected the Gouraud shading is not working and I can see each triangle shaded uniformly across its surface. I plan to try creating a Mesh, but I wander how Direct3D will calculate the Gouraud shading, is there some that I have to do or will this be sorted out for me when I create the Mesh, if anyone can shed some light on the matter I would be very great full. Julian

Share this post


Link to post
Share on other sites
Advertisement
You have to calculate normals for each vertex in your mesh (currently you set all vertices of a surface to the surface normal). Then the rendering pipeline will calculate the lighting for each vertex and the resulting color is interpolated over the surface.

Hope that helps

Share this post


Link to post
Share on other sites
Also keep in mind, that you should calculate the indices for the IndexBuffer and throw out double vertices in the process before creating the mesh, if you haven't thought about that already.

Share this post


Link to post
Share on other sites
unless you're doing anything "clever" with face normals then you could just create a mesh (D3DXCreateMesh()) and populate it with the position data. Using either ID3DXMesh::OptimizeInPlace() or D3DXCleanMesh()/D3DXWeldMesh() will remove any duplicate information. You can then use D3DXMeshComputeNormals() which uses adjacency information to create averaged/smoothed normals. You'll then get nice smooth gouraud shading.

If you're sticking with face-normals then you might want to change the shading mode to be D3DRS_SHADEMODE = D3DSHADE_FLAT. Currently the hardware will probably be interpolating constant parameters (unless its very clever) and thus burning processing time on a rather pointless operation [smile]

hth
Jack

Share this post


Link to post
Share on other sites
D3DX Meshes are a very convenient and powerful tool, but they aren't always the best choice.

Be sure you familiarise yourself with the D3DX Mesh functions in the DirectX SDK reference documentation. Have a scan-read of the various functions and you'll start to get an idea of how much work the API will do for you...

hth
Jack

Share this post


Link to post
Share on other sites
Thanks for the info Jack. I have been looking at the documentation and found this:

If you use the Device Draw...Primitives methods to render your scene, define the object with sharp edges as a triangle list, rather than a triangle strip. When you define an object as a triangle strip, Direct3D treats it as a single polygon composed of multiple triangular faces. Gouraud shading is applied both across each face of the polygon and between adjacent faces. The result is an object that is smoothly shaded from face to face. Because a triangle list is a polygon composed of a series of disjoint triangular faces, Direct3D applies Gouraud shading across each face of the polygon. However, it is not applied from face to face. If two or more triangles of a triangle list are adjacent, they appear to have a sharp edge between them.

I am using a triangle list, so basically unless I am using a triangle strip, I am not going to get good results. I do not understand what it means by ‘and between adjacent faces’. Do you think I am wasting my time, as my data is not in triangle strip form?

Thank you

Julian

Share this post


Link to post
Share on other sites
No, you're not wasting your time - you can achieve exactly the same results with a triangle-list.

That section you quoted is correct, but what its really saying is that you dont get the choice with a STRIP - it will gouraud shade between adjacent triangles whether you like it or not (you can however disable gouraud shading entirely and still get sharp edges if you really want). On the other hand, a LIST does NOT do any gouraud shading unless you specifically set it up to do so.

It all comes down to how the two layouts are defined.

Each triangle in a LIST is its own entity - it has its own three vertices each with whatever arbitrary properties you like (lets just ignore index buffers for now [wink]).

Each triangle in a STRIP is based on the last two vertices from the previous triangle. They share a common edge. This simple act of sharing stops the two triangles from having different/independent properties.

To put a finer point on it, your quoted text just points out that one arrangement shares and the other doesn't.

BUT, where it gets interesting is if you set neighbouring (adjacent) triangles in a LIST to have identical properties. You can do this simply by duplicating the data, or you could have both triangles reference the same physical data by using an index buffer. Now the list is effectively sharing data the same way that the STRIP always shares data. But how andwhat it shares is now defined by you and not Direct3D.

An example is the difference between VERTEX and FACE normals. A vertex normal tends to be the averaged face normal for any/all adjacent triangles. You end up with a shared vertex where the data is comprised of an equal amount of information from each of the faces sharing the vertex. It would be quite reasonable for the three normals fetched in order to render a single triangle to not point in the direction of the true surface/face normal.

Anyway... I think that covers it [smile]

D3DX meshes are internally represented as LIST's and you can use various functions like I mentioned earlier to generate the appropriate data. If you have adjacency information (or you use GenerateAdjacency()) then the D3DXMeshComputeNormals() will do the "smoothing" of each face normal to become an averaged vertex normal. You will then get gouraud shading. Alternatively, if you dont have (or dont use) adjacency then D3DXComputeNormals() should just clone your single face normal to each of the three vertices that make up the corresponding triangle. You'll end up with flat shading.

hth
Jack

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
ok, let me explain:

you have a triangle defined like this:
3 vertices, 1 normal

what d3d needs is 3 vertices, and every vertex needs a normal.
so how does d3d compute the 3 normals ?
it takes the face normal, for each vertex.

when you have 2 triangles next to each other, you have (up to) 2 "connection" points.
but these points are not the same, because both points exist twice, 1 for each triangle. these two points are at the same position, but they have different normals.
when d3d renders triangle 1, it detects, that all vertex normals are the same, so it does flat shading. rendering triangle 2, d3d also applies flat shading.

the solution to this is:
all vertices at the same point should have the same normal. you can recalculate the normal and take the average value of all the normals of the vectors at that position. or, in other words, by averaging the normal of all connected triangles.

now the vertices of one triangle have different normals. and now d3d applies gouraud shading.

now you see, you could have 1 point, that has many vertices, because many triangles are connected to it. to save memory, you can index vertices, or connect them to a strip. then you have 1 vertex for 1 point. and then it is not possible to do flat shading, since you cannot have more than 1 normal per vertex.

Share this post


Link to post
Share on other sites
Thanks guys, things are making a lot more sense now.
The reason I am playing around with reading in STL files, is that I am going to have a third party generate some models for me, in real time. I will be rendering these models my self but I need to specify the data required.
I want to use Gouraud shading, but in light of your excellent info I fear it will be a lot more complicated than I first thought.
It will be my decision if I use Mesh’s or use DrawPrimitives. Performance is a real issue so it may be better for the developer to provide the normal’s as required to get the desired results, perhaps if you don’t mind, please take a look at what I am trying to achived:

Model


I think I will need a combination of VERTEX and FACE normals, you can see that the wall of the yellow slot is Gouraud shaded, but where the slot meets the grey outside is very sharp and a different colour, like wise the bottom of the yellow slot, is sharp where it meets the walls. I think this info will have to be provided by the developer, I can’t see how I could get a Mesh to work all that out, so I am moving away from Mesh’s at the moment

Do you agree that a combination of VERTEX and FACE normal’s would be needed to achieve the desired results?

Thanks

Julian

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!