我使用Poser生成了3D模型,以将其与Android应用程序中的openGL 1.0一起使用。渲染网格时,我可以看到在Poser 8中生成的3D模型,但是不幸的是,仅渲染了一半的三角形-看起来我不得不绘制某种正方形。有什么方法可以镜像现有的三角形,以便我可以绘制丢失的三角形?
我的网格是从波前对象生成的。因此,我使用了一个称为网格的类
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%的Triangles,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24266681/