OpenGL 法线
法线是垂直于物体表面的“方向箭头”,用来告诉计算机这个面朝哪边,从而计算光照、阴影、反射等效果
一. 定义
几何定义:法线是一个单位向量(长度为1的箭头),垂直于物体表面
平面:所有点的法线方向相同
曲面:每个点的法线方向不同(如球体)
在计算机图形学中:法线通常用
(x, y, z)三个数值表示,范围在[-1, 1]
二. OpenGL 法线用途
法线的主要作用是告诉光照系统“表面朝哪边”,从而影响视觉效果
1. 计算光照(明暗)
原理:光线照射到表面时,入射角(光线与法线的夹角)决定亮度
法线朝向光源 → 更亮(如
dot(N, L) = 1)法线背对光源 → 更暗(如
dot(N, L) = -1)
示例:
float brightness = dot(normal, lightDirection); // 计算光照强度
2. 实现阴影和立体感
没有法线:物体看起来像平面(如纸片)。
有法线:物体看起来有体积感(如球体)。
3. 反射和环境光
法线决定反射光的方向(如镜面高光、环境光遮蔽)。
4. 法线贴图(伪造细节)
用法线贴图修改表面朝向,让低模看起来有凹凸细节(如砖墙、锈迹)。
三. 法线的类型
1. 顶点法线(Vertex Normal)
每个顶点有一个法线,用于平滑曲面(如球体)
计算方式:相邻面的法线平均值
2. 面法线(Face Normal)
每个三角形面有一个法线(所有顶点共享同一个法线)
适用于硬表面(如立方体)
3. 切线空间法线(Tangent-Space Normal)
用于法线贴图,存储相对于模型表面的局部方向
四. 代码示例
1. 顶点着色器传递法线
#version 330 core
layout (location = 0) in vec3 aPos; // 顶点位置
layout (location = 1) in vec3 aNormal; // 顶点法线out vec3 Normal; // 传递给片段着色器void main() {gl_Position = projection * view * model * vec4(aPos, 1.0);Normal = mat3(transpose(inverse(model))) * aNormal; // 修正法线(考虑模型变换)
}2. 片段着色器计算光照
#version 330 core
in vec3 Normal;
out vec4 FragColor;uniform vec3 lightDir; // 光源方向(归一化)void main() {float diff = max(dot(Normal, lightDir), 0.0); // 漫反射强度vec3 color = diff * vec3(1.0, 0.0, 0.0); // 红色 + 光照FragColor = vec4(color, 1.0);
}