java - 带有 openGL 1.0 的 Poser Mesh,50% 的三角形似乎丢失

标签 java android opengl-es

我使用 Poser 生成了一个 3D 模型,以便在 Android 应用程序中将其与 openGL 1.0 一起使用。当我渲染网格时,我可以看到在 Poser 8 中生成的 3D 模型,但不幸的是只有一半的三角形被渲染 - 看起来我必须绘制某种正方形。有没有什么方法可以镜像现有的三角形,以便我可以绘制缺失的三角形?

我的网格是从波前对象生成的。因此我使用了一个名为 Mesh 的类

public final class Mesh {

public enum PrimitiveType {
    Points,
    Lines,
    Triangles,
    LineStrip,
    TriangleStrip,
    TriangleFan
}

// gl instance
private GL10 gl;

// vertex position buffer, array
private float vertices[];
private int vertexHandle;
private FloatBuffer vertexBuffer;

// color buffer, array
private float colors[];
private int colorHandle;
private FloatBuffer colorBuffer;

// texture coordinate buffer, array
private float texCoords[];
private int texHandle;
private FloatBuffer texBuffer;

// normal (for illumination) buffer, array
private float normals[];
private int normalHandle;
private FloatBuffer normalBuffer;

// index where next vertices will be inserted
private int index = 0;

// number vertices for mesh
private int numVertices = 0;

// renderer support vbos
private boolean globalVBO = true;

// is mesh dirty
private boolean dirty = true;

// last mesh
private static Mesh lastMesh;

// mesh count
public static int numMeshes = 0;

/**
 * after calling constructor first set attribute (color, texture, normal), then fix the vertex by calling vertex(...)
 *
 * @param gl                    GL10
 * @param numVertices           number vertices of mesh
 * @param hasColors             using colors?
 * @param hasTextureCoordinates using textures coordinates
 * @param hasNormals            using normals?
 */
public Mesh(GL10 gl, int numVertices, boolean hasColors, boolean hasTextureCoordinates, boolean hasNormals) {
    this.gl = gl;
    vertices = new float[numVertices * 3];
    int[] buffer = new int[1];

    if (!globalVBO) {
        vertexBuffer = allocateBuffer(numVertices * 3);
    } else {
        ((GL11) gl).glGenBuffers(1, buffer, 0);
        vertexHandle = buffer[0];
        vertexBuffer = FloatBuffer.wrap(vertices);
    }

    if (hasColors) {
        colors = new float[numVertices * 4];

        if (!globalVBO) {
            colorBuffer = allocateBuffer(numVertices * 3);
        } else {
            ((GL11) gl).glGenBuffers(1, buffer, 0);
            colorHandle = buffer[0];
            colorBuffer = FloatBuffer.wrap(colors);
        }
    }

    if (hasTextureCoordinates) {
        texCoords = new float[numVertices * 2];

        if (!globalVBO) {
            texBuffer = allocateBuffer(numVertices * 3);
        } else {
            ((GL11) gl).glGenBuffers(1, buffer, 0);
            texHandle = buffer[0];
            texBuffer = FloatBuffer.wrap(texCoords);
        }
    }

    if (hasNormals) {
        normals = new float[numVertices * 3];

        if (!globalVBO) {
            normalBuffer = allocateBuffer(numVertices * 3);
        } else {
            ((GL11) gl).glGenBuffers(1, buffer, 0);
            normalHandle = buffer[0];
            normalBuffer = FloatBuffer.wrap(normals);
        }
    }
}

/**
 * allocates FloatBuffer of size
 *
 * @param size size number of floats
 * @return FloatBuffer
 */
private FloatBuffer allocateBuffer(int size) {
    ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4);
    buffer.order(ByteOrder.nativeOrder());
    return buffer.asFloatBuffer();
}

/**
 * renders mesh given type, starts at offset wirh numVertices vertices
 *
 * @param type        PrimitiveType (see above)
 * @param offset      offset in number of vertices
 * @param numVertices number of vertices to use
 */
