Open GL中体素模型上的纹理映射 [英] Texture mapping on voxel model in Open GL

查看:97
本文介绍了Open GL中体素模型上的纹理映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在观看有关使用LWJGL在YouTube上播放Open GL的视频系列,到目前为止,我已经设法使用obj格式渲染3d模型并对其进行适当的纹理处理.我想在游戏中使用基于体素的模型,因此我进入了MagicaVoxel软件,导出了具有obj格式的纹理示例,但纹理未正确映射.确实,某些颜色似乎已正确映射,但其他人的脸则具有整个纹理.

以下是预期结果的图片:

和实际结果:

我认为问题出在纹理和 opengl 插入它的方式上,纹理是一条 1*256 的带颜色的线,在 obj 文件中,只有所需的颜色放在 uv 坐标上.

我制作了一个更简单的示例来帮助理解发生了什么:只是彼此对齐的3个多维数据集,以及具有3种不同颜色的3像素长的纹理,这是obj文件的代码,并且纹理太小可以看到,但实际上只有3个彩色像素.

 #个法线vn -1 0 0vn 1 0 0vn 0 0 1vn 0 0 -1vn 0 -1 0vn 0 1 0#texcoords体积0.25 0.5vt 0.5 0.5摄氏0.75 0.5#个版本v -0.1 0 0v -0.1 0 -0.1v -0.1 0.1 0v -0.1 0.1 -0.1v 0.2 0 0v 0.2 0 -0.1v 0.2 0.1 0v 0.2 0.1 -0.1v -0.1 0 0v -0.1 0.1 0v 0 0 0v 0 0.1 0v 0.1 0 0v 0.1 0.1 0v 0.2 0 0v 0.2 0.1 0v -0.1 0 -0.1v -0.1 0.1 -0.1v 0 0 -0.1v 0 0.1 -0.1v 0.1 0 -0.1v 0.1 0.1 -0.1v 0.2 0 -0.1v 0.2 0.1 -0.1v -0.1 0 0v 0 0 0v 0.1 0 0v 0.2 0 0v -0.1 0 -0.10 0 -0.1v 0.1 0 -0.1v 0.2 0 -0.1v -0.1 0.1 0v 0 0.1 0v 0.1 0.1 0v 0.2 0.1 0v -0.1 0.1 -0.1v 0 0.1 -0.1v 0.1 0.1 -0.1v 0.2 0.1 -0.1#张面孔f 3/2/1 2/2/1 1/2/1f 4/2/1 2/2/1 3/2/1f 5/1/2 6/1/2 7/1/2f 7/1/2 6/1/2 8/1/2f 11/2/3 10/2/3 9/2/3f 12/2/3 10/2/3 11/2/3f 13/3/3 12/3/3 11/3/3f 14/3/3 12/3/3 13/3/3f 15/1/3 14/1/3 13/1/3f 16/1/3 14/1/3 15/1/3f 17/2/4 18/2/4 19/2/4f 19/2/4 18/2/4 20/2/4f 19/3/4 20/3/4 21/3/4f 21/3/4 20/3/4 22/3/4f 21/1/4 22/1/4 23/1/4f 23/1/4 22/1/4 24/1/4f 29/2/5 26/2/5 25/2/5f 30/3/5 27/3/5 26/3/5f 30/2/5 26/2/5 29/2/5f 31/1/5 28/1/5 27/1/5f 31/3/5 27/3/5 30/3/5f 32/1/5 28/1/5 31/1/5f 33/2/6 34/2/6 37/2/6f 34/3/6 35/3/6 38/3/6f 37/2/6 34/2/6 38/2/6f 35/1/6 36/1/6 39/1/6f 38/3/6 35/3/6 39/3/6f 39/1/6 36/1/6 40/1/6 

您可以看到,每个面的3个顶点拾取的3个UV坐标都是相同的,但是在OpenGL中,这是结果(应该是红色,蓝色和黄色):

