【问题标题】:How to save fragment shader image changes to image output file?如何将片段着色器图像更改保存到图像输出文件?
【发布时间】:2019-12-21 04:06:14
【问题描述】:

简介

我有一个用 C++ 和 Lua 编码的游戏项目(我知道主题中写的是“Python”,不用担心),并且在那里,我将片段(不是顶点!)着色器应用到游戏画面。由于我的项目的一部分不是由我制作的(因为它是开源的),使用 OpenGL 应用片段着色器的系统已经由其他人制作,但不是 2xSal 片段着色器本身。我认为自己是这门学科的初学者。我“制作”的唯一一段代码是片段着色器(我不知道是否有必要,但我的代码基于以下链接的代码:https://github.com/libretro/glsl-shaders/blob/master/xsal/shaders/2xsal-level2-pass2.glsl)。

这是我对 2xSal 片段着色器所做的更改(在我的游戏中):

#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D

#ifdef GL_ES
    #ifdef GL_FRAGMENT_PRECISION_HIGH
        precision highp float;
    #else
        precision mediump float;
    #endif
    #define COMPAT_PRECISION mediump
#else
    #define COMPAT_PRECISION
#endif

// uniform COMPAT_PRECISION int FrameDirection; // Not in use
// uniform COMPAT_PRECISION int FrameCount; // Not in use
// uniform COMPAT_PRECISION vec2 OutputSize; // Not in use
// uniform COMPAT_PRECISION vec2 TextureSize;
// uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
//COMPAT_VARYING vec4 TEX0;
// in variables go here as COMPAT_VARYING whatever

// fragment compatibility #defines
#define Source Texture
//#define vTexCoord TEX0.xy

COMPAT_VARYING vec2 v_TexCoord;

#define InputSize vec2(800.0, 608.0) // Width and height in pixels of game screen
#define SourceSize vec4(InputSize, 1.0 / InputSize) //either TextureSize or InputSize
// #define outsize vec4(OutputSize, 1.0 / OutputSize) // Not in use

void main()
{
    vec2 tex = v_TexCoord;
    //vec2 texsize = IN.texture_size;
    float dx = 0.25*SourceSize.z;
    float dy = 0.25*SourceSize.w;
    vec3  dt = vec3(1.0, 1.0, 1.0);

    vec4 yx = vec4(dx, dy, -dx, -dy);
    vec4 xh = yx*vec4(3.0, 1.0, 3.0, 1.0);
    vec4 yv = yx*vec4(1.0, 3.0, 1.0, 3.0);

    vec3 c11 = COMPAT_TEXTURE(Source, tex        ).xyz;
    vec3 s00 = COMPAT_TEXTURE(Source, tex + yx.zw).xyz;
    vec3 s20 = COMPAT_TEXTURE(Source, tex + yx.xw).xyz;
    vec3 s22 = COMPAT_TEXTURE(Source, tex + yx.xy).xyz;
    vec3 s02 = COMPAT_TEXTURE(Source, tex + yx.zy).xyz;
    vec3 h00 = COMPAT_TEXTURE(Source, tex + xh.zw).xyz;
    vec3 h20 = COMPAT_TEXTURE(Source, tex + xh.xw).xyz;
    vec3 h22 = COMPAT_TEXTURE(Source, tex + xh.xy).xyz;
    vec3 h02 = COMPAT_TEXTURE(Source, tex + xh.zy).xyz;
    vec3 v00 = COMPAT_TEXTURE(Source, tex + yv.zw).xyz;
    vec3 v20 = COMPAT_TEXTURE(Source, tex + yv.xw).xyz;
    vec3 v22 = COMPAT_TEXTURE(Source, tex + yv.xy).xyz;
    vec3 v02 = COMPAT_TEXTURE(Source, tex + yv.zy).xyz;

    float m1 = 1.0/(dot(abs(s00 - s22), dt) + 0.00001);
    float m2 = 1.0/(dot(abs(s02 - s20), dt) + 0.00001);
    float h1 = 1.0/(dot(abs(s00 - h22), dt) + 0.00001);
    float h2 = 1.0/(dot(abs(s02 - h20), dt) + 0.00001);
    float h3 = 1.0/(dot(abs(h00 - s22), dt) + 0.00001);
    float h4 = 1.0/(dot(abs(h02 - s20), dt) + 0.00001);
    float v1 = 1.0/(dot(abs(s00 - v22), dt) + 0.00001);
    float v2 = 1.0/(dot(abs(s02 - v20), dt) + 0.00001);
    float v3 = 1.0/(dot(abs(v00 - s22), dt) + 0.00001);
    float v4 = 1.0/(dot(abs(v02 - s20), dt) + 0.00001);

    vec3 t1 = 0.5*(m1*(s00 + s22) + m2*(s02 + s20))/(m1 + m2);
    vec3 t2 = 0.5*(h1*(s00 + h22) + h2*(s02 + h20) + h3*(h00 + s22) + h4*(h02 + s20))/(h1 + h2 + h3 + h4);
    vec3 t3 = 0.5*(v1*(s00 + v22) + v2*(s02 + v20) + v3*(v00 + s22) + v4*(v02 + s20))/(v1 + v2 + v3 + v4);

    float k1 = 1.0/(dot(abs(t1 - c11), dt) + 0.00001);
    float k2 = 1.0/(dot(abs(t2 - c11), dt) + 0.00001);
    float k3 = 1.0/(dot(abs(t3 - c11), dt) + 0.00001);

    FragColor = vec4((k1*t1 + k2*t2 + k3*t3)/(k1 + k2 + k3), 1.0);
}

问题

这就是说,我现在需要的与我的游戏无关,而是与我向您展示的代码本身有关。 我需要将此片段着色器应用于给定路径的输入图像,并将输出保存到另一个(和新的)图像文件,使用 Python,但我不想在窗口内显示它们(比如使用 GLFW或过剩)

这个想法太简单了,但我不知道该怎么做。 我只需要保存输入图像中片段更改的输出结果

我不需要顶点着色器。我不需要窗口来显示结果,我根本不需要窗口。我只想将结果保存到图像文件中。

我尝试过的

我在 Python 中找到了一个代码,其中将图像输入显示到 GLFW 窗口中。我以为我会一寸一寸地到达我想要的地方,但我找不到如何:

  1. 应用我向您展示的 2xSal 片段着色器(将片段着色器分离到 .glsl 文件会很棒);
  2. 移除 GLFW 窗口;
  3. 删除顶点着色器(如果可能的话),因为我不需要对顶点进行任何更改;
  4. 将结果保存到输出文件。

另外,我注意到 Python 代码存在拉伸或缩小图像的问题,因为顶点形成一个正方形并在其中绘制输入图像纹理。所以对于实际的代码,我认为它只适用于正方形的图像。

Python实际代码

# # Requirements # #
# Execute these commands on terminal:
# pip install glfw
# pip install pyopengl
# pip install pyrr
# pip install pillow

import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
from PIL import Image


def main():

    # initialize glfw
    if not glfw.init():
        return

    window = glfw.create_window(800, 600, "My OpenGL window", None, None)

    if not window:
        glfw.terminate()
        return

    glfw.make_context_current(window)
    #           positions        colors          texture coords
    quad = [   -0.5, -0.5, 0.0,  1.0, 0.0, 0.0,  0.0, 0.0,
                0.5, -0.5, 0.0,  0.0, 1.0, 0.0,  1.0, 0.0,
                0.5,  0.5, 0.0,  0.0, 0.0, 1.0,  1.0, 1.0,
               -0.5,  0.5, 0.0,  1.0, 1.0, 1.0,  0.0, 1.0]

    quad = numpy.array(quad, dtype = numpy.float32)

    indices = [0, 1, 2,
               2, 3, 0]

    indices = numpy.array(indices, dtype= numpy.uint32)

    print(quad.itemsize * len(quad))
    print(indices.itemsize * len(indices))
    print(quad.itemsize * 8)

    vertex_shader = """
    #version 330
    in layout(location = 0) vec3 position;
    in layout(location = 1) vec3 color;
    in layout(location = 2) vec2 inTexCoords;
    out vec3 newColor;
    out vec2 outTexCoords;
    void main()
    {
        gl_Position = vec4(position, 1.0f);
        newColor = color;
        outTexCoords = inTexCoords;
    }
    """

    fragment_shader = """
    #version 330
    in vec3 newColor;
    in vec2 outTexCoords;
    out vec4 outColor;
    uniform sampler2D samplerTex;
    void main()
    {
        outColor = texture(samplerTex, outTexCoords) * vec4(newColor, 1.0f);
    }
    """
    shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                              OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))

    VBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, VBO)
    glBufferData(GL_ARRAY_BUFFER, quad.itemsize * len(quad), quad, GL_STATIC_DRAW)

    EBO = glGenBuffers(1)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.itemsize * len(indices), indices, GL_STATIC_DRAW)

    # position = glGetAttribLocation(shader, "position")
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)

    # color = glGetAttribLocation(shader, "color")
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(12))
    glEnableVertexAttribArray(1)

    # texture_coords = glGetAttribLocation(shader, "inTexCoords")
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(24))
    glEnableVertexAttribArray(2)

    texture = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texture)
    # texture wrapping params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    # texture filtering params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    image = Image.open("res/test.jpg")
    # img_data = numpy.array(list(image.getdata()), numpy.uint8)
    flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
    img_data = flipped_image.convert("RGBA").tobytes()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
    # print(image.width, image.height)

    glUseProgram(shader)

    glClearColor(0.2, 0.3, 0.2, 1.0)

    while not glfw.window_should_close(window):
        glfw.poll_events()

        glClear(GL_COLOR_BUFFER_BIT)

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)

        glfw.swap_buffers(window)

    glfw.terminate()


