Criperum's picture

Issue with normal buffer data

Hello everyone.

I'm totally noob in OpenTK and 3D as well. I was trying to modificate and launch one of the examples (code below).
I was trying to slightly randomize lighting through randomizing normals buffer. But I've encountered with strange issue: when I randomize Normal buffer data (as in code sample) the cube wraps itself. When I randomize positions - the lighting wraps. As I understand there must be the opposite behavior (normals for lighting and positions for shape).

What am I doing wrong? Please help.

using System;
using System.Diagnostics;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
 
namespace OpenTKTestProject
{
    public class TestWindow: GameWindow
    {
        string vertexShaderSource = @"
#version 130
 
precision highp float;
 
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
 
in vec3 in_position;
in vec3 in_normal;
 
out vec3 normal;
 
void main(void)
{
  //works only for orthogonal modelview
  normal = (modelview_matrix * vec4(in_normal, 0)).xyz;
 
  gl_Position = projection_matrix * modelview_matrix * vec4(in_position, 1);
}";
 
        string fragmentShaderSource = @"
#version 130
 
precision highp float;
 
const vec3 ambient = vec3(0.1, 0.1, 0.1);
const vec3 lightVecNormalized = normalize(vec3(0.5, 0.5, 2.0));
const vec3 lightColor = vec3(0.9, 0.9, 0.7);
 
in vec3 normal;
 
out vec4 out_frag_color;
 
void main(void)
{
  float diffuse = clamp(dot(lightVecNormalized, normalize(normal)), 0.0, 1.0);
  out_frag_color = vec4(ambient + diffuse * lightColor, 1.0);
}";
 
        int vertexShaderHandle,
            fragmentShaderHandle,
            shaderProgramHandle,
            modelviewMatrixLocation,
            projectionMatrixLocation,
            vaoHandle,
            positionVboHandle,
            normalVboHandle,
            eboHandle;
 
        Vector3[] positionVboData = new Vector3[]{
            new Vector3(-1.0f, -1.0f,  1.0f),
            new Vector3( 1.0f, -1.0f,  1.0f),
            new Vector3( 1.0f,  1.0f,  1.0f),
            new Vector3(-1.0f,  1.0f,  1.0f),
            new Vector3(-1.0f, -1.0f, -1.0f),
            new Vector3( 1.0f, -1.0f, -1.0f), 
            new Vector3( 1.0f,  1.0f, -1.0f),
            new Vector3(-1.0f,  1.0f, -1.0f) };
 
        Vector3[] normalVector3 = new Vector3[8];
 
 
        int[] indicesVboData = new int[]{
             // front face
                0, 1, 2, 2, 3, 0,
                // top face
                3, 2, 6, 6, 7, 3,
                // back face
                7, 6, 5, 5, 4, 7,
                // left face
                4, 0, 3, 3, 7, 4,
                // bottom face
                0, 1, 5, 5, 4, 0,
                // right face
                1, 5, 6, 6, 2, 1, };
 
        Matrix4 projectionMatrix, modelviewMatrix;
 
        public TestWindow()
            : base(640, 480,
            new GraphicsMode(), "OpenGL 3 Example", 0,
            DisplayDevice.Default, 3, 0,
            GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
        { }
 
        protected override void OnLoad (System.EventArgs e)
        {
            VSync = VSyncMode.On;
 
            CreateShaders();
            CreateVBOs();
            CreateVAOs();
 
            // Other state
            GL.Enable(EnableCap.DepthTest);
            GL.ClearColor(Color.MidnightBlue);
        }
 
        void CreateShaders()
        {
            vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
            fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
 
            GL.ShaderSource(vertexShaderHandle, vertexShaderSource);
            GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource);
 
            GL.CompileShader(vertexShaderHandle);
            GL.CompileShader(fragmentShaderHandle);
 
            Debug.WriteLine(GL.GetShaderInfoLog(vertexShaderHandle));
            Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle));
 
            // Create program
            shaderProgramHandle = GL.CreateProgram();
 
            GL.AttachShader(shaderProgramHandle, vertexShaderHandle);
            GL.AttachShader(shaderProgramHandle, fragmentShaderHandle);
 
            GL.LinkProgram(shaderProgramHandle);
 
            Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
 
