问题
Summary: My original question and observations are followed by an updated working OpenGL code for Intel HD Graphics 4000 GPU.
Original question: Two cubes are shown on Nvidia NVS 4200m GPU and 1 cube shown on Intel HD Graphics 4000 GPU.
- Using OpenGL 3.2 forward profile and OpenTK to render 2 simple cubes on screen
- It shows the first cube centered at (0,0,0) on Intel HD Graphics 4000 with the latest GPU driver 7/2/2014 ver 10.18.0010.3621. It should show 2 cubes.
- We're using a Vertex Array Object (VAO), vertex buffer, index buffer, attributes, normals and GLSL shaders
- Rebinding the element array buffer just after activating the VAO and before glDrawElements() still shows one cube on Intel and two cubes on Nvidia (VAO and element array buffer state)
- Shaders
- The vertex and fragment shaders compile and link OK
- The vertex and fragment shaders only read from input variables and write only to output variables. They do not read and write to an input/output/uniform. https://communities.intel.com/thread/36284
- glGetError() calls were done after each OpenGL call and returned no errors.
- The first cube is centered at (0,0,0), the second one is offset to (4,0,0) and both cubes rotate about (0,0,0)
- We build the buffers first, attributes next, then create the VAO and hook buffers/attributes to the VAO. Is there a special ordering needed for Intel to work? See: OpenGL, VAOs and multiple buffers
- Deactivating the VAO after glDrawElements() does not seem to help
Here is the source code based on the OpenTK example program "Open GL 3.0". It should show two cubes, rotating about (0,0,0) with a directional light source.
Update: 11/17/2014: The below code works on both Nvidia and Intel HD Graphics 4000 GPU.
Changes:
- Create VAO before creating buffers for the vertex, index, ... associated with the VAO
- Move GL.BindAttribLocation() call to just before linking the shader
- Rebind the element array buffer just before using GL.DrawElements() to render the 3d object
Deactivate the buffer and VAO after rendering
using System; using System.Diagnostics; using System.IO; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; namespace Examples.Tutorial { [Example("OpenGL 3.0 v2 2 vao works", ExampleCategory.OpenGL, "3.x", Documentation="HelloGL3 - v2 - create vao first")] public class HelloGL3v3 : 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, 20.0)); //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; Matrix4 projectionMatrix, modelviewMatrix; public HelloGL3v3() : base(800, 600, new GraphicsMode(), "OpenGL 3 Example", 0, DisplayDevice.Default, 3, 2, GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug) { } protected override void OnLoad (System.EventArgs e) { VSync = VSyncMode.On; CreateShaders(); CreateVaoOne(); CreateVaoTwo(); // Other state GL.Enable(EnableCap.DepthTest); E(); GL.ClearColor(System.Drawing.Color.MidnightBlue); E(); } void CreateShaders() { vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader); E(); fragmentShaderHandle = GL.CreateShader(ShaderType.FragmentShader); E(); GL.ShaderSource(vertexShaderHandle, vertexShaderSource); E(); GL.ShaderSource(fragmentShaderHandle, fragmentShaderSource); E(); GL.CompileShader(vertexShaderHandle); E(); GL.CompileShader(fragmentShaderHandle); E(); Debug.WriteLine(GL.GetShaderInfoLog(vertexShaderHandle)); Debug.WriteLine(GL.GetShaderInfoLog(fragmentShaderHandle)); // Create program shaderProgramHandle = GL.CreateProgram(); E(); GL.AttachShader(shaderProgramHandle, vertexShaderHandle); E(); GL.AttachShader(shaderProgramHandle, fragmentShaderHandle); E(); //BindAttribLocation() for shader needs to be done before linking the shader program GL.BindAttribLocation(shaderProgramHandle, 0, "in_position"); E(); GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal"); E(); GL.LinkProgram(shaderProgramHandle); E(); Debug.WriteLine(GL.GetProgramInfoLog(shaderProgramHandle)); GL.UseProgram(shaderProgramHandle); E(); // get uniform locations projectionMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "projection_matrix"); E(); modelviewMatrixLocation = GL.GetUniformLocation(shaderProgramHandle, "modelview_matrix"); 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, 13, 15), new Vector3(0, 0, 0), new Vector3(0, 1, 0)); GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix); E(); GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelviewMatrix); E(); } int vaoHandle, eboHandle; 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, }; void CreateVaoOne() { int positionVboHandle, normalVboHandle; 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, 2.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) }; // 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); E(); GL.BindVertexArray(vaoHandle); E(); //---------------------------------------------------------------------------- { GL.GenBuffers(1, out positionVboHandle); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); E(); GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData.Length * Vector3.SizeInBytes), positionVboData, BufferUsageHint.StaticDraw); E(); GL.EnableVertexAttribArray(0); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle); E(); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0); E(); //GL.BindAttribLocation(shaderProgramHandle, 0, "in_position"); E(); } //---------------------------------------------------------------------------- { GL.GenBuffers(1, out normalVboHandle); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle); E(); GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData.Length * Vector3.SizeInBytes), positionVboData, BufferUsageHint.StaticDraw); E(); GL.EnableVertexAttribArray(1); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle); E(); GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0); E(); //GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal"); E(); } { GL.GenBuffers(1, out eboHandle); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); E(); GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * indicesVboData.Length), indicesVboData, BufferUsageHint.StaticDraw); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); E(); } //---------------------------------------------------------------------------- GL.BindBuffer(BufferTarget.ArrayBuffer, 0); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); E(); GL.BindVertexArray(0); E(); } int vaoHandle2, eboHandle2; int[] indicesVboData2 = 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, }; void CreateVaoTwo() { int positionVboHandle2, normalVboHandle2; Vector3[] positionVboData2 = 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, 5.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[] normalsVboData2 = 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) }; //translate the points in the second cube away from the origin for (int i = 0; i < positionVboData2.Length; i++) positionVboData2[i] = Vector3.Add(positionVboData2[i], new Vector3(2.0f, 0f, 0f)); GL.GenVertexArrays(1, out vaoHandle2); E(); GL.BindVertexArray(vaoHandle2); E(); //---------------------------------------------------------------------------- //vertex array GL.GenBuffers(1, out positionVboHandle2); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle2); E(); GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(positionVboData2.Length * Vector3.SizeInBytes), positionVboData2, BufferUsageHint.StaticDraw); E(); GL.EnableVertexAttribArray(0); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, positionVboHandle2); E(); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0); E(); //GL.BindAttribLocation(shaderProgramHandle, 0, "in_position"); E(); //------------------------------------------------------------ //normals array GL.GenBuffers(1, out normalVboHandle2); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle2); E(); GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, new IntPtr(normalsVboData2.Length * Vector3.SizeInBytes), normalsVboData2, BufferUsageHint.StaticDraw); E(); GL.EnableVertexAttribArray(1); E(); GL.BindBuffer(BufferTarget.ArrayBuffer, normalVboHandle2); E(); GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, true, Vector3.SizeInBytes, 0); E(); //GL.BindAttribLocation(shaderProgramHandle, 1, "in_normal"); E(); //------------------------------------------------------------ //element (index) array GL.GenBuffers(1, out eboHandle2); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2); E(); GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(uint) * indicesVboData2.Length), indicesVboData2, BufferUsageHint.StaticDraw); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2); E(); //------------------------------------------------------------ GL.BindBuffer(BufferTarget.ArrayBuffer, 0); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); E(); GL.BindVertexArray(0); E(); } protected override void OnUpdateFrame(FrameEventArgs e) { if ((Keyboard[OpenTK.Input.Key.ControlLeft]) || (Keyboard[OpenTK.Input.Key.ControlRight])) return; 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.Viewport(0, 0, Width, Height); E(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); E(); //GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); GL.BindVertexArray(vaoHandle); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle); E(); GL.DrawElements(BeginMode.Triangles, indicesVboData.Length, DrawElementsType.UnsignedInt, IntPtr.Zero); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); GL.BindVertexArray(0); //----------------------------------------------------------------------- GL.BindVertexArray(vaoHandle2); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, eboHandle2); E(); GL.DrawElements(BeginMode.Triangles, indicesVboData2.Length, DrawElementsType.UnsignedInt, IntPtr.Zero); E(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); E(); GL.BindVertexArray(0); E(); SwapBuffers(); E(); } [STAThread] public static void Main() { using (HelloGL3v3 example = new HelloGL3v3()) { Utilities.SetWindowTitle(example); example.Run(30); } } private void E() { ErrorCode errorCode = GL.GetError(); if (errorCode == ErrorCode.NoError) return; throw new Exception("Error code - " + errorCode.ToString()); // some open GL Error } } }
来源:https://stackoverflow.com/questions/26876407/opengl-how-to-render-2-simple-vaos-on-intel-hd-graphics-4000-gpu