细分的icosphere不能正确呈现。顶点顺序不正确?

时间:2017-08-08 20:51:47

标签: java opengl model rendering lwjgl

我目前正致力于分割我的icosphere,最终看起来很疯狂(见下文)。如果我没有细分它,它工作正常,所以我相信错误是在我的递归for循环或getMiddlePoint方法(见下文)。我对为什么会发生这种情况的想法是我以错误的顺序添加顶点和索引。如果是这种情况,我应该将它们添加到什么顺序?关于如何解决这个问题的任何想法?

结果:

Here

循环递归:

for (int i = 0; i < RECURSION_LEVEL; i++) {
            List<Vector3i> indices2 = new ArrayList<Vector3i>();
            for (Vector3i face : indices) {
                int a = getMiddlePoint(face.x, face.y);
                int b = getMiddlePoint(face.y, face.z);
                int c = getMiddlePoint(face.z, face.x);

                indices2.add(new Vector3i(face.x, a, c));
                indices2.add(new Vector3i(face.y, b, a));
                indices2.add(new Vector3i(face.z, c, b));
                indices2.add(new Vector3i(a, b, c));
            }
            indices = indices2;
        }

getMiddlePoints方法:

private int getMiddlePoint(int p1, int p2) {
        boolean firstIsSmaller = p1 < p2;
        int smallerIndex = firstIsSmaller ? p1 : p2;
        int greaterIndex = firstIsSmaller ? p2 : p1;
        int key = (smallerIndex << 32) + greaterIndex;

        Integer ret = middlePointIndexCache.get(key);
        if (ret != null) {
            return ret;
        }

        Vector3f point1 = vertices.get(p1);
        Vector3f point2 = vertices.get(p2);
        Vector3f middle = new Vector3f(
                (point1.x + point2.x) / 2.0f,
                (point1.y + point2.y) / 2.0f,
                (point1.z + point2.z) / 2.0f
                );

        int i = addVertex(middle);
        middlePointIndexCache.put(key, i);
        return i;
    }

我的icosphere生成器的所有代码: (忽略纹理坐标,它们是临时的,以防止我的渲染器崩溃。)

package com.robert.game.planet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector3i;

import com.robert.engine.loader.Loader;
import com.robert.engine.models.Mesh;

public class BasePlanetGenerator {

    private List<Vector3f> vertices = new ArrayList<Vector3f>();
    private List<Vector3f> normals = new ArrayList<Vector3f>();
    private List<Vector3i> indices = new ArrayList<Vector3i>(); // think of this as faces
    private List<Vector2f> textureCoords = new ArrayList<Vector2f>();
    private Map<Integer, Integer> middlePointIndexCache = new HashMap<Integer, Integer>();

    private static final int RECURSION_LEVEL = 2;

    private int index = 0;

    float t = (float) ((1.0 + Math.sqrt(5.0)) / 2);

    // Initial vertices
    {
//      vertices.add(new Vector3f(-1,  t,  0));
//      vertices.add(new Vector3f(1,  t,  0));
//      vertices.add(new Vector3f(-1, -t,  0));
//      vertices.add(new Vector3f(1, -t,  0));
//      
//      vertices.add(new Vector3f(0, -1,  t));
//      vertices.add(new Vector3f(0,  1,  t));
//      vertices.add(new Vector3f(0, -1, -t));
//      vertices.add(new Vector3f(0,  1, -t));
//      
//      vertices.add(new Vector3f(t,  0, -1));
//      vertices.add(new Vector3f(t,  0,  1));
//      vertices.add(new Vector3f(-t,  0, -1));
//      vertices.add(new Vector3f(-t,  0,  1));

        addVertex(new Vector3f(-1,  t,  0));
        addVertex(new Vector3f(1,  t,  0));
        addVertex(new Vector3f(-1, -t,  0));
        addVertex(new Vector3f(1, -t,  0));

        addVertex(new Vector3f(0, -1,  t));
        addVertex(new Vector3f(0,  1,  t));
        addVertex(new Vector3f(0, -1, -t));
        addVertex(new Vector3f(0,  1, -t));

        addVertex(new Vector3f(t,  0, -1));
        addVertex(new Vector3f(t,  0,  1));
        addVertex(new Vector3f(-t,  0, -1));
        addVertex(new Vector3f(-t,  0,  1));
    }

