Python 使用OpenGL绘制纹理时翻转纹理

Python 使用OpenGL绘制纹理时翻转纹理,python,python-3.x,opengl,glsl,pyopengl,Python,Python 3.x,Opengl,Glsl,Pyopengl,我最近下载了一个使用pyOpenGl和pygame的批处理渲染程序。我想编辑绘制功能,以便在绘制纹理时能够翻转纹理。这是批处理渲染程序的代码 import numpy from OpenGL import GL from OpenGL.GL import shaders import ctypes def setup_shaders(vpMatrix): global shaderProgram, vshader, fshader global texCoordAttribut

我最近下载了一个使用pyOpenGl和pygame的批处理渲染程序。我想编辑绘制功能,以便在绘制纹理时能够翻转纹理。这是批处理渲染程序的代码

import numpy
from OpenGL import GL
from OpenGL.GL import shaders
import ctypes

def setup_shaders(vpMatrix):
    global shaderProgram, vshader, fshader
    global texCoordAttribute, positionAttribute
    
    vshader = shaders.compileShader('''#version 440

    layout (location = 0) uniform mat4 vpMatrix;

    layout (location = 0) in vec2 vPosition;
    layout (location = 1) in vec2 vTexCoord0;
    //layout (location = 2) in vec4 vVertColor;

    out vec2 texCoord0;
    //out vec4 vertColor;

    void main(void) {
        gl_Position = vpMatrix * vec4(vPosition, 0.0, 1.0);
        texCoord0 = vTexCoord0;
    }''', GL.GL_VERTEX_SHADER)

    fshader = shaders.compileShader('''#version 440

    in vec2 texCoord0;
    //in vec4 vertColor;
    layout (location = 1) uniform sampler2D u_texture0;

    void main(void) {
        gl_FragColor = texture2D(u_texture0, texCoord0);
    }''', GL.GL_FRAGMENT_SHADER)

    shaderProgram = shaders.compileProgram(vshader, fshader)

    texCoordAttribute = GL.glGetAttribLocation(shaderProgram, 'vTexCoord0')
    positionAttribute = GL.glGetAttribLocation(shaderProgram, 'vPosition')
    texUniform = GL.glGetUniformLocation(shaderProgram, 'u_texture0')

    GL.glEnableVertexAttribArray(positionAttribute)
    GL.glEnableVertexAttribArray(texCoordAttribute)
    
    GL.glUseProgram(shaderProgram)
    
    GL.glUniformMatrix4fv(
        GL.glGetUniformLocation(shaderProgram, 'vpMatrix'),
        1,
        False,
        vpMatrix,
    )
    GL.glUniform1i(texUniform, 0)
    
    # TODO: cleanup (delete shaders)

class GLTexture:
    def __init__(self, textureId, width, height):
        self.texture = textureId
        self.width, self.height = width, height

    def delete(self):
        GL.glDeleteTextures([self.texture])

class GLTextureRegion:
    def __init__(self, glTexture, subX, subY, subWidth, subHeight):
        self.texture = glTexture
        #self.tx, self.ty = subX, subY
        self.tw, self.th = subWidth, subHeight

        self.normalizedCoords = (
            subX / glTexture.width, subY / glTexture.height,
            (subX + subWidth) / glTexture.width, subY / glTexture.height,
            subX / glTexture.width, (subY + subHeight) / glTexture.height,
            (subX + subWidth) / glTexture.width, (subY + subHeight) / glTexture.height,
        )

    def write_tex_coords(self, aj):
        nc = self.normalizedCoords
        aj[4 * 0 + 2] = nc[0]
        aj[4 * 0 + 3] = nc[1]
        aj[4 * 1 + 2] = nc[2]
        aj[4 * 1 + 3] = nc[3]
        aj[4 * 2 + 2] = nc[4]
        aj[4 * 2 + 3] = nc[5]
        aj[4 * 3 + 2] = nc[6]
        aj[4 * 3 + 3] = nc[7]

    def write_vertices(self, aj, x, y):
        aj[4 * 0 + 0] = x
        aj[4 * 0 + 1] = y
        aj[4 * 1 + 0] = x + self.tw
        aj[4 * 1 + 1] = y
        aj[4 * 2 + 0] = x
        aj[4 * 2 + 1] = y + self.th
        aj[4 * 3 + 0] = x + self.tw
        aj[4 * 3 + 1] = y + self.th

    def update_array(self, vboData, arrayIndex, x, y):
        aj = vboData[arrayIndex]
        self.write_vertices(aj, x, y)
        self.write_tex_coords(aj)

    def delete(self):
        '''deletes the underlying texture'''
        self.texture.delete()

