View Full Version : Reflection in 3D engine

 yakul03 March 2007, 03:47 PMI am writing a 3D engine in directX, and I wonder how should the reflection work. From the book I am reading, the reflection is factored with the diffuse color. x = reflection factor r = reflection color d = material diffuse c = material color. ResultDiffuseColor = x*r+(1-x)*d*c I dont understand why the reflection is "competing" on the texture color by a factor sum, and not simply added like: x*r+d*c Additionally, I dont understand why the reflection light intensity or power, is calculated with the same equation of the diffuse light intensity. If p is the point lighted, and e is the vector from p to the light source, n is the vector normal to the surface at point p. Then the intensity of the diffuse light and reflection light is: max {e dot n, 0} Should I implement the reflection by the book? Is reflection implemented differently in 3D rendering software? What about lightwave? How is it implemented int lightwave? Thank you.
gga
03 March 2007, 10:19 PM
I dont understand why the reflection is "competing" on the texture color by a factor sum, and not simply added like: x*r+d*c

Because otherwise you are not preserving energy. In real life, you cannot have a surface that is 100% reflective and that still has its own diffuse color (don't confuse this with tinting the reflection, thou).
Just adding the reflection without compensating for the amount of reflection can lead to washed out (read: >1) colors, even if the lighting is normal.

Additionally, I dont understand why the reflection light intensity or power, is calculated with the same equation of the diffuse light intensity.

Err... there's not really such thing as "reflection light". You problably have some terms confused. Are you referring to the specular of the light as it hits the surface?

Should I implement the reflection by the book?
Is reflection implemented differently in 3D rendering software? What about lightwave? How is it implemented int lightwave?

Lightwave is indeed one of the few packages that implements reflections as additive in its base shader (not in some plugins, thou), without taking into account energy conservation. Thus, if you set your reflection to 100% and you reflect pure white and your object's diffuse is not 0, you will get a washed out image.
Also, Lightwave's traditional shader model did not allow tinting reflections with a color different than the object's diffuse (albeit nowawadays there are ways to do it, including plugin shaders).

If you are going for a physically correct shader, you should implement reflection respecting energy conservation.
If you are going for matching Lightwave or you want to allow your user to have more control (and also the burden) of having himself deal with respecting energy conservation by having him tweak two sliders (reflection and diffuse), you should not. For the user, this approach is more of a pain for creating, for example, a "real" glass, but it can also help artists achieve reflecting objects that are more "glowing" or "ghost like", which can also have some uses.

yakul
03 March 2007, 07:34 AM
I dont understand what do you mean by washed up color?
If the color is above 1.0 then it is clipped to 1.
There is no problem with the energy about reflection, because reflection is not the result of direct light of the light source. The result of direct light is specular and diffuse.
Reflection is the result of light from the enviorment. So its actually non direct light, which comes from the light source by "bouncing" on the enviorment back to the object.
Am I right?
What I mean is, the reflection of a light source is specular.
And diffuse is the scattered return of direct light.
But the reflection as it is done in software, is actually the return of light from the enviorment and not the light source.

gga
03 March 2007, 09:03 AM
duplicated post.

gga
03 March 2007, 09:09 AM
I dont understand what do you mean by washed up color?
If the color is above 1.0 then it is clipped to 1..

Not in any decent renderer. Floating point numbers can go beyond 1.0. If you are clipping values during shading, you are probably screwing it up. That will prevent you from dealing with HDR properly (which is values going beyond 1.0 because of too bright light sources for the current exposure).
Clipping should only happen for display and/or converting to non-float image formats.

There is no problem with the energy about reflection, because reflection is not the result of direct light of the light source. The result of direct light is specular and diffuse.

But the reflection as it is done in software, is actually the return of light from the enviorment and not the light source.

Ok, your terminolgy is all wrong, but I understood what you meant. So, yes, but what is the environment? Think about it again. I'll make the example in simple terms. Think of reflection as reflecting actual objects with raytracing (not as simple environment mapping).

Let's say the light has a value of 0.5 (whatever unit) that is lighting a scene with a cube and a sphere. They both are perfectly diffuse, but the sphere is also perfectly reflective (something that, like I said, in real life is currently impossible to do).
Disregarding phong shading, light decay, form factors and the like, the light arriving at the cube is then also 0.5 as no light was lost. And so is the amount of light arriving at the sphere.
If the sphere is also reflecting the cube and just adds its reflection as is, suddenly those pixels in your sphere have values equal to 1. Energy preservation is gone.
You just created more light than there is. To the artist it will look like the cube is being reflected, but it will also look as if it were twice as bright (ghostly) in the reflection than it is in the scene.
If you attenuate the diffuse coefficient by the reflection coefficient as in that formula, you will be able to preserve the energy that the light originally emitted and you will see a cube reflected with pixel values of 0.5, instead of 1.

yakul
03 March 2007, 11:17 AM
Triple post

yakul
03 March 2007, 11:56 AM
TriplePost

yakul
03 March 2007, 11:56 AM
The sphere will be twice as bright as the cube. But not because the sphere return too much light, but because the cube return too less light.

Because the cube does not return the radiosity light. If you would turn on rediosity, then the cube should return the same light as the sphere.
Anyway, I am creating a space game. So my objects are going to reflect only the stars in the background. Since these stars are emitting light and are not taken into consideration with the light source (the sun), then the reflection of the stars on the space ship should be added instead of factored.
Dont you think?

gga
03 March 2007, 06:46 PM
Buddy, I mean it in a right way, but your first two paragraphs make no sense. You probably should take a course in 3d gfx to at least learn some basic terminology so you can express your thoughts a little bit more clearly.

Anyway, I am creating a space game. So my objects are going to reflect only the stars in the background. Since these stars are emitting light and are not taken into consideration with the light source (the sun), then the reflection of the stars on the space ship should be added instead of factored.

Is that a question? Short answer, it does not matter.
Long answer, no, If you want to deal with light mathematically. You should stick to hadle reflections properly and find a proper balance of the ship's reflection coefficient vs. its diffuse coefficient, so your ship has some coloring while still reflects the stars (I'm assuming that's what you want). The math really does not change. If you later decide you also want to reflect a planet, you could end up in trouble, otherwise.
In practice, if what you are reflecting are only small dots (stars), then, quite honestly, it won't make much of a difference if you reflect them additively. Noone will be able to tell the difference for one or two isolated pixels.

yakul
03 March 2007, 01:03 PM
No need to be angry :)

