基本流水线
上图是基本的渲染流水线。
[留坑待续]
ADS基本光照模型
ADS光照模型是最常用模型,它根据光照的性质将顶点或者像素在光照下的颜色分解为
- 环境(Ambient)
- 漫反射(Diffuse)
- 高光(Specular)
- 自发光(Emission)
几个分量的和。如下面诸图例所示表现形式和计算公式:
在公式中,Ambient和Diffuse叫做Lambert光照模型。对高光Specular成分来说,有Phong和Blinn-Phong两种计算方式,后者用一个H向量简化了计算。
以前的硬件设备通常使用顶点光照(VertexLit),即将光源和顶点位置、法线、材质,根据ADS模型计算得到颜色值存放在顶点上,然后在三角形光栅化阶段根据三个顶点的颜色,对三角形内部的像素颜色进行插值计算。顶点光照也叫做Gouraud Shading。
因为已经普及了shader,现代硬件设备则使用Phong Shading——不再用顶点和光源计算颜色,而是取像素的法线。要么在光栅化阶段对三个顶点的法线进行插值,要么访问一张法线贴图。然后在Pixel Shader中根据ADS模型用该法线处理光照,也就是逐像素光照,效果有很大提升。
另外,除了ADS 模型,还有各向异性光照模型,以及现在非常流行的PBR(Physically-Based Rendering)光照模型(PBR用BRDF公式来替换Diffuse和Specular分量模型)等等。
[留坑待续]
Shader效果文件
现在的shader编写一般采用单独的效果文件来进行。每一个效果被编写进一个单独的文件里,每一个文件有多个该效果的不同实现,每一个实现可能会通过一个到多个pass。比如DX的HLSL效果文件是这样的:
// effect.txt
technique T0
{
// first and only pass for this technique
pass P0
{
...[specify pass device states, shaders, samplers, etc.]
}
}
technique T1
{
// first pass
pass P0
{
...[specify pass device states, shaders, samplers, etc.]
}
// second pass
pass P1
{
...[specify pass device states, shaders, samplers, etc.]
}
}
Shader "MyShader" {
Properties {
_MyTexture ("My Texture", 2D) = "white" { }
// Place other properties like colors or vectors here as well
}
SubShader {
// here goes your
// - Surface Shader or
// - Vertex and Fragment Shader or
// - Fixed Function Shader
pass{...}
pass{...}
}
SubShader {
pass{...}
pass{...}
} // Place a simpler "fallback" version of the SubShader above
// that can run on older graphics cards here
}
每一次pass渲染该对象一次到当前缓冲区里面(比如一个RTT的FBO)。而pass之间会使用一些预先设定好的检测和逻辑计算合并相同位置的颜色,一般默认都是后面的颜色直接替换之前的颜色。
[留坑待续]
关于OpenGL的一些常识
OpenGL中的FBO是application-created framebuffer,而窗口系统默认生成并管理的叫做window-system-provided framebuffer,二者结构类似。一个FBO会提供多个attachment points,比如color1, depth, stencil等等挂接点。每点可挂接两种framebuffer-attachable image(texture和renderbuffer)中的一种。使用texture叫做“render to texture(RTT)”,用glFramebufferTexture2D()挂接;使用renderbuffer叫做“offscreen rendering”,用glFramebufferRenderbuffer() 挂接。另外,显卡一般允许FBO有多个color挂接点,若程序中通过glDrawBuffer()给FBO的多个color点进行挂接,则可以结合glsl实施MRT。
当一个OpenGL函数调用完毕,它并不会马上执行产生的命令。而是将它们存在CPU端的device command queue中。OGL driver可能会在多帧之后执行这些command,取决于GPU的工作效率和driver的当前配置。这种异步延迟对整体性能是有益的,因为实际上是对application隐藏了driver和GPU交互过程中的latency。
正因为OGL application thread和driver thread的异步处理,application对于一个VBO的修改(比如通过glBufferSubData()方法),可能因为driver正对该VBO的渲染而被driver阻塞,直到完成其渲染。这样的一个阻塞叫做implicit synchronization(隐式同步)。消除这种同步对OGL application深度优化很重要。
[留坑待续]