donglangtun1850
donglangtun1850
2015-11-16 16:30
浏览 94
已采纳

glReadPixels不会将数据写入数组

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).

package main

import (
    "fmt"
    "github.com/go-gl/gl/v4.1-core/gl"
    "github.com/veandco/go-sdl2/sdl"
    "math/rand"
    "os"
    "runtime"
)

func main() {
    // Random crashes, this seems to fix
    runtime.LockOSThread()

    var wWidth, wHeight int = 500, 500

    // Initialize SDL
    if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
        panic(err)
    }
    defer sdl.Quit()

    // Initialize OpenGL
    if err := gl.Init(); err != nil {
        panic(err)
    }

    // Create the OpenGL-capable window
    win, err := sdl.CreateWindow(
        "glReadPixels Test",
        sdl.WINDOWPOS_CENTERED,
        sdl.WINDOWPOS_CENTERED,
        wWidth, wHeight,
        sdl.WINDOW_OPENGL)

    if err != nil {
        panic(err)
    }
    defer win.Destroy()

    // Setup OpenGL context
    var ctx sdl.GLContext
    ctx, err = sdl.GL_CreateContext(win)
    if err != nil {
        panic(err)
    }
    defer sdl.GL_DeleteContext(ctx)

    // Settings
    initGL(wWidth, wHeight)

    for {
        for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
            switch event.(type) {
            case *sdl.QuitEvent:
                os.Exit(0)
            }
        }

        // Clear and draw
        gl.Clear(gl.COLOR_BUFFER_BIT)
        gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)

        rx, ry := rand.Intn(wWidth), rand.Intn(wHeight)

        gl.ReadBuffer(gl.FRONT) // Not working with gl.BACK either
        data := make([]byte, 3)
        //data[0], data[1], data[2] = 123, 213, 132 // Test if it's overwritten
        gl.ReadPixels(int32(rx), int32(ry), 1, 1, gl.RGB, gl.UNSIGNED_BYTE, gl.Ptr(&data))
        fmt.Println("Read at", rx, ry, data)

        // Show on window
        sdl.GL_SwapWindow(win)

        // Check for errors...
        if gl.GetError() != gl.NO_ERROR {
            fmt.Println("GL ERROR Somewhere!")
        }

        sdl.Delay(uint32(300))
    }
}

func initGL(winW, winH int) {
    gl.ClearColor(0.2, 0.2, 0.3, 1.0)
    gl.Viewport(0, 0, int32(winW), int32(winH))

    // Shader sources
    vertShaderSrc := gl.Str(`
#version 130

in vec3 vertPos;
in vec2 vertUV;

out vec2 fragUV;

void main() {
    gl_Position = vec4(vertPos, 1.0f);
    fragUV = vertUV;
}
` + "\x00")

    fragShaderSrc := gl.Str(`#version 130
in vec2 fragUV;
out vec3 outColor;

void main() {
    if (fragUV.x < 0.5 ^^ fragUV.y < 0.5)
        outColor = vec3(1.0, 0.0, 0.0);
    else
        outColor = vec3(0.0, 0.0, 1.0);
}
` + "\x00")

    // Shaders
    var vShader, fShader uint32
    vShader = gl.CreateShader(gl.VERTEX_SHADER)
    fShader = gl.CreateShader(gl.FRAGMENT_SHADER)
    gl.ShaderSource(vShader, 1, &vertShaderSrc, nil)
    gl.ShaderSource(fShader, 1, &fragShaderSrc, nil)
    gl.CompileShader(vShader)
    gl.CompileShader(fShader)

    // Program
    var progr uint32 = gl.CreateProgram()
    gl.AttachShader(progr, vShader)
    gl.AttachShader(progr, fShader)
    gl.BindAttribLocation(progr, 0, gl.Str("vertPos\x00"))
    gl.BindAttribLocation(progr, 1, gl.Str("vertUV\x00"))
    gl.LinkProgram(progr)
    gl.UseProgram(progr)

    const N float32 = -0.5
    const P float32 = 0.5

    // Setup the "canvas": a simple quad
    canvasData := []float32{
        N, N, 0, 0.0, 0.0,
        P, N, 0, 1.0, 0.0,
        N, P, 0, 0.0, 1.0,
        P, P, 0, 1.0, 1.0,
    }

    var vboID uint32
    gl.GenBuffers(1, &vboID)
    gl.BindBuffer(gl.ARRAY_BUFFER, vboID)
    gl.BufferData(gl.ARRAY_BUFFER, len(canvasData)*4, gl.Ptr(canvasData), gl.STATIC_DRAW)

    var vaoID uint32
    gl.GenVertexArrays(1, &vaoID)
    gl.BindVertexArray(vaoID)

    gl.EnableVertexAttribArray(0)
    gl.EnableVertexAttribArray(1)

    gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))
    gl.VertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doulianglou0898
    doulianglou0898 2015-11-17 05:47
    已采纳

    The problem is likely

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

    Specifically

    gl.Ptr(&data)
    

    The documentation for that function is:

    // Ptr takes a slice or pointer (to a singular scalar value or the first
    // 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.

    func Ptr(data interface{}) unsafe.Pointer {
        if data == nil {
            return unsafe.Pointer(nil)
        }
        var addr unsafe.Pointer
        v := reflect.ValueOf(data)
        switch v.Type().Kind() {
        case reflect.Ptr:
            e := v.Elem()
            switch e.Kind() {
            case
                reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
                reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
                reflect.Float32, reflect.Float64:
                addr = unsafe.Pointer(e.UnsafeAddr())
            }
        case reflect.Uintptr:
            addr = unsafe.Pointer(v.Pointer())
        case reflect.Slice:
    
    
    addr = unsafe.Pointer(v.Index(0).UnsafeAddr())
        default:
            panic(fmt.Sprintf("Unsupported type %s; must be a pointer, slice, or array", v.Type()))
        }
        return addr
    }
    

    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(&data[0]) or gl.Ptr(data). It's honestly kind of surprising this wasn't segfaulting.

    点赞 评论

相关推荐