Advertisement

[DX9] Problem with smooth shading of mesh

Started by August 22, 2011 01:14 PM
4 comments, last by Postie 13 years, 2 months ago
Hi Guys.

I've been doing a bit of DirectX 9 under Delphi (I normally dabble in SlimDX), and have created a 3DS file loader. While testing it I noted that the mesh I'm displaying has "highlights" along some of the face edges, as demonstrated in the following image.. Note that despite the mesh being made up of triangles, none of the diagonals are highlighted, only the orthogonal edges.

< image removed>

I've tried my renderer with about 10 different 3ds files, and even created some by hand in code rather than loading through the 3ds file loader, but I always get the same result. The renderer I'm using as to work on older hardware that doesn't support pixel/vertex shaders, so I'm using the fixed function pipeline, but I've created a simple shader to test on my dev system (which does support shaders) to see if that is the cause, and the image looks slightly better, but still has issues.

The way I am calculating the vertex normals is to sum together all the face normals and then normalise the end result. I googled different approaches to this, and tried a technique involving the angle of each triangle at the shared vertex to scale the face normals to reduce the bias caused by large angles vs small angles at the vertex, but that didn't seem to make a difference.

Anyone have any ideas, or am I going insane?
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler
If you move the light to a different positions you should be able to get the diagonals. In the above images, if the diagonals are "mostly vertical" (in screen space) then they will be interpolated correctly. Perhaps try rotate 90 degrees to have a check. Do you confirm?


It looks like standard vertex shading behavior to me.

Previously "Krohm"

Advertisement
Can you post your shader code that you are using to recreate the images? It looks to me like you are not normalizing your normal after interpolating it in the pixel shader. Try that out before doing any calculations in the pixel shader, and I think that will take care of the issue.

What I think is happening is this: when the normal vectors are interpolated, their length is slightly less than 1.0. This effect would be the most pronounced at the center of any primitives that are being rendered. Then, when you take your N dot L, the result has a slightly diminished color due to the shorter normal vector. If you renormalize before calculating, then the effect should go away.

In effect, if you use higher tessellation of your sphere, then this effect could be minimized without the normalization. I really don't know how to fix the issue in a fixed function pipeline, but I'm sure there must be some way to do so...
The model is controllable by a free rotation system, and the lines shown don't change regardless of the orientation.

Not re-normalising the normal in the pixel shader was definitely having an effect, and managed to reduce the appearance of the lines to a certain degree. If the model is static, the lines are almost imperceptible. However, as soon as you rotate the model in any way the lines appear very obvious. I suspect that's a function of the human eye being better at detecting gradient differences in movement than a graphics glitch.

This isn't really an effective solution, as the hardware this needs to run on doesn't support shaders, so I have to go with a fixed function pipeline based solution. The HLSL pixel shader code I used for testing is as follows:

float4 creaturePS( VS_OUTPUT IN) : COLOR0
{
float4 light = float4(1.0,1.0,0.8,1.0) * saturate(dot(IN.Light, normalize(IN.Normal)));

return light;
}


Interestingly, not renormalising in the pixel shader looks almost identical to the fixed function pipeline version, suggesting to me that the ffp isn't renormalising per pixel. I'm aware of the D3DRS_NORMALIZENORMALS setting, which I've tried but it had no effect, because I believe its for renormalising at the vertex level, and I always ensure all my normals are unit length anyway.

During my testing I produced a cylinder that had much higher tesselation than the sphere in the original image but never achieved properly smooth shading across multiple faces. I've also loaded the sphere.3ds file into the Assimp viewer and it appears smoothly shaded, so I know that the tesselation of the model isn't a defining factor in the issue. Actually, I just loaded it again just to be sure, and AssimpView has the lines appearing when I rotate the model around as well.

Man this is frustrating. Perhaps it is the tesselation level, but I would have thought that even with 2 faces at 45 degrees to each other (ie, much greater angle than the model I'm using) it would be possible to achieve smooth shading between them.

The thing I don't understand is that if the normals are being interpolated how is it that the result of the dot product produces a local maximum at either end that is notably brighter than the surrounding pixels?

Could it have something to do with the way the draw call is happening? However, I'm using an indexed triangle list, so each vertex and normal is specified only once.

Argh.
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler
Have you tried taking a look at a frame from this in PIX? Perhaps you can see something interesting there... either in the pixel debugger or even by looking at your geometry before and after the vertex shader to see if it is really what you expect that it is. I would double check the number of vertices, the number of faces, and the expected number of indices to ensure that it matches what you think it should.

If renormalizing doesn't fix the issue, then I would say that it is probably an issue with the input geometry. If the sphere is centered around the origin in object space, try just normalizing the position in the vertex shader to produce a normal vector. That will ensure that it is pointing in the proper direction, and if you also renormalize then it should make a very nicely shaded surface. If you get different results with that option then you are likely not calculating the normals properly.
Well, I let it sit for a while and came back to the problem later and I've come to the conclusion that its caused by the tessellation of the sphere. The project it is for has progressed to the stage where the 3d artist has produced some proper meshes for me to test against, and they are working fine without the weird highlights.

Thanks for the suggestions.



[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

This topic is closed to new replies.

Advertisement