You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:06:01