if __name__ == "__main__":
    main()

>由Rabbid76解决

感谢@Rabbid76,我能够编写此代码。

因为我喜欢人们发布结果,所以这是我的最终代码:

# # Requirements # #
# Execute these commands on PyCharm terminal:
# pip install glfw
# pip install pyopengl
# pip install pyrr
# pip install pillow


"""
    The OpenGL specification doesn't allow you to create a context without a window,
    since it needs the pixel format that you set into the device context.
    Actually, it is necessary to have a window handler to create a "traditional" rendering context.
    It is used to fetch OpenGL information and extensions availability.
    Once you got that information, you can destroy the render context and release the "dummy" window.
    So, in this code, the window is created, the context is set to this window,
    the image result is saved to an output image file and, then, this window is released.
"""


import glfw
from OpenGL.GL import *
import OpenGL.GL.shaders
import numpy
from PIL import Image


def main():
    # Initialize glfw
    if not glfw.init():
        return

    # Create window
    window = glfw.create_window(1, 1, "My OpenGL window", None, None)  # Size (1, 1) for show nothing in window
    # window = glfw.create_window(800, 600, "My OpenGL window", None, None)

    # Terminate if any issue
    if not window:
        glfw.terminate()
        return

    # Set context to window
    glfw.make_context_current(window)

    #

    # Initial data
    # Positions, colors, texture coordinates
    '''
    #           positions        colors          texture coords
    quad = [   -0.5, -0.5, 0.0,  1.0, 0.0, 0.0,  0.0, 0.0,
                0.5, -0.5, 0.0,  0.0, 1.0, 0.0,  1.0, 0.0,
                0.5,  0.5, 0.0,  0.0, 0.0, 1.0,  1.0, 1.0,
               -0.5,  0.5, 0.0,  1.0, 1.0, 1.0,  0.0, 1.0]
    '''
    #       positions      colors       texture coords
    quad = [-1., -1., 0.,  1., 0., 0.,  0., 0.,
             1., -1., 0.,  0., 1., 0.,  1., 0.,
             1.,  1., 0.,  0., 0., 1.,  1., 1.,
            -1.,  1., 0.,  1., 1., 1.,  0., 1.]
    quad = numpy.array(quad, dtype=numpy.float32)
    # Vertices indices order
    indices = [0, 1, 2,
               2, 3, 0]
    indices = numpy.array(indices, dtype=numpy.uint32)

    # print(quad.itemsize * len(quad))
    # print(indices.itemsize * len(indices))
    # print(quad.itemsize * 8)

    #

    # Vertex shader
    vertex_shader = """
    #version 330

    in layout(location = 0) vec3 position;

    //in layout(location = 1) vec3 inColor;
    //out vec3 outColor;

    in layout(location = 2) vec2 inTexCoords;
    out vec2 outTexCoords;

    void main()
    {
        gl_Position = vec4(position, 1.0f);

        //outColor = inColor;

        outTexCoords = inTexCoords;
    }
    """

    # Fragment shader
    fragment_shader = """
    #version 330

    //in vec3 outColor;

    out vec4 gl_FragColor;
    uniform sampler2D source;
    in vec2 outTexCoords;

    float intensityFactor = 2.;

    void main()
    {
        ivec2 textureSize2d = textureSize(source, 0); // Width and height of texture image

        vec2 inputSize = vec2(float(textureSize2d.x) / intensityFactor, float(textureSize2d.y) / intensityFactor);
        vec2 sourceSize = 1. / inputSize; // Either TextureSize or InputSize

        float dx = 0.25*sourceSize.x;
        float dy = 0.25*sourceSize.y;
        vec3  dt = vec3(1.0, 1.0, 1.0);

        vec4 yx = vec4(dx, dy, -dx, -dy);
        vec4 xh = yx*vec4(3.0, 1.0, 3.0, 1.0);
        vec4 yv = yx*vec4(1.0, 3.0, 1.0, 3.0);

        vec3 c11 = texture(source, outTexCoords        ).xyz;
        vec3 s00 = texture(source, outTexCoords + yx.zw).xyz;
        vec3 s20 = texture(source, outTexCoords + yx.xw).xyz;
        vec3 s22 = texture(source, outTexCoords + yx.xy).xyz;
        vec3 s02 = texture(source, outTexCoords + yx.zy).xyz;
        vec3 h00 = texture(source, outTexCoords + xh.zw).xyz;
        vec3 h20 = texture(source, outTexCoords + xh.xw).xyz;
        vec3 h22 = texture(source, outTexCoords + xh.xy).xyz;
        vec3 h02 = texture(source, outTexCoords + xh.zy).xyz;
        vec3 v00 = texture(source, outTexCoords + yv.zw).xyz;
        vec3 v20 = texture(source, outTexCoords + yv.xw).xyz;
        vec3 v22 = texture(source, outTexCoords + yv.xy).xyz;
        vec3 v02 = texture(source, outTexCoords + yv.zy).xyz;

        float m1 = 1.0/(dot(abs(s00 - s22), dt) + 0.00001);
        float m2 = 1.0/(dot(abs(s02 - s20), dt) + 0.00001);
        float h1 = 1.0/(dot(abs(s00 - h22), dt) + 0.00001);
        float h2 = 1.0/(dot(abs(s02 - h20), dt) + 0.00001);
        float h3 = 1.0/(dot(abs(h00 - s22), dt) + 0.00001);
        float h4 = 1.0/(dot(abs(h02 - s20), dt) + 0.00001);
        float v1 = 1.0/(dot(abs(s00 - v22), dt) + 0.00001);
        float v2 = 1.0/(dot(abs(s02 - v20), dt) + 0.00001);
        float v3 = 1.0/(dot(abs(v00 - s22), dt) + 0.00001);
        float v4 = 1.0/(dot(abs(v02 - s20), dt) + 0.00001);

        vec3 t1 = 0.5*(m1*(s00 + s22) + m2*(s02 + s20))/(m1 + m2);
        vec3 t2 = 0.5*(h1*(s00 + h22) + h2*(s02 + h20) + h3*(h00 + s22) + h4*(h02 + s20))/(h1 + h2 + h3 + h4);
        vec3 t3 = 0.5*(v1*(s00 + v22) + v2*(s02 + v20) + v3*(v00 + s22) + v4*(v02 + s20))/(v1 + v2 + v3 + v4);

        float k1 = 1.0/(dot(abs(t1 - c11), dt) + 0.00001);
        float k2 = 1.0/(dot(abs(t2 - c11), dt) + 0.00001);
        float k3 = 1.0/(dot(abs(t3 - c11), dt) + 0.00001);

        // gl_FragColor = texture(source, outTexCoords) * vec4(outColor, 1.0f);
        gl_FragColor = vec4((k1*t1 + k2*t2 + k3*t3)/(k1 + k2 + k3), 1.0f);
        //gl_FragColor = vec4(s00, 1.0f);
    }
    """

    #

    # Compile shaders
    shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
                                              OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))

    # VBO
    v_b_o = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, v_b_o)
    glBufferData(GL_ARRAY_BUFFER, quad.itemsize * len(quad), quad, GL_STATIC_DRAW)

    # EBO
    e_b_o = glGenBuffers(1)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, e_b_o)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.itemsize * len(indices), indices, GL_STATIC_DRAW)

    # Configure positions of initial data
    # position = glGetAttribLocation(shader, "position")
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)

    # Configure colors of initial data
    # color = glGetAttribLocation(shader, "color")
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(12))
    glEnableVertexAttribArray(1)

    # Configure texture coordinates of initial data
    # texture_coords = glGetAttribLocation(shader, "inTexCoords")
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, quad.itemsize * 8, ctypes.c_void_p(24))
    glEnableVertexAttribArray(2)

    # Texture
    texture = glGenTextures(1)
    # Bind texture
    glBindTexture(GL_TEXTURE_2D, texture)
    # Texture wrapping params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    # Texture filtering params
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    #

    # Open image
    image = Image.open("res/piece.png")
    #
    # img_data = numpy.array(list(image.getdata()), numpy.uint8)
    #
    # flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
    # img_data = flipped_image.convert("RGBA").tobytes()
    #
    img_data = image.convert("RGBA").tobytes()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
    # print(image.width, image.height)

    #

    # Create render buffer with size (image.width x image.height)
    rb_obj = glGenRenderbuffers(1)
    glBindRenderbuffer(GL_RENDERBUFFER, rb_obj)
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, image.width, image.height)

    # Create frame buffer
    fb_obj = glGenFramebuffers(1)
    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb_obj)

    # Check frame buffer (that simple buffer should not be an issue)
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
    if status != GL_FRAMEBUFFER_COMPLETE:
        print("incomplete framebuffer object")

    #

    # Install program
    glUseProgram(shader)

    # Bind framebuffer and set viewport size
    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glViewport(0, 0, image.width, image.height)

    # Draw the quad which covers the entire viewport
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)

    #

    # PNG
    # Read the data and create the image
    image_buffer = glReadPixels(0, 0, image.width, image.height, GL_RGBA, GL_UNSIGNED_BYTE)
    image_out = numpy.frombuffer(image_buffer, dtype=numpy.uint8)
    image_out = image_out.reshape(image.height, image.width, 4)
    img = Image.fromarray(image_out, 'RGBA')
    img.save(r"res/image_out.png")

    # JPG
    '''
    # Read the data and create the image
    image_buffer = glReadPixels(0, 0, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE)
    image_out = numpy.frombuffer(image_buffer, dtype=numpy.uint8)
    image_out = image_out.reshape(image.height, image.width, 3)
    img = Image.fromarray(image_out, 'RGB')
    img.save(r"res/image_out.jpg")
    '''

    #

    # Bind default frame buffer (0)
    glBindFramebuffer(GL_FRAMEBUFFER, 0)

    # Set viewport rectangle to window size
    glViewport(0, 0, 0, 0)  # Size (0, 0) for show nothing in window
    # glViewport(0, 0, 800, 600)

    # Set clear color
    glClearColor(0., 0., 0., 1.)

    #

    # Program loop
    while not glfw.window_should_close(window):
        # Call events
        glfw.poll_events()

        # Clear window
        glClear(GL_COLOR_BUFFER_BIT)

        # Draw
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)

        # Send to window
        glfw.swap_buffers(window)

        # Force terminate program, since it will work like clicked in 'Close' button
        break

    #

    # Terminate program
    glfw.terminate()


