Visible artefacts from some distance (was angle)

Started by
10 comments, last by scippie 15 years, 11 months ago
Hi, I'm working on a project where I import meshes from 3ds max. I've written my own export plugin that exports vertices, normals, tangents, binormals and texcoords and it looks goooooood in my 3d engine. I've put per-pixel-lighting and environment mapping on the metal-looking models and usually everything looks very nice and realistic. But from some angles, I can see some visual artifacts of the trangles and now I am wondering why I'm getting that. It seems to be gone if I don't use reflection, but it might just not be visible because of the color. Screenshot of the problem, so btw. this is only visible from some angles, not always: Is this a problem with my shader? (the code is generated automatically by my 3d engine, so the code looks a little weird) Vertex shader (3.0):

float4x4 matWorldViewProj;
float4x4 matWorld;
float3 EyePosition;
float3 PointLight0Pos;
float PointLight0Range;
struct VS_OUTPUT
{
	float4 Pos: POSITION;
	float3 Normal: NORMAL;
	float4 Col: COLOR0;
	float3 View: TEXCOORD0;
	float3 Reflect: TEXCOORD1;
	float4 PointLight0: TEXCOORD2;
};
VS_OUTPUT vertexMain(float4 Pos: POSITION, float4 Col: COLOR0, float2 Tex: TEXCOORD0, float3 Normal: NORMAL, float3 Tangent: TEXCOORD1, float3 Binormal: TEXCOORD2)
{
	VS_OUTPUT Out = (VS_OUTPUT)0;
	Out.Pos = mul(Pos, matWorldViewProj);
	Out.Normal = normalize(mul(Normal, matWorld));
	Out.Col = Col;
	float3 worldPos = mul(Pos, matWorld);
	float3 Incident = normalize(worldPos - EyePosition);
	Out.Reflect = reflect(Incident, Out.Normal);
	float3 vecPointLight0 = PointLight0Pos - worldPos;
	float distPointLight0 = saturate(1 - dot(vecPointLight0 * PointLight0Range, vecPointLight0 * PointLight0Range));
	Out.View = EyePosition - worldPos;
	Out.PointLight0.xyz = normalize(vecPointLight0);
	Out.PointLight0.w = distPointLight0;
	return Out;
}







Pixel shader (3.0):

float ReflectionFactor;
float ShininessFactor;
float4 PointLight0Col;
float4 AmbientColor;
struct VS_OUTPUT
{
	float4 Pos: POSITION;
	float3 Normal: NORMAL;
	float4 Col: COLOR0;
	float3 View: TEXCOORD0;
	float3 Reflect: TEXCOORD1;
	float4 PointLight0: TEXCOORD2;
};
sampler reflectionMap : register(s2);
float4 pixelMain(VS_OUTPUT In) : COLOR
{
	float4 baseColor = In.Col;
	float4 Color = AmbientColor * baseColor;
	Color = Color + ReflectionFactor * texCUBE(reflectionMap, In.Reflect);
	float DotPointLight0 = dot(In.Normal, In.PointLight0.xyz);
	float PointLightDiffuse0 = saturate(DotPointLight0);
	float PointLightShadow0 = saturate(4 * DotPointLight0);
	float3 PointLightReflect0 = normalize(2 * PointLightDiffuse0 * In.Normal - In.PointLight0.xyz);
	float PointLightSpecular0 = min(pow(saturate(dot(PointLightReflect0, In.View)), 3), ShininessFactor);
	Color = Color + (PointLightShadow0 * (baseColor * PointLight0Col * (PointLightDiffuse0 + PointLightSpecular0)) * (In.PointLight0.w));
	return Color;
}







Or is there probably something else wrong? Can someone help me out? Dirk. [Edited by - scippie on May 9, 2008 1:34:38 PM]
Advertisement
Some extra (probably important) note:

The camera is *always* at (0, 0, 0), the objects move around the camera, which is, I know, not the usual way.
My guess is that it has to do with how you calculate the reflectance factor in the vertex shader. Because it gets interpolated over the triangles, those triangles that have two vertices with greater reflectance will tend to be more reflective over all. Maybe you should try calculating it in the pixel shader?
Thanks for that tip SnotBob, but sadly, the problem persists, although the reflection is now MUCH nicer (banging my head that I didn't see this one myself).

But I now discovered that it doesn't exactly have to do with the angle, but more with the distance. The further away I go, the less reflection is visible and the more gray material color is visible.

But it gets even more strange when that problem only occurs on object that are not facing upwards. One object has a normal of (0, 1, 0) and always has perfect reflection, but an object with a different normal gets vaguer over the distance until none of the reflection is visible anymore.

So I believe something is wrong with my calculations?

It might have something to do with the fact that the camera stays on (0, 0, 0) and the objects move around it, but I'm not mathematically smart enough to see why that would change my code.

I don't see it... someone?
I'm glad that the reflections improved, although I somehow misread your code. I though that you had computed ReflectionFactor in the vertex shader instead of the vector Reflect.

Why don't you try eliminating stuff and seeing what works and what doesn't. Try removing all the lighting and stuff from the pixel shader and simply output ReflectionFactor * texCUBE(reflectionMap, In.Reflect);

The only other thing I can think of is that your normals for the inside triangles of the cylinder are wrong.
I'm sorry, the problem is NOT the same anymore. It just clarified a bit by showing up differently by doing the reflect calculation in the pixel shader, it are no longer triangle-artefacts, but pixel-artefacts now :-).

I checked the normals (looked like one hairy mess :-)) but they looked perfect.

