glReadPixels不会将数据写入数组中。

huangapple go评论120阅读模式
英文:

glReadPixels does not write data to array

问题

我被卡在glReadPixels上了:似乎没有数据写入输出数组。

根据手册(https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glReadPixels.xml)中的说明,如果发生错误,则不会更改数据的内容,但是glGetError()没有返回任何错误。

我真的不明白出了什么问题...这是一个在屏幕上采样随机点的代码示例(使用golang)。它始终打印[0 0 0],尽管没有像素应该是黑色的(甚至不是背景)。

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/go-gl/gl/v4.1-core/gl"
  5. "github.com/veandco/go-sdl2/sdl"
  6. "math/rand"
  7. "os"
  8. "runtime"
  9. )
  10. func main() {
  11. // 随机崩溃,这似乎可以修复
  12. runtime.LockOSThread()
  13. var wWidth, wHeight int = 500, 500
  14. // 初始化SDL
  15. if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
  16. panic(err)
  17. }
  18. defer sdl.Quit()
  19. // 初始化OpenGL
  20. if err := gl.Init(); err != nil {
  21. panic(err)
  22. }
  23. // 创建支持OpenGL的窗口
  24. win, err := sdl.CreateWindow(
  25. "glReadPixels Test",
  26. sdl.WINDOWPOS_CENTERED,
  27. sdl.WINDOWPOS_CENTERED,
  28. wWidth, wHeight,
  29. sdl.WINDOW_OPENGL)
  30. if err != nil {
  31. panic(err)
  32. }
  33. defer win.Destroy()
  34. // 设置OpenGL上下文
  35. var ctx sdl.GLContext
  36. ctx, err = sdl.GL_CreateContext(win)
  37. if err != nil {
  38. panic(err)
  39. }
  40. defer sdl.GL_DeleteContext(ctx)
  41. // 设置
  42. initGL(wWidth, wHeight)
  43. for {
  44. for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
  45. switch event.(type) {
  46. case *sdl.QuitEvent:
  47. os.Exit(0)
  48. }
  49. }
  50. // 清除并绘制
  51. gl.Clear(gl.COLOR_BUFFER_BIT)
  52. gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
  53. rx, ry := rand.Intn(wWidth), rand.Intn(wHeight)
  54. gl.ReadBuffer(gl.FRONT) // 使用gl.BACK也不起作用
  55. data := make([]byte, 3)
  56. //data[0], data[1], data[2] = 123, 213, 132 // 测试是否被覆盖
  57. gl.ReadPixels(int32(rx), int32(ry), 1, 1, gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&data))
  58. fmt.Println("Read at", rx, ry, data)
  59. // 在窗口上显示
  60. sdl.GL_SwapWindow(win)
  61. // 检查错误...
  62. if gl.GetError() != gl.NO_ERROR {
  63. fmt.Println("GL ERROR Somewhere!")
  64. }
  65. sdl.Delay(uint32(300))
  66. }
  67. }
  68. func initGL(winW, winH int) {
  69. gl.ClearColor(0.2, 0.2, 0.3, 1.0)
  70. gl.Viewport(0, 0, int32(winW), int32(winH))
  71. // 着色器源代码
  72. vertShaderSrc := gl.Str(`
  73. #version 130
  74. in vec3 vertPos;
  75. in vec2 vertUV;
  76. out vec2 fragUV;
  77. void main() {
  78. gl_Position = vec4(vertPos, 1.0f);
  79. fragUV = vertUV;
  80. }
  81. ` + "\x00")
  82. fragShaderSrc := gl.Str(`#version 130
  83. in vec2 fragUV;
  84. out vec3 outColor;
  85. void main() {
  86. if (fragUV.x < 0.5 ^^ fragUV.y < 0.5)
  87. outColor = vec3(1.0, 0.0, 0.0);
  88. else
  89. outColor = vec3(0.0, 0.0, 1.0);
  90. }
  91. ` + "\x00")
  92. // 着色器
  93. var vShader, fShader uint32
  94. vShader = gl.CreateShader(gl.VERTEX_SHADER)
  95. fShader = gl.CreateShader(gl.FRAGMENT_SHADER)
  96. gl.ShaderSource(vShader, 1, &vertShaderSrc, nil)
  97. gl.ShaderSource(fShader, 1, &fragShaderSrc, nil)
  98. gl.CompileShader(vShader)
  99. gl.CompileShader(fShader)
  100. // 程序
  101. var progr uint32 = gl.CreateProgram()
  102. gl.AttachShader(progr, vShader)
  103. gl.AttachShader(progr, fShader)
  104. gl.BindAttribLocation(progr, 0, gl.Str("vertPos\x00"))
  105. gl.BindAttribLocation(progr, 1, gl.Str("vertUV\x00"))
  106. gl.LinkProgram(progr)
  107. gl.UseProgram(progr)
  108. const N float32 = -0.5
  109. const P float32 = 0.5
  110. // 设置“画布”:一个简单的四边形
  111. canvasData := []float32{
  112. N, N, 0, 0.0, 0.0,
  113. P, N, 0, 1.0, 0.0,
  114. N, P, 0, 0.0, 1.0,
  115. P, P, 0, 1.0, 1.0,
  116. }
  117. var vboID uint32
  118. gl.GenBuffers(1, &vboID)
  119. gl.BindBuffer(gl.ARRAY_BUFFER, vboID)
  120. gl.BufferData(gl.ARRAY_BUFFER, len(canvasData)*4, gl.Ptr(canvasData), gl.STATIC_DRAW)
  121. var vaoID uint32
  122. gl.GenVertexArrays(1, &vaoID)
  123. gl.BindVertexArray(vaoID)
  124. gl.EnableVertexAttribArray(0)
  125. gl.EnableVertexAttribArray(1)
  126. gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))
  127. gl.VertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))
  128. }