public void render(PrimitiveType type, int offset, int numVertices) {
    boolean wasDirty = dirty;
    if (dirty) {
        update();
    }

    if (this == lastMesh && !wasDirty) {
        gl.glDrawArrays(getPrimitiveType(type), offset, numVertices);
        return;
    } else {
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    }

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    if (globalVBO) {
        ((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexHandle);
        ((GL11) gl).glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
    } else {
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    }

    if (colors != null) {
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        if (globalVBO) {
            ((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, colorHandle);
            ((GL11) gl).glColorPointer(4, GL10.GL_FLOAT, 0, 0);
        } else
            gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
    }

    if (texCoords != null) {
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        if (globalVBO) {
            ((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, texHandle);
            ((GL11) gl).glTexCoordPointer(2, GL10.GL_FLOAT, 0, 0);
        } else
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer);
    }

    if (normals != null) {
        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        if (globalVBO) {
            ((GL11) gl).glBindBuffer(GL11.GL_ARRAY_BUFFER, normalHandle);
            ((GL11) gl).glNormalPointer(GL10.GL_FLOAT, 0, 0);
        } else
            gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
    }

    gl.glDrawArrays(getPrimitiveType(type), offset, numVertices);
    lastMesh = this;
}

/**
 * renders mesh as given type with numVertices from calling vertex()
 *
 * @param type PrimitveType
 */
public void render(PrimitiveType type) {
    render(type, 0, numVertices);
}

/**
 * returns openGL constant of PrimitiveType
 *
 * @param type PrimitiveType (enum above)
 * @return openGL constant
 */
private int getPrimitiveType(PrimitiveType type) {
    if (type == PrimitiveType.Lines) {
        return GL10.GL_LINES;
    } else if (type == PrimitiveType.Triangles) {
        return GL10.GL_TRIANGLES;
    } else if (type == PrimitiveType.LineStrip) {
        return GL10.GL_LINE_STRIP;
    } else if (type == PrimitiveType.TriangleStrip) {
        return GL10.GL_TRIANGLE_STRIP;
    } else if (type == PrimitiveType.Points) {
        return GL10.GL_POINTS;
    } else {
        return GL10.GL_TRIANGLE_FAN;
    }
}

/**
 * updates the direct buffers in case the user
 */
private void update() {
    if (!globalVBO) {
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        if (colors != null) {
            colorBuffer.put(colors);
            colorBuffer.position(0);
        }

        if (texCoords != null) {
            texBuffer.put(texCoords);
            texBuffer.position(0);
        }

        if (normals != null) {
            normalBuffer.put(normals);
            normalBuffer.position(0);
        }
    } else {
        GL11 gl = (GL11) this.gl;

        gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vertexHandle);
        gl.glBufferData(GL11.GL_ARRAY_BUFFER, vertices.length * 4, vertexBuffer, GL11.GL_DYNAMIC_DRAW);

        if (colors != null) {
            gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, colorHandle);
            gl.glBufferData(GL11.GL_ARRAY_BUFFER, colors.length * 4, colorBuffer, GL11.GL_DYNAMIC_DRAW);
        }

        if (normals != null) {
            gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, normalHandle);
            gl.glBufferData(GL11.GL_ARRAY_BUFFER, normals.length * 4, normalBuffer, GL11.GL_DYNAMIC_DRAW);
        }

        if (texCoords != null) {
            gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, texHandle);
            gl.glBufferData(GL11.GL_ARRAY_BUFFER, texCoords.length * 4, texBuffer, GL11.GL_DYNAMIC_DRAW);
        }

        gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, 0);
    }

    numVertices = index;
    index = 0;
    dirty = false;
}

/**
 * defines position of current vertex, before calling call method like color, normal or texCoord
 *
 * @param x x coordinate
 * @param y y coordinate
 * @param z z coordinate
 */
public void vertex(float x, float y, float z) {
    dirty = true;
    int offset = index * 3;
    vertices[offset] = x;
    vertices[offset + 1] = y;
    vertices[offset + 2] = z;
    index++;
}