    // Initial indices
    {
        indices.add(new Vector3i(0, 11, 5));
        indices.add(new Vector3i(0, 5, 1));
        indices.add(new Vector3i(0, 1, 7));
        indices.add(new Vector3i(0, 7, 10));
        indices.add(new Vector3i(0, 10, 11));

        indices.add(new Vector3i(1, 5, 9));
        indices.add(new Vector3i(5, 11, 4));
        indices.add(new Vector3i(11, 10, 2));
        indices.add(new Vector3i(10, 7, 6));
        indices.add(new Vector3i(7, 1, 8));

        indices.add(new Vector3i(3, 9, 4));
        indices.add(new Vector3i(3, 4, 2));
        indices.add(new Vector3i(3, 2, 6));
        indices.add(new Vector3i(3, 6, 8));
        indices.add(new Vector3i(3, 8, 9));

        indices.add(new Vector3i(4, 9, 5));
        indices.add(new Vector3i(2, 4, 11));
        indices.add(new Vector3i(6, 2, 10));
        indices.add(new Vector3i(8, 6, 7));
        indices.add(new Vector3i(9, 8, 1));

//      indices = Arrays.asList(new Integer[] {
//              0, 11, 5,
//              0, 5, 1,
//              0, 1, 7,
//              0, 7, 10,
//              0, 10, 11,
//              
//              1, 5, 9,
//              5, 11, 4,
//              11, 10, 2,
//              10, 7, 6,
//              7, 1, 8,
//              
//              3, 9, 4,
//              3, 4, 2,
//              3, 2, 6,
//              3, 6, 8,
//              3, 8, 9,
//              
//              4, 9, 5,
//              2, 4, 11,
//              6, 2, 10,
//              8, 6, 7,
//              9, 8, 1
//      });
    }

    // Inital textureCoords
    {
        textureCoords.add(new Vector2f(1, 1));
    }

    float[] verticesArray;
    int[] indicesArray;
    float[] normalsArray;
    float[] textureCoordsArray;

    public Mesh generateBasePlanet(Loader loader) {

        for (int i = 0; i < RECURSION_LEVEL; i++) {
            List<Vector3i> indices2 = new ArrayList<Vector3i>();
            for (Vector3i face : indices) {
                int a = getMiddlePoint(face.x, face.y);
                int b = getMiddlePoint(face.y, face.z);
                int c = getMiddlePoint(face.z, face.x);

                indices2.add(new Vector3i(face.x, a, c));
                indices2.add(new Vector3i(face.y, b, a));
                indices2.add(new Vector3i(face.z, c, b));
                indices2.add(new Vector3i(a, b, c));
            }
            indices = indices2;
        }

        for (int i = 0; i < vertices.size(); i ++) {
            Vector3f normal = vertices.get(i);
//          normal.normalize();
//          float length = normal.length();     
//          normals.add(new Vector3f(normal.x / length, normal.y / length, normal.z / length));
            normals.add(normal);
        }

        convertToArrays();

        return loader.createMesh(verticesArray, textureCoordsArray, normalsArray, indicesArray);
    }

    private int getMiddlePoint(int p1, int p2) {
        boolean firstIsSmaller = p1 < p2;
        int smallerIndex = firstIsSmaller ? p1 : p2;
        int greaterIndex = firstIsSmaller ? p2 : p1;
        int key = (smallerIndex << 32) + greaterIndex;

        Integer ret = middlePointIndexCache.get(key);
        if (ret != null) {
            return ret;
        }

        Vector3f point1 = vertices.get(p1);
        Vector3f point2 = vertices.get(p2);
        Vector3f middle = new Vector3f(
                (point1.x + point2.x) / 2.0f,
                (point1.y + point2.y) / 2.0f,
                (point1.z + point2.z) / 2.0f
                );

        int i = addVertex(middle);
        middlePointIndexCache.put(key, i);
        return i;
    }

    private void convertToArrays() {
        verticesArray = new float[vertices.size() * 3];
        indicesArray = new int[indices.size() * 3];
        normalsArray = new float[normals.size() * 3];
        textureCoordsArray = new float[textureCoords.size() * 2];

        for (int i = 0; i < vertices.size(); i ++) {        
            Vector3f vertex = vertices.get(i);
            verticesArray[(i * 3)] = vertex.x;
            verticesArray[(i * 3) + 1] = vertex.y;
            verticesArray[(i * 3) + 2] = vertex.z;
        }

        for (int i = 0; i < indices.size(); i ++) {
            Vector3i indice = indices.get(i);
            indicesArray[(i * 3)] = indice.x;
            indicesArray[(i * 3) + 1] = indice.y;
            indicesArray[(i * 3) + 2] = indice.z;
//          indicesArray[i] = indices.get(i);
        }

        for (int i = 0; i < normals.size(); i ++) {
            Vector3f normal = normals.get(i);
            normalsArray[(i * 3)] = normal.x;
            normalsArray[(i * 3) + 1] = normal.y;
            normalsArray[(i * 3) + 2] = normal.z;
        }

        for (int i = 0; i < textureCoords.size(); i ++) {
            textureCoordsArray[(i * 2)] = textureCoords.get(i).x;
            textureCoordsArray[(i * 2) + 1] = textureCoords.get(i).y;
        }
    }

    private int addVertex(Vector3f vector) {
        float length = vector.length();
        vertices.add(new Vector3f(vector.x / length, vector.y / length, vector.z / length));
        return index++;
    }
}

1 个答案:

答案 0 :(得分:0)

oracle java specification清楚地说:

  

积分类型的值是以下范围内的整数:
   - 对于int,从-2147483648到2147483647,包括

这意味着数据类型int是一个大小为32位的整数数据类型。

在函数getMiddlePoint中,行

int key = (smallerIndex << 32) + greaterIndex;

导致溢出。

将其更改为

int key = (smallerIndex << 16) + greaterIndex;

并且您的代码将正常工作。