Python之OpenGL笔记(12):画纹理四边形

一、目的

1、画一个四边形并加载纹理。

二、程序运行结果
Python之OpenGL笔记(12):画纹理四边形_第1张图片

三、纹理

  纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节。
  为了能够把纹理映射(Map)到四边形上,我们需要指定四边形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。
  纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。
   一般情况下,纹理图片是上下颠倒的,这是因为OpenGL要求y轴0.0坐标是在图片的底部的,但是图片的y轴0.0坐标通常在顶部。我们可以改变顶点数据的纹理坐标,翻转y值(用1减去y坐标)。

四、glTexImage2D解析

   纹理绑定后,我们可以使用前面载入的图片数据生成一个纹理了。载入纹理的函数见参考文献2.
   纹理可以通过glTexImage2D来生成:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
   第一个参数指定了纹理目标(Target)。设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。
   第二个参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
   第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们也把纹理储存为RGB值。
   第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
   下个参数应该总是被设为0(历史遗留问题)。
   第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为char(byte)数组,我们将会传入对应值。
   最后一个参数是真正的图像数据。
   当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像。

五、源代码

"""
glfw_square05.py.py
Author: dalong10
Description: Draw a texture square, learning OPENGL 
"""
import glutils  #Common OpenGL utilities,see glutils.py
import sys, random, math
import OpenGL
from OpenGL.GL import *
from OpenGL.GL.shaders import *
import numpy 
import numpy as np
import glfw
from PIL import Image

strVS = """
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 inTexcoord;
out vec2 outTexcoord;

void main()
{
    gl_Position = vec4(position, 1.0f);
    outTexcoord = inTexcoord;
}
"""

strFS = """
#version 330 core
out vec4 FragColor;
in vec2 outTexcoord;
uniform sampler2D texture1;

void main()
{
    FragColor = texture(texture1, outTexcoord);
}
"""

class FirstSquare:
    def __init__(self):
        # load shaders     
        self.program = glutils.loadShaders(strVS, strFS)
        glUseProgram(self.program)
       # attributes
        self.vertIndex = glGetAttribLocation(self.program, b"position")
        self.texIndex = glGetAttribLocation(self.program, b"inTexcoord")
         
        vertices = [      
             -0.5,-0.5,0,  
             0.5,-0.5,0,      
             0.5,0.5,0,  
            -0.5,0.5,0     
             ]             
       # texture coords
        quadT = [
            1.0, 1.0,
            0.0, 1.0,
            0.0, 0.0,
            1.0, 0.0
            ]               
        # set up vertex array object (VAO)
        self.vao = glGenVertexArrays(1)     
        glBindVertexArray(self.vao)        
        # set up VBOs
        vertexData = numpy.array(vertices, numpy.float32)
        self.vertexBuffer = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER,self.vertexBuffer)
        glBufferData(GL_ARRAY_BUFFER, 4 *len(vertexData), vertexData, GL_STATIC_DRAW)

        tcData = numpy.array(quadT, numpy.float32)
        self.tcBuffer = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, self.tcBuffer)
        glBufferData(GL_ARRAY_BUFFER, 4*len(tcData), tcData,GL_STATIC_DRAW)

        # enable arrays
        glEnableVertexAttribArray(self.vertIndex)
        glEnableVertexAttribArray(self.texIndex)

        # Position attribute
        glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
        glVertexAttribPointer(self.vertIndex, 3, GL_FLOAT, GL_FALSE, 0,None)
        
        # TexCoord attribute
        glBindBuffer(GL_ARRAY_BUFFER, self.tcBuffer)        
        glVertexAttribPointer(self.texIndex, 2, GL_FLOAT, GL_FALSE, 0,None)

        # unbind VAO
        glBindVertexArray(0)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
        glBindBuffer(GL_ARRAY_BUFFER, 0) 
         
    def render(self,texid ):
        self.texid = texid
        # enable texture
        glActiveTexture(GL_TEXTURE0)
        glBindTexture(GL_TEXTURE_2D, self.texid)
        # use shader
        glUseProgram(self.program)
        
        # bind VAO
        glBindVertexArray(self.vao)
        # draw
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
        # unbind VAO
        glBindVertexArray(0)
        
if __name__ == '__main__':
    import sys
    import glfw
    import OpenGL.GL as gl
    def on_key(window, key, scancode, action, mods):
        if key == glfw.KEY_ESCAPE and action == glfw.PRESS:
            glfw.set_window_should_close(window,1)

    # Initialize the library
    if not glfw.init():
        sys.exit()

    # Create a windowed mode window and its OpenGL context
    window = glfw.create_window(300, 300, "Texture Square", None, None)
    if not window:
        glfw.terminate()
        sys.exit()

    # Make the window's context current
    glfw.make_context_current(window)
    # Install a key handler
    glfw.set_key_callback(window, on_key)

    texid = glutils.loadTexture("wall.png")
    # Loop until the user closes the window
    while not glfw.window_should_close(window):
        # Render here
        width, height = glfw.get_framebuffer_size(window)
        ratio = width / float(height)
        gl.glViewport(0, 0, width, height)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)
        gl.glClearColor(0.2,0.3,0.3,1.0)
        
        firstSquare0 = FirstSquare()
        # render                                               
        glBindTexture(GL_TEXTURE_2D, texid)       
        firstSquare0.render(texid)
        # Swap front and back buffers
        glfw.swap_buffers(window)
        # Poll for and process events
        glfw.poll_events()

    glfw.terminate()

六、参考文献

1、learnopengl教程https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/06%20Textures/#_1
2、大龙10https://www.jianshu.com/p/4382b25ad797

你可能感兴趣的:(Python之OpenGL笔记(12):画纹理四边形)