【问题标题】:Mapping a texture onto a quad with OpenGL 4, Python, and vertex shaders使用 OpenGL 4、Python 和顶点着色器将纹理映射到四边形
【发布时间】:2015-12-18 04:44:04
【问题描述】:

我正在尝试使用现代 OpenGL 代码创建一个程序,该程序显示一个带有纹理映射到其上的 QUAD。

应该拉伸纹理以匹配四边形大小。现在纹理重复。

如果每个顶点和映射在代码中单独完成,我已经看到将纹理映射到四边形的代码。但是,我认为现在我们应该使用顶点着色器?使用 OpenGL 4.5 或其他什么,这应该如何完成?

"""
Open a window that displays a quad with an image on it.

"""

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from math import *
from time import *


class MyApplication:
    """ Main application class. """

    def __init__(self):
        self.vao = 0

    def load_texture(self, file_name):
        image  = Image.open(file_name)
        width  = image.size[0]
        height = image.size[1]
        image_bytes  = image.convert("RGBA").tobytes ( "raw", "RGBA", 0, -1)
        texture = glGenTextures(1)

        glBindTexture     ( GL_TEXTURE_2D, texture )
        glTexParameterf   ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT )
        glTexParameterf   ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT )
        glTexParameteri   ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR )
        glTexParameteri   ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR )

        gluBuild2DMipmaps ( GL_TEXTURE_2D, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image_bytes )

        return texture

    def compile_shaders(self):
        """ Get the shaders ready. """

        # Create a triangle with three (x, y, z, ?) points.
        vertex_shader_source = """
        #version 450 core
        void main( void)
        {
            // Declare a hard-coded array of positions
            const vec4 vertices[4] = vec4[4](vec4(-0.5,  0.5, 0.5, 1.0),
                                             vec4( 0.5,  0.5, 0.5, 1.0),
                                             vec4( 0.5, -0.5, 0.5, 1.0),
                                             vec4(-0.5, -0.5, 0.5, 1.0));

            // Index into our array using gl_VertexID
            gl_Position = vertices[gl_VertexID];
            }
        """

        vertex_shader = glCreateShader(GL_VERTEX_SHADER)
        glShaderSource(vertex_shader, vertex_shader_source)
        glCompileShader(vertex_shader)

        # Specify the color of our fragment (RGBA)

        texture = self.load_texture("test_ship.png")

        fragment_shader_source = """
        #version 450 core
        uniform sampler2D s;
        out vec4 color;
        void main(void)
        {
            color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
        }
        """

        fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
        glShaderSource(fragment_shader, fragment_shader_source)
        glCompileShader(fragment_shader)

        # --- Create a program
        program = glCreateProgram()
        glAttachShader(program, vertex_shader)
        glAttachShader(program, fragment_shader)
        glLinkProgram(program)

        glGenVertexArrays(1, self.vao)
        glBindVertexArray(self.vao)

        # --- Clean up now that we don't need these shaders anymore.
        glDeleteShader(vertex_shader)
        glDeleteShader(fragment_shader)

        return program

    def startup(self):
        self.rendering_program = self.compile_shaders()
        self.vertex_array_object = GLuint()
        glCreateVertexArrays(1, self.vertex_array_object)

    def render(self):
        # Support transparency
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        # Get a color based on the time
        color = (sin(time()), cos(time()), 0)

        # Clear the screen
        glClearBufferfv(GL_COLOR, 0, color)

        # Tell the computer what to render
        glUseProgram(self.rendering_program)
        glDrawArrays(GL_QUADS, 0, 4)

        # Display
        glutSwapBuffers()

    def animate(self):
        glutPostRedisplay()

    def run(self):
        glutInit(sys.argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(500, 500)
        glutInitWindowPosition(0, 0)

        glutCreateWindow(b"Simple PyOpenGL example")

        self.startup()

        glutIdleFunc(self.animate)
        glutDisplayFunc(self.render)

        glutMainLoop()


my_application = MyApplication()
my_application.run()

【问题讨论】:

    标签: python opengl


    【解决方案1】:

    我认为这里有两个问题:

    1) 如果您看到重复图案,鉴于您当前的 WRAP_S 和 WRAP_T 设置,您可以假设您的 UV 坐标是错误的。

    在您的片段着色器中,您使用以下计算获得 UV 坐标:

    color = texture(s, gl_FragCoord.xy / textureSize(s, 0));
    

    但是,查看您的四边形坐标,这不会映射到纹理坐标所需的 [0,1] 区间。 (如果低于或超出此区间,您将得到该值的模数)。

    2) 如果您不想重复,请使用以下内容:

     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
    

    【讨论】:

    • UV 坐标应该是多少?我什至没有在代码中看到它们被指定的地方。如果我夹住它,什么都不会出现。
    • 可能是片段着色器中的这一行吗? gl_FragCoord.xy / textureSize(s, 0)
    • 这确实改变了映射。事实上,我可以乘以 2 并获得两倍的项目。但我不确定如何编写该行来进行直接映射。甚至让图像从四边形的左上角开始。
    • 我认为你的四边形坐标有问题。在您的最终计算中,您需要在两个维度上映射到 [0, 1] 的 UV 坐标。
    • 作为调试的好方法,我建议使用 UV 坐标作为片段的双通道原始颜色输出(这样您就可以知道值是如何变化的)。
    猜你喜欢
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    相关资源
    最近更新 更多