Combining texture and light

Hello.

I am trying to emulate fixed OpenGL texturing and lighting in GLSL, but have some problems and don’t seem to find anything useful in GLSL tutorials and books that i have, all of them inconsistent on this point.

i have attenuation, spoteffect, ambient, diffuse, specular computed for lighting;

from redbook
lighting = emmision + ambientmodel + attenuation * spoteffect * (ambient + diffuse + specular);

...
vec4 texture = texture2D(tex_base, texcoord);
vec4 lighting = attenuation * spoteffect * (ambient + diffuse + specular);

gl_FragColor = gl_LightModel.ambient * gl_FrontMaterial.ambient + lighting * texture;

This is what i am doing now, and i don’t think i am doing it right.
How can i combine texture and light, or at least where can i find “The Mathematics of Texturing AND Lighting” version that explains how OpenGL does this?

Thank You.

I would advice you to see the OpenGL specifications, the exact formula is written there.

BTW, your calculations seem ok to me.

Your specular needs to be mixed in with the fragment seprate than the diffuse.

I have always used:

(diffusepow includes attenuation and ambient factors. specularpow includes material “shininess” or gloss map factors)

gl_FragColor.r = (diffusepow * light_diffuse_color.r * texcolor.r) + (specularpow * light_specular_color.r);
gl_FragColor.g = (diffusepow * light_diffuse_color.g * texcolor.g) + (specularpow * light_specular_color.g);
gl_FragColor.b = (diffusepow * light_diffuse_color.b * texcolor.b) + (specularpow * light_specular_color.b);
gl_FragColor.a = 1.0;

Thanks for quick responses.

After checking OpenGL 2.1 Specification and sample code, i figured that i forgot secondary color.

// For GL_SINGLE_COLOR :
vec4 primary   = attenuation * spoteffect * (ambient + diffuse + specular) + gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient;
vec4 secondary = vec4(0, 0, 0, 1);

// For GL_SEPARATE_SPECULAR_COLOR :
vec4 primary   = attenuation * spoteffect * (ambient + diffuse) + gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient;
vec4 secondary = attenuation * spoteffect * specular;

// and finally :
gl_FragColor = primary * texture + secondary;

Results still don’t look same. This is the exact model? Since i still trying to find exact formula.

Thanks.

Edit : code

I take it that the sample for GL_SEPARATE_SPECULAR_COLOR has already mixed the diffuse light color with the texture color and stored them into “ambient” and “diffuse” values?

BTW, under what circumstance would a light’s specular color be different than it’s diffuse color? Just out of curiousity…

float coeff;	
if(0 == spec_model) {
	// blinn-phong
	vec3 h = normalize(e + l);
	coeff = max(dot(h, n), 0.0);
}
else {
	// phong
	vec3 r = normalize(reflect(-l, n));
	coeff = max(dot(e, r), 0.0);
}

float ndl = dot(n, l);

ambient  = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
diffuse  = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * max(ndl, 0.0);
specular = gl_LightSource[0].specular * gl_FrontMaterial.specular * pow(coeff, gl_FrontMaterial.shininess) * (ndl > 0.0 ? 1.0 : 0.0);

Well… “Therefore, if you want to create a realistic effect, set the GL_SPECULAR
parameter to the same value as the GL_DIFFUSE parameter” Redbook :slight_smile:

BTW, under what circumstance would a light’s specular color be different than it’s diffuse color? Just out of curiousity…
The specular reflection from most real surfaces is the color of the light source, hence the specular color should be white (or grey if its a very dull surface)
Only a few metals such as gold have a specular highlight the same color as the material, and hence these are the only materials that should use single-color mode if you want a realistic look.
For a textured surface, both the primary & secondary colors will usually be white, but you still need the separate secondary color to prevent the specular highlight being colored by the texture.

The full lighting equations are:

L = Direction of light
v = inverse of L
d = Spotlight pointing direction
s = half-angle vector
n = Vertex Normal

Light[0].Attenuation = 1/(ConstantAttenuation + (LinearAttenuation * Light[0].DistanceFromVertex) + (QuadraticAttenuation * Pow(Light[0].DistanceFromVertex,2)))

if spotlight then
if vertex outside light-cone then
Light[0].SpotlightEffect = 0
else
Light[0].SpotlightEffect = pow( max( dot(v,d),0 ), Light[0].SpotlightExponent )
else
Light[0].SpotlightEffect = 1;

NOTE: In the following equations all terms including “Light[0]” are repeated and summed for each light, while all other terms (emmisive & ambient) are only included once in the sum.

PrimaryColor = Material.Emission + (Light[0].Ambient * Material.Ambient) + ( Light[0].Attenuation * Light[0].SpotlightEffect * ((Light[0].Ambient * Material.Ambient) + (max(dot(L,n),0) * Light[0].Diffuse 8 Material.Diffuse))

SecondaryColor = Light[0].Attenuation * Light[0].SpotLightEffect * ( pow(max(dot(s,n), 0), Material.Shininess) * Light[0].Specular * Material.Specular );

(IF texturing is enabled THEN combine the texture color at the current texture coords with the PrimaryColor using the currently enabled replace, modulate, decal or blend texture function)

FragmentColor = PrimaryColor + SecondaryColor;

I get really different(weird?) results from my implementation of phong and blinn-phong.
i am missing something in these lines?
e = normal from vertex to eye
n = vertex normal
l = normal from vertex to lightpos.

float coeff;
if(0 == spec_model) {
	// blinn-phong
	vec3 h = normalize(e + l);
	coeff = max(dot(h, n), 0.0);
}
else if(1 == spec_model) {
	// phong
	vec3 r = reflect(-l, n);
	coeff = max(dot(e, r), 0.0);
}
else {
	// phong - test
	vec3 r = reflect(-l, n);
	coeff = dot(e, r);
}

// which will be used for
pow(coeff, gl_FrontMaterial.shininess)

And some screenshots…
OpenGL fixed.

GLSL using blinn.

GLSL using phong.

GLSL using phong(negative specular included for testing)

Looks like code is right.
Problem lies in material(shininess) properties of cloth.
I couldn’t figure it until now, because there is a huge difference between blinn and phong shaders, which made me think bug is in shader.

Blinn [always] gives you a positive specular coefficient if you see the vertex, because half vector lies between eye and light (h = normal(e + l)), and dot(h, n) >= 0.
This is different in Phong, because r (r = reflect(-l, n)) does not always lie between eye and light vectors(actually it does if you consider exterior angles :slight_smile: ), and dot(r, e) can be negative even if you see vertex.

So, phong realistic (exact?), blinn looks same at some situations and faster specular light model?

Thanks.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.