.-_'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.
FingersLingers's picture

Well, I'm now sure where things are going wrong for you bro....

Took your render code and slapped it into my sim environment (Changed it from a gl3.0 to gl2.0), with this code, like yours, but i needed to add a few more things.

        public override void Render() {
            GL.Enable(EnableCap.Texture2D);
            GL.Enable(EnableCap.DepthTest);
            GL.DepthFunc(DepthFunction.Lequal);
            GL.Enable(EnableCap.CullFace);
            GL.CullFace(CullFaceMode.Back);
            GL.FrontFace(FrontFaceDirection.Cw);
            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 = camera.LookAtMatrix();
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref modelview);
 
            texture.BindTextureUnit(0);
 
            Vector3 lightPos = new Vector3(1.0f, 0.0f, 1.0f);
            Vector4 lightDiff = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
            if(currentProgram!=null&&currentProgram.ID >=0) {
                currentProgram.Use();
                currentProgram.ApplyUniform("lightPosition", ref lightPos);
                currentProgram.ApplyUniform("lightDiffuse", ref lightDiff);
                currentProgram.ApplyUniform("color_texture", (int)0);
            } else GL.UseProgram(0);
 
 
            GL.Begin(BeginMode.TriangleFan);
 
            GL.Color4(0.0f, 0.0f, 1.0f, 1.0f);
            GL.TexCoord2(0.0f, 0.0f);
            GL.Normal3(0.0f, 0.0f, 1.0f);
            GL.Vertex3(-1.0f, -1.0f, 0.0f);
            GL.TexCoord2(0.0f, 1.0f);
            GL.Normal3(0.0f, 0.0f, 1.0f);
            GL.Vertex3(-1.0f, 1.0f, 0.0f);
            GL.TexCoord2(1.0f, 1.0f);
            GL.Normal3(0.0f, 0.0f, 1.0f);
            GL.Vertex3(1.0f, 1.0f, 0.0f);
            GL.TexCoord2(1.0f, 0.0f);
            GL.Normal3(0.0f, 0.0f, 1.0f);
            GL.Vertex3(1.0f, -1.0f, 0.0f);
 
            GL.End();
        }

I've attached 2 pictures, One which is blue, indicated the default shader is being used, as you can see I set the default color to blue,

Failed Shader Render

The second is with the shader code, exactly as you have it in this post(The most recent one), and it's doing what it is supposed to.

Latest Shader in post

You might want to check into your render routines and texture bindings perhaps.

Hope this helped bro :D

Happy Coding :D

FingersLingers's picture

To Elaborate a bit more, now that I've seen the shader run, This is what it looks like at present,

Current Render

As you can see the Lighting is uniform which is contributed to this line in the fragment shader

lightDir = normalize(vec3(lightPosition));

To get the result I think you are trying to achieve have a look at the next pic:

This is what it should look like

you can see the light is on the right hand side here, as the shading is brighter on the right, and duller on the left.

Here is the Modified Shaders, All thats been added is the interpolated Position, which is passed to the fragment shader from the vertex shader, and in the fragment shader, the light direction is calculated per fragment.

Vertex Shader

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

Fragment Shader

#version 120
 
varying vec2 texture_coordinate;
varying vec3 normal_out;
varying vec3 position_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(position_out-lightPosition));
  NdotL = max(dot(normal, lightDir), 0.0f);
 
  // Colors
  diffuse = gl_FrontMaterial.diffuse * lightDiffuse;
  gl_FragColor = sqrt(texture2D(color_texture, texture_coordinate) * NdotL * diffuse);
}

Happy Coding bro :D

.-_'s picture

I'm beginning to think my normals might be the problem. I use XML serialization to store my models.

pastebin.com/Axuq76Lc

FingersLingers's picture

Unfortunately, I'm not going to be much help there, Looking at that file, the normals look right, but i manage my stuff a bit different for gl3. Sry bro.

