赞
踩
源码下载:https://github.com/openglredbook/examples
1、程序的初始化
从哪里入口的?
宏定义发挥了及其重要的作用,有一定的迷惑性。
DEFINE_APP(FurApplication, "Fur Rendering")
首先:FurApplication是一个类,如何定义这个类:
也是使用的宏定义:
BEGIN_APP_DECLARATION(FurApplication)
END_APP_DECLARATION()
传入的FurApplication,被展开之后,得到的是:class FurApplication:pulic VermilionApplication
#define BEGIN_APP_DECLARATION(appclass) \
class appclass : public VermilionApplication \
{ \
public: \
typedef class VermilionApplication base; \
static VermilionApplication * Create(void) \
{ \
return (s_app = new appclass); \
}
#define END_APP_DECLARATION() \
};
宏定义没啥难的,就是替换。
下面是看入口的地方:DEFINE_APP(FurApplication, “Fur Rendering”)
这个主循环是WinMain发起的。
2、第一个pass的vertex
#version 410
layout (location = 0) in vec4 position_in;
layout (location = 1) in vec3 normal_in;
layout (location = 2) in vec2 texcoord_in;
uniform mat4 model_matrix;
uniform mat4 projection_matrix;
out VS_FS_VERTEX
{
vec3 normal;
} vertex_out;
void main(void)
{
vertex_out.normal = normal_in;
gl_Position = projection_matrix * (model_matrix * position_in);
};
第一个处理顶点的程序,输入的数据有顶点位置、法线、纹理坐标;M和P矩阵
输出的数据包在一个块中:顶点位置、法线、纹理坐标。没有做任何的变换,其中内置变量gl_Position用于接收本地坐标。
3、第一个pass的fragment
#version 410
layout (location = 0) out vec4 color;
in VS_FS_VERTEX
{
vec3 normal;
} vertex_in;
void main(void)
{
vec3 normal = vertex_in.normal;
color = vec4(0.2, 0.1, 0.5, 1.0) * (0.2 + pow(abs(normal.z), 4.0)) + vec4(0.8, 0.8, 0.8, 0.0) * pow(abs(normal.z), 137.0);
};
为何要做这种颜色的计算,不明白。
4、第二个pass的vertex
#version 410 layout (location = 0) in vec4 position_in; layout (location = 1) in vec3 normal_in; layout (location = 2) in vec2 texcoord_in; out VS_GS_VERTEX { vec3 normal; vec2 tex_coord; }vertex_out; void main(void) { vertex_out.normal = normal_in; vertex_out.tex_coord = texcoord_in; gl_Position = position_in; };
第二个处理顶点的程序,输入的数据有顶点位置、法线、纹理坐标。
输出的数据包在一个块中:顶点位置、法线、纹理坐标。没有做任何的变换,其中内置变量gl_Position用于接收本地坐标。
5、第二个pass的geometry
#version 410 layout (triangles) in; layout (triangle_strip, max_vertices = 120) out; uniform mat4 model_matrix; uniform mat4 projection_matrix; uniform int fur_layers = 30; uniform float fur_depth = 8.0; in VS_GS_VERTEX { vec3 normal; vec2 tex_coord; } vertex_in[]; out GS_FS_VERTEX { vec3 normal; vec2 tex_coord; flat float fur_strength; } vertex_out; void main(void) { int i, layer; float disp_delta = 1.0 / float(fur_layers); float d = 0.0; vec4 position; for (layer = 0; layer < fur_layers; layer++) { for (i = 0; i < gl_in.length(); i++) { vec3 n = vertex_in[i].normal; vertex_out.normal = n; vertex_out.tex_coord = vertex_in[i].tex_coord; vertex_out.fur_strength = 1.0 - d; position = gl_in[i].gl_Position + vec4(n * d * fur_depth, 0.0); gl_Position = projection_matrix * (model_matrix * position); EmitVertex(); } d += disp_delta; EndPrimitive(); } };
几何着色器的输入图元的定义我三角形;
输出定义为三角条带,输出的最大顶点数限制为120;
四个uniform变量,用于cpu传入shader,外面设置使用;
其中fur_layers定义了分层的数量;也就是毛发有几段构成;
fur_depth定义了毛发的长度;
VS_GS_VERTEX接口块,定义了由vs到gs的输入数据结构,这个参考上面vertex shader的输出。
不同的是,这里的输入是一个数组vertex_in[];
GS_FS_VERTEX和VS_GS_VERTEX数据成员一样,但是多了一个成员:fur_strength,后面使用。
还有一个不同的是GS_FS_VERTEX的是它的实例化成员不是数组,还是一个vertex_out变量。
再接着就是main函数了。
disp_delta = 1.0 / float(fur_layers);
for第一层是枚举每层;
for第二层是枚举图片的三个输入点;
对于每个点,进行处理;
for (i = 0; i < gl_in.length(); i++) 为啥不是使用vexter_in[]呢?其实也可以。他们的length是相同的。
vec3 n = vertex_in[i].normal;
vertex_out.normal = n;
vertex_out.tex_coord = vertex_in[i].tex_coord;
初始化每个点的成员。
vertex_out.fur_strength = 1.0 - d;
后面处理完一层之后对d进行d += disp_delta;处理。也就是说层数越多的时候,fur_strength越小。
position = gl_in[i].gl_Position + vec4(n * d * fur_depth, 0.0);
这个是在原有的local顶点位置,沿着法线方向增加了:d*fur_depth增量。
比如分成4层,fur_depth=10,那么每层是10/4=2.5长度。
然后对这个点进行mvp处理:gl_Position = projection_matrix * (model_matrix * position);
注意这里的view矩阵没有,默认就是单位矩阵了。
EmitVertex();最后进行发射这个顶点,于是乎在原顶点的沿着法线的方向生成了一个新的顶点。
然后进行: d += disp_delta;处理。
第二层for结束之后,也就结束了当前图元三角形的处理了。调用EndPrimitive()结束当前图元的处理。于是多了一个三角形了。如下图:
一层处理好之后,就多了上面的三个红色的点了。
其他层就再类似处理了。但是最大是我们限定的layout (triangle_strip, max_vertices = 120) out;120个顶点。
6、第二个paas的fragment
#version 410 layout (location = 0) out vec4 color; uniform sampler2D fur_texture; uniform vec4 fur_color = vec4(1, 1, 0, 1.0); in GS_FS_VERTEX { vec3 normal; vec2 tex_coord; flat float fur_strength; } fragment_in; void main(void) { vec4 rgba = texture(fur_texture, fragment_in.tex_coord); float t = rgba.a; t *= fragment_in.fur_strength; color = fur_color * vec4(1.0, 1.0, 1.0, t); }
去除纹理颜色,对其alpha值进行层的渐变,层越高,颜色越浅。
7、第一个shader的绘制
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
将擦除颜色设置为黑色;
glClearDepth(1.0f);
将擦除深度设置为1.0,最大值就是1.0了,最小值为0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
开始真正的擦除,颜色缓冲用黑色擦除;深度缓冲用1.0擦除。
glDisable(GL_BLEND);
禁用混合;
glEnable(GL_CULL_FACE);
启用剔除
glCullFace(GL_FRONT);
剔除的是前表面
glEnable(GL_DEPTH_TEST);
启用深度测试
glDepthFunc(GL_LEQUAL);
设置深度测试函数<=才通过
最后开始绘制:
object.Render();
8、第二个shader的绘制
glEnable(GL_BLEND);
开启混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
设置混合的函数为src,one-src
glDepthMask(GL_FALSE);
禁止深度写入,以为要混合;
开始绘制:
object.Render();
最后恢复设置:
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
如果没有禁用深度写入,则是如下的左图效果,正确的是右图效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。