像往常一样,当我尝试用现代OpenGL弄湿手指时,使用我在某些博客上可以找到的一个聪明的演示,出现问题。
预期行为:绘制一个三角形,颜色应在3个顶点之间进行插值。
找到行为:三角形为红色。我写入颜色数组的颜色并不重要。
代码优先(抱歉160行 - 现代OpenGL是垃圾邮件......)。
open System
open System.Drawing
open System.Collections.Generic
open OpenTK
open OpenTK.Graphics
open OpenTK.Graphics.OpenGL
open OpenTK.Input
module Shaders =
let vertexShader =
"""#version 330
in vec3 vPosition;
in vec3 vColor;
out vec4 color;
uniform mat4 modelview;
void
main()
{
gl_Position = modelview * vec4(vPosition, 1.0);
color = vec4( vColor, 1.0);
}
"""
let fragmentShader =
"""#version 330
in vec4 color;
out vec4 outputColor;
void
main()
{
outputColor = color;
}
"""
let initShaders () : int =
let makeShader shaderType src =
let sh = GL.CreateShader(shaderType)
GL.ShaderSource(sh,src)
GL.CompileShader(sh)
sh
let pgmId = GL.CreateProgram()
let vsh = makeShader ShaderType.VertexShader vertexShader
let fsh = makeShader ShaderType.FragmentShader fragmentShader
GL.AttachShader(pgmId,vsh)
GL.AttachShader(pgmId,fsh)
GL.LinkProgram(pgmId)
pgmId
let failMinusOne = function
| -1 -> failwith "Something is -1 which should not be -1!"
| x -> x
type Game(width,height) =
inherit GameWindow(width, height, GraphicsMode.Default, "F# OpenTK Sample")
do base.VSync <- VSyncMode.On
let mutable shaderProgramId = -1
let mutable attribute_vcol = -1
let mutable attribute_vpos = -1
let mutable uniform_mview = -1
let mutable vbo_col = 0
let mutable vbo_pos = 0
let vertex_data =
[|
Vector3(-0.8f, -0.8f, 0.f)
Vector3( 0.8f, -0.8f, 0.f)
Vector3( 0.f, 0.8f, 0.f)
|]
let col_data =
[|
Vector3( 1.f, 1.f, 1.f)
Vector3( 0.f, 0.f, 1.f)
Vector3( 0.f, 1.f, 0.f)
|]
let mview_data = [| Matrix4.Identity |]
/// <summary>Load resources here.</summary>
/// <param name="e">Not used.</param>
override o.OnLoad e =
base.OnLoad(e)
o.Title <- "Hello OpenTK!"
shaderProgramId <- Shaders.initShaders ()
GL.ClearColor(Color.CornflowerBlue)
GL.Enable(EnableCap.DepthTest)
attribute_vpos <- GL.GetAttribLocation(shaderProgramId, "vPosition") |> failMinusOne
attribute_vcol <- GL.GetAttribLocation(shaderProgramId, "vColor") |> failMinusOne
uniform_mview <- GL.GetUniformLocation(shaderProgramId, "modelview") |> failMinusOne
vbo_col <- GL.GenBuffer()
vbo_pos <- GL.GenBuffer()
/// <summary>
/// Called when your window is resized. Set your viewport here. It is also
/// a good place to set up your projection matrix (which probably changes
/// along when the aspect ratio of your window).
/// </summary>
/// <param name="e">Not used.</param>
override o.OnResize e =
base.OnResize e
GL.Viewport(base.ClientRectangle.X, base.ClientRectangle.Y, base.ClientRectangle.Width, base.ClientRectangle.Height)
let projection = Matrix4.CreatePerspectiveFieldOfView(float32 (Math.PI / 4.), float32 base.Width / float32 base.Height, 1.f, 64.f)
GL.MatrixMode(MatrixMode.Projection)
GL.LoadMatrix(ref projection)
/// <summary>
/// Called when it is time to setup the next frame. Add you game logic here.
/// </summary>
/// <param name="e">Contains timing information for framerate independent logic.</param>
override o.OnUpdateFrame e =
base.OnUpdateFrame e
if base.Keyboard.[Key.Escape] then base.Close()
else
GL.BindBuffer(BufferTarget.ArrayBuffer,vbo_col)
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,Array.length col_data * Vector3.SizeInBytes,col_data,BufferUsageHint.StaticDraw)
GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, false, 0, 0)
GL.BindBuffer(BufferTarget.ArrayBuffer,vbo_pos)
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer,Array.length vertex_data * Vector3.SizeInBytes,vertex_data,BufferUsageHint.StaticDraw )
GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0)
GL.UniformMatrix4(uniform_mview,false,ref mview_data.[0])
GL.BindBuffer(BufferTarget.ArrayBuffer,0)
GL.UseProgram(shaderProgramId)
/// <summary>
/// Called when it is time to render the next frame. Add your rendering code here.
/// </summary>
/// <param name="e">Contains timing information.</param>
override o.OnRenderFrame(e) =
base.OnRenderFrame e
GL.Clear(ClearBufferMask.ColorBufferBit ||| ClearBufferMask.DepthBufferBit);
GL.EnableVertexArrayAttrib(attribute_vpos,0)
GL.EnableVertexArrayAttrib(attribute_vcol,0)
GL.DrawArrays(PrimitiveType.Triangles,0,Array.length vertex_data)
GL.DisableVertexArrayAttrib(attribute_vpos,0)
GL.DisableVertexArrayAttrib(attribute_vcol,0)
GL.Flush()
base.SwapBuffers()
[<EntryPoint>]
let main argv =
use game = new Game(800,600)
do game.Run(30.,30.)
0 // return an integer exit code
几个小时后,我试图找出问题所在。 添加更多三角形似乎也失败了。但是,三角形显示为顶点的事实让我想到,将数据下载到gpu是可以的。
但对于那些白天做的人来说,可能很容易发现问题出在哪里。
答案 0 :(得分:4)
您正在使用OpenGL 4.5函数EnableVertexArrayAttrib
在ID为的顶点数组对象(VAO)上启用顶点属性数组。这很奇怪,因为你的着色器被版本化为330
,因为你没有使用任何VAO,所以它更老,但更重要的是无效。
您可以使用经典方式启用/禁用顶点属性数组,如下所示:
GL.EnableVertexAttribArray(attribute_vpos)
GL.EnableVertexAttribArray(attribute_vcol)
GL.DisableVertexAttribArray(attribute_vpos)
GL.DisableVertexAttribArray(attribute_vcol)
这会在我的NVidia GTX 760桌面上生成正确颜色的三角形,因为它会对当前活动的顶点阵列信息起作用。
我建议您再次查看使用状态机的方式。启用顶点数组并通过VertexAttribPointer
定义其结构是特定于程序的并且属于一起。通常,您将使用VAO对此信息进行分组,并在绘制完成后将其解除绑定。如果顶点属性数组应该是全局状态,那么禁用它们是没有意义的,这个事实应该有详细记录。因此,代码存在开发看似无关的函数之间的虚假交互的危险,因为它共享OpenGL状态机的复杂状态。
可能的方法是:
设置
创建着色器,保持着色器程序句柄和属性位置
创建缓冲区,初始化数据,然后保存其句柄并使其不受约束
将顶点数组结构创建为VAO,然后保存其句柄并使其保持未绑定状态
绘图
这样的方法以更结构化的方式将与状态机的交互分组,并减少程序对OpenGL状态机值的依赖性保持不变。
不需要各种可变值及其初始化为-1。它们可以按顺序绑定,直接分配正确的句柄(假设OpenGL上下文已经存在;请参阅注释。)