[TOC]
3. Generating Texture Coordinates
(书上只写了两个简单的例子,我并没有理解这部分讲的是什么,之后补充,先上例子)
Example 8-4: Sphere Map Texture Coordinate Generation
vec2 sphere_map (vec3 position, vec3 normal)
{
reflection = reflect (position, normal);
m = 2.0 * sqrt (reflection.x * reflection.x + reflection.y * reflection.y + (reflection.z + 1.0) * (reflection.z + 1.0));
return vec2((reflection.x / m + 0.5), (reflection.y / m + 0.5));
}
Example 8-5: Cubemap Texture Coordinate Generation
vec3 cube_map (vec3 position, vec3 normal)
{
return reflect(position, normal);
}
4. Vertex Skinning
(写在前面:关于蒙皮,我自己也不理解,先把书上的翻译下来)
顶点蒙皮是一种用来平滑多边形之间连接点的常用技术,通过向每个顶点附加一定权重的额外变换矩阵来实现。用来给一个顶点进行蒙皮的矩阵的数量一般是2~4个,这些用来进行蒙皮的矩阵储存在一个matrix palette(调色板?)中。
顶点蒙皮的计算公式如下:
下面来具体看一个例子,在这个例子中,我们假设matrix palette中含有32个矩阵,并且这些矩阵都是行优先的正交矩阵(正交矩阵的逆矩阵也是它的转置矩阵),每个顶点由4个矩阵来进行变换:
Example 8-6
#version 300 es
#define NUM_MATRICES 32
const int c_zero = 0;
const int c_one = 1;
const int c_two = 2;
const int c_three = 3;
uniform vec4 matrix_palette[NUM_MATRICES * 3];
in vec4 a_position;
in vec3 a_normal;
in vec4 a_matrixweights;
in vec4 a_matrixindices;
void skin_position (in vec4 position, float m_wt, int m_indx, out vec4 skinned_position)
{
vec4 tmp;
tmp.x = dot (position, matrix_palette[m_indx]);
tmp.y = dot (position, matrix_palette[m_indx + c_one]);
tmp.z = dot (position, matrix_palette[m_indx + c_two]);
tmp.w = position.w;
skinned_position += m_wt * tmp;
}
void skin_normal (in vec3 normal, float m_wt, int m_indx, inout vec3 skinned_normal)
{
vec3 tmp;
tmp.x = dot (normal, matrix_palette[m_indx].xyz);
tmp.y = dot (normal, matrix_palette[m_indx + c_one].xyz);
tmp.z = dot (normal, matrix_palette[m_indx + c_two].xyz);
skinned_normal += m_wt * tmp;
}
void do_skinning (in vec4 position, in vec3 normal, out vec4 skinned_position, out vec3 skinned_normal)
{
skinned_position = vec4 (float(c_zero));
skinned_normal = vec3 (float(c_zero));
float m_wt = a_matrixweights[0];
int m_indx = int (a_matrixindices[0]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
m_wt = a_matrixweights[1];
m_indx = int (a_matrixindices[1]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
m_wt = a_matrixweights[2];
m_indx = int (a_matrixindices[2]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
m_wt = a_matrixweights[3];
m_indx = int (a_matrixindices[3]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
}
在例8-6中,顶点shader用4个矩阵和相应的权重来变换顶点,从而生成蒙皮顶点。而实际上,这些矩阵的权重为0的情况非常常见,所以在进行变换之前,先检查一下权重是否为0可能会更好。例如下面这样:
Example 8-7
void do_skinning (in vec4 position, in vec3 normal, out vec4 skinned_position, out vec3 skinned_normal)
{
skinned_position = vec4 (float(c_zero));
skinned_normal = vec3 (float(c_zero));
int m_indx = 0;
float m_wt = a_matrixweights[0];
if (m_wt > 0.0) {
m_indx = int (a_matrixindices[0]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
}
m_wt = a_matrixweights[1];
if (m_wt > 0.0) {
m_indx = int (a_matrixindices[1]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
}
m_wt = a_matrixweights[2];
if (m_wt > 0.0) {
m_indx = int (a_matrixindices[2]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
}
m_wt = a_matrixweights[3];
if (m_wt > 0.0) {
m_indx = int (a_matrixindices[3]) * c_three;
skin_position(position, m_wt, m_indx, skinned_position);
skin_normal(normal, m_wt, m_indx, skinned_normal);
}
}
乍一看,例8-7的性能更好,但事实并不一定如此,实际上哪个更好是要根据GPU来决定。原因是在shader中,对于条件控制语句(if、for、while),不同结构的GPU(SIMD、MIMD)的处理效率是不同的。
if (a)
b = f();
else
b = g();
对于SIMD结构,所有的处理器在同一时刻必须处理相同的指令,所以如果一些顶点的a为true,另一些顶点的a为false,那些a为false的顶点就要等到a为true的顶点的指令执行完之后,才能执行。这就减小了性能。所以,在shader中,一定要慎用条件控制语句。
(具体可参考:https://www.zhihu.com/question/27084107)
(具体可参考:http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html)