微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OpenGL中的纹理数组

如何解决OpenGL中的纹理数组

我正在一个项目上,我需要使用纹理数组来应用纹理。我已经问了很多问题,没有一个我完全满意的答案(Get access to later versions of GLSLOpenGL: Access Array Texture in GLSLOpenGL: How would I implement texture arrays?),所以我想问一个更广泛的问题希望得到回应。无论如何,我将如何在OpenGL中构造对象(更具体地说是PyOpenGL,但如果将答案放在C ++中就可以了)。我已经有一种加载纹理数组的方法,只是没有一种应用它的方法。这是理想的结果:

Example

来自opengl-tutorial图片

这是我目前用于加载数组纹理的内容

def load_texture_array(path,width,height):
    teximg = pygame.image.load(path)
    texels = teximg.get_buffer().raw
    texture = gluint(0)

    layerCount = 6
    mipLevelCount = 1

    glGenTextures(1,texture)
    glBindTexture(GL_TEXTURE_2D_ARRAY,texture)
    glTexStorage3D(GL_TEXTURE_2D_ARRAY,mipLevelCount,GL_RGBA8,height,layerCount)
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY,layerCount,GL_RGBA,GL_UNSIGNED_BYTE,texels)

    glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE)
    glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE)

TLDR:如何使用纹理数组将纹理应用于OpenGL中的对象?

如有必要,我会很乐意提供其他信息。

解决方法

如果要对多维数据集使用2D Array Texture,则6面的6个纹理中的每一个必须具有相同的大小。 您可以通过3维纹理坐标查找纹理。纹理坐标的第三个组成部分是2d纹理数组中2d纹理的索引。
因此,这6个面的纹理坐标为

0:  [(0,0),(1,1,(0,0)]
1:  [(0,1),1)]
2:  [(0,2),2)]
3:  [(0,3),3)]
4:  [(0,4),4)]
5:  [(0,5),5)]

在顶点着色器中获取三维纹理坐标属性,并将其传递给片段着色器:

in a_uv;
out v_uv;

// [...]

void main()
{
    v_uv = a_uv;

    // [...]
}

使用3维纹理坐标在片段着色器中查找sampler2DArray

out v_uv;
uniform sampler2DArray u_texture;

// [...]

void main()
{
    vec4 texture(u_texture,v_uv.xyz);

    // [...]
}

创建一个GL_TEXTURE_2D_ARRAY并使用glTexSubImage3D将6个二维图像加载到2D Array Texture的6个平面上。以下image_planes是具有6个二维图像平面的列表:

tex_obj = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D_ARRAY,self.tex_obj)
glTexImage3D(GL_TEXTURE_2D_ARRAY,GL_RGBA,sizeX,sizeY,6,GL_UNSIGNED_BYTE,None)
for i in range(6):
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY,i,image_planes[i])
glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR)

查看示例:

import os,math,ctypes
import glm
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from OpenGL.arrays import *
import pygame

pygame.init()

image_path = r"images"
image_names = ["banana64.png","apple64.png","fish64.png","rocket64.png","ice64.png","boomerang64.png"]

