OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(三)

[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(调色板?)中。

顶点蒙皮的计算公式如下:


OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(三)_第1张图片

下面来具体看一个例子,在这个例子中,我们假设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)

你可能感兴趣的:(OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(三))