if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python opengl glsl fragment-shader pyopengl


    【解决方案1】:

    你必须渲染到Framebuffer Object

    使用渲染目标创建一个与图像大小相同的帧缓冲区:

    # create render buffer with size (image.width x image.height)
    rb_obj = glGenRenderbuffers(1)
    glBindRenderbuffer(GL_RENDERBUFFER, rb_obj )
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, image.width, image.height)
    
    # create framebuffer
    fb_obj = glGenFramebuffers(1)
    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb_obj )
    
    # check framebuffer (that simple buffer should not be an issue)
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
    if status != GL_FRAMEBUFFER_COMPLETE:
        print("incomplete framebuffer object") 
    

    [...] 我不需要顶点着色器。 [...]

    无论如何,您都需要一个顶点着色器,因为您必须在整个视口上绘制一个四边形。着色器程序需要一个顶点着色器和一个片段着色器。 由于几何图形必须覆盖整个视口,因此顶点坐标必须在 [-1, 1] 范围内。此外,您还必须更改纹理坐标,否则窗口会被翻转:

    #           positions        colors          texture coords
    quad = [   -1.0, -1.0, 0.0,  1.0, 0.0, 0.0,  0.0, 1.0,
                1.0, -1.0, 0.0,  0.0, 1.0, 0.0,  1.0, 1.0,
                1.0,  1.0, 0.0,  0.0, 0.0, 1.0,  1.0, 0.0,
               -1.0,  1.0, 0.0,  1.0, 1.0, 1.0,  0.0, 0.0]
    

    [...] 我不需要窗户 [...]

    您需要窗口来创建 OpenGL 上下文。见:
    Minimal Windowless OpenGL Context Initialization
    Windowless OpenGL
    How to render offscreen on OpenGL?
    How to use GLUT/OpenGL to render to a file?

    绑定帧缓冲区,设置视口矩形为帧缓冲区大小,安装着色器程序,绑定纹理并渲染四边形:

    # bind texture
    glBindTexture(GL_TEXTURE_2D, texture)
    
    # install program
    glUseProgram(shader)
    
    # bind framebuffer and set viewport size
    glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
    glViewport(0, 0, image.width, image.height)
    
    # draw the quad which covers the entire viewport
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
    

    最后使用glReadPixels从framebuffer中读取数据:

    # read the data and create the image
    image_buffer = glReadPixels(0, 0, image.width, image.height, GL_RGBA, GL_UNSIGNED_BYTE)
    imageout = numpy.frombuffer(image_buffer, dtype=numpy.uint8)
    imageout = imageout.reshape(image.height, image.width, 4)
    img = Image.fromarray(imageout, 'RGBA')
    img.save(r"image_out.png")
    
    # bind default framebuffer (0) and set viewport rectangle to window size
    glBindFramebuffer(GL_FRAMEBUFFER, 0)
    glViewport(0, 0, 800, 600)
    

    上面的代码生成了一个 png 文件。如果要生成jpg,则改为:

    image_buffer = glReadPixels(0, 0, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE)
    imageout = numpy.frombuffer(image_buffer, dtype=numpy.uint8)
    imageout = imageout.reshape(image.height, image.width, 3)
    img = Image.fromarray(imageout, 'RGB')
    img.save(r"image_out.jpg") 
    

    你根本不需要渲染循环,但之后就可以渲染到窗口了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 2012-01-27
      • 2011-06-09
      • 2015-11-02
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多