我正在使用Android Open GL教程来了解Open GL,我试图实现我自己的SimpleTriangle绘图,它应该像其他Triangle类一样工作,但它会占用整个屏幕。
public class SimpleTriangle {
private static float x, y;
private static float[] triangleCoords = {
x, 5.773502692f, 0.0f, // top
x-(float)5, y-2.886851346f, 0.0f,
x+(float)5, y-2.886851346f, 0.0f
};
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f };
public SimpleTriangle(float xInt, float yInt){
x = xInt;
y = yInt;
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
}
public void draw(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(
mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
我觉得我的Matrix.setLookAt方法存在问题,因为我并不完全了解如何设置我的观看范围。
public class MyGLRenderer implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRenderer";
private SimpleTriangle firstTriangle;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
private float mAngle;
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
firstTriangle = new SimpleTriangle(0f, 0f);
}
@Override
public void onDrawFrame(GL10 unused) {
float[] scratch = new float[16];
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, 1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
firstTriangle.draw(scratch);
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
为了澄清,这是这里的确切教程:http://developer.android.com/training/graphics/opengl/index.html 我只是想明确说明我想要一个三角形。
那么为什么我的三角形占据了我的整个视口?
答案 0 :(得分:0)
您传递给SimpleTriangle.draw(float[])
的临时矩阵对我来说似乎不正确。
据我所知,您可以使用mViewMatrix
和mProjectionMatrix
获得正确的MVP矩阵。 mRotationMatrix
在哪里设置?您可以按mAngle
进行旋转,但如果矩阵全部为零,则表示不会发生变化。如果mRotationMatrix
实际上全为零,则当您将其乘以mMVPMatrix
时,这将产生一个全零的矩阵。
我会尝试评论Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
行,看看是否有用。
答案 1 :(得分:0)
查看您的坐标和变换,您的三角形将覆盖整个窗口是有道理的。
您的三角形位于z = 0.0平面内。将坐标四舍五入为下一整数以便于阅读,3个顶点的(x, y)
坐标为:
(0, 6)
(-5, -3)
(5, -3)
因此,三角形宽约10个单位,高9个单位,以原点为中心。
现在走过变革。 mRotationMatrix
是一个单位矩阵,因为它旋转0度,所以它不起作用。
然后来mViewMatrix
,在此处设置:
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
基于这些论点,您的观点是(0, 0, -3)
,看(0, 0, 0)
。由于你的三角形在z = 0平面上,因此眼点距离三角形有3个单位,从头看它。
最后,应用投影矩阵,在此处设置:
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
Android文档没有详细记录参数,但参数似乎与传统OpenGL glFrustum()
(doc)调用的参数相匹配。因此,左/右/底部/顶部值是在近平面距离处测量的。
如前所述,三角形距眼点为3个单位,与近平面距离(frustum
的第7个参数)相同。所以三角形恰好在近平面上。在近平面上,平截头体内坐标的范围由第3到第6个参数给出,对于x坐标是(-ratio, ratio)
,对于y坐标是(-1, 1)
。
由于你的三角形比那个距离的平截头体的(-ratio, ratio) x (-1, 1)
尺寸大得多,它覆盖整个窗口,然后覆盖整个窗口。除非宽高比非常大。
如果你想让你的三角形显得更小,你可能想要增加眼距(setLookAtM()
的第五个参数,并调整近/远平面距离({{的第7和第8个参数)相应的。一组典型的值会使你的眼距在近距离和远距离之间的中间位置。