
Non-Circular Light in Edge of Face; Light Disappears in Center
Posted Thursday, 10 February, 2011 - 17:47 by GraysonPeddie inHi, everyone. I have a couple of codes and an image to show you what's going on, so what I'm trying to do is project a rounded light, but now, the light is quite weird. Have a look at my vertex/fragment code:
Vertex Shader (main.vert):
#version 140 // World space uniform mat4 world_matrix; // object space to camera space transformation uniform mat4 view_matrix; // camera space to clip coordinates uniform mat4 projection_matrix; // incoming vertex position in vec3 vertexPosition; // incoming vertex normal in vec3 vertexNormal; out vec3 position, normal; void main(void) { normal = normalize((world_matrix * vec4(vertexNormal, 1)).xyz); vec4 worldPosition = world_matrix * vec4(vertexPosition, 1); vec4 viewPosition = view_matrix * worldPosition; gl_Position = projection_matrix * viewPosition; position = worldPosition.xyz; }
Fragment Shader (Main.frag):
#version 140 precision highp float; uniform vec3 lightPosition; uniform vec4 lightColor, modelColor; in vec3 position, normal; out vec4 out_frag_color; void main(void) { vec3 lightVector = lightPosition - position; float dist = length(lightVector); // attenuation = 1.0 / (constantFactor + linearFactor * distance + quadraticFactor * distance * distance) float attenuationDiffuse = 1.0 / (0.0 + 1.0 * dist + 0.0 * dist * dist); lightVector = normalize(lightVector); float nxDir = max(0.0, dot(normal, lightVector)); out_frag_color = modelColor * lightColor * nxDir * attenuationDiffuse + vec4(0.1, 0.1, 0.1, 1.0); }
Here is the image:
I will give you the whole code so you can try them out:
MainGame.cs:
using System; using System.Diagnostics; using System.IO; using System.Windows.Forms; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; namespace HelloOpenGL { class MainGame : GameWindow { string vertexShaderSource, fragmentShaderSource; int vertexShaderHandle, fragmentShaderHandle, shaderProgramHandle, worldMatrixLocation, viewMatrixLocation, projectionMatrixLocation, modelColorLocation, lightColorLocation, lightPositionLocation; int cubeVboHandle, cubeIndicesVboHandle, floorVboHandle, floorIndicesVboHandle; Vector3[] cubePositionData = new Vector3[]{ new Vector3(-0.5f, -0.5f, 0.5f), new Vector3( 0.5f, -0.5f, 0.5f), new Vector3( 0.5f, 0.5f, 0.5f), new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3( 0.5f, -0.5f, -0.5f), new Vector3( 0.5f, 0.5f, -0.5f), new Vector3(-0.5f, 0.5f, -0.5f)}; Vector3[] cubeNormalData = new Vector3[]{ new Vector3( 0.0f, 0.0f, 1.0f), new Vector3( 0.0f, 1.0f, 0.0f), new Vector3( 1.0f, 0.0f, 0.0f), new Vector3( 0.0f, 0.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f)}; VertexPositionNormal[] cube; VertexPositionNormal[] floor = new VertexPositionNormal[] { new VertexPositionNormal(-32, 0, -32, 0, 1, 0), new VertexPositionNormal(32, 0, -32, 0, 1, 0), new VertexPositionNormal(32, 0, 32, 0, 1, 0), new VertexPositionNormal(-32, 0, 32, 0, 1, 0)}; // Projection and View matrix for camera; world matrix for object Matrix4 matProjection, matView, matWorld; ushort[] cubeIndicesVboData = new ushort[]{ 0, 1, 2, 2, 3, 0, // Front 4, 5, 6, 6, 7, 4, // Top 8, 9, 10, 10, 11, 8, // Back 12, 13, 14, 14, 15, 12, // Right 16, 17, 18, 18, 19, 16, // Bottom 20, 21, 22, 22, 23, 20}; // Left ushort[] floorIndicesVboData = new ushort[]{ 0, 1, 2, 2, 3, 0}; public MainGame() : base(1280, 720, new GraphicsMode(new ColorFormat(32)), "Hello OpenGL!", 0, DisplayDevice.Default, 3, 1, GraphicsContextFlags.Debug) { } protected override void OnLoad(EventArgs e) { base.OnLoad(e); cube = new VertexPositionNormal[]{ new VertexPositionNormal(cubePositionData[0], cubeNormalData[0]), new VertexPositionNormal(cubePositionData[1], cubeNormalData[0]), new VertexPositionNormal(cubePositionData[2], cubeNormalData[0]), new VertexPositionNormal(cubePositionData[3], cubeNormalData[0]), new VertexPositionNormal(cubePositionData[3], cubeNormalData[1]), new VertexPositionNormal(cubePositionData[2], cubeNormalData[1]), new VertexPositionNormal(cubePositionData[6], cubeNormalData[1]), new VertexPositionNormal(cubePositionData[7], cubeNormalData[1]), new VertexPositionNormal(cubePositionData[1], cubeNormalData[2]), new VertexPositionNormal(cubePositionData[5], cubeNormalData[2]), new VertexPositionNormal(cubePositionData[6], cubeNormalData[2]), new VertexPositionNormal(cubePositionData[2], cubeNormalData[2]), new VertexPositionNormal(cubePositionData[7], cubeNormalData[3]), new VertexPositionNormal(cubePositionData[6], cubeNormalData[3]), new VertexPositionNormal(cubePositionData[5], cubeNormalData[3]), new VertexPositionNormal(cubePositionData[4], cubeNormalData[3]), new VertexPositionNormal(cubePositionData[0], cubeNormalData[4]), new VertexPositionNormal(cubePositionData[1], cubeNormalData[4]), new VertexPositionNormal(cubePositionData[5], cubeNormalData[4]), new VertexPositionNormal(cubePositionData[4], cubeNormalData[4]), new VertexPositionNormal(cubePositionData[4], cubeNormalData[5]), new VertexPositionNormal(cubePositionData[0], cubeNormalData[5]), new VertexPositionNormal(cubePositionData[3], cubeNormalData[5]), new VertexPositionNormal(cubePositionData[7], cubeNormalData[5])}; vertexShaderSource = ReadFileToString("Shaders\\main.vert"); fragmentShaderSource = ReadFileToString("Shaders\\main.frag"); CreateShaders(); CreateProgram(); GL.UseProgram(shaderProgramHandle); QueryLocations(); float aspectRatio = (float)(ClientSize.Width) / (float)(ClientSize.Height); SetProjectionMatrix(Matrix4.CreatePerspectiveFieldOfView( ((float)(Math.PI) / 180.0f) * 45.0f, aspectRatio, 1.0f, 20.0f)); SetViewMatrix(Matrix4.CreateRotationX(0.5f) * Matrix4.CreateTranslation(0, 0, -16)); GL.GenBuffers(1, out floorVboHandle); GL.BindBuffer(BufferTarget.ArrayBuffer, floorVboHandle); GL.BufferData<VertexPositionNormal>(BufferTarget.ArrayBuffer, new IntPtr(floor.Length * VertexPositionNormal.SizeInBytes), floor, BufferUsageHint.StaticDraw); floorIndicesVboHandle = LoadIndexer(floorIndicesVboData); GL.GenBuffers(1, out cubeVboHandle); GL.BindBuffer(BufferTarget.ArrayBuffer, cubeVboHandle); GL.BufferData<VertexPositionNormal>(BufferTarget.ArrayBuffer, new IntPtr(cube.Length * VertexPositionNormal.SizeInBytes), cube, BufferUsageHint.StaticDraw); cubeIndicesVboHandle = LoadIndexer(cubeIndicesVboData); LoadVertexType(0, "vertexPosition"); LoadVertexType(1, "vertexNormal"); GL.Uniform4(lightColorLocation, Color4.White); GL.Enable(EnableCap.DepthTest); GL.ClearColor(Color4.Black); Keyboard.KeyDown += new EventHandler<OpenTK.Input.KeyboardKeyEventArgs>(Keyboard_KeyDown); this.WindowBorder = OpenTK.WindowBorder.Fixed; } private string ReadFileToString(string fileName) { bool error = false; string result = String.Empty; if (File.Exists(fileName)) { StreamReader file = null; string line; try { file = new StreamReader(fileName); while ((line = file.ReadLine()) != null) { result += line + "\n"; } } catch { MessageBox.Show("Error processing the file:\n\n" + fileName, Title); error = true; } finally { if (file != null) { file.Close(); file = null; } } } else { MessageBox.Show(fileName + " does not exist.", Title); error = true; } if (error) Exit(); return result; } private void CreateShaders() { vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader); GL.ShaderSource(vertexShaderHandle, vertexShaderSource); GL.CompileShader(vertexShaderHandle); Console.WriteLine(GL.GetShaderInfoLog(vertexShaderHandle)); fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader); GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource); GL.CompileShader(fragmentShaderHandle); Console.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle)); } private void CreateProgram() { shaderProgramHandle = GL.CreateProgram(); GL.AttachShader(shaderProgramHandle, vertexShaderHandle); GL.AttachShader(shaderProgramHandle, fragmentShaderHandle); GL.LinkProgram(shaderProgramHandle); Console.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle)); } private void QueryLocations() { projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix"); viewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "view_matrix"); worldMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "world_matrix"); modelColorLocation = GL.GetUniformLocation(shaderProgramHandle, "modelColor"); lightColorLocation = GL.GetUniformLocation(shaderProgramHandle, "lightColor"); lightPositionLocation = GL.GetUniformLocation(shaderProgramHandle, "lightPosition"); } private void SetWorldMatrix(Matrix4 matrix) { matWorld = matrix; GL.UniformMatrix4(worldMatrixLocation, false, ref matWorld); } private void SetViewMatrix(Matrix4 matrix) { matView = matrix; GL.UniformMatrix4(viewMatrixLocation, false, ref matView); } private void SetProjectionMatrix(Matrix4 matrix) { matProjection = matrix; GL.UniformMatrix4(projectionMatrixLocation, false, ref matProjection); } private void LoadVertexType(int index, string type) { GL.EnableVertexAttribArray(index); GL.BindAttribLocation(shaderProgramHandle, index, type); GL.VertexAttribPointer(index, 3, VertexAttribPointerType.Float, false, VertexPositionNormal.SizeInBytes, 0); } private int LoadIndexer(ushort[] indices) { int handle; GL.GenBuffers( 1, out handle ); GL.BindBuffer( BufferTarget.ElementArrayBuffer, handle ); GL.BufferData<ushort>( BufferTarget.ElementArrayBuffer, new IntPtr( indices.Length * sizeof(ushort) ), indices, BufferUsageHint.StaticDraw ); return handle; } void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs e) { switch (e.Key) { case OpenTK.Input.Key.Escape: Exit(); break; } } protected override void OnUpdateFrame(FrameEventArgs e) { } float rotateY = 0, moveLight = 0; protected override void OnRenderFrame(FrameEventArgs e) { GL.Viewport(0, 0, this.Width, this.Height); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); SetViewMatrix(matView); GL.Uniform3(lightPositionLocation, new Vector3((float)Math.Cos(moveLight) * 8.0f, 2, 0)); GL.BindBuffer(BufferTarget.ArrayBuffer, floorVboHandle); GL.VertexPointer(3, VertexPointerType.Float, 0, 0); GL.NormalPointer(NormalPointerType.Float, 0, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, floorIndicesVboHandle); GL.Uniform4(modelColorLocation, Color4.White); SetWorldMatrix( Matrix4.CreateRotationX((float)Math.PI / 180 * 270) * Matrix4.CreateTranslation(0, -0.5f, 0) * Matrix4.Scale(16.0f)); GL.DrawElements(BeginMode.Triangles, floorIndicesVboData.Length, DrawElementsType.UnsignedShort, 0); /*GL.BindBuffer(BufferTarget.ArrayBuffer, cubeVboHandle); GL.VertexPointer(3, VertexPointerType.Float, 0, 0); GL.NormalPointer(NormalPointerType.Float, 0, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, cubeIndicesVboHandle); GL.Uniform4(modelColorLocation, Color4.Blue); SetWorldMatrix(Matrix4.CreateRotationY((float)e.Time + rotateY) * Matrix4.CreateTranslation(0, 0.5f, 0)); GL.DrawElements(BeginMode.Triangles, cubeIndicesVboData.Length, DrawElementsType.UnsignedShort, 0);*/ GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); rotateY += (float)Math.PI / 360.0f; moveLight += (float)Math.PI / 1440.0f; GL.Flush(); SwapBuffers(); } } }
VertexPositionNormal.cs:
using System; using OpenTK; namespace HelloOpenGL { public struct VertexPositionNormal { public Vector3 position, normal; public VertexPositionNormal(float x, float y, float z, float nx, float ny, float nz) { position = new Vector3(x, y, z); normal = new Vector3(nx, ny, nz); } public VertexPositionNormal(Vector3 position, Vector3 normal) { this.position = position; this.normal = normal; } public static int SizeInBytes { get { return sizeof(float) * 6; } } } }
I have commented out the spinning cube code so you can see the effect without the cube shown).



Comments
Re: Non-Circular Light in Edge of Face; Light Disappears in ...
Hi, everyone. I found a way to get the light rounded in the surface of th polygons.
Here's the vertex shader:
And here's the fragment shader:
The result?
Well, what can I say? It took me a very long time to figure this out. It's trial and error until I get it right. Now, if only I could figure out how to adjust the radius of the point light... And I think it'll be interesting to try out uniform arrays for multiple dynamic lights! :) (Hmm...welcome to the world of programmable shaders. :))
Update: Here's an improved version of vertex and fragment shaders:
Vertex Shader:
Fragment Shader:
This is a clean-up version compared to my previous shader code from above.
I use multiple dynamic lights. For beginners, if you're going to need 4 lights in an array, your must create multiple location handles by doing something like this:
Then, when you are going to set values to the variables in GLSL, you can do this:
Here is my final result:
Neat, huh? Well, I hope I can be of help to those who need it.
Now, if only I could figure it out how to adjust the duration of the light source; I mean, from the center of the light source to the point where there is no light left...
Re: Non-Circular Light in Edge of Face; Light Disappears in ...
Now, if only I could figure it out how to adjust the duration of the light source; I mean, from the center of the light source to the point where there is no light left...
This is usually called falloff, you should find some examples on the net (linear falloff, exponential etc.).
Re: Non-Circular Light in Edge of Face; Light Disappears in ...
Hmm... Are you referring to this equation that I have in my code above?
attenuation = 1.0 / (constantFactor + linearFactor * distance + quadraticFactor * distance * distance)
I read Constant-Linear-Quadratic Falloff and I've realized that attenuation is falloff, but then I am starting to wonder how to increase the falloff (distance) without increasing the intensity of the light?
(A few minutes later...)
Hmm... This seems to make sense:
I'm thinking it might be impossible to not increase the intensity of the light while still increase the distance of the falloff. It has taken me a lot of searching to find what I'm looking for, though.
Re: Non-Circular Light in Edge of Face; Light Disappears in ...
Don't forget to clamp your attenuation:
Depending on the values of falloff and dist, your light can get brighter than 1.0 which is not what you want. Try this and see if it solves the light intensity issue.
Re: Non-Circular Light in Edge of Face; Light Disappears in ...
Oh, know what? I think this is what I want. As I move the light source as far away from the surface of the plane (it's just 2 polygons connected together), the intensity decreases while the falloff distance is the same (a misunderstanding on my part). Well, here's my final code that I have:
(The "color[i]" contains an array of ambient colors, so I changed the * to a + sign before modelColor, lightColor[i], and attenmuation gets multiplied.
Thanks for your help.