class Batch:
    def __init__(self, maxQuads = 10000):
        self.maxQuads = maxQuads

        self.vboIndices = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, self.vboIndices)
        vidA = []
        for i in range(maxQuads):
            vidA.extend([
                4 * i + 0,
                4 * i + 2,
                4 * i + 1,
                4 * i + 2,
                4 * i + 1,
                4 * i + 3
            ])
        self.vboIndexData = numpy.array(vidA, numpy.ushort)
        del vidA
        GL.glBufferData(
            GL.GL_ELEMENT_ARRAY_BUFFER,
            self.vboIndexData,
            GL.GL_STATIC_DRAW,
        )

        self.vbo = GL.glGenBuffers(1)  # texture coords & vertices
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo)
        self.vboData = numpy.zeros((maxQuads, 4 * 4), numpy.float32)
        GL.glBufferData(
            GL.GL_ARRAY_BUFFER,
            self.vboData,
            GL.GL_DYNAMIC_DRAW
        )

        self.currentTexture = None
        self.objectIndex = 0

    def begin(self):
        GL.glBindBuffer(
            GL.GL_ARRAY_BUFFER,
            self.vbo,
        )
        if self.currentTexture:
            GL.glBindTexture(
                GL.GL_TEXTURE_2D,
                self.currentTexture.texture,
            )
        GL.glEnable(GL.GL_TEXTURE_2D)
        GL.glActiveTexture(GL.GL_TEXTURE0)

    def draw(self, textureRegion, x, y, flip = False):
        
        
        if self.currentTexture != textureRegion.texture:
            self.flush()
            self.currentTexture = textureRegion.texture
            GL.glBindTexture(
                GL.GL_TEXTURE_2D,
                textureRegion.texture.texture,
            )
        elif self.objectIndex >= self.maxQuads:
            self.flush()
        
        textureRegion.update_array(
            self.vboData,
            self.objectIndex,
            x, y
        )
        
        self.objectIndex += 1

    def end(self):
        self.flush()

    def flush(self):
        if not self.objectIndex:
            return
        GL.glVertexAttribPointer(
            texCoordAttribute,
            2,
            GL.GL_FLOAT,
            GL.GL_TRUE,
            4 * self.vboData.itemsize,
            ctypes.c_void_p(2 * self.vboData.itemsize)
        )
        GL.glVertexAttribPointer(
            positionAttribute,
            2,
            GL.GL_FLOAT,
            GL.GL_FALSE,
            4 * self.vboData.itemsize,
            ctypes.c_void_p(0)
        )
        GL.glBufferSubData(
            GL.GL_ARRAY_BUFFER,
            0,
            16 * self.objectIndex * self.vboData.itemsize,
            self.vboData,
        )
        GL.glDrawElements(
            GL.GL_TRIANGLES,
            6 * self.objectIndex,
            GL.GL_UNSIGNED_SHORT,
            ctypes.c_void_p(0),
        )
        self.objectIndex = 0

    def delete(self):
        GL.glDeleteBuffers(1, [self.vbo])
        GL.glDeleteBuffers(1, [self.vboIndices])
到目前为止,我已经尝试了一些涉及
glscalef
(正如我在互联网上找到的答案所建议的那样)的东西,但是我无法让它对纹理产生任何影响。有没有办法在draw函数中实现这一点,或者我必须完全尝试另一种方法?

您可以在顶点着色器中“翻转”纹理坐标的y分量:

void主管道(void){
// [...]        
texCoord0=vec2(vTexCoord0.x,1.0-vTexCoord0.y);
}

如果要单独“翻转”纹理,则需要翻转纹理坐标属性。将
True
False
传递给参数
flipY

GLTextureRegion类:
# [...]
def write_tex_coords(self、aj、flipY):
nc=自规范化坐标
对于范围(4)中的i:
aj[i*4+2]=nc[i*2]
aj[i*4+3]=1-nc[i*2+1]如果flipY else nc[i*2+1]
# [...]
def更新_阵列(自身、vboData、阵列索引、x、y、flipY):
aj=vboData[arrayIndex]
自写_顶点(aj,x,y)
self.write_tex_coords(aj,flipY)

或者,您可以在顶点着色器中通过均匀缩放纹理坐标。通过初始化制服

布局(位置=0)统一mat4 VP矩阵;
布局(位置=1)统一的vec2 uTexCoordScale;
vec2 V位置中的布局(位置=0);
vec2 vTexCoord0中的布局(位置=1);
输出向量2 texCoord0;
真空总管(真空)
{
gl_Position=vpMatrix*vec4(vpposition,0.0,1.0);
texCoord0=uTexCoordScale*vTexCoord0;
}

如果要“翻转”纹理,请将统一的
uTexCoordScale
初始化为(1.0,1.0),并将其更改为(1.0,-1.0)。

我希望能够翻转单个纹理,但是这会翻转整个屏幕上的每个纹理,有没有办法改变它,使它不会翻转所有内容,而是翻转我想要的内容?