2015-12-18 64 views
1

我正嘗試使用現代OpenGL代碼創建一個程序,該程序顯示QUAD並將紋理映射到其上。使用OpenGL 4,Python和頂點着色器將紋理映射到四邊形

紋理應拉伸以匹配四邊形尺寸。現在紋理重複。

我看過代碼將紋理映射到四邊形,如果每個頂點和映射在代碼中單獨完成。但是,我認爲現在我們應該使用頂點着色器?有了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() 

回答

0

我認爲有兩個問題在這裏:

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) 
+0

又該UV座標是什麼?我甚至沒有在代碼中看到它們被指定的地方。 如果我把它夾住,什麼都沒有顯示出來。 –

+0

它可能是你的片段着色器中的這條線嗎? gl_FragCoord.xy/textureSize(s,0) –

+0

這確實會改變映射。事實上,我可以乘以兩倍,並獲得兩倍的項目。但我不確定如何編寫該行來進行直接映射。甚至可以讓圖像從四邊形的左上角開始。 –