这是我的OBJ文件阅读器代码(Java),我调用它来创建vao和要渲染的内容:

 公共静态RawModel loadObjModel(String fileName,Loader loader){FileReader fr = null;尝试 {fr = new FileReader(new File("res/" + fileName +".obj"));} catch(FileNotFoundException e){System.err.println(无法加载文件!");e.printStackTrace();}BufferedReader 阅读器 = 新的 BufferedReader(fr);弦线;List< Vector3f>顶点= new ArrayList< Vector3f>();List< Vector2f>Textures = new ArrayList< Vector2f>();List< Vector3f>法线=新的ArrayList< Vector3f>();List< Integer>索引=新的ArrayList< Integer>();float [] verticesArray = null;float [] normalsArray = null;float [] textureArray = null;int [] indexArray = null;尝试 {而(真){行= reader.readLine();String [] currentLine = line.split(");如果(line.startsWith("v")){Vector3f顶点=新的Vector3f(Float.parseFloat(currentLine [1]),Float.parseFloat(currentLine [2]),Float.parseFloat(currentLine [3]));vertices.add(vertex);}否则,如果(line.startsWith(" vt)){Vector2f纹理=新的Vector2f(Float.parseFloat(currentLine [1]),Float.parseFloat(currentLine [2]));textures.add(texture);}否则,如果(line.startsWith(" vn)){Vector3f normal =新Vector3f(Float.parseFloat(currentLine [1]),Float.parseFloat(currentLine [2]),Float.parseFloat(currentLine [3]));normals.add(normal);}否则,如果(line.startsWith("f")){textureArray = new float [vertices.size()* 2];normalsArray = new float [vertices.size()* 3];休息;}}而(行!= null){如果(!line.startsWith("f")){行= reader.readLine();继续;}String [] currentLine = line.split(");String []顶点1 = currentLine [1] .split("/");String [] vertex2 = currentLine [2] .split("/");String [] vertex3 = currentLine [3] .split("/");processVertex(顶点1,索引,纹理,法线,textArray,normalsArray);processVertex(vertex2,indexes,textures,normals,textureArray,normalsArray);processVertex(顶点3,索引,纹理,法线,textureArray,normalsArray);行= reader.readLine();}reader.close();} catch(Exception e){e.printStackTrace();}verticesArray = new float [vertices.size()* 3];indexArray =新的int [indices.size()];int vertexPointer = 0;for(Vector3f顶点:顶点){verticesArray [vertexPointer ++] = vertex.x;verticesArray [vertexPointer ++] = vertex.y;verticesArray [vertexPointer ++] = vertex.z;}for(int i = 0; i< indices.size(); i ++){indexArray [i] = index.get(i);}返回loader.loadToVAO(verticesArray,indexsArray,textureArray);}私有静态无效processVertex(String [] vertexData,List< Integer>索引,List< Vector2f>纹理,List< Vector3f>法线,float [] textureArray,float [] normalsArray){int currentVertexPointer = Integer.parseInt(vertexData [0])-1;index.add(currentVertexPointer);Vector2f currentTex = textures.get(Integer.parseInt(vertexData [1])-1);textureArray [currentVertexPointer * 2] = currentTex.x;textureArray [currentVertexPointer * 2 + 1] = 1-currentTex.y;Vector3f currentNorm = normals.get(Integer.parseInt(vertexData [2])-1);normalsArray [currentVertexPointer * 3] = currentNorm.x;normalsArray [currentVertexPointer * 3 + 1] = currentNorm.y;normalsArray [currentVertexPointer * 3 + 2] = currentNorm.z;} 

这是我的片段着色器:

  #version 400核心在vec2中pass_textureCoords;vec4 out_colour;统一采样器2D textureSampler;void main(void){out_colour = texture(textureSampler,pass_textureCoords);} 

这是我的顶点着色器:

  #version 400核心处于vec3位置;在vec2 textureCoords中;vec2 pass_textureCoords;统一的mat4 TransformationMatrix;均匀的mat4 projectionMatrix;统一的mat4 viewMatrix;void main(void){gl_Position = projectionMatrix * viewMatrix * TransformationMatrix * vec4(position.xyz,1.0);pass_textureCoords = textureCoords;} 

这是我的渲染方法,称为每一帧:

  public void render(EntityEntity,StaticShader shader){TexturedModel TexturedModel = entity.getTexturedModel();RawModel模型= TexturedModel.getRawModel();GL30.glBindVertexArray(model.getVaoID());GL20.glEnableVertexAttribArray(0);GL20.glEnableVertexAttribArray(1);Matrix4f TransformationMatrix = Maths.createTransformationMatrix(entity.getPosition(),entity.getRotation(),entity.getScale());shader.loadTransformationMatrix(transformationMatrix);GL13.glActiveTexture(GL13.GL_TEXTURE0);GL11.glBindTexture(GL11.GL_TEXTURE_2D,TexturedModel.getTexture().getID());GL11.glDrawElements(GL11.GL_TRIANGLES,model.getVertexCount(),GL11.GL_UNSIGNED_INT,0);GL20.glDisableVertexAttribArray(0);GL20.glDisableVertexAttribArray(1);GL30.glBindVertexArray(0);} 

我不明白我所缺少的内容,并且它再次适用于具有大纹理的搅拌器模型:

解决方案

您的Wavefront OBJ文件加载程序实际上仅在非常特殊的情况下有效,即,当任意两个顶点都没有纹理坐标或法线共享时,因此v,vn和vt规范彼此之间具有1:1的对应关系.但是,通常情况并非如此.撇开Wavefront OBJ文件加载器也仅在所有"f"行排在所有v,vt和vn行之后(也并非总是如此)之后才起作用的事实,那么您仍然还有其他一些问题.因此,当前的主要问题是您假设'v'和'vt'行之间的比例为1:1,而事实并非如此.通常,您不能简单地将'v'索引(通过'f'行中的第一个'/'分隔值指定)用作OpenGL元素缓冲区索引,因为OpenGL只有一个单个元素索引才能索引到位置,纹理和法线阵列统一,而Wavefront OBJ文件格式具有三个不同的索引,每个索引分别用于位置,纹理和法线.因此,应该要做的是重新考虑/重写Wavefront OBJ文件加载器,以便它基本上收集所有位置(v),纹理坐标(vt)和法线(vn)信息,然后每当遇到在(f)面中,您可以将指定索引处(在"f"行中)的位置,纹理和法线信息附加到最终结果缓冲区中.您不能简单地使用从'f'行的位置索引派生的单个索引.您要么根本不使用任何索引,要么简单地使用连续的递增索引作为OpenGL元素缓冲区.

但是首先,我强烈建议您阅读Wavefront OBJ文件格式的实际规范,例如: http://paulbourke.net/dataformats/obj/

I'm following a video series about Open GL on YouTube using LWJGL, so far I've managed to render 3d models and texture them properly using the obj format. I want to use voxel-based models for my game so I went in the software MagicaVoxel, exported a textured example with the obj format, but the texture is not mapped correctly. Indeed, some colors seem to be correctly mapped, but other faces have the entire texture on them.

Here is a picture of the expected result:

and the actual result:

I think the problem comes with the texture and the way opengl interpolate it, the texture is a 1*256 line with colors, and on the obj file only the desired colors are put on the uv coordinates.

I made a simpler example to help understand what is going on: just 3 cubes aligned with each other, and a 3-pixel long texture with 3 different colors, here is the code of the obj file and the texture is too small to be seen but it's really just 3 colored pixels.

# normals
vn -1 0 0
vn 1 0 0
vn 0 0 1
vn 0 0 -1
vn 0 -1 0
vn 0 1 0

# texcoords
vt 0.25 0.5
vt 0.5 0.5
vt 0.75 0.5

# verts
v -0.1 0 0
v -0.1 0 -0.1
v -0.1 0.1 0
v -0.1 0.1 -0.1
v 0.2 0 0
v 0.2 0 -0.1
v 0.2 0.1 0
v 0.2 0.1 -0.1
v -0.1 0 0
v -0.1 0.1 0
v 0 0 0
v 0 0.1 0
v 0.1 0 0
v 0.1 0.1 0
v 0.2 0 0
v 0.2 0.1 0
v -0.1 0 -0.1
v -0.1 0.1 -0.1
v 0 0 -0.1
v 0 0.1 -0.1
v 0.1 0 -0.1
v 0.1 0.1 -0.1
v 0.2 0 -0.1
v 0.2 0.1 -0.1
v -0.1 0 0
v 0 0 0
v 0.1 0 0
v 0.2 0 0
v -0.1 0 -0.1
v 0 0 -0.1
v 0.1 0 -0.1
v 0.2 0 -0.1
v -0.1 0.1 0
v 0 0.1 0
v 0.1 0.1 0
v 0.2 0.1 0
v -0.1 0.1 -0.1
v 0 0.1 -0.1
v 0.1 0.1 -0.1
v 0.2 0.1 -0.1

# faces
f 3/2/1 2/2/1 1/2/1
f 4/2/1 2/2/1 3/2/1
f 5/1/2 6/1/2 7/1/2
f 7/1/2 6/1/2 8/1/2
f 11/2/3 10/2/3 9/2/3
f 12/2/3 10/2/3 11/2/3
f 13/3/3 12/3/3 11/3/3
f 14/3/3 12/3/3 13/3/3
f 15/1/3 14/1/3 13/1/3
f 16/1/3 14/1/3 15/1/3
f 17/2/4 18/2/4 19/2/4
f 19/2/4 18/2/4 20/2/4
f 19/3/4 20/3/4 21/3/4
f 21/3/4 20/3/4 22/3/4
f 21/1/4 22/1/4 23/1/4
f 23/1/4 22/1/4 24/1/4
f 29/2/5 26/2/5 25/2/5
f 30/3/5 27/3/5 26/3/5
f 30/2/5 26/2/5 29/2/5
f 31/1/5 28/1/5 27/1/5
f 31/3/5 27/3/5 30/3/5
f 32/1/5 28/1/5 31/1/5
f 33/2/6 34/2/6 37/2/6
f 34/3/6 35/3/6 38/3/6
f 37/2/6 34/2/6 38/2/6
f 35/1/6 36/1/6 39/1/6
f 38/3/6 35/3/6 39/3/6
f 39/1/6 36/1/6 40/1/6 

As you can see for each face, the 3 UV coordinates picked up for the 3 vertices are the same, but in OpenGL, this is the result (they are supposed to be red, blue and yellow):

Here is my OBJ file reader code (in Java), that I call to create the vao and stuff to render:

public static RawModel loadObjModel(String fileName, Loader loader) {
        FileReader fr = null;
        try {
            fr = new FileReader(new File("res/" + fileName + ".obj"));
        } catch (FileNotFoundException e) {
            System.err.println("Couldn't load file!");
            e.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(fr);
        String line;
        List<Vector3f> vertices = new ArrayList<Vector3f>();
        List<Vector2f> textures = new ArrayList<Vector2f>();
        List<Vector3f> normals = new ArrayList<Vector3f>();
        List<Integer> indices = new ArrayList<Integer>();
        float[] verticesArray = null;
        float[] normalsArray = null;
        float[] textureArray = null;
        int[] indicesArray = null;
        try {

            while (true) {
                line = reader.readLine();
                String[] currentLine = line.split(" ");
                if (line.startsWith("v ")) {
                    Vector3f vertex = new Vector3f(Float.parseFloat(currentLine[1]),
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    vertices.add(vertex);
                } else if (line.startsWith("vt ")) {
                    Vector2f texture = new Vector2f(Float.parseFloat(currentLine[1]),
                            Float.parseFloat(currentLine[2]));
                    textures.add(texture);
                } else if (line.startsWith("vn ")) {
                    Vector3f normal = new Vector3f(Float.parseFloat(currentLine[1]),
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    normals.add(normal);
                } else if (line.startsWith("f ")) {
                    textureArray = new float[vertices.size() * 2];
                    normalsArray = new float[vertices.size() * 3];
                    break;
                }
            }

            while (line != null) {
                if (!line.startsWith("f ")) {
                    line = reader.readLine();
                    continue;
                }
                String[] currentLine = line.split(" ");
                String[] vertex1 = currentLine[1].split("/");
                String[] vertex2 = currentLine[2].split("/");
                String[] vertex3 = currentLine[3].split("/");
                
                processVertex(vertex1,indices,textures,normals,textureArray,normalsArray);
                processVertex(vertex2,indices,textures,normals,textureArray,normalsArray);
                processVertex(vertex3,indices,textures,normals,textureArray,normalsArray);
                line = reader.readLine();
            }
            reader.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
        
        verticesArray = new float[vertices.size()*3];
        indicesArray = new int[indices.size()];
        
        int vertexPointer = 0;
        for(Vector3f vertex:vertices){
            verticesArray[vertexPointer++] = vertex.x;
            verticesArray[vertexPointer++] = vertex.y;
            verticesArray[vertexPointer++] = vertex.z;
        }
        
        for(int i=0;i<indices.size();i++){
            indicesArray[i] = indices.get(i);
        }
        return loader.loadToVAO(verticesArray, indicesArray, textureArray);

    }

    private static void processVertex(String[] vertexData, List<Integer> indices,
            List<Vector2f> textures, List<Vector3f> normals, float[] textureArray,
            float[] normalsArray) {
        int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
        indices.add(currentVertexPointer);
        Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1])-1);
        textureArray[currentVertexPointer*2] = currentTex.x;
        textureArray[currentVertexPointer*2+1] = 1 - currentTex.y;
        Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2])-1);
        normalsArray[currentVertexPointer*3] = currentNorm.x;
        normalsArray[currentVertexPointer*3+1] = currentNorm.y;
        normalsArray[currentVertexPointer*3+2] = currentNorm.z; 
    }

Here is my fragment shader:

#version 400 core

in vec2 pass_textureCoords;

out vec4 out_colour;

uniform sampler2D textureSampler;

void main(void){

    out_colour = texture(textureSampler,pass_textureCoords);
}

Here is my vertex shader:

#version 400 core

in vec3 position;
in vec2 textureCoords;

out vec2 pass_textureCoords;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;

void main(void){

    gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position.xyz,1.0);
    pass_textureCoords = textureCoords;
}

