PDA

View Full Version : Directional light shaders

M//Hax
12-20-2010, 02:28 PM
I tried following this tutorial (http://zach.in.tu-clausthal.de/teaching/cg_literatur/glsl_tutorial/index.html#ogldir1) for implementing a directional light per pixel in my code, but it's just not working.

Here my .frag and .vert :

// .vert
uniform float pointRadius; // point size in world space
uniform float pointScale; // scale to calculate size in pixels
varying vec3 posEye;
void main()
{
// calculate window-space point size
posEye = vec3(gl_ModelViewMatrix * vec4(gl_Vertex.xyz, 1.0));
float dist = length(posEye);
gl_PointSize = pointRadius * (pointScale / dist);
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}

uniform float pointRadius; // point size in world space
varying vec3 posEye; // position of center in eye space
uniform vec3 lightDir;
void main()
{

lightDir = normalize(vec3(gl_LightSource[0].position));
// calculate normal from texture coordinates
vec3 N;
N.xy = gl_TexCoord[0].xy*vec2(2.0, -2.0) + vec2(-1.0, 1.0);
float mag = dot(N.xy, N.xy);
if (mag > 1.0) discard; // kill pixels outside circle
N.z = sqrt(1.0-mag);
// calculate lighting
float diffuse = max(0.0, dot(lightDir, N));
gl_FragColor = gl_Color * diffuse;
}

Alfonse Reinheart
12-20-2010, 04:36 PM
I tried following this tutorial (http://zach.in.tu-clausthal.de/teaching/cg_literatur/glsl_tutorial/index.html#ogldir1) for implementing a directional light per pixel in my code

You made some pretty substantial changes to the code for something that is supposed to be following the tutorial. For example, the camera-space surface normal in the tutorial was passed as a varying in the tutorial. In your code...

Well really, that's likely your problem. In your code, you "calculate normal from texture coordinates". But you didn't pass any texture coordinates from your vertex shader. It never sets gl_TexCoord[0]. Why this isn't a linker error, I don't know.

This is one reason why you should always declare your shader inputs and outputs, even if they're built-ins. That way, you can know at a glance what your shaders read and right. It's also why avoiding built-ins is a good idea for a beginner; it forces you to explicitly say what you're doing.

M//Hax
12-21-2010, 06:29 AM
I tried following this tutorial (http://zach.in.tu-clausthal.de/teaching/cg_literatur/glsl_tutorial/index.html#ogldir1) for implementing a directional light per pixel in my code

You made some pretty substantial changes to the code for something that is supposed to be following the tutorial. For example, the camera-space surface normal in the tutorial was passed as a varying in the tutorial. In your code...

Well really, that's likely your problem. In your code, you "calculate normal from texture coordinates". But you didn't pass any texture coordinates from your vertex shader. It never sets gl_TexCoord[0]. Why this isn't a linker error, I don't know.

This is one reason why you should always declare your shader inputs and outputs, even if they're built-ins. That way, you can know at a glance what your shaders read and right. It's also why avoiding built-ins is a good idea for a beginner; it forces you to explicitly say what you're doing. ThatMs because i want the point sprites to stay as spheres, if i change something else, the points will appear as point. So that's why i'm having trouble using the tutorial.

Alfonse Reinheart
12-21-2010, 07:21 AM
ThatMs because i want the point sprites to stay as spheres, if i change something else, the points will appear as point.

That sounds like an even bigger bug. Admittedly, I haven't used point sprites much, so I don't fully understand the vagaries around them. But I don't understand how which inputs/outputs you use affects where it is a "sphere" or a "point".

But your problem remains as stated. Your vertex shader does not output the correct information to the fragment shader. Until you do so, you will not get proper lighting.

M//Hax
12-21-2010, 08:08 AM
ThatMs because i want the point sprites to stay as spheres, if i change something else, the points will appear as point.

That sounds like an even bigger bug. Admittedly, I haven't used point sprites much, so I don't fully understand the vagaries around them. But I don't understand how which inputs/outputs you use affects where it is a "sphere" or a "point".

But your problem remains as stated. Your vertex shader does not output the correct information to the fragment shader. Until you do so, you will not get proper lighting.
im trying to modify it because i don't want the light to follow the user eye position (right now, no matter how you are rotating around the point sprites, it's always looking the same, the sphere is always the same).

Alfonse Reinheart
12-21-2010, 08:38 AM
That code makes no sense.

Points are not quads. They have never been quads. The varyings are not interpolated over the area of the point. Therefore, if you pass a varying, every fragment gets the same value. Which means that you cannot use a varying to compute where you are on the surface.

(note: the above is true for shaders. Fixed function works differently)

If you want to know where you are on a point, you use gl_PointCoord. You can then do interpolation as you see fit.

M//Hax
12-21-2010, 09:28 AM
That code makes no sense.

Points are not quads. They have never been quads. The varyings are not interpolated over the area of the point. Therefore, if you pass a varying, every fragment gets the same value. Which means that you cannot use a varying to compute where you are on the surface.

(note: the above is true for shaders. Fixed function works differently)

If you want to know where you are on a point, you use gl_PointCoord. You can then do interpolation as you see fit.

I use point sprites to simulate alot of spheres, over 2 millions. Since it would be hard to render that many spheres using quads, i use point sprite, and use a shader to make them look like spheres. Now, the points sprites are always facing the user. I need them to stay fixed, so i can move around to really have the sensation of a 3d sphere.

Alfonse Reinheart
12-21-2010, 09:44 AM
Now, the points sprites are always facing the user. I need them to stay fixed, so i can move around to really have the sensation of a 3d sphere.

Assuming you have corrected the problem I mentioned, you still have other problems. For example, you are doing your lighting in camera space. This means that your light direction needs to be relative to the camera. It therefore changes when the camera changes.

However, you use a constant light direction:

const vec3 lightDir = vec3(0.577, 0.577, 0.577);

So it isn't relative to the camera.

M//Hax
12-21-2010, 10:04 AM
It is constant, relative to the position of the camera. Right now, The light is indeed following the camera. What i'm trying to do is the OPPOSITE.

ZbuffeR
12-21-2010, 11:05 AM
M//Hax you where already told you have to change this uniform to make camera and light independent from each other !

M//Hax
12-21-2010, 11:08 AM
M//Hax you where already told you have to change this uniform to make camera and light independent from each other !

Like this ? :

uniform float pointRadius; // point size in world space
varying vec3 posEye; // position of center in eye space
uniform vec3 lightDir;
void main()
{
lightDir = vec3(0.577, 0.577, 0.577);

Alfonse Reinheart
12-21-2010, 11:32 AM
Like this ? :

That won't even compile. You cannot set uniforms from a shader (except as a constant initializer). They can only be set from code.

You have a light direction in world space. This represents the direction from the object to the light. You need a light direction in camera space. Therefore, you must transform the world space light direction into camera space. This is done on the CPU; the shader is then given the light direction in camera space as a uniform.

ZbuffeR
12-21-2010, 11:33 AM
Not at all, try this instead :
http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml

M//Hax
12-21-2010, 12:02 PM
ok so it should be something like that?

uniform float pointRadius; // point size in world space
varying vec3 posEye; // position of center in eye space
uniform vec3 lightDir;
void main()

//in void initPointSprites(), in main.cpp