Android OpenGL 旋转变色立方体平面光照按三角面显示异常求助
问题原因
你的实现存在两个核心问题导致光照按三角面拆分:
- 没有为顶点配置法向量,OpenGL光照计算依赖法向量判断面的朝向和光照角度
- 采用了8顶点共享的立方体结构,单个顶点无法同时对应多个不同面的法向量,flat shading模式下同一个四边形面的两个三角面会拿到不一致的光照计算结果
修改方案
需要将立方体顶点改为非共享结构,每个面单独定义4个顶点,绑定对应面的统一法向量,再新增法向量缓冲传入渲染管线即可。
修改后的Cube2.java代码
import android.graphics.Color; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; public class Cube2 { private FloatBuffer mVertexBuffer; private FloatBuffer mNormalBuffer; private ByteBuffer mIndexBuffer; private int colorIndex = 0; private int colorTimer = 0; private int colorWait = 5; private int colorCant = 360; private double colorJump = 360.0 / (colorCant * 1.0); private int[] colors = new int[colorCant]; // 非共享顶点:6个面,每个面4个顶点,共24个顶点 private float vertices[] = { // 前面 Z=1 -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // 后面 Z=-1 -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, // 上面 Y=1 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, // 下面 Y=-1 -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // 右面 X=1 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, // 左面 X=-1 -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f }; // 每个面对应的法向量,同一个面的4个顶点法向量相同 private float normals[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }; // 索引数组,每个面2个三角形共6个索引,6个面总计36个索引 private byte indices[] = { 0,1,2, 0,2,3, 4,5,6, 4,6,7, 8,9,10, 8,10,11, 12,13,14, 12,14,15, 16,17,18, 16,18,19, 20,21,22, 20,22,23 }; public Cube2() { ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4); byteBuf.order(ByteOrder.nativeOrder()); mVertexBuffer = byteBuf.asFloatBuffer(); mVertexBuffer.put(vertices); mVertexBuffer.position(0); // 初始化法向量缓冲 byteBuf = ByteBuffer.allocateDirect(normals.length * 4); byteBuf.order(ByteOrder.nativeOrder()); mNormalBuffer = byteBuf.asFloatBuffer(); mNormalBuffer.put(normals); mNormalBuffer.position(0); mIndexBuffer = ByteBuffer.allocateDirect(indices.length); mIndexBuffer.put(indices); mIndexBuffer.position(0); for (int i = 0; i < colors.length; i++) { colors[i] = Color.HSVToColor(new float[]{(float) (colorJump * i), 1.0f, 1.0f}); } } public void draw(GL10 gl) { gl.glFrontFace(GL10.GL_CW); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer); // 传入法向量数据 gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalBuffer); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); gl.glColor4f((Color.red(colors[colorIndex])) / 255.0f, (Color.green(colors[colorIndex])) / 255.0f, (Color.blue(colors[colorIndex])) / 255.0f, 1.0f); gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); colorTimer++; if (colorTimer < colorWait) { colorTimer++; } else { colorTimer = 0; colorIndex = (colorIndex < colors.length - 1) ? colorIndex + 1 : 0; } } }
MyGLRenderer.java无需修改
你原有Renderer中已经开启了GL_FLAT着色模式和光照配置,不需要额外调整,替换Cube2.java后即可得到同面统一着色的flat光照效果。
内容的提问来源于stack exchange,提问作者blinero
相关产品推荐
相关产品推荐

