problem with shader

Hey,

I’m trying to achieve this effect:

one texture on the dark side, other on the light side. I tried to do it, and this is the result I get:

notice the dark side isnt very well shaded… it should affect half the globe but it doesnt…
what could be wrong?
here the shaders:

Vertex shader:

  
varying vec3 lightDir,normal, viewVec;
	
void main()
{
	normal = normalize(gl_NormalMatrix * gl_Normal);
	lightDir = normalize(vec3(gl_LightSource[0].position));
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
}

Fragmeng shader:

 
varying vec3 lightDir, normal;
uniform sampler2D tex, tex2;

void main()
{
	vec3 nnormal = normalize(normal);	
	float intensity = max(dot(lightDir, nnormal),0.0);
	
	gl_FragColor = mix(texture2D(tex,gl_TexCoord[0].st).rgba, texture2D(tex2,gl_TexCoord[0].st).rgba, intensity);
}

any help?

thanks

In your vertex shader, you’re computing the light vector incorrectly. You’re computing the normalized light position, not the light direction. Light direction is light position - viewing position. That’s probably the big mistake right there.

something like:

varying vec3 lightDir, normal;
	
void main()
{
	vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
	normal = normalize(gl_NormalMatrix * gl_Normal);
	lightDir = vec3(normalize(gl_LightSource[0].position - viewPos));
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
}

I get the same results :frowning:

oh, and noticed something else too: I have my light position at {1.0, 0.0, 0.0} and the sphere I posted is 1.0 radius. However the dark hemisphere instead of crossing the poles… it doesnt, is not alined with them :frowning:

Hmm…in your fragment shader, you might not want to mix your alpha values as well. In a few instances, I’ve noticed that, if your alpha value is not exactly 1.0, you’ll end up with blending errors. Try this instead:

  vec3 color=mix(texture2D(tex,gl_TexCoord[0].st).rgb,texture2D(tex2,gl_TexCoord[0].st).rgb,intensity);
  gl_FragColor=vec4(color,1.0);

still, exactly the same result :frowning:

Since the light is simulating the sun which is almost directional light, your old lightDir calculating code was better than the one with the viewpos altrough that will also work, if the light is far enougth to appear as the directional one.

The reason why you are not getting the expected result is following:
The values of the function dot change from -1.0 to 1.0. The 0.0 is at the place where you expect the night-day boundary to be.
The mix function returns full first texture for factor 0.0 and full second texture for factor 1.0