希望对你有所帮助!

英文:

I am stuck with glReadPixels: it appears that no data is written in the output array.

From the manual (https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glReadPixels.xml) it's written that If an error is generated, no change is made to the contents of data., but apparently no error is returned by glGetError().

I really can't understand what's wrong... Here's the code - in golang - that samples random point in the screen. It always print [0 0 0], although no pixel should be black (not even the background).

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;github.com/go-gl/gl/v4.1-core/gl&quot;
  5. &quot;github.com/veandco/go-sdl2/sdl&quot;
  6. &quot;math/rand&quot;
  7. &quot;os&quot;
  8. &quot;runtime&quot;
  9. )
  10. func main() {
  11. // Random crashes, this seems to fix
  12. runtime.LockOSThread()
  13. var wWidth, wHeight int = 500, 500
  14. // Initialize SDL
  15. if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
  16. panic(err)
  17. }
  18. defer sdl.Quit()
  19. // Initialize OpenGL
  20. if err := gl.Init(); err != nil {
  21. panic(err)
  22. }
  23. // Create the OpenGL-capable window
  24. win, err := sdl.CreateWindow(
  25. &quot;glReadPixels Test&quot;,
  26. sdl.WINDOWPOS_CENTERED,
  27. sdl.WINDOWPOS_CENTERED,
  28. wWidth, wHeight,
  29. sdl.WINDOW_OPENGL)
  30. if err != nil {
  31. panic(err)
  32. }
  33. defer win.Destroy()
  34. // Setup OpenGL context
  35. var ctx sdl.GLContext
  36. ctx, err = sdl.GL_CreateContext(win)
  37. if err != nil {
  38. panic(err)
  39. }
  40. defer sdl.GL_DeleteContext(ctx)
  41. // Settings
  42. initGL(wWidth, wHeight)
  43. for {
  44. for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
  45. switch event.(type) {
  46. case *sdl.QuitEvent:
  47. os.Exit(0)
  48. }
  49. }
  50. // Clear and draw
  51. gl.Clear(gl.COLOR_BUFFER_BIT)
  52. gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
  53. rx, ry := rand.Intn(wWidth), rand.Intn(wHeight)
  54. gl.ReadBuffer(gl.FRONT) // Not working with gl.BACK either
  55. data := make([]byte, 3)
  56. //data[0], data[1], data[2] = 123, 213, 132 // Test if it&#39;s overwritten
  57. gl.ReadPixels(int32(rx), int32(ry), 1, 1, gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&amp;data))
  58. fmt.Println(&quot;Read at&quot;, rx, ry, data)
  59. // Show on window
  60. sdl.GL_SwapWindow(win)
  61. // Check for errors...
  62. if gl.GetError() != gl.NO_ERROR {
  63. fmt.Println(&quot;GL ERROR Somewhere!&quot;)
  64. }
  65. sdl.Delay(uint32(300))
  66. }
  67. }
  68. func initGL(winW, winH int) {
  69. gl.ClearColor(0.2, 0.2, 0.3, 1.0)
  70. gl.Viewport(0, 0, int32(winW), int32(winH))
  71. // Shader sources
  72. vertShaderSrc := gl.Str(`
  73. #version 130
  74. in vec3 vertPos;
  75. in vec2 vertUV;
  76. out vec2 fragUV;
  77. void main() {
  78. gl_Position = vec4(vertPos, 1.0f);
  79. fragUV = vertUV;
  80. }
  81. ` + &quot;\x00&quot;)
  82. fragShaderSrc := gl.Str(`#version 130
  83. in vec2 fragUV;
  84. out vec3 outColor;
  85. void main() {
  86. if (fragUV.x &lt; 0.5 ^^ fragUV.y &lt; 0.5)
  87. outColor = vec3(1.0, 0.0, 0.0);
  88. else
  89. outColor = vec3(0.0, 0.0, 1.0);
  90. }
  91. ` + &quot;\x00&quot;)
  92. // Shaders
  93. var vShader, fShader uint32
  94. vShader = gl.CreateShader(gl.VERTEX_SHADER)
  95. fShader = gl.CreateShader(gl.FRAGMENT_SHADER)
  96. gl.ShaderSource(vShader, 1, &amp;vertShaderSrc, nil)
  97. gl.ShaderSource(fShader, 1, &amp;fragShaderSrc, nil)
  98. gl.CompileShader(vShader)
  99. gl.CompileShader(fShader)
  100. // Program
  101. var progr uint32 = gl.CreateProgram()
  102. gl.AttachShader(progr, vShader)
  103. gl.AttachShader(progr, fShader)
  104. gl.BindAttribLocation(progr, 0, gl.Str(&quot;vertPos\x00&quot;))
  105. gl.BindAttribLocation(progr, 1, gl.Str(&quot;vertUV\x00&quot;))
  106. gl.LinkProgram(progr)
  107. gl.UseProgram(progr)
  108. const N float32 = -0.5
  109. const P float32 = 0.5
  110. // Setup the &quot;canvas&quot;: a simple quad
  111. canvasData := []float32{
  112. N, N, 0, 0.0, 0.0,
  113. P, N, 0, 1.0, 0.0,
  114. N, P, 0, 0.0, 1.0,
  115. P, P, 0, 1.0, 1.0,
  116. }
  117. var vboID uint32
  118. gl.GenBuffers(1, &amp;vboID)
  119. gl.BindBuffer(gl.ARRAY_BUFFER, vboID)
  120. gl.BufferData(gl.ARRAY_BUFFER, len(canvasData)*4, gl.Ptr(canvasData), gl.STATIC_DRAW)
  121. var vaoID uint32
  122. gl.GenVertexArrays(1, &amp;vaoID)
  123. gl.BindVertexArray(vaoID)
  124. gl.EnableVertexAttribArray(0)
  125. gl.EnableVertexAttribArray(1)
  126. gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))
  127. gl.VertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))
  128. }

