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

Kotlin/Android/OpenGL ES:使用法线实现3D光照失败,报错无效顶点属性索引(期望索引:4294967295,最大索引:16)

解决OpenGL ES光照实现中的"Invalid vertex attribute index"错误

这个错误的核心原因很明确:你看到的4294967295其实是**-1的无符号整数表示**,意味着glGetAttribLocation(program, "vertexNormal")返回了-1——OpenGL在你的着色器程序里找不到vertexNormal这个属性变量。导致这个问题的主要原因有两个,我们一步步拆解并解决:

问题根源分析

  1. 片段着色器未使用顶点着色器的输出,导致编译器优化删除了法线相关代码
    你的顶点着色器里计算了fragColour这个varying变量,但片段着色器完全没用到它,反而用了一个无关的uniform vec4 vertexColour。GLSL编译器会自动移除所有未被使用的代码,包括vertexNormal的读取和变换逻辑,最终vertexNormal这个attribute被从程序中彻底剔除,自然找不到它的索引。

  2. 顶点着色器和片段着色器的vertexColour定义不一致
    顶点着色器里vertexColour是attribute vec3(顶点属性),但片段着色器里却定义成了uniform vec4(全局变量),这不仅逻辑错误,也加剧了编译器的优化行为。

分步解决方案

1. 修正片段着色器

让片段着色器正确使用顶点着色器传递过来的fragColour变量,这样顶点着色器里的法线计算逻辑就不会被优化掉:

private val fragmentShaderCode = "precision mediump float;" +
        "varying vec3 fragColour;" +
        "void main() {" +
        " gl_FragColor = vec4(fragColour, 1.0);" +
        "}"

2. 修复顶点着色器的clamp操作

你原来的clamp(fragColour, 0.0, 1.0);没有将结果赋值回fragColour,等于无效操作,修正为:

// 替换原来的clamp行
fragColour = clamp(fragColour, 0.0, 1.0);

3. 修正绘制代码的逻辑错误

3.1 补充顶点颜色的缓冲区(假设你有对应顶点颜色的数组triangleColours)

private var vertexColourBuffer: FloatBuffer = ByteBuffer.allocateDirect(triangleColours.size * 4).run {
    order(ByteOrder.nativeOrder())
    asFloatBuffer().apply {
        put(triangleColours)
        position(0)
    }
}

3.2 调整绘制流程:先激活程序,再获取属性/Uniform位置

属性和Uniform的位置是和当前激活的程序绑定的,必须先调用glUseProgram再获取位置,同时修正vertexColour的处理方式(它是顶点属性,不是Uniform):

fun draw(mvpMatrix: FloatArray) {
    // 先激活着色器程序
    glUseProgram(program)

    // 获取各个属性和Uniform的位置
    positionHandle = glGetAttribLocation(program, "vertexPosition")
    val vertexColourHandle = glGetAttribLocation(program, "vertexColour")
    vertexNormalLocation = glGetAttribLocation(program, "vertexNormal")
    vPMatrixHandle = glGetUniformLocation(program, "modelView")

    // 设置模型视图矩阵
    glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0)

    // 配置顶点位置属性
    glVertexAttribPointer(
        positionHandle,
        3,
        GLES20.GL_FLOAT,
        false,
        vertexStride,
        vertexBuffer
    )
    glEnableVertexAttribArray(positionHandle)

    // 配置顶点颜色属性
    glVertexAttribPointer(
        vertexColourHandle,
        3,
        GLES20.GL_FLOAT,
        false,
        0,
        vertexColourBuffer
    )
    glEnableVertexAttribArray(vertexColourHandle)

    // 配置法线属性
    glVertexAttribPointer(
        vertexNormalLocation,
        3,
        GLES20.GL_FLOAT,
        false,
        0,
        normalsBuffer
    )
    glEnableVertexAttribArray(vertexNormalLocation)

    // 绘制图形
    glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)

    // 禁用属性数组
    glDisableVertexAttribArray(positionHandle)
    glDisableVertexAttribArray(vertexColourHandle)
    glDisableVertexAttribArray(vertexNormalLocation)
}

额外注意事项

  • 确保你的法线数组normals的长度和顶点数量匹配(每个顶点对应一个法线向量),否则绘制时会出现异常。
  • 如果你不需要顶点颜色,可以直接在顶点着色器里写死反射系数,不用保留vertexColour属性,进一步简化代码。

内容的提问来源于stack exchange,提问作者JLK700

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:23:12