.-_'s picture

Per pixel lighting?

I am trying to achieve per pixel lighting in my game. When I run my game, everything shows up solid black.

My VS:

varying vec2 texture_coordinate;
 
void main()
{
  vec3 normal, lightDir;
  vec4 diffuse;
  float NdotL;
 
  // Positions
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  texture_coordinate = vec2(gl_MultiTexCoord0);
 
  // Normals
  normal = normalize(gl_NormalMatrix * gl_Normal);
  lightDir = normalize(vec3(gl_LightSource[0].position));
  NdotL = max(dot(normal, lightDir), 0.0);
 
  // Colors
  diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
  gl_FrontColor = NdotL * diffuse;
}

My FS:

varying vec2 texture_coordinate;
 
uniform sampler2D color_texture;
 
void main()
{
    gl_FragColor = texture2D(color_texture, texture_coordinate) * gl_Color;
}

I don't really know how to set gl_LightSource[0], I set them parameters on light source 0, and enable it.
Any help?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
XZibit's picture

Replace gl_LightSource[0] with a set of uniform vectors and set them during rendering or once during initialisation

.-_'s picture

I tried replacing the light source params with uniforms. I still get a black square where my object should be. My code now looks like this:

varying vec2 texture_coordinate;
 
uniform vec3 lightPosition = vec3(1.0,  0.0, -1.0);
uniform vec4 lightDiffuse  = vec4(1.0,  1.0,  1.0,  1.0);
 
void main()
{
  vec3 normal, lightDir;
  vec4 diffuse;
  float NdotL;
 
  // Positions
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  texture_coordinate = vec2(gl_MultiTexCoord0);
 
  // Normals
  normal = normalize(gl_NormalMatrix * gl_Normal);
  lightDir = normalize(vec3(lightPosition));
  NdotL = max(dot(normal, lightDir), 0.0);
 
  // Colors
  diffuse = gl_FrontMaterial.diffuse * lightDiffuse;
  gl_FrontColor = NdotL * diffuse;
}

My GLSL skillz are very lacking :/. I'm still learning GLSL.

FingersLingers's picture

Dude, Can you provide a bit more information Like :

1) Whats your Shaders Version Declaration,
2) What GL Profile are you using , GL1.1, 2.0, 3.3 etc. ... Core or Compatibility if it's a higher version.
3) How are you trying to set the uniforms from the program, cause your shader declaration doen't look right.

Regards :D

PS: By the way your shaders are configured, It look like you are trying to do flat per-vertex lighting, not per-pixel(fragment) lighting.

.-_'s picture

1) I am using vesrion 120. Should that be specified in the shader with #version 120?
2) GL 2.0
3) How do I set uniforms from the program? Can they be set from the shader?

How should I be setting up my shaders to do per-fragment lighting?
Thank you for your patience, as I ahve already metioned, I am still learning

FingersLingers's picture
.-_ wrote:

1) I am using vesrion 120. Should that be specified in the shader with #version 120?
2) GL 2.0
3) How do I set uniforms from the program? Can they be set from the shader?

How should I be setting up my shaders to do per-fragment lighting?
Thank you for your patience, as I ahve already metioned, I am still learning

1) Yes #version 120 is the correct declaration for version 1.20

3a)Setting uniforms from the program is a done like this (Using your uniform declatations above)

// Storage variables
int programID;
int lightPositionUniform;
int lightDiffuseUniform;
 
// Done somewhere after a successful compile and link of the program
lightPositionUniform = GL.GetUniformLocation(programID, "lightPosition");
lightDiffuseUniform = GL.GetUniformLocation(programID, "lightDiffuse");
 
// Done in the render
Vector3 lightPos = new Vector3(1.0f,  0.0f, -1.0f);
Vector4 lightDiff  = new Vector4(1.0f,  1.0f,  1.0f,  1.0f);
GL.UseProgram(programID);
GL.Uniform3(lightPositionUniform, ref lightPos);
GL.Uniform4(lightDiffuseUniform, ref lightDiff);

Thats all good and well, but probably useless to you if you don't know why you're doing it , I'll explain in a bit:D

3b) Yes they can be set from the shader like you have done, however they are then static, and you could have just used const's instead.

OK, a bit of a explain here ...

Uniforms are used if you want to set a particular value, or values across all shaders within a program, this value can be changed by the host whenever it needs to, like your lightPos, could change and have a moving light, setting it in the shader, makes it static and useless if you actually want to move it around. Also, all objects drawn with that shader program will then have the updated light position, etc. information available, so set once when activating the program, and draw however many objects you wish. Another thing that can be done is to use uniform blocks, which is data that is accessable by multiple programs, you set it once, and only update as necessary, and any program that declares and is bound to that block of information can use it, however, uniform blocks are only available from GLSL 1.40 upwards.

