我有一个以3d对象为特色的项目。用户可以用手指手势旋转和缩放它。我遇到的问题是在旋转立方体时(其他实体也会导致相同的错误,但我会在立方体上设置一个示例),它的边缘会崩溃(如屏幕截图所示)。旋转越快,问题就越严重。
我试图通过禁用面部剔除来掩盖它,以便用户看到立方体的内部,它基本上具有相同的颜色。然而,项目经理对该解决方案并不满意(我承认它不能很好地工作)。
立方体有6个面,每个面包含大约242个多边形。
public void onDrawFrame(GL10 glUnused)
{
GLES20.glDisable(GLES20.GL_BLEND);
isBlendingEnabled = false;
Matrix.setLookAtM(mViewMatrix, 0, mEyeX, mEyeY, mEyeZ, mLookX, mLookY, mLookZ, mUpX, mUpY, mUpZ);
if(!mSolid.equals(((ActivityMain) mContext).getSolid())){
refreshSolid();
refreshTextureData();
}
if(mSolid.hasChanged){
refreshSolid();
}
if(mSolid.hasTexturesChanged){
refreshTextureData();
mSolid.hasTexturesChanged = false;
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set per-vertex lighting program.
GLES20.glUseProgram(mProgramHandle);
// Set program handles for solid drawing.
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
mLightPosHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightPos");
mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
mNormalHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Normal");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
// Calculate position of the light. Handle it's rotation
Matrix.setIdentityM(mLightModelMatrix, 0);
Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, -2.0f);
Matrix.rotateM(mLightModelMatrix, 0, mAngleInDegrees, 0.0f, 1.0f, 0.0f);
Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, 3.5f);
Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);
//Doing that step for each of the faces
for(int i = 0; i < mSolid.get3dMesh().size(); i++){
// Draw a solid.
// Translate the solid into the screen.
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -3.5f);
// Set a matrix that contains the current rotation.
Matrix.setIdentityM(mCurrentRotation, 0);
Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 1.0f, 0.0f, 0.0f);
//handle inertia
if(Math.abs(mDeltaX) > 2f){
mDeltaX = Math.signum(mDeltaX);
mDeltaX = 0.5f*mDeltaX;
}else if(Math.abs(mDeltaX) > 0.05f){
mDeltaX = 0.99f*mDeltaX;
}else
mDeltaX = 0.0f;
if(Math.abs(mDeltaY) > 2f){
mDeltaY = Math.signum(mDeltaY);
mDeltaY = 0.5f*mDeltaY;
}else if(Math.abs(mDeltaY) > 0.05f){
mDeltaY = 0.99f*mDeltaY;
}else
mDeltaY = 0.0f;
// Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
// Rotate the cube taking the overall rotation into account.
Matrix.multiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[i]);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
drawCube(i);
}
if(ModelCorePrefs.getDrawMesh())
drawVertices();
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc (GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
isBlendingEnabled = true;
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, -3.5f, -3.5f);
Matrix.scaleM(mModelMatrix, 0, 2f, 1.0f, 2f);
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[mSolid.get3dMesh().size()]);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
drawShadow();
}
private void drawCube(int i)
{
// Pass in the position information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubePositionsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the color information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeColorsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the normal information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeNormalsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mNormalHandle);
GLES20.glVertexAttribPointer(mNormalHandle, mNormalDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the texture coordinate information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeTexCoordsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, 0);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mTemporaryMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
System.arraycopy(mTemporaryMatrix, 0, mMVPMatrix, 0, 16);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
// Draw the cube.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mSolid.get3dMesh().get(i).length/3);
}
答案 0 :(得分:1)
我强烈建议您从glGet*Location (...)
方法中移除onDrawFrame (...)
来电。最初链接程序后,这些内容不会改变,并且每个框架按字符串名称搜索这些位置会妨碍您的性能。同样,您只需要为每个程序设置一次采样器均匀,因为它始终使用纹理图像单元0。
我没有看到循环中每个面都有自己独特的模型矩阵的证据,所以你应该移动逻辑,将矩阵逐步转换出循环。否则,您将单独旋转多维数据集中的每个面,这是您的图表所显示的。说实话,我不知道你为什么要一次画一张脸。
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
// ^^^^^ ONLY DO THAT ONCE!
// Translate the solid into the screen.
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -3.5f);
// Set a matrix that contains the current rotation.
Matrix.setIdentityM(mCurrentRotation, 0);
Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 1.0f, 0.0f, 0.0f);
//handle inertia
if(Math.abs(mDeltaX) > 2f){
mDeltaX = Math.signum(mDeltaX);
mDeltaX = 0.5f*mDeltaX;
}else if(Math.abs(mDeltaX) > 0.05f){
mDeltaX = 0.99f*mDeltaX;
}else
mDeltaX = 0.0f;
if(Math.abs(mDeltaY) > 2f){
mDeltaY = Math.signum(mDeltaY);
mDeltaY = 0.5f*mDeltaY;
}else if(Math.abs(mDeltaY) > 0.05f){
mDeltaY = 0.99f*mDeltaY;
}else
mDeltaY = 0.0f;
// Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
// Rotate the cube taking the overall rotation into account.
Matrix.multiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);
//Doing that step for each of the faces
for(int i = 0; i < mSolid.get3dMesh().size(); i++){
// Draw a solid.
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[i]);
drawCube(i);
}