/**
 * sets color of current vertex
 *
 * @param r red
 * @param g green
 * @param b blue
 * @param a alpha
 */
public void color(float r, float g, float b, float a) {
    dirty = true;
    int offset = index * 4;
    colors[offset] = r;
    colors[offset + 1] = g;
    colors[offset + 2] = b;
    colors[offset + 3] = a;
}

/**
 * sets the normal of current vertex
 *
 * @param x x components
 * @param y y components
 * @param z z components
 */
public void normal(float x, float y, float z) {
    dirty = true;
    int offset = index * 3;
    normals[offset] = x;
    normals[offset + 1] = y;
    normals[offset + 2] = z;

}

/**
 * sets texture coordinates of current vertex
 *
 * @param s s coordinate (correlates x)
 * @param t t coordinate (correlates y)
 */
public void texCoord(float s, float t) {
    dirty = true;
    int offset = index * 2;
    texCoords[offset] = s;
    texCoords[offset + 1] = t;
}

/**
 * deletes all buffers, sets all attributes to null
 */
public void dispose() {
    if (globalVBO) {
        GL11 gl = (GL11) this.gl;
        if (vertexHandle != -1)
            gl.glDeleteBuffers(1, new int[]{vertexHandle}, 0);
        if (colorHandle != -1)
            gl.glDeleteBuffers(1, new int[]{colorHandle}, 0);
        if (normalHandle != -1)
            gl.glDeleteBuffers(1, new int[]{normalHandle}, 0);
        if (texHandle != -1)
            gl.glDeleteBuffers(1, new int[]{texHandle}, 0);
    }

    vertices = null;
    vertexBuffer = null;
    colors = null;
    colorBuffer = null;
    normals = null;
    normalBuffer = null;
    texCoords = null;
    texBuffer = null;
    numMeshes--;

}

/**
 * @return number of vertices
 */
public int getMaximumVertices() {
    return vertices.length / 3;
}

/**
 * resets index
 */
public void reset() {
    dirty = true;
    index = 0;
}

}

还有一个叫做 MeshLoader 的类

