我正在做一些3D建模,它需要一些稍微不尋常的轉換(基本上我需要做傾斜/傾斜轉換而不是旋轉)。由於我之前沒有做過任何opengl編程,因此我使用了2D畫布繪製庫並創建了自己的3D - > 2D變換矩陣來進行概念驗證。使用線框模型很有效。對我來說,orthoM與frustumM做同樣的事情(即顯示透視圖)
要將其轉換爲3D,我使用了繪製正方形和三角形的SDK示例OpenGLS20Complete程序。我修改了這個將抽象方法作爲接口(IDrawable)抽象出來,這樣我就可以處理IDrawables列表。爲了測試,我通過形成一個正方形列表來構造一個具有6個面的立方體。
一切工作正常,但立方體顯然是與透視繪製,因爲頂面比底面大。據我所知,OrthoM返回一個與frustumM不同的矩陣(矩陣值不同),但它做的是同樣的事情。我需要一個用於這個應用程序的正交視角(即沒有視角)。我無法讓它工作。
我已經剝奪我的代碼到顯示一個多維數據集進行測試如下:
在OpenGLS20Complete onSurfaceCreated的代碼是:
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
transformedshapes = new ArrayList<IDrawable>();
cubeSide = 0.3f;
IDrawable cube1 = new Cube(-0.4f, cubeSide, -0.4f, cubeSide, 0f, cubeSide, Color.GRAY, Color.RED, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.CYAN);
transformedshapes.add(cube1);
// next line added by me
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
}
立方體構造立方體(左,cubewidth,右,cubelength ,basez,cubeheight,...六種顏色)只是創建6個面(作爲IDrawable對象),列出了6種顏色中的每一種顏色。是否應該這樣做。
的OnSurfaceChanged代碼是:
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
// Adjust the viewport based on geometry changes,
// such as screen rotation
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width/(float) height;
// Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); // original
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
屏幕上的結果是相同的我是否使用.frustumM或.orthoM方法。如我所料,更改frustumM方法中的值會更改顯示。使用調試器,我可以看到平截頭體和正方體方法準備不同的矩陣。
該方法的OnDraw看起來像這樣:
@Override
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mVMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
// Draw untransformed shapes
for (IDrawable shape:untransformedshapes)
shape.draw(mMVPMatrix);
float [] rotatedmMVPMatrix = new float[16];
float netRotationAboutX = mAngleRotateAboutX - mAngleStartRotateAboutX;
float netRotationAboutY = mAngleRotateAboutY - mAngleStartRotateAboutY;
float netRotationAboutZ = mAngleRotateAboutZ - mAngleStartRotateAboutZ;
Matrix.setRotateM(mRotationMatrix, 0, netRotationAboutY, 0, -1f, 0f);
float[] xRotationMatrix = new float[16];
Matrix.setRotateM(xRotationMatrix, 0, netRotationAboutX, -1f, 0, 0f);
Matrix.multiplyMM(mRotationMatrix, 0, xRotationMatrix, 0,
mRotationMatrix, 0);
// Combine the rotation matrix with the projection and camera view
Matrix.multiplyMM(rotatedmMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
for (IDrawable shape : transformedshapes)
shape.draw(rotatedmMVPMatrix);
}
以上進行旋轉,而不是一個歪斜矩陣,使其更容易調試。它的工作原理是,當我更改mAngleRotateAboutX和mAngleRotateAboutY時,立方體或多維數據集會旋轉。
方法.setLookAtM()似乎不適合正交投影。由於沒有必要的視角,z距離(在這種情況下爲3)看起來沒有必要。正射投影應該只需要一個方向(即2個獨立變量)而不是視圖位置(3個獨立變量)。也許我不應該用這個?
屬於我的多維數據集的正方形是PWRectShape類的實例,它實現了我的IDrawable接口的繪製方法。這是方形的繪圖方法OpenGLS20Complete
class PWRectShape implements IDrawable{
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
" gl_Position = vPosition * uMVPMatrix;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
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 short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
// Set color with default red, green, blue and alpha (opacity) values
float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };
public PWRectShape(float [] rectCoords, int colour) { // the constructor
// initialize vertex byte buffer for shape coordinates
color[0] = (float)Color.red(colour)/256f;
color[1] = (float)Color.green(colour)/256f;
color[2] = (float)Color.blue(colour)/256f;
color[3] = 1f;
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
rectCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(rectCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.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) { // the draw method
// 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 square
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
有一個設置了簡單的着色器等額外的代碼,所有這些都爲OpenGLES20Complete不變的猴子看,猴子做修改。如有必要,我可以發佈。但是,這一切似乎都行得通。實際上,一切正常 - 我可以在多個位置繪製多個立方體,甚至可以通過自定義投影矩陣正確偏斜它們。唯一不起作用的是立方體的頂面比底面大,顯然是使用透視圖,無論是使用.frustumM還是.orthoM。
有關爲什麼我在運行此代碼時獲得透視圖而不是正射投影的任何建議或想法?
您是否嘗試過在gl_Position中始終使用1.0的w座標?這將防止視角差異產生任何影響。 –
代碼中唯一的gl_Position在頂點着色器中作爲傳遞給硬件的程序字符串的一部分。試圖改變這一點,但不知道我在做什麼,並使程序崩潰。當然orthoM的作品,但它不在我的程序。也許我有一些額外的行覆蓋它。我不指望有人爲我調試我的代碼;我只是貼出來,因爲如果我沒有人會要求它。我更希望有人能記起類似的行爲,並能告訴我爲什麼會發生。 –
對,'gl_Position'是頂點着色器的輸出。儘管目前GPU具有高度可編程性,但即使在着色器中編寫頂點位置之後,也會出現一個步驟。硬件做了一個角度劃分(也就是說,它通過'gl_Position.w'分割'gl_Position.xyz')。給定一個非透視投影矩陣,W通常爲1.0,但在你的問題中,所有非標準矩陣操作都可以用轉換後的1.0值以外的值來表示。 –