image_planes = [
    (GLubyte * 4)(255,255),(GLubyte * 4)(0,255,(GLubyte * 4)(255,255)]
image_size = (1,1)

for i,filename in enumerate(image_names):
    try:
        image = pygame.image.load(os.path.join(image_path,filename))
        image_size = image.get_size()
        image_planes[i] = pygame.image.tostring(image,'RGBA')
    except:
        pass

class MyWindow:

    __glsl_vert = """
        #version 130

        in vec3 a_pos;
        in vec3 a_nv;
        in vec3 a_uv;

        out vec3 v_pos;
        out vec3 v_nv;
        out vec3 v_uv;

        uniform mat4 u_proj;
        uniform mat4 u_view;
        uniform mat4 u_model;

        void main()
        {
            mat4 model_view = u_view * u_model;
            mat3 normal     = mat3(model_view);

            vec4 view_pos   = model_view * vec4(a_pos.xyz,1.0);

            v_pos       = view_pos.xyz;
            v_nv        = normal * a_nv;  
            v_uv        = a_uv;  
            gl_Position = u_proj * view_pos;
        }
    """

    __glsl_frag = """
        #version 130

        out vec4 frag_color;
        in  vec3 v_pos;
        in  vec3 v_nv;
        in  vec3 v_uv;

        uniform sampler2DArray u_texture;

        void main()
        {
            vec3  N     = normalize(v_nv);
            vec3  V     = -normalize(v_pos);
            float ka    = 0.1;
            float kd    = max(0.0,dot(N,V)) * 0.9;
            vec4  color = texture(u_texture,v_uv.xyz);
            frag_color  = vec4(color.rgb * (ka + kd),color.a);
        }
    """

    def __init__(self,w,h):
        self.__caption = 'OpenGL Window'
        self.__vp_size = [w,h]

        pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE,24)  
        self.__screen = pygame.display.set_mode(self.__vp_size,pygame.DOUBLEBUF| pygame.OPENGL)
        
        self.__program = compileProgram( 
            compileShader( self.__glsl_vert,GL_VERTEX_SHADER ),compileShader( self.__glsl_frag,GL_FRAGMENT_SHADER ),)
        self.___attrib = { a : glGetAttribLocation (self.__program,a) for a in ['a_pos','a_nv','a_uv'] }
        print(self.___attrib)
        self.___uniform = { u : glGetUniformLocation (self.__program,u) for u in ['u_model','u_view','u_proj'] }
        print(self.___uniform)

        v = [[-1,-1,1],[1,[-1,-1],-1]]
        n = [[0,0],[0,0]]
        e = [[0,2,3],5,2],[5,4,7,6],[4,3,7],[3,5]]
        t = [[0,1]]
        index_array = [si*4+[0,3][vi] for si in range(6) for vi in range(6)]
        attr_array = []
        for si in range(len(e)):
            for i,vi in enumerate(e[si]):
                attr_array += [*v[vi],*n[si],*t[i],si]

        self.__no_vert = len(attr_array) // 10
        self.__no_indices = len(index_array)
        vertex_attributes = (ctypes.c_float * len(attr_array))(*attr_array)
        indices = (ctypes.c_uint32 * self.__no_indices)(*index_array)

        self.__vao = glGenVertexArrays(1)
        self.__vbo,self.__ibo = glGenBuffers(2)

        glBindVertexArray(self.__vao)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,self.__ibo)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,indices,GL_STATIC_DRAW)
        glBindBuffer(GL_ARRAY_BUFFER,self.__vbo)
        glBufferData(GL_ARRAY_BUFFER,vertex_attributes,GL_STATIC_DRAW)

        float_size = ctypes.sizeof(ctypes.c_float)   
        glVertexAttribPointer(self.___attrib['a_pos'],GL_FLOAT,False,9*float_size,None)
        glVertexAttribPointer(self.___attrib['a_nv'],ctypes.c_void_p(3*float_size))
        glVertexAttribPointer(self.___attrib['a_uv'],ctypes.c_void_p(6*float_size))
        glEnableVertexAttribArray(self.___attrib['a_pos'])
        glEnableVertexAttribArray(self.___attrib['a_nv'])
        glEnableVertexAttribArray(self.___attrib['a_uv'])

        glEnable(GL_DEPTH_TEST)
        glUseProgram(self.__program)

        glActiveTexture(GL_TEXTURE0)
        sizeX,sizeY = image_size
        self.tex_obj = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D_ARRAY,self.tex_obj)
        glTexImage3D(GL_TEXTURE_2D_ARRAY,None)
        for i in range(6):
            glTexSubImage3D(GL_TEXTURE_2D_ARRAY,image_planes[i])
        glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_LINEAR)

    def run(self):
        self.__starttime = 0
        self.__starttime = self.elapsed_ms()
        
        run = True
        while run:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    run = False
            self.__mainloop()
            pygame.display.flip()

        pygame.quit()

    def elapsed_ms(self):
      return pygame.time.get_ticks() - self.__starttime

    def __mainloop(self):

        proj,view,model  = glm.mat4(1),glm.mat4(1),glm.mat4(1)
        aspect = self.__vp_size[0]/self.__vp_size[1]
        proj = glm.perspective(glm.radians(90.0),aspect,0.1,10.0)
        view = glm.lookAt(glm.vec3(0,-3,glm.vec3(0,1))
        angle1 = self.elapsed_ms() * math.pi * 2 / 5000.0
        angle2 = self.elapsed_ms() * math.pi * 2 / 7333.0
        model = glm.rotate(model,angle1,glm.vec3(1,0))
        model = glm.rotate(model,angle2,0))

        glUniformMatrix4fv(self.___uniform['u_proj'],GL_FALSE,glm.value_ptr(proj) )
        glUniformMatrix4fv(self.___uniform['u_view'],glm.value_ptr(view) )
        glUniformMatrix4fv(self.___uniform['u_model'],glm.value_ptr(model) )

        glClearColor(0.2,0.3,1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glDrawElements(GL_TRIANGLES,self.__no_indices,GL_UNSIGNED_INT,None)

window = MyWindow(800,600)
window.run()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。