Because of this, entire one hemisphere <-1,0> is occupied by day and the other hemisphere (0,1> is fully covered by transition between day and night so full night texture is present only on few pixels (if any).

You need to modify the intensity calculation so it maps e.g <-0.3, 0.3> range (depends on how wide the transition should be) of dot products to <0,1> range of mix factors.

Hmmm…okay, I entered your code into a shader previewer, and tweaked it until I got something I liked. Yours was working, just not fast enough, so you might want to add something like this:

	intensity=smoothstep(0.0,1.0,intensity*3.0);

It seems to work okay for me, but if not, you can always tweak the 3.0 to whatever value you want.

Since the light is simulating the sun which is almost directional light, your old lightDir calculating code was better than the one with the viewpos altrough that will also work, if the light is far enougth to appear as the directional one.

The reason why you are not getting the expected result is following:
The values of the function dot change from -1.0 to 1.0. The 0.0 is at the place where you expect the night-day boundary to be.
The mix function returns full first texture for factor 0.0 and full second texture for factor 1.0

Because of this, entire one hemisphere <-1,0> is occupied by day and the other hemisphere (0,1> is fully covered by transition between day and night so full night texture is present only on few pixels (if any).

You need to modify the intensity calculation so it maps e.g <-0.3, 0.3> range (depends on how wide the transition should be) of dot products to <0,1> range of mix factors.
how can I do that? is it something like Nychold suggested?

Originally posted by Nychold:
[b] Hmmm…okay, I entered your code into a shader previewer, and tweaked it until I got something I liked. Yours was working, just not fast enough, so you might want to add something like this:

	intensity=smoothstep(0.0,1.0,intensity*3.0);

It seems to work okay for me, but if not, you can always tweak the 3.0 to whatever value you want. [/b]
added that line… but the result is kinda weird (from a top view):

the division between the light and dark sides is a curve where it should be a straight line, right?
and tweaking the 3.0 still results in the same…

Originally posted by pedrosl:

how can I do that? is it something like Nychold suggested?

Yes, almost the same altrough with slightly different parameters so the transition is symetrical.

smoothstep( -0.1, 0.1, dot(lightDir, nnormal) )

ok! huge thanks for all the help.
Just one more thing: I’m having a hard time integrating this texture thing with some decent lighting. Can you give me some pointers? please?
Cause what I’m getting now is this:

which doesnt look very well on the lit part…

thanks again

Originally posted by pedrosl:

Just one more thing: I’m having a hard time integrating this texture thing with some decent lighting. Can you give me some pointers? please?

Unfortunatelly I know nothing about that, I never needed such information. Maybe you should look at some photos of the Earth I can only give you some ideas to try.

  • Use result of the dot product to modulate the color.[*]The real Earth has the atmosphere that under light creates the bluish tone (and the corona) whose intensity increases with the distance from the center of the sphere. The intensity propably depends on the thickness of the lit atmosphere between eye and surface.

ok, so I want to use a per vertex light with the per fragment effect above. I would say the output in my vertex shader would be something like:

	gl_FrontColor = (gl_LightSource[0].diffuse * diffuseAmount * max(dot(lightDir, normal), 0.0)) +
					(gl_LightSource[0].specular * specAmount * specValue);

but this couldnt work cause I’m also outputing a fragcolor in my frag shader, which would overwrite my gl_FrontColor, right? How can I make this work?

Thanks again

The value you write to the gl_FrontColor is available as gl_Color variable inside the fragment shader so you can combine it (probably by multiplication of the day texture) with your current calculation.
I would also suggest that you calculate the lighting per pixel, especially when the specular lighting is us used.

Originally posted by Komat:
The value you write to the gl_FrontColor is available as gl_Color variable inside the fragment shader so you can combine it (probably by multiplication of the day texture) with your current calculation.
something like:

mix(texture2D(tex,gl_TexCoord[0].st).rgba * gl_Color, texture2D(tex2,gl_TexCoord[0].st).rgba, intensity)

now my day texture doesnt appear, its just black :frowning:

Originally posted by Komat:
I would also suggest that you calculate the lighting per pixel, especially when the specular lighting is us used.
i tried using per pixel lighting but I didnt like the results, i think a simple vertex lighting works better… earth isn’t so shiny :wink:

Originally posted by pedrosl:
i tried using per pixel lighting but I didnt like the results, i think a simple vertex lighting works better… earth isn’t so shiny :wink:
If the calculations are the same, the maximal possible shinines is the same. The difference is that with vertex lighting it may change when the object is rotated which might be not what you want.

The correct way is to modify the equation so it is not that much shiny.

Originally posted by Komat:
[b] [quote]Originally posted by pedrosl:
i tried using per pixel lighting but I didnt like the results, i think a simple vertex lighting works better… earth isn’t so shiny :wink:
If the calculations are the same, the maximal possible shinines is the same. The difference is that with vertex lighting it may change when the object is rotated which might be not what you want.

The correct way is to modify the equation so it is not that much shiny. [/b][/QUOTE]ok, i guess you’re right. But even so, I can’t make this texture effect work with the lighting… I have the fragment color from the light, thru the lighting equation, and the frag color from the texture. How do I combine these two values?

thanks again

Originally posted by pedrosl:
[b]
mix(texture2D(tex,gl_TexCoord[0].st).rgba * gl_Color, texture2D(tex2,gl_TexCoord[0].st).rgba, intensity)

now my day texture doesnt appear, its just black :frowning:
[/b]
The factor is based on dot product and has value bigger than zero, where the object should be lit. For factor 1.0 the mix function returns the second parameter so you are showing the day texture on the unlit part of the sphere. You need to exchange first two parameters to the mix function.

Originally posted by pedrosl:
I have the fragment color from the light, thru the lighting equation, and the frag color from the texture. How do I combine these two values?

The diffuse part of lighting should be used to multiply the value from the texture. The specular part of the lighting should be added to the result of the multiplication.

first of all… huge thx for all the replies. But just one more thing :stuck_out_tongue: , I ended up with this:

Vert shader

#version 110

varying vec3 lightDir,normal, viewVec;
	
void main()
{
	vec3 ecPos = vec3(gl_ModelViewMatrix * gl_Vertex);
	viewVec = vec3(normalize(-ecPos));

	normal = normalize(gl_NormalMatrix * gl_Normal);
	lightDir = normalize(vec3(gl_LightSource[0].position) - ecPos);
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
} 

Frag shader

varying vec3 lightDir,normal, viewVec;
uniform sampler2D tex, tex2;

void main()
{
	vec3 ct,cf;
	vec4 texel;
	float intensity,at,af;
	
	vec3 nnormal = normalize(normal);
	
	intensity = smoothstep(-0.1, 0.1, dot(lightDir, nnormal));
	
	float specValue = clamp(dot(reflect(-normalize(lightDir), nnormal), normalize(viewVec)), 0.0, 1.0);
	specValue = pow(specValue, 6.0);
	
	cf = intensity * (gl_FrontMaterial.diffuse).rgb + 
					  (gl_FrontMaterial.ambient.rgb) + specValue;
	af = gl_FrontMaterial.diffuse.a;
	
	texel = texture2D(tex, gl_TexCoord[0].st);
	ct = texel.rgb;
	at = texel.a;
	
	gl_FragColor = mix(texture2D(tex2, gl_TexCoord[0].st).rgba, vec4(ct * cf, at * af), intensity);
}

and the result is kinda weird:

this shot was taken when a light was rotating around earth at a constant Y coord, so the day/night line should always be crossing the poles, but it isnt :frowning:

huge huge thx

Because you are using point light, the lights needs to be sufficiently far from the sphere so the effect would be similiar to the directional light. Or you can use directional light instead.