openGL中Phong 着色
openGL系列文章目录
前言
Bui Tuong Phong 在犹他大学的研究生期间开发了一种平滑的着色算法,在1973 年的论文[PH73]中对其进行了描述,并在[PH75]中发表。该算法的结构类似于Gouraud 着色的算法,其不同之处在于光照计算是按像素而非顶点完成。由于光照计算需要法向量N 和光向量L,但在模型中仅顶点包含这些信息,因此Phong 着色通常使用巧妙的“技巧”来实现,其中N和L 在顶点着色器中进行计算,并在光栅化期间插值。图1概述了此策略。
图1
C++/OpenGL 代码完全如前。之前部分在顶点着色器中完成的过程现在回放入片段着色器中进行。法向量插值的效果如图2 所示。现在我们已经准备好使用Phong 着色实现位置光照射下的环面了。大多数代码与实现Gouraud 着色的代码相同。由于C++/OpenGL 代码完全没有改变,在此我们只展示修改过的顶点着色器和片段着色器,如图3所示,Phong 着色修正了Gouraud 着色中出现的伪影。
图2
图3
顶点着色器
#version 430
layout (location=0) in vec3 vertPos;
layout (location=1) in vec3 vertNormal;
out vec3 varyingNormal; // 视觉空间顶点法向量
out vec3 varyingLightDir; // 指向光源的向量
out vec3 varyingVertPos; // 视觉空间中的顶点位置
// 结构体和统一变量与Gouraud 着色相同
. . .
void main(void)
{ // 输出顶点位置、光照方向和法向量到光栅器以进行插值
varyingVertPos=(mv_matrix * vec4(vertPos,1.0)).xyz;
varyingLightDir = light.position - varyingVertPos;
varyingNormal=(norm_matrix * vec4(vertNormal,1.0)).xyz;
gl_Position=proj_matrix * mv_matrix * vec4(vertPos,1.0);
}
片元着色器
#version 430
in vec3 varyingNormal;
in vec3 varyingLightDir;
in vec3 varyingVertPos;
out vec4 fragColor;
// 结构体和统一变量与Gouraud 着色相同
. . .
void main(void)
{ // 正规化光照向量、法向量、视觉向量
vec3 L = normalize(varyingLightDir);
vec3 N = normalize(varyingNormal);
vec3 V = normalize(-varyingVertPos);
// 计算光照向量基于N 的反射向量
vec3 R = normalize(reflect(-L, N));
// 计算光照与平面法向量间的角度
float cosTheta = dot(L,N);
// 计算视觉向量与反射光向量的角度
float cosPhi = dot(V,R);
// 计算ADS 分量(按像素),并合并以构建输出颜色
```cpp
vec3 ambient = ((globalAmbient * material.ambient) + (light.ambient * material.ambient)).xyz;
vec3 diffuse = light.diffuse.xyz * material.diffuse.xyz * max(cosTheta,0.0);
vec3 specular =
light.specular.xyz * material.specular.xyz * pow(max(cosPhi,0.0), material.shininess);
fragColor = vec4((ambient + diffuse + specular), 1.0);
}
虽然Phong 着色有着比Gouraud 着色更真实的效果,但这是建立在增大性能消耗的基础上的。James Blinn 在1977 年提出了一种对于Phong 着色的优化方法[BL77],被称为Blinn-Phong反射模型。这种优化是基于观察到Phong 着色中消耗最大的计算之一是解出反射向量R。Blinn 发现向量R 在计算过程中并不是必需的——R 只是用来计算角φ 的手段。角φ 的计算可以不用向量R,而通过L 与V 的角平分线向量H 得到。如图4 所示,H 和N 之间的角α 刚好等于1⁄2(φ)。虽然α 与φ 不同,但Blinn 展示了使用α 代替φ 就已经可以获得足够好的结果。角平分线向量可以简单地使用L+V 得到(见图5),之后cos(α)可以通过•) )H N的点积计算。
图4
图5
这些计算可以在片段着色器中进行,甚至为了性能考虑(经过一些调整)也可以在顶点着色器中进行。图6 展示了使用Blinn-Phong 着色的环面。它在图形质量上几乎与Phong渲染相同,同时节省了大量性能损耗。
图6
程序3 中展示了修改后顶点着色器和片段着色器,它们用来将程序7.2 中的Phong 着色示例转换为Blinn-Phong 着色。C++ / OpenGL 代码与之前一样没有变化。
程序3 Blinn-Phong 着色的环面
顶点着色器
#version 430layout (location = 0) in vec3 vertPos;
layout (location = 1) in vec3 vertNormal;
out vec4 varyingColor;struct PositionalLight
{ vec4 ambient;vec4 diffuse;vec4 specular;vec3 position;
};
struct Material
{ vec4 ambient;vec4 diffuse;vec4 specular;float shininess;
};uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;void main(void)
{ vec4 color;// convert vertex position to view spacevec4 P = mv_matrix * vec4(vertPos,1.0);// convert normal to view spacevec3 N = normalize((norm_matrix * vec4(vertNormal,1.0)).xyz);// calculate view-space light vector (from point to light)vec3 L = normalize(light.position - P.xyz);// view vector is negative of view space positionvec3 V = normalize(-P.xyz);// R is reflection of -L around the plane defined by Nvec3 R = reflect(-L,N);// ambient, diffuse, and specular contributionsvec3 ambient =((globalAmbient * material.ambient)+ (light.ambient * material.ambient)).xyz;vec3 diffuse =light.diffuse.xyz * material.diffuse.xyz* max(dot(N,L), 0.0);vec3 specular =pow(max(dot(R,V), 0.0f), material.shininess)* material.specular.xyz * light.specular.xyz;// send the color output to the fragment shadervaryingColor = vec4((ambient + diffuse + specular), 1.0);// send the position to the fragment shader, as beforegl_Position = proj_matrix * mv_matrix * vec4(vertPos,1.0);
}
片元着色器
#version 430in vec4 varyingColor;
out vec4 fragColor;// uniforms match those in the vertex shader,
// but aren’t used directly in this fragment shaderstruct PositionalLight
{ vec4 ambient; vec4 diffuse; vec4 specular; vec3 position;
};struct Material
{ vec4 ambient; vec4 diffuse; vec4 specular; float shininess;
};uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 norm_matrix;// interpolate lighted color
// (interpolation of gl_Position is automatic)void main(void)
{ fragColor = varyingColor;
}
图7
参考
计算机图形学编程 使用OpenGL和C++
openGL中Phong 着色相关推荐
- Learn OpenGL(七)——OpenGL中使用着色器的基本步骤及GLSL渲染简单示例
OpenGL着色语言(OpenGL Shading Language,GLSL)是用来在OpenGL中着色编程的语言,是一种具有C/C++风格的高级过程语言,同样也以main函数开始,只不过执行过程是 ...
- OpenGL中phong光照模型详解
版权 cesuolidec4 https://blog.csdn.net/xiewenzhao123/article/details/54600191 引言 现实世界的光照是极其复杂的,而且会受到诸多 ...
- OpenGL中的着色模式GL_SMOOTH与GL_FLAT
glShadeModel void glShadeModel ( GLenum mode)是OpenGL1.0提供的接口.作用是设置着色模式. 参数mode可以是GL_SMOOTH(默认值)或GL_F ...
- Opengl ES之着色器
前言 在前面我们介绍了 OpenglEs之EGL环境搭建 ,在后面的例子中,我们将无可避免地需要使用到着色器.而着色器才是Opengl的灵魂所在,有了着色器才有了Opengl天马行空的世界. 图形渲染 ...
- OpenGL中环境光、漫反射、镜面反射对光的影响(如何被抽象成向量进行着色的)
文章目录 Phong算法中影响光照的三个因素 环境光(Ambient)对光线的影响 漫反射(Diffuse)对光的影响 镜面反射(Specular)对光的影响 衰减(Attenuation) Phon ...
- OpenGL在frag着色器中模拟手电筒效果
在[OpenGL在frag着色器中模拟点光源]的基础上进行修改,得到手电筒效果(https://blog.csdn.net/qq_37340753/article/details/105029079) ...
- OpenGL中的曲面细分和几何着色器
[摘要]本文我们先介绍OpenGL中的曲面细分的一些基本概念,然后给两个例子说明不得不用这项技术的理由. 曲面细分是OpenGL 4.0之后才定义的功能,使用之前请确认你的显卡驱动支持OpenGL4. ...
- OpenGL ES像素着色器
OpenGL ES像素着色器 原文 http://www.tairan.com/archives/7509 目 录 准备开始 像素着色器 vs 顶点/片段着色器 像素着色器101:渐变 像素着色器 ...
- OpenGL ES像素着色器教程
OpenGL ES像素着色器教程 时间 2014-08-27 09:54:51 泰然 原文 http://www.tairan.com/archives/7509 主题 OpenGL ES ...
最新文章
- 微信小程序绑定数据以及自定义指令
- 一致性hash算法简介
- 【数据竞赛】长文本竞赛上分的三种策略。
- docker-compose部署常用服务
- django 2.0 url匹配
- dbscan论文_论文分享 :Linkage Based Face Clustering via GCN
- 【招聘(深圳)】TCL通讯科技控股有限公司
- 【HDU - 5873】Football Games(兰道定理,知识点总结)
- 如何读入一个多行的txt文件,给每行的数据加双引号并保存为一行输出
- 集成电路总设计(Ⅴ)
- 自定义微信小程序弹框
- matepadpro升级鸿蒙,鸿蒙OS下月推出!MatePad Pro升级EMUI 11,提前预演
- ASCLL UTF-8 GBK URL编码
- 信息安全快讯丨一起为亚运健儿加油!
- 全国计算机王牌专业的一本大学,全国大学最牛专业排行,报考必读!
- 【鸡啄米】VC++串口通信编程详解
- 余压监控系统在高层民用建筑的应用
- 请谨慎使用预训练的深度学习模型
- 利用python爬取实习僧网站上的数据
- 3t硬盘分区 Linux win,3TB使用大难题 得先学会怎么分区_内存硬盘行情-中关村在线...