:(

.-_'s picture

New shader doesn't work either. Perhaps there is something else in my rendering code? I host my code in a github repo; perhaps, if we take a look at all of the code, something will become apparent?

https://github.com/josephd/opentk-tetris

FingersLingers's picture

I'll download it and have a look over the weekend, It's a long weekend here, so I'll only have internet on monday again :D

FingersLingers's picture

K, So I Went through your code, I couldn't run it due to dependencies I don't have on my home machine, However, I grabbed a texture, a model and the Mesh Loader you are using and got this result with a few changes to the Shaders.

Z On Green Block

Thats using the Z.png texture with the blockGreen Mesh, as you can see the Normals etc. are all working correctly, the changes to the shaders, are to reflect how the mesh drawer is actually giving the information to the shaders, so the matching Vertex Shader is this one, the only change in it is the setting of GL_FrontColor.

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

The fragment shader then uses the Color from the Vertex shader to do the calcs, also I added in a bit of ambient light, so I could see the block itself.

#version 120
 
varying vec2 texture_coordinate;
varying vec3 normal_out;
varying vec3 position_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(position_out-lightPosition));
  NdotL = max(dot(normal, lightDir), 0.0f);
 
  // Colors
  diffuse = gl_Color * lightDiffuse;
// Frag Color = ( texture Based Color Calc + Ambient );
  gl_FragColor = (texture2D(color_texture, texture_coordinate) * NdotL * diffuse) + (gl_Color * 0.1f);
}

Hope this helps to get you going again :D

EDIT: Also, the reason I Use the gl_Color in the fragment shader and not gl_FrontMaterial, is the MeshRenderer does not seem to be placing valid values for the shader to use, If I Override this in the code, it does work.

.-_'s picture

https://www.dropbox.com/s/sua2qoerq746kf6/tetris.png

This is what the above shader gives me. It's a result, which is good, but everything is dark, and no textures are visible (I think, it's hard to tell). Any ideas?

Thanks

FingersLingers's picture

Looks like your textures are not being addressed properly then.

Firstly, the dim colors:
For the dullness, thats sRBG out, you need to enable it, or in the shader just sqrt the output color to get a approximation of how it should look then.

Secondly, you might want to try these changes and see if it works for you:

Address the texture by creating a sampler for it your original texture loader

id = GL.GenTexture();
      GL.BindTexture(TextureTarget.Texture2D, id);
      BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
      GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0, GLPixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);
      bmp.UnlockBits(bmp_data);
      GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
      GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

Needs to change to this

// Store Texture ID
id = GL.GenTexture();
// Bind Texture
      GL.BindTexture(TextureTarget.Texture2D, id);
// Load Bitmap
      BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
      GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0, GLPixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);
      bmp.UnlockBits(bmp_data);
// Create a Sampler for the Texture
GL.GenSamplers(1, out samplerID);
// Set the texture access and bondries information for the Sampler
            GL.SamplerParameter(samplerID, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.SamplerParameter(samplerID, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.SamplerParameter(samplerID, SamplerParameter.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
            GL.SamplerParameter(samplerID, SamplerParameter.TextureWrapT, (int)TextureWrapMode.ClampToEdge);

You're going to need to store the sampler ID for later use, Then when you load ad compile the Program, you need to store another uniform location

SamplerUniform = GL.GetUniformLocation(Simple_Shader, "color_texture");

After that, when you render, you need to add the sampler to the uniform setting, here I'm binding the sampler to texture unit 0:

GL.Uniform3(ResourceCommons.LightPositionUniform, ref lightPos);
GL.Uniform4(ResourceCommons.LightDiffuseUniform, ref lightDiff);
GL.Uniform1(ResourceCommons.SamplerUniform, (IntPtr)(0));

then all the places you bind the texture need to change slightly

// This is what it is
//GL.BindTexture(TextureTarget.Texture2D, ResourceCommons.Block);
 
// To use the sampler binding the texture to Texture unit 0
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, ResourceCommons.Block);
GL.BindSampler(0, ResourceCommons.BlockSampler); // BlockSampler would be a variable that holds the location of the sampler created with the above texture loader

And as long as i haven't missed something, That should get you working with samplers, and hopefully you should see something on the screen

Happy Coding

.-_'s picture

How do I enable sRGB out? (I sense this is a really simply question)