Unity中使用高版本GLSL着色器出现顶点坐标异常如何解决
Unity中直接运行高版本GLSL着色器的问题修复
问题复现
初始可正常运行的legacy GLSL测试着色器代码:
GLSLPROGRAM #ifdef VERTEX void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } #endif #ifdef FRAGMENT void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } #endif ENDGLSL
添加#version 450声明后触发编译报错:
error C7616: global variable gl_Vertex is removed after version 140
按照现代GLSL规范修改后代码无编译报错,但渲染坐标完全错乱,修改后的问题代码:
GLSLPROGRAM #version 450 #ifdef VERTEX layout(location = 0) in vec4 pos; void main() { gl_Position = gl_ModelViewProjectionMatrix * pos; } #endif #ifdef FRAGMENT out vec4 FragColor; void main() { FragColor = vec4(1.0, 0.0, 0.0, 1.0); } #endif ENDGLSL
错乱原因
坐标异常来自两个适配错误:
- 顶点属性类型和绑定规则不匹配:Unity高版本GLSL模式下,顶点位置属性绑定在
location = 0,但该属性是3分量float类型,直接声明为vec4读取时,会把后续顶点法线属性的第一个分量错误读为pos.w,导致顶点坐标数据错位。 - 废弃内置变量未替换:版本140以上的core profile GLSL中,Unity不会自动注入
gl_ModelViewProjectionMatrix、gl_Vertex这类legacy内置变量,直接调用会读取到未初始化的脏数据,矩阵计算结果完全错误。
可行修复方案
无需转译HLSL,直接按Unity的GLSL适配规则修改代码即可批量复用现有GLSL资源,核心适配规则如下:
- 顶点属性固定location映射:
layout(location = 0) in vec3 _pos:顶点位置layout(location = 1) in vec3 _normal:顶点法线layout(location = 2) in vec2 _uv:顶点纹理坐标layout(location = 3) in vec4 _tangent:顶点切线
- 手动声明Unity内置变换uniform,替换所有legacy GLSL内置矩阵:
uniform mat4 unity_ObjectToWorld:模型空间到世界空间变换矩阵uniform mat4 unity_MatrixVP:世界空间到裁剪空间变换矩阵- MVP矩阵计算逻辑为
unity_MatrixVP * unity_ObjectToWorld * vec4(顶点位置, 1.0)
- 片元阶段废弃
gl_FragColor,自定义out vec4类型的输出变量即可。
修复后可正常运行的450版本GLSL测试代码:
GLSLPROGRAM #version 450 #ifdef VERTEX layout(location = 0) in vec3 pos; uniform mat4 unity_ObjectToWorld; uniform mat4 unity_MatrixVP; void main() { vec4 worldPos = unity_ObjectToWorld * vec4(pos, 1.0); gl_Position = unity_MatrixVP * worldPos; } #endif #ifdef FRAGMENT out vec4 FragColor; void main() { FragColor = vec4(1.0, 0.0, 0.0, 1.0); } #endif ENDGLSL
- 批量适配现有GLSL的注意事项:
- 所有legacy内置属性、状态变量、矩阵全部替换为上述自定义顶点输入和手动声明的Unity内置uniform,不要依赖140版本前的隐式注入逻辑
- 顶点属性严格按照映射表的类型声明,避免多读取分量导致的顶点流错位
- 不要使用GLSL core profile之外的非标准扩展,否则会在Windows等平台触发编译失败
内容的提问来源于stack exchange,提问作者rheadio
相关产品推荐
相关产品推荐

