Poser Mesh с OpenGL 1.0, похоже, не хватает 50% треугольников

#java #android #opengl-es

#java #Android #opengl-es

Вопрос:

Я сгенерировал 3D-модель с помощью Poser, чтобы использовать ее с OpenGL 1.0 в приложении для Android. Когда я визуализирую сетку, я вижу 3D-модель, созданную в Poser 8, но, к сожалению, визуализируется только половина треугольников — похоже, вместо этого мне нужно нарисовать какие-то квадраты. Есть ли какой-либо способ отразить существующие треугольники, чтобы я мог нарисовать недостающие?

Моя сетка генерируется из объекта волнового фронта. Для этого я использую класс с именем 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 amp;amp; !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 .

Это отлично работает с простыми объектами. Но не с 3D-моделями, созданными Poser 8.

У кого-нибудь есть идея, как решить эту проблему?

Ответ №1:

Я решил это.

Я триангулировал сетку и уменьшил количество вершин до 32.000. Поэтому я экспортировал сетку из Poser в виде Collada-файла и импортировал ее в Blender (потому что есть больше руководств: D).