我遇到了一些问题,如果你们不尝试,我无法很好地解释。
我无法正确加载多维数据集。不过,我能够让它在所有轴上很好地旋转。 (“axis”的复数是“axes”?)
我还没有尝试过光照和纹理,所以如果您似乎还不能辨认出模型,我很抱歉。
这是它现在的样子(自由旋转模型的快照):
这是预期的结果:
这是我的 GLSurfaceView.Renderer
的代码:
package dd.ww;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.Matrix;
public class Render implements Renderer {
private Context context;
private Cube cube;
private float[] modelViewProjectionMatrix = new float[16];
private float[] projectionMatrix = new float[16];
private float[] viewMatrix = new float[16];
private float[] rotationMatrix = new float[16];
private float angle = 0f;
public Render(Context context) {
this.context = context;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(1f, 1f, 1f, 1f);
cube = new Cube(context);
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / (float) height;
Matrix.frustumM(projectionMatrix, 0, -3f, 3f, -3f, 3f, 1f, 10f);
}
@Override
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//Camera position
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -4f, 0f, 0f, 0f, 0f, 1f, 0f);
// projection x view = modelView
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
//Creating rotation matrix
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1f);
//rotation x camera = modelView
Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, -1f, 0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, -1f, 0f, 0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, rotationMatrix, 0, modelViewProjectionMatrix, 0);
cube.draw(modelViewProjectionMatrix);
angle += 0.7f;
if (angle > 360f)
angle = 0f;
}
}
这是 Cube 类及其 OBJ 加载器的代码。 OBJ Loader 用于加载从 Blender 导出的 OBJ 模型(这是 Cube 的预期结果,在 Blender 中显示。):
package dd.ww;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import android.content.Context;
import android.content.res.AssetManager;
import android.opengl.GLES20;
import android.util.Log;
public class Cube {
private Context context;
private FloatBuffer vertexBuffer;
private ShortBuffer indexBuffer;
private int shaderProgram;
//TODO: Go to Google Code, find OpenGL ES 2.0 Programming Guide source code, Android,
//check in the ESShapes.java, and study the FloatBuffers...
public Cube(Context c) {
context = c;
loadCube("cube/cube.obj");
}
private void loadCube(String filename) {
ArrayList<Float> tempVertices = new ArrayList<Float>();
//ArrayList<Float> tempNormals = new ArrayList<Float>();
ArrayList<Short> vertexIndices = new ArrayList<Short>();
//ArrayList<Short> normalIndices = new ArrayList<Short>();
try {
AssetManager manager = context.getAssets();
BufferedReader reader = new BufferedReader(new InputStreamReader(manager.open(filename)));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("v")) {
tempVertices.add(Float.valueOf(line.split(" ")[1])); //vx
tempVertices.add(Float.valueOf(line.split(" ")[2])); //vy
tempVertices.add(Float.valueOf(line.split(" ")[3])); //vz
}
// else if (line.startsWith("vn")) {
// tempNormals.add(Float.valueOf(line.split(" ")[1])); //nx
// tempNormals.add(Float.valueOf(line.split(" ")[2])); //ny
// tempNormals.add(Float.valueOf(line.split(" ")[3])); //nz
// }
else if (line.startsWith("f")) {
/*
vertexIndices.add(Short.valueOf(tokens[1].split("/")[0])); //first point of a face
vertexIndices.add(Short.valueOf(tokens[2].split("/")[0])); //second point
vertexIndices.add(Short.valueOf(tokens[3].split("/")[0])); //third point
normalIndices.add(Short.valueOf(tokens[1].split("/")[2])); //first normal
normalIndices.add(Short.valueOf(tokens[2].split("/")[2])); //second normal
normalIndices.add(Short.valueOf(tokens[3].split("/")[2])); //third
*/
// for (int i = 1; i <= 3; i++) {
// //String[] s = tokens[i].split("/");
// vertexIndices.add(Short.valueOf());
// //normalIndices.add(Short.valueOf(s[2]));
// }
vertexIndices.add(Short.valueOf(line.split(" ")[1]));
vertexIndices.add(Short.valueOf(line.split(" ")[2]));
vertexIndices.add(Short.valueOf(line.split(" ")[3]));
}
}
float[] vertices = new float[tempVertices.size()];
for (int i = 0; i < tempVertices.size(); i++) {
Float f = tempVertices.get(i);
vertices[i] = (f != null ? f : Float.NaN);
}
short[] indices = new short[vertexIndices.size()];
for (int i = 0; i < vertexIndices.size(); i++) {
Short s = vertexIndices.get(i);
indices[i] = (s != null ? s : 1);
}
vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer.put(vertices).position(0);
indexBuffer = ByteBuffer.allocateDirect(indices.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();
indexBuffer.put(indices).position(0);
int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexShader, vertexCode);
GLES20.glCompileShader(vertexShader);
int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentCode);
GLES20.glCompileShader(fragmentShader);
shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);
GLES20.glLinkProgram(shaderProgram);
int[] linked = new int[1];
GLES20.glGetProgramiv(shaderProgram, GLES20.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0){
Log.d("DEBUG", "Shader code error.");
Log.d("DEBUG", GLES20.glGetProgramInfoLog(shaderProgram));
GLES20.glDeleteProgram(shaderProgram);
return;
}
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
}
catch (Exception e) {
Log.d("DEBUG", "Error.", e);
}
}
private String vertexCode = "" +
"attribute vec4 a_position; \n" +
"uniform mat4 mvpMatrix; \n" +
"void main() { \n" +
" gl_Position = a_position * mvpMatrix;\n" +
"} \n";
private String fragmentCode = "" +
"precision mediump float; \n" +
"void main() { \n" +
" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" +
"} \n";
private int attribute_Position;
private int uniform_mvpMatrix;
public void draw(float[] mvpMatrix){
GLES20.glUseProgram(shaderProgram);
attribute_Position = GLES20.glGetAttribLocation(shaderProgram, "a_position");
GLES20.glVertexAttribPointer(attribute_Position, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer);
GLES20.glEnableVertexAttribArray(attribute_Position);
uniform_mvpMatrix = GLES20.glGetUniformLocation(shaderProgram, "mvpMatrix");
GLES20.glUniformMatrix4fv(uniform_mvpMatrix, 1, false, mvpMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indexBuffer.capacity(), GLES20.GL_UNSIGNED_SHORT, indexBuffer);
GLES20.glDisableVertexAttribArray(attribute_Position);
}
}
最后,这是 APK 附件(已上传到 Mediafire,不应删除。它是未经许可的免费软件)。附加的 APK 文件已签名,直接从我的项目中导出,并且只能在 Gingerbread 或更高版本上运行。 (这就是 OpenGL ES 2.0 的用途……): Mediafire download link to the APK file.
如果有人愿意帮助我意识到我做错了什么,我会为我的余生感到高兴。 This question here is the closest that I find when searching on SO that has a 40% chance my problem is related to.不幸的是,他的模型仍然被扭曲了。我发现的所有其他问题似乎都与纹理渲染不正确、模型转换等有关。但我会尽力找到与我有类似问题的问题。
最佳答案
天哪...
我终于让它工作了。
问题在于 OpenGL ES 2.0 矩阵的工作方式。
引自 SO 用户 Tim:
I believe it should be mvpMatrix * mRotationMatrix, but you're not supposed to use the same matrix as the input and output to that function, you need to use a temporary matrix. Android.opengl.Matrix " The same float array may be passed for result, lhs, and/or rhs. However, the result element values are undefined if the result elements overlap either the lhs or rhs elements." If that doesn't help then post your entire code.
粗体文本表示如果您这样做:
//Creating rotation matrix
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1f);
//rotation x camera = modelView
Matrix.multiplyMM(modelViewProjectionMatrix, 0, modelViewProjectionMatrix, 0, rotationMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, -1f, 0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, modelViewProjectionMatrix, 0, rotationMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, -1f, 0f, 0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, modelViewProjectionMatrix, 0, rotationMatrix, 0);
cube.draw(modelViewProjectionMatrix);
这看起来很正常,立方体看起来会歪斜。原因是,lhs 和 rhs 不应该与您的结果矩阵相同。
但是,如果你这样做:
//Creating rotation matrix
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1f);
//rotation x camera = modelView
float[] duplicateMatrix = Arrays.copyOf(modelViewProjectionMatrix, 16);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, duplicateMatrix, 0, rotationMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, 0f, -1f, 0f);
duplicateMatrix = Arrays.copyOf(modelViewProjectionMatrix, 16);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, duplicateMatrix, 0, rotationMatrix, 0);
Matrix.setRotateM(rotationMatrix, 0, angle, -1f, 0f, 0f);
duplicateMatrix = Arrays.copyOf(modelViewProjectionMatrix, 16);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, duplicateMatrix, 0, rotationMatrix, 0);
cube.draw(modelViewProjectionMatrix);
它将正确显示。
Where I found the helpful hint from.
这就是我意识到为什么有 3 个人投票关闭这个问题的地方。他们肯定早就知道这个问题的答案了,要我自己想办法。向他们致敬...
我向上帝发誓,这是一个我终于攻克的难题。浪费了 2 年的生命付之东流......
关于java - Android OpenGL ES 2.0 : Cube model is not only distorted (perspective is wrong?),但面部加载不正确(顶点不正确?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15653379/