OpenGL 中未使用的颜色数据 "Hello world"
Color data not used in OpenGL "Hello world"
像往常一样,当我尝试使用现代 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 是可以的。
但是对于那些日复一日地这样做的人来说,可能很容易发现哪里出了问题。
您正在使用 OpenGL 4.5 函数 EnableVertexArrayAttrib
在 ID 为 0 的顶点数组对象 (VAO) 上启用顶点属性数组 。这是很奇怪的,因为你的着色器被版本化为 330
,这是非常非常旧的,但更重要的是无效,因为你没有使用任何 VAO。
您可以 enable/disable 顶点属性数组的经典方式,如下所示:
GL.EnableVertexAttribArray(attribute_vpos)
GL.EnableVertexAttribArray(attribute_vcol)
GL.DisableVertexAttribArray(attribute_vpos)
GL.DisableVertexAttribArray(attribute_vcol)
这会在我的 NVidia GTX 760 桌面上生成正确着色的三角形,因为它作用于当前活动的顶点数组信息。
我建议再看看您使用状态机的方式。通过 VertexAttribPointer
启用顶点数组并定义它们的结构是 program-specific 并且属于一起。通常,您会使用 VAO 对这些信息进行分组,并在绘图完成后解除绑定。如果顶点属性数组应该是全局状态,那么禁用它们是没有意义的,这个事实应该是 well-documented。照原样,代码有在看似无关的函数之间形成虚假交互的危险,因为它共享 OpenGL 状态机的复杂状态。
一种可能的方法是:
设置
创建着色器,保留着色器程序句柄和属性位置
创建缓冲区,初始化数据,然后保存它们的句柄并保持它们未绑定
将顶点数组结构创建为 VAO,然后保存其句柄并使其保持未绑定状态
- 对于每个顶点数组,启用并指定(例如 VertexAttribPointer)
绘图
- 绑定 VAO
- 绑定 changing/additional 缓冲区(如果需要)
- 绑定程序
- 绘图调用
- 再次解除绑定(如果错误地依赖 OpenGL 状态,则快速失败)
像这样的方法以更结构化的方式将与状态机的交互分组,并减少程序对保持不变的 OpenGL 状态机值的依赖。
不需要各种可变值并将它们初始化为 -1。它们可以按顺序绑定,直接分配正确的句柄(假设 OpenGL 上下文已经存在;请参阅评论。)
像往常一样,当我尝试使用现代 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 是可以的。
但是对于那些日复一日地这样做的人来说,可能很容易发现哪里出了问题。
您正在使用 OpenGL 4.5 函数 EnableVertexArrayAttrib
在 ID 为 0 的顶点数组对象 (VAO) 上启用顶点属性数组 。这是很奇怪的,因为你的着色器被版本化为 330
,这是非常非常旧的,但更重要的是无效,因为你没有使用任何 VAO。
您可以 enable/disable 顶点属性数组的经典方式,如下所示:
GL.EnableVertexAttribArray(attribute_vpos)
GL.EnableVertexAttribArray(attribute_vcol)
GL.DisableVertexAttribArray(attribute_vpos)
GL.DisableVertexAttribArray(attribute_vcol)
这会在我的 NVidia GTX 760 桌面上生成正确着色的三角形,因为它作用于当前活动的顶点数组信息。
我建议再看看您使用状态机的方式。通过 VertexAttribPointer
启用顶点数组并定义它们的结构是 program-specific 并且属于一起。通常,您会使用 VAO 对这些信息进行分组,并在绘图完成后解除绑定。如果顶点属性数组应该是全局状态,那么禁用它们是没有意义的,这个事实应该是 well-documented。照原样,代码有在看似无关的函数之间形成虚假交互的危险,因为它共享 OpenGL 状态机的复杂状态。
一种可能的方法是:
设置
创建着色器,保留着色器程序句柄和属性位置
创建缓冲区,初始化数据,然后保存它们的句柄并保持它们未绑定
将顶点数组结构创建为 VAO,然后保存其句柄并使其保持未绑定状态
- 对于每个顶点数组,启用并指定(例如 VertexAttribPointer)
绘图
- 绑定 VAO
- 绑定 changing/additional 缓冲区(如果需要)
- 绑定程序
- 绘图调用
- 再次解除绑定(如果错误地依赖 OpenGL 状态,则快速失败)
像这样的方法以更结构化的方式将与状态机的交互分组,并减少程序对保持不变的 OpenGL 状态机值的依赖。
不需要各种可变值并将它们初始化为 -1。它们可以按顺序绑定,直接分配正确的句柄(假设 OpenGL 上下文已经存在;请参阅评论。)