When the distance gets bigger, the reflection gets darker (ie. immediately black (ambient color) at some point but as it grows per pixel as the distance goes bigger, it looks like it's fading, but it isn't).

So after thinking and thinking, it seems that the Reflect vector gets corrupt or something like that, as there are NO black texels in the cubemap. texCube() must be returning black because it can't translate the Reflect vector to the cube map.

Oh, I took your advice and threw away the light (it's not the reason). This is what the code looks like now:

VS:
float4x4 matWorldViewProj;float4x4 matWorld;float3 EyePosition;struct VS_OUTPUT{	float4 Pos: POSITION;	float3 Normal: NORMAL;	float4 Col: COLOR0;	float3 Incident: TEXCOORD0;};VS_OUTPUT vertexMain(float4 Pos: POSITION, float4 Col: COLOR0, float2 Tex: TEXCOORD0, float3 Normal: NORMAL, float3 Tangent: TEXCOORD1, float3 Binormal: TEXCOORD2){	VS_OUTPUT Out = (VS_OUTPUT)0;	Out.Pos = mul(Pos, matWorldViewProj);	Out.Normal = normalize(mul(Normal, matWorld));	Out.Col = Col;	float3 worldPos = mul(Pos, matWorld);	Out.Incident = normalize(worldPos - EyePosition);	return Out;}


PS:
float ReflectionFactor;float4 AmbientColor;struct VS_OUTPUT{	float4 Pos: POSITION;	float3 Normal: NORMAL;	float4 Col: COLOR0;	float3 Incident: TEXCOORD0;};sampler reflectionMap : register(s2);float4 pixelMain(VS_OUTPUT In) : COLOR{	float4 baseColor = In.Col;	float4 Color = AmbientColor * baseColor;	float3 Reflect = reflect(In.Incident, In.Normal);	Color = Color + ReflectionFactor * texCUBE(reflectionMap, Reflect);	return Color;}


(ReflectionFactor is not the reason, I double checked)

So why is Reflect getting corrupted? That can only be because Incident is getting corrupted.

I read that the reflect() function is the same as:
Reflect = In.Incident - 2 * In.Normal * dot(In.Incident, In.Normal)

So this formula must get messed up with the wrong Incident or Normal. But as the Normal has always been fine (I really think so, lighting always seemed to be correct) before, the real trouble must be Incident, which might give strange results with the dot product.

Now, my mathematical skills (though not bad) are not good enough to understand why this happens and what must be happening wrong to mess up this formula.

Is there someone who can?

Thanks,
Dirk.
Autch... seems you were right earlier.
It seems that there's something wrong with the normals after all.

If I show the normals on top of the mesh, they seem to be correct, but the problem with the worse-getting-reflection over distance is there.

If I calculate my own normals, the problem is gone!!! (but the mesh is not smooth anymore of course, otherwise I would always recalculate the normals myself) but the normals look the same!!?? (visually speaking, of course they're not exactly the same values)

So, the problem is with the normals I get from my 3ds max 7 export plugin. I'm using the IGameMesh exporter tool and I can 't find any reason why that shouldn't work. (I do the same as what their examples tells me to do and I haven't found any topics on normals)

I know this thread is getting a little bit off-topic now...

Anyone?
I believe you should normalize at least your Normal in the pixel shader. If you don't, that can affect the result of reflect(), changing the direction of the resulting vector. I don't know if this fixes your problem though. If it doesn't, you should give more details. How are you calculating your normals, when you say that fixes the problem? How do you know that the exported normals are OK? Where do they point on the edge, normal to the surface or away from the edge?
Hi,

Meanwhile, I've been reasoning and found out what should be normalized and what not. It didn't help as everything was probably rather normalized to begin with.

But I've come up with the real reason of the problem, and that is, that texCUBE() returns a black pixel because Reflect has two ordinates of the same magnitude example: (0.7, -0.7, 0.25).

I know that behind the scene, texCUBE finds the ordinate with the highest magnitude, takes that axis as the cube-axis-part, divides the other ordinates by that magnitude (absolute) and uses that (1 + x) / 2, as texture coordinate.

If you think about that, it is logical that texCUBE will not be able to know what side of the cube to use when two ordinates are of the same magnitude, and that's when black comes in. This seems to always be at the corner of the cubes (which is logical with two same ordinates)

Now the problem with the reflection, as the distance grows bigger, is that the black begins to overwhelm and nothing is left of the reflection.

This is exactly what is happening, and it is only visible on a round surface where the normals are in all directions (so that you will have a case where this happens).

If I could use a sphere map, this problem wouldn't occur, but as we all know, that's not really a possibility.

To prove this, I have changed my pixel shader so that it will return the yellow color in stead of the reflection when the Reflect vector has 2 same-magnitude ordinates (within a rounding error). And here it is:


I would think that this is a common problem, yet I can't find anything about it... How do I fix this??
Actually, if you think about it, the case where two coordinates have the same magnitude is quite common and ordinary. I couldn't find documentation on texCube, but I'm pretty sure it just prefers one axis over the other in this case. What happens is that the resulting texel is accessed from the border of one of the cube maps. For some reason your cube map borders are blank. Or one of them is at least.

This topic is closed to new replies.

Advertisement