I will give you an example.

Suppose you have a dark room.
In the dark room you have a mirror and a wall in front of the mirror.
Now you have a flashlight. You use your flashlight to light on the wall, which mean you do not light with the flashlight directly on the mirror.
So the diffuse light on the mirror is 0 (if we neglect radiosity), but the mirror should still reflect the light on the wall.
However, the diffuse value is 0, and since we calculate reflection as part of the the diffuse value, the reflection will also be 0.

gga
03 March 2007, 01:10 AM
However, the diffuse value is 0, and since we calculate reflection as part of the the diffuse value, the reflection will also be 0.

Sigh. No. Look at the formula you posted. Reflection is uneffected by the value of the diffuse. It is the other way around. Diffuse values get diminished by the reflection amount.

yakul
03 March 2007, 05:07 AM
I guess I wasnt clear enough, I will post part of the shader code:

float s = max(dot(lightVecW, normalW), 0.0f);

float3 ambientMtrl = gReflectivity*reflectedColor + (1.0-gReflectivity)*(gMtrl.ambient*texColor);
float3 diffuseMtrl = gReflectivity*reflectedColor + (1.0-gReflectivity)*(gMtrl.diffuse*texColor);
// Compute the ambient, diffuse and specular terms separately.
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(diffuseMtrl*gLight.diffuse.rgb);
float3 ambient = ambientMtrl*gLight.ambient;
float3 final = ambient + diffuse + spec;
// Output the color and the alpha.
return float4(final, gMtrl.diffuse.a*texColor.a);

