Luage's picture

GLSL variables switching values

I'm trying to make my first program that uses shaders. I copied some code from the example that comes with the program, and made some tweeks to enable myself to render some different objects.
It turns out that when I run the program on my computer, I have to set "in_position"="in_normal" and vise versa, for the correct output to show up.
On my friends computer the program runs as expected.
I'm using an intel 3000 graphics card. Driver is up to date. Code looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
namespace OpenGL_3_with_GLSL
{
    class Game : GameWindow
    {
        int vertexShaderHandle,
            fragmentShaderHandle,
            shaderProgramHandle,
            modelviewMatrixLocation,
            projectionMatrixLocation,
            vaoHandle,
            positionVboHandle,
            normalVboHandle,
            eboHandle;
 
        Matrix4 projectionMatrix, modelviewMatrix;
 
        DrawPlane dp;
 
 
        public Game()
            : base(640, 480,
            new GraphicsMode(), "OpenGL 3 Example", 0,
            DisplayDevice.Default, 3, 0,
            GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
        { }
 
        protected override void OnLoad (EventArgs e)
        {
            VSync = VSyncMode.On;
 
            dp = new DrawPlane(Vector3.Zero, 10.0f, 10.0f, 50, 50);
 
            CreateShaders();
            Console.WriteLine(GL.GetError());
            CreateVBOs();
            Console.WriteLine(GL.GetError());
            CreateVAOs();
            Console.WriteLine(GL.GetError());
 
            // Other state
            GL.Enable(EnableCap.DepthTest);
            GL.ClearColor(Color4.MidnightBlue);
        }
 
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            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 CreateShaders()
        {
            vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
            fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
 
 
            GL.ShaderSource(vertexShaderHandle, File.ReadAllText("vertexShader.vert"));
            GL.ShaderSource(fragmentShaderHandle, File.ReadAllText("fragmentShader.frag"));
 
            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()
        {
            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.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                new IntPtr(dp.positionVboData.Length * Vector3.SizeInBytes),
                dp.positionVboData, BufferUsageHint.StaticDraw);
 
            GL.GenBuffers(1, out normalVboHandle);
            GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle);
            //GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
            //    new IntPtr(positionVboData.Length * Vector3.SizeInBytes),
            //    positionVboData, BufferUsageHint.StaticDraw);
            GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,
                new IntPtr(dp.positionVboData.Length * Vector3.SizeInBytes),
                dp.normalVboData, 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.BufferData(BufferTarget.ElementArrayBuffer,
                new IntPtr(sizeof(uint) * dp.indicesVboData.Length),
                dp.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);
        }
 
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            Matrix4 rotation = Matrix4.CreateRotationY((float)e.Time*0.5f);
            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)
        {
            Title = String.Format("FPS: {0}", (1 / e.Time));
            GL.Viewport(0, 0, Width, Height);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.BindVertexArray(vaoHandle);
            GL.DrawElements(BeginMode.Triangles, dp.indicesVboData.Length,
                DrawElementsType.UnsignedInt, IntPtr.Zero);
 
            SwapBuffers();
        }
 
 
 
        [STAThread]
        static void Main(string[] args)
        {
            using (Game game = new Game())
            {
                game.Run(30.0);
            }
 
        }
    }
}

And the "DrawPlane" class I made to generate the vertex data:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
 
namespace OpenGL_3_with_GLSL
{
    class DrawPlane
    {
        Vector3 center;
        float width;
        float depth;
        int widthRes;
        int depthRes;
 
 
        public Vector3[] positionVboData { get; private set; }
        public Vector3[] normalVboData { get; private set; }
        public uint[] indicesVboData { get; private set; }
 
 
        public DrawPlane(Vector3 Center, float Width, float Depth, int WidthRes, int DepthRes)
        {
            center = Center;
            width = Width;
            depth = Depth;
            widthRes = WidthRes;
            depthRes = DepthRes;
 
            CalcPositionAndNormal();
            CalcIndices();
        }
 
 
        void CalcPositionAndNormal()
        {
            positionVboData = new Vector3[(widthRes + 1) * (depthRes + 1)];
            normalVboData = new Vector3[(widthRes + 1) * (depthRes + 1)];
            float widthStepSize = width / widthRes;
            float depthStepSize = depth / depthRes;
            float widthStepSize2 = widthStepSize * widthStepSize;
            float depthStepSize2 = depthStepSize * depthStepSize;
            int halfWidth = (widthRes + 1) / 2;
            int halfDepth = (depthRes + 1) / 2;
 
            for (int i = 0; i < widthRes+1; i++)
                for (int j = 0; j < depthRes+1; j++)
                    positionVboData[i * (depthRes + 1) + j] = new Vector3((i-halfWidth) * widthStepSize, (float)Math.Exp(-((i-halfWidth) * (i-halfWidth) * widthStepSize2 + (j-halfDepth) * (j-halfDepth) * depthStepSize2)), (j-halfDepth) * depthStepSize)+center;
 
 
            for (int i = 0; i < widthRes+1; i++)
                for (int j = 0; j < depthRes+1; j++)
                    normalVboData[i * (depthRes + 1) + j] = new Vector3(2 * (i - halfWidth) * widthStepSize * (float)Math.Exp(-((i - halfWidth) * (i - halfWidth) * widthStepSize2 + (j - halfDepth) * (j - halfDepth) * depthStepSize2)), 1.0f, 2 * (j - halfDepth) * depthStepSize * (float)Math.Exp(-((i - halfWidth) * (i - halfWidth) * widthStepSize2 + (j - halfDepth) * (j - halfDepth) * depthStepSize2)));
 
        }
 
        void CalcIndices()
        {
            indicesVboData = new uint[6 * widthRes * depthRes];
            int index=0;
 
            for (int i = 0; i < widthRes; i++)
                for (int j = 0; j < depthRes; j++)
                    for (int k = 0; k < 6; k++)
                        indicesVboData[index++] = (uint)(k % 2 + (widthRes + 1) * Convert.ToInt32(k%5>1) + i * (widthRes + 1) + j);
 
        }
 
 
 
    }
}

Comments

Comment viewing options

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

This might be a driver bug. One thing you could do is to query the attribute location at runtime using GL.GetAttribLocation, same as what you do for uniforms. This should give you the correct result regardless of the driver.

Edit: you can also try calling CreateVAOs() before CreateShaders(). This is allowed as per the glBindAttribLocation spec.

Luage's picture

Following your second suggestion to some degree solved the problem (the way my code is set up does not allow changing the order of those functions, but moving the GL.BindAttribLocation call to the Create shaders function worked. As specialpatrol on reddit pointed out, GL.BindAttribLocation has to be called before GL.LinkProgram. http://www.reddit.com/r/opengl/comments/1ojmpl/problem_with_shaders/

The sample from the "OpenTK eksample browser" doesn't take this into account, but maybe that's because it isn't required for all graphics cards?
Anyways, thank you very much for your quick response :)
It helped out a lot.

the Fiddler's picture

Hmm, this makes sense. I will double-check and update the example code.