我目前正在Android上开发.obj文件加载器。我已经完成了基础知识,并使用OpenGl正确绘制了3d网格。不幸的是我在绑定纹理时遇到了问题。让我解释一下更多细节:
.obj文件具有以下结构:
v -0.751804 0.447968 -1.430558
v -0.751802 2.392585 -1.428428
... etc list with all the vertices ...
vt 0.033607 0.718905
vt 0.033607 0.718615
... etc list with all the texture coordinates ...
f 237/1 236/2 253/3 252/4
f 236/2 235/5 254/6 253/3
... etc list with all the faces ...
f 线条用于存储相应顶点和纹理坐标的索引,例如
f vertex_index/texture_coord_index
所以我的程序
Vector<Float>
,Vector<Float>
Vector<Short>
中,并将每个纹理坐标索引存储在Vector<Short>
在完成所有这些代码后,我创建了适当的缓冲区:
public void buildVertexBuffer(){
ByteBuffer vBuf = ByteBuffer.allocateDirect(vertices.size() * 4);
vBuf.order(ByteOrder.nativeOrder());
vertexBuffer = vBuf.asFloatBuffer();
vertexBuffer.put(toFloatArray(vertices));
vertexBuffer.position(0);
}
其中vertices
是存储浮点顶点的向量
public void buildFaceBuffer(){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(faces.size() * 2);
byteBuffer.order(ByteOrder.nativeOrder());
faceBuffer = byteBuffer.asShortBuffer();
faceBuffer.put(toShortArray(faces));
faceBuffer.position(0);
}
其中faces
是存储索引和
public void buildTextureBuffer(Vector<Float> textures){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(texturePointers.size() * 4 * 2);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
for(int i=0; i<texturePointers.size(); i++){
float u = textures.get(texturePointers.get(i) * 2);
float v = textures.get(texturePointers.get(i) * 2 + 1);
textureBuffer.put(u);
textureBuffer.put(v);
}
textureBuffer.position(0);
}
其中textures
是浮动纹理坐标,texturePointers
指向纹理&#39;值。
绑定发生在这里:
public int[] loadTexture(GL10 gl, Context context){
if(textureFile == null)
return null;
int resId = getResourceId(textureFile, R.drawable.class);
if(resId == -1){
Log.d("Bako", "Texture not found...");
return null;
}
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
/*gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);*/
/*int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer buffer = ByteBuffer.allocateDirect(size);
bitmap.copyPixelsToBuffer(buffer);
gl.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_INT, buffer);*/
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
return textures;
}
最后,我网格的draw()
方法看起来像这样
public void draw(GL10 gl){
if(bindedTextures != null){
gl.glBindTexture(GL10.GL_TEXTURE_2D, bindedTextures[0]);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL10.GL_CW);
}
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
for(int i=0; i<parts.size(); i++){
ModelPart modelPart = parts.get(i);
Material material = modelPart.getMaterial();
if(material != null){
FloatBuffer a = material.getAmbientColorBuffer();
FloatBuffer d = material.getDiffuseColorBuffer();
FloatBuffer s = material.getSpecularColorBuffer();
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, a);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, s);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, d);
}
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, modelPart.getTextureBuffer()); // returns the texture buffer created with the buildTextureBuffer() method
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL10.GL_FLOAT, 0, modelPart.getNormalBuffer());
gl.glDrawElements(GL10.GL_TRIANGLES, modelPart.getFacesSize(), GL10.GL_UNSIGNED_SHORT, modelPart.getFaceBuffer());
//gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
//gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
当我运行这个应用程序时,3d模型被绘制成一个魅力,但纹理以某种方式拉伸。包含纹理的图像具有红色背景,中间具有适当的图像,并且该红色背景被绘制到整个3d模型上。
我的第一个问题是textureBuffer
是否正确构建。我是否必须更改buildTextureBuffer()
中的代码?
第二个; draw()
方法是正确的吗?我的问题是否必须与faces
缓冲区一起使用?
答案 0 :(得分:1)
因此,在OpenGL中,顶点是描述模型上特定点的任何信息组合。您正在使用旧的固定管道,因此顶点是一个位置,一些纹理坐标,法线和颜色中的一个或多个。
在OBJ中,vt
只是一个位置。映射到顶点的OpenGL概念的东西是每个独特的组合 - 在您的情况下 - 在f
之后给出的位置+纹理坐标对。
你需要一个映射,如果f
表示56/92那么你可以查找56/92然后发现你认为它是,例如,顶点23并且已经将合适的数组传递给OpenGL,这样第23个插槽中的位置值是OBJ作为v
给出的第56个内容,以及作为vt
给出的第92个内容。
换句话说,OBJ文件具有额外的间接级别,而OpenGL则没有。
在我看来,你似乎并没有解决这个问题。一种常见的方法是使用v / vt对中的HashMap
输出索引,在解析f
时按需构建输出数组。