Not sure if you know the difference between per-vertex and per fragment, so I'll give a brief overview, hope it helps(Short and sweet version):
If you have a triangle, it has 3 vertexes the Vertex shader is run 3 times, once for each vertex, from that the fragments are generated, so we can have a unknown amount of fragments, and for simplicity, lets say that one fragment is one pixel, so the fragment shader will run once per pixel. So what you probably want to be doing is the following. Each vertex stage setup the interpolated values necessary for the Fragment shader to use (Fragment shader Only gets interpolated values from the vertex shader), then your lighting calculations need to be done in the Fragment shader instead.

Vertex
Set Position,
Set Texture Coord Out
Set Normal Out

Fragment
get Normal AND NORMALIZE IT -- (Reason for normalizing here is simple, we are getting 3 vertex normals being interpolated here, so it will most likely not be a unit vector)
use uniforms to do your calculatioons etc. blah blah blah ...
Write the color out.
Done

Happy coding bro :D

.-_'s picture

Ok, I understand these concepts, but after corrections I am still getting nothing but black.

My VS:

#version 120
 
varying vec2 texture_coordinate;
varying vec3 normal_out;
 
uniform vec3 lightPosition;
uniform vec4 lightDiffuse;
 
void main()
{
 
  // Positions
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  texture_coordinate = vec2(gl_MultiTexCoord0);
 
  normal_out = gl_Normal;
}

My FS:

#version 120
 
varying vec2 texture_coordinate;
varying vec3 normal_out;
 
uniform sampler2D color_texture;
 
uniform vec3 lightPosition;
uniform vec4 lightDiffuse;
 
void main()
{
  vec3 normal, lightDir;
  vec4 diffuse;
  float NdotL;
 
  // Normals
  normal = normalize(gl_NormalMatrix * normal_out);
  lightDir = normalize(vec3(lightPosition));
  NdotL = max(dot(normal, lightDir), 0.0);
 
  // Colors
  diffuse = gl_FrontMaterial.diffuse * lightDiffuse;
  gl_FragColor = texture2D(color_texture, texture_coordinate) * NdotL * diffuse;
}

I have a feeling I am doing a lot of things very wrong in this, but I am having trouble coding shaders.

FingersLingers's picture

Lets go back a bit, Can you compile and execute a simple shader and get something on the screen, eg. vertex shader just sets the position and fragment just sets a color passed from the vertex shader ?

.-_'s picture

Yes, I have a shader that draw position color, and texture. That works fine.

FingersLingers's picture

Are you able to perhaps post your render routines code ?

.-_'s picture

Loading code:

      int status_code;
      string info;
      vertexObject = GL.CreateShader(ShaderType.VertexShader);
      fragmentObject = GL.CreateShader(ShaderType.FragmentShader);
      GL.ShaderSource(vertexObject, vs);
      GL.CompileShader(vertexObject);
      GL.GetShaderInfoLog(vertexObject, out info);
      GL.GetShader(vertexObject, ShaderParameter.CompileStatus, out status_code);
      if (status_code != 1)
	throw new ApplicationException(info);
      GL.ShaderSource(fragmentObject, fs);
      GL.CompileShader(fragmentObject);
      GL.GetShaderInfoLog(fragmentObject, out info);
      GL.GetShader(fragmentObject, ShaderParameter.CompileStatus, out status_code);
      if (status_code != 1)
	throw new ApplicationException(info);
      program = GL.CreateProgram();
      GL.AttachShader(program, fragmentObject);
      GL.AttachShader(program, vertexObject);
      GL.LinkProgram(program);

Rendering code:

      GL.Enable(EnableCap.Texture2D);
      GL.Enable(EnableCap.DepthTest);
      GL.Enable(EnableCap.CullFace);
      GL.Enable(EnableCap.Blend);
      GL.BlendEquation(BlendEquationMode.FuncAdd);
      GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
 
      GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
      GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
 
      Matrix4 modelview = Matrix4.LookAt(pos_eye, pos_field, Vector3.UnitY);
      GL.MatrixMode(MatrixMode.Modelview);
      GL.LoadMatrix(ref modelview);
 
      Vector3 lightPos = new Vector3(1.0f,  0.0f, -1.0f);
      Vector4 lightDiff  = new Vector4(1.0f,  1.0f,  1.0f,  1.0f);
      GL.UseProgram(ResourceCommons.Simple_Shader);
      GL.Uniform3(ResourceCommons.LightPositionUniform, ref lightPos);
      GL.Uniform4(ResourceCommons.LightDiffuseUniform, ref lightDiff);
 
      base.OnRenderFrame(e); // base class contains several vbos and textures that are rendered before buffer swap
 
      base.SwapBuffers();