phong光照模型

tech2026-08-14  6

phong光照模型 经验模型 phong光照模型 = 环境光+漫反射+镜面高光

环境光: 光通常都不是来自于同一光源,而是来自散落于我们周围的很多光源,即使它们可能并不是那么显而易见。光的一个属性是,它可以向很多方向发散和反弹,所以光最后到达的地点可能并不是它所临近的直射方向;光能够像这样反射(Reflect)到其他表面,一个物体的光照可能受到来自一个非直射的光源影响。考虑到这种情况的算法叫做全局照明(Global Illumination)算法,但是这种算法既开销高昂又极其复杂。所以我们将会使用一种简化的全局照明模型,叫做环境光照(Ambient Lighting)。使用一个(数值)很小的常量(光)颜色添加进物体片段(Fragment,指当前讨论的光线在物体上的照射点)的最终颜色里,这看起来就像即使没有直射光源也始终存在着一些发散的光。

漫反射 根据光的位置以及顶点位置 求出光方向向量,顶点数据传入顶点的法向量数据,法向量与光方向向量点乘再乘以光照得到 漫反射颜色 顶点传入法向量数据

GLfloat vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f }; //顶点位置属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); //顶点颜色属性 //glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3 * sizeof(float))); //glEnableVertexAttribArray(1); //纹理颜色属性 //glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); //glEnableVertexAttribArray(2); //纹理法向量 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal;

传入光照位置以及颜色

GLint objectColorLoc = glGetUniformLocation(shader.ID, "objColor"); GLint ambientColorLoc = glGetUniformLocation(shader.ID, "ambientColor"); GLint lightPosLoc = glGetUniformLocation(shader.ID, "lightPos"); GLint lightCorLoc = glGetUniformLocation(shader.ID, "lightColor"); GLint cameraPosLoc = glGetUniformLocation(shader.ID, "cameraPos"); glUniform3f(objectColorLoc, 1.0f, 0.5f, 0.31f);// 我们所熟悉的珊瑚红 glUniform3f(ambientColorLoc, 0.2f, 0.2f, 0.2f); // light color glUniform3f(lightPosLoc, 10.0f, 10.0f, 5.0f); // 光位置 glUniform3f(lightCorLoc, 1.0f, 1.0f, 1.0f); // 光位置 glUniform3f(cameraPosLoc, camera.Position.x, camera.Position.y, camera.Position.z); // 光位置

顶点片段着色器计算漫反射

#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; uniform mat4 modelMat; uniform mat4 viewMat; uniform mat4 projectionMat; out vec3 FragPos; out vec3 Normal; void main() { gl_Position =projectionMat *viewMat*modelMat* vec4(aPos.xyz, 1.0); FragPos = (modelMat*vec4(aPos.xyz,1.0)).xyz; Normal = mat3(transpose(inverse(modelMat))) * aNormal; } vec3 lightDir = normalize(lightPos-FragPos); float diff = max(dot(lightDir,Normal),0); vec3 diffuse = diff*lightColor;

关于法向量 无论何时当我们提交一个不等比缩放(注意:等比缩放不会破坏法线,因为法线的方向没被改变,而法线的长度很容易通过标准化进行修复),法向量就不会再垂直于它们的表面了,这样光照会被扭曲。 修复这个行为的诀窍是使用另一个为法向量专门定制的模型矩阵。这个矩阵称之为正规矩阵(Normal Matrix),它是进行了一点线性代数操作移除了对法向量的错误缩放效果。 正规矩阵被定义为“模型矩阵左上角的逆矩阵的转置矩阵”。注意,定义正规矩阵的大多资源就像应用到模型观察矩阵(Model-view Matrix)上的操作一样,但是由于我们只在世界空间工作(而不是在观察空间),我们只使用模型矩阵。 在顶点着色器中,我们可以使用inverse和transpose函数自己生成正规矩阵,inverse和transpose函数对所有类型矩阵都有效。注意,我们也要把这个被处理过的矩阵强制转换为3×3矩阵,这是为了保证它失去了平移属性,之后它才能乘以法向量。

镜面光: 反射光与眼睛方向点积乘以光颜色 并做pow运算

vec3 reflrctVec = reflect(-lightDir,Normal); vec3 cameraVec = normalize(cameraPos-FragPos); float specularAmount = pow(max(dot(reflrctVec,cameraVec),0),32); vec3 specular = specularAmount*lightColor;

最终三种光照叠加

FragColor = vec4((diffuse+ambientColor+specular)*objColor,1.0f);
最新回复(0)