And here is my render method called every frame:

public void render(Entity entity,StaticShader shader) {

        TexturedModel texturedModel = entity.getTexturedModel();
        RawModel model = texturedModel.getRawModel();
        GL30.glBindVertexArray(model.getVaoID());
        
        GL20.glEnableVertexAttribArray(0);
        GL20.glEnableVertexAttribArray(1);
        
        Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotation(), entity.getScale());
        shader.loadTransformationMatrix(transformationMatrix);
        
        GL13.glActiveTexture(GL13.GL_TEXTURE0);



        GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getID());
        
        GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(),GL11.GL_UNSIGNED_INT,0);
        
        GL20.glDisableVertexAttribArray(0);
        GL20.glDisableVertexAttribArray(1);

        GL30.glBindVertexArray(0);
    }

I don't understand what I'm missing, and again it already worked for a blender model with a large texture:

解决方案

Your Wavefront OBJ file loader really only works in a very particular case, namely, when no texture coordinates or normals are shared by any two vertices, so that v, vn and vt specifications have a 1:1 correspondence to each another. This generally is not the case, though. Leaving out the fact that your Wavefront OBJ file loader also only works when all 'f' lines come after all v, vt and vn lines (which is also not always the case), then you still have a few other problems. So the main problem as is currently is that you assume a 1:1 correspondence between 'v' and 'vt' lines, which is not the case. Generally, you cannot simply use the 'v' index (as specified via the first '/'-delimited value in an 'f' line) as your OpenGL element buffer index, because OpenGL only has one single element index, to index into position, texture and normals arrays uniformly, whereas the Wavefront OBJ file format has three different indices, each for position, textures and normals separately. So, what you should do is rethink/rewrite your Wavefront OBJ file loader so that it basically collects all position (v), texture coordinates (vt) and normals (vn) information and then whenever you encounter a face (f) you append the position, texture and normals information at the specified indices (in the 'f' line) into your final result buffers. You cannot simply use a single index derived from the position index of the 'f' line. You either don't use any indices at all or simply use a contiguous incrementing index as your OpenGL element buffer.

But first, I highly recommend reading an actual specification for the Wavefront OBJ file format, such as this: http://paulbourke.net/dataformats/obj/

这篇关于Open GL中体素模型上的纹理映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