So the reflection is multiplied by s which is a result of the direct light from the light source.
So how do you suggest to do it?

playmesumch00ns
03 March 2007, 10:45 AM
That code is incredibly confusing. It looks like you're mixing the mirror reflections into both the diffuse and ambient terms?

I personally find it much simpler to calculate each term entirely seperately, then just add them all together at the end. Makes it much clearer what's going on...

gga
03 March 2007, 01:19 PM
// calculate diffuse + texture
float3 diff = gMtrl.diffuse.rgb * texColor;

// calculate ambient
float3 Ka = gMtrl.ambient.rgb * diff;

float s = max(dot(lightVecW, normalW), 0.0f);
float3 Kd = s * diff * gLight.diffuse.rgb;

// calculate specular (you might also want to modulate the spec by the texture)
// this uses a simple blinn's phong model
float3 H = normalize( viewV + lightVecW );
float t = pow( max( dot( H, normalW ), 0.0f ), shiny ); // shiny == phong's shiny factor
float3 Ks = t * gMtrl.spec.rgb * gLight.spec.rgb;

// calculate reflection
float3 reflColor = float3(1,1,1); // should be a shader parameter
float3 Kr = texEnvColor * reflColor;
// ...you might also want to handle fresnel here, to make reflections
// stronger when seen on edge...

// Handle final equation
float g = gReflectivity; // just to make code clear
float one_g = 1.0 - gReflectivity;

// under normal lighting conditions, this total should ideally be [0...1]
// note that huge Ka values can still make it go overboard.
// same with specular, as phong shaders are not physically correct shaders.
// this formula is more or less akin to Softimage's shading model.
// if you want something akin to LW's, remove the one_g multiplication.
// if you want something akin to Maya's, remove the one_g multiplication and make
// the last terms g * Kr * Ks + Ks, instead of g * Kr + Ks.
float3 final = one_g * (Ka + Kd) + g * Kr + Ks;

return float4(final, gMtrl.diffuse.a*texColor.a);

yakul
03 March 2007, 04:54 PM
// calculate diffuse + texture
float3 diff = gMtrl.diffuse.rgb * texColor;

// calculate ambient
float3 Ka = gMtrl.ambient.rgb * diff;

float s = max(dot(lightVecW, normalW), 0.0f);
float3 Kd = s * diff * gLight.diffuse.rgb;

// calculate specular (you might also want to modulate the spec by the texture)
// this uses a simple blinn's phong model
float3 H = normalize( viewV + lightVecW );
float t = pow( max( dot( H, normalW ), 0.0f ), shiny ); // shiny == phong's shiny factor
float3 Ks = t * gMtrl.spec.rgb * gLight.spec.rgb;

// calculate reflection
float3 reflColor = float3(1,1,1); // should be a shader parameter
float3 Kr = texEnvColor * reflColor;
// ...you might also want to handle fresnel here, to make reflections
// stronger when seen on edge...

// Handle final equation
float g = gReflectivity; // just to make code clear
float one_g = 1.0 - gReflectivity;

// under normal lighting conditions, this total should ideally be [0...1]
// note that huge Ka values can still make it go overboard.
// same with specular, as phong shaders are not physically correct shaders.
// this formula is more or less akin to Softimage's shading model.
// if you want something akin to LW's, remove the one_g multiplication.
// if you want something akin to Maya's, remove the one_g multiplication and make
// the last terms g * Kr * Ks + Ks, instead of g * Kr + Ks.
float3 final = one_g * (Ka + Kd) + g * Kr + Ks;

return float4(final, gMtrl.diffuse.a*texColor.a);

This looks intersting, I shall try it with my engine.

CGTalk Moderation
03 March 2007, 04:54 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.

1