答案1

得分: 2

问题可能出在这里:

  1. gl.ReadPixels(int32(rx), int32(ry), 1, 1, gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&amp;data))

具体来说是这一部分:

  1. gl.Ptr(&amp;data)

该函数的文档如下:

  1. // Ptr接受一个切片或指针(指向一个标量值或数组/切片的第一个元素)并返回其GL兼容的地址。

你传递了一个指向切片的指针。如果你看一下实现,这是有问题的。

  1. func Ptr(data interface{}) unsafe.Pointer {
  2. if data == nil {
  3. return unsafe.Pointer(nil)
  4. }
  5. var addr unsafe.Pointer
  6. v := reflect.ValueOf(data)
  7. switch v.Type().Kind() {
  8. case reflect.Ptr:
  9. e := v.Elem()
  10. switch e.Kind() {
  11. case
  12. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  13. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  14. reflect.Float32, reflect.Float64:
  15. addr = unsafe.Pointer(e.UnsafeAddr())
  16. }
  17. case reflect.Uintptr:
  18. addr = unsafe.Pointer(v.Pointer())
  19. case reflect.Slice:
  20. addr = unsafe.Pointer(v.Index(0).UnsafeAddr())
  21. default:
  22. panic(fmt.Sprintf(&quot;Unsupported type %s; must be a pointer, slice, or array&quot;, v.Type()))
  23. }
  24. return addr
  25. }

如你所见,如果你传递的是指向除了基本的uint/float/int之外的任何类型的指针,它将会静默失败,并返回一个空的unsafe.Pointer,如果它不是正确的类型。所以你要么传递gl.Ptr(&amp;data[0]),要么传递gl.Ptr(data)。说实话,这样不会导致段错误,有点令人惊讶。

英文:

The problem is likely

  1. gl.ReadPixels(int32(rx), int32(ry), 1, 1, gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&amp;data))

Specifically

  1. gl.Ptr(&amp;data)

The documentation for that function is:

  1. // Ptr takes a slice or pointer (to a singular scalar value or the first
  2. // element of an array or slice) and returns its GL-compatible address.

You're passing a POINTER to a slice. This is... problematic if you look at the implementation.

  1. func Ptr(data interface{}) unsafe.Pointer {
  2. if data == nil {
  3. return unsafe.Pointer(nil)
  4. }
  5. var addr unsafe.Pointer
  6. v := reflect.ValueOf(data)
  7. switch v.Type().Kind() {
  8. case reflect.Ptr:
  9. e := v.Elem()
  10. switch e.Kind() {
  11. case
  12. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  13. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  14. reflect.Float32, reflect.Float64:
  15. addr = unsafe.Pointer(e.UnsafeAddr())
  16. }
  17. case reflect.Uintptr:
  18. addr = unsafe.Pointer(v.Pointer())
  19. case reflect.Slice:
  20. addr = unsafe.Pointer(v.Index(0).UnsafeAddr())
  21. default:
  22. panic(fmt.Sprintf(&quot;Unsupported type %s; must be a pointer, slice, or array&quot;, v.Type()))
  23. }
  24. return addr
  25. }

As you can see, if you pass in a pointer to anything other than a basic uint/float/int, it will fail silently and return a null unsafe.Pointer if it's not of the correct type. So you either want to pass in gl.Ptr(&amp;data[0]) or gl.Ptr(data). It's honestly kind of surprising this wasn't segfaulting.

huangapple
  • 本文由 发表于 2015年11月17日 00:30:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/33740157.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定