            GL.UseProgram(shaderProgramHandle);
 
            // Set uniforms
            projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix");
            modelviewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "modelview_matrix");
 
            float aspectRatio = ClientSize.Width / (float)(ClientSize.Height);
            Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1, 100, out projectionMatrix);
            modelviewMatrix = Matrix4.LookAt(new Vector3(0, 3, 5), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
 
            GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);
            GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix);
        }
 
        void CreateVBOs()
        {
            Random rand = new Random();
            for (var i = 0; i < positionVboData.Length; i++)
            {
                Vector3 vec = positionVboData[i];
                normalVector3[i] = vec;
                vec.X = vec.X * (float)rand.NextDouble();
                vec.Y = vec.Y * (float)rand.NextDouble();
                vec.Z = vec.Z * (float)rand.NextDouble();
                positionVboData[i] = vec;
            }
 
 
            GL.GenBuffers(1, out positionVboHandle);
            GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                new IntPtr(positionVboData.Length * Vector3.SizeInBytes),
                positionVboData, BufferUsageHint.StaticDraw);
 
            GL.GenBuffers(1, out normalVboHandle);
            GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);
 
 
 
 
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                new IntPtr(normalVector3.Length * Vector3.SizeInBytes),
                normalVector3, BufferUsageHint.StaticDraw);
 
            GL.GenBuffers(1, out eboHandle);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
            GL.BufferData(BufferTarget.ElementArrayBuffer,
                new IntPtr(sizeof(uint) * indicesVboData.Length),
                indicesVboData, BufferUsageHint.StaticDraw);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        }
 
        void CreateVAOs()
        {
            // GL3 allows us to store the vertex layout in a "vertex array object" (VAO).
            // This means we do not have to re-issue VertexAttribPointer calls
            // every time we try to use a different vertex layout - these calls are
            // stored in the VAO so we simply need to bind the correct VAO.
            GL.GenVertexArrays(1, out vaoHandle);
            GL.BindVertexArray(vaoHandle);
 
            GL.EnableVertexAttribArray(0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
            GL.BindAttribLocation(shaderProgramHandle, 0, "in_position");
 
            GL.EnableVertexAttribArray(1);
            GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);
            GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0);
            GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal");
 
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle);
 
            GL.BindVertexArray(0);
 
            GL.Viewport(0, 0, Width, Height);
            GL.BindVertexArray(vaoHandle);
 
        }
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            Matrix4 rotation = Matrix4.CreateRotationY((float)e.Time);
            Matrix4.Mult(ref rotation, ref modelviewMatrix, out modelviewMatrix);
            GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix);
 
            if (Keyboard[OpenTK.Input.Key.Escape])
                Exit();
        }
 
        protected override void OnRenderFrame(FrameEventArgs e)
        {
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
 
 
            GL.DrawElements(BeginMode.Triangles, indicesVboData.Length,
                DrawElementsType.UnsignedInt, IntPtr.Zero);
 
            SwapBuffers();
        }
 
 
        [STAThread]
        static void Main(string[] args)
        {
            using (TestWindow example = new TestWindow())
            {
                //Utilities.SetWindowTitle(example);
                example.Run(30);
            }
        }
    }
}

Comments

Comment viewing options

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

When you relink the program, all uniforms are lost. You need to reset their values:

        protected override void OnLoad(System.EventArgs e)
        {
            VSync = VSyncMode.On;
 
            CreateShaders();
            CreateVBOs();
            CreateVAOs();
 
            GL.LinkProgram(shaderProgramHandle);
            Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle));
            GL.UseProgram(shaderProgramHandle);
 
            // Set uniforms
            projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix");
            modelviewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "modelview_matrix");
 
            float aspectRatio = ClientSize.Width / (float)(ClientSize.Height);
            Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, aspectRatio, 1, 100, out projectionMatrix);
            modelviewMatrix = Matrix4.LookAt(new Vector3(0, 3, 5), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
 
            GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);
            GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix);
 
            // Other state
            GL.Enable(EnableCap.DepthTest);
            GL.ClearColor(Color.MidnightBlue);
        }

This works for me.

Criperum's picture

That worked. Thank you. May be downloadable example code should be fixed? If it is still supported.

the Fiddler's picture

Fixed in 0e7f237 :)