public class MeshLoader {
/**
 *
 * Loads a mesh from the given InputStream
 * @param gl GL10 instance
 * @return The mesh
 */
public static Mesh loadObj( GL10 gl, InputStream in )
{
    String line = "";

    try
    {
        BufferedReader reader = new BufferedReader( new InputStreamReader(in) );
        StringBuffer b = new StringBuffer();
        String l = reader.readLine();
        while( l != null )
        {
            b.append( l );
            b.append( "\n" );
            l = reader.readLine();
        }

        line = b.toString();
        reader.close();
    }
    catch( Exception ex )
    {
        throw new RuntimeException(ex.getMessage() + " " +
                "couldn't load file mesh from input stream" );
    }
    return loadObjFromString( gl, line );
}

/**
 * Loads a mesh from the given string in obj format
 *
 * @param obj The string
 * @return The Mesh
 */
public static Mesh loadObjFromString( GL10 gl, String obj )
{
    String[] lines = obj.split( "\n" );
    float[] vertices = new float[lines.length * 3];
    float[] normals = new float[lines.length * 3];
    float[] uv = new float[lines.length * 3];

    int numVertices = 0;
    int numNormals = 0;
    int numUV = 0;
    int numFaces = 0;

    int[] facesVerts = new int[lines.length * 3];
    int[] facesNormals = new int[lines.length * 3];
    int[] facesUV = new int[lines.length * 3];
    int vertexIndex = 0;
    int normalIndex = 0;
    int uvIndex = 0;
    int faceIndex = 0;

    for( int i = 0; i < lines.length; i++ )
    {
        String line = lines[i];
        if( line.startsWith( "v " ) )
        {
            String[] tokens = line.split( " " );
            vertices[vertexIndex] = Float.parseFloat(tokens[1]);
            vertices[vertexIndex+1] = Float.parseFloat(tokens[2]);
            vertices[vertexIndex+2] = Float.parseFloat(tokens[3]);
            vertexIndex += 3;
            numVertices++;
            continue;
        }

        if( line.startsWith( "vn " ) )
        {
            String[] tokens = line.split( " " );
            normals[normalIndex] = Float.parseFloat(tokens[1]);
            normals[normalIndex+1] = Float.parseFloat(tokens[2]);
            normals[normalIndex+2] = Float.parseFloat(tokens[3]);
            normalIndex += 3;
            numNormals++;
            continue;
        }

        // coords of each texture point
        if( line.startsWith( "vt" ) )
        {
            String[] tokens = line.split( " " );
            uv[uvIndex] = Float.parseFloat(tokens[1]);
            uv[uvIndex+1] = Float.parseFloat(tokens[2]);
            uvIndex += 2;
            numUV++;
            continue;
        }

        if( line.startsWith( "f " ) )
        {
            String[] tokens = line.split( " " );

            String[] parts = tokens[1].split("/");
            facesVerts[faceIndex] = getIndex(parts[0], numVertices);
            facesNormals[faceIndex] = getIndex(parts[2], numNormals);
            facesUV[faceIndex] = getIndex(parts[1], numUV);
            faceIndex++;

            parts = tokens[2].split("/");
            facesVerts[faceIndex] = getIndex(parts[0], numVertices);
            facesNormals[faceIndex] = getIndex(parts[2], numNormals);
            facesUV[faceIndex] = getIndex(parts[1], numUV);
            faceIndex++;

            parts = tokens[3].split("/");
            facesVerts[faceIndex] = getIndex(parts[0], numVertices);
            facesNormals[faceIndex] = getIndex(parts[2], numNormals);
            facesUV[faceIndex] = getIndex(parts[1], numUV);
            faceIndex++;
            numFaces++;
            continue;
        }
    }

    Mesh mesh = new Mesh(gl, numFaces * 3, false ,numUV > 0, numNormals > 0  );

    for( int i = 0; i < numFaces*3; i++ )
    {
        if( numNormals > 0 )
        {
            int normalIdx = facesNormals[i] * 3;
            mesh.normal( normals[normalIdx], normals[normalIdx+1], normals[normalIdx+2] );
        }
        if( numUV > 0 )
        {
            int uvIdx = facesUV[i] * 2;
            mesh.texCoord( uv[uvIdx], uv[uvIdx+1]);
        }

        int vertexIdx = facesVerts[i] *3;
        mesh.vertex( vertices[vertexIdx], vertices[vertexIdx+1], vertices[vertexIdx+2] );
    }

    return mesh;
}

private static int getIndex( String index, int size )
{
    if( index == null || index.length() == 0 )
        return 0;
    int idx = Integer.parseInt( index );
    if( idx < 0 )
        return size + idx;
    else
        return idx - 1;
}

}

每个 3D 对象都是一个网格,将由 MeshLoader.loadObject 方法生成。

这对简单的对象非常有效。但不是 Poser 8 生成的 3D 模型。

有没有人知道如何解决这个问题?

最佳答案

我解决了。

我对网格进行了三角剖分,并将顶点数减少到 32.000 以下。因此,我将 Poser 中的 Mesh 导出为 Collada-File,并将其导入到 Blender(因为有更多教程 :D)。

关于java - 带有 openGL 1.0 的 Poser Mesh,50% 的三角形似乎丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24266681/

相关文章:

java - 使用可观察对象或事件或接口(interface)传递值

java - 谷歌 OAUTH : The redirect URI in the request did not match a registered redirect URI

java - 如何使用 MusicPlayService 播放音乐

Android——麦克风输入电平?

android - AndEngine:两个 Sprite 的碰撞

java - 在 Android 中从服务器加载大量图像

android - GCM android,未收到推送通知

java - new Runnable(){} 类型的 findViewById(int) 方法未定义

c++ - 纹理映射到瓷砖

c++ - Android NDK OpenGL ES 2 上下文初始化