后处理中的 模糊、眩光、投影纹理:Blur,Bloom&ShadowMappingt in PostProcess - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki

后处理

一般结合 FBO 和 Shader,处理上一般处理的 Pass。

一般来说,Post Process 有以下经典模式:

1.将场景渲染到屏幕外 FBO 中

2.将 FBO 绑定一个来源,在屏幕上渲染

3.执行 FragmentShader,在屏幕范围内进行过滤

模糊

14_5_2_step_blur

偏移 4 次取平均

void main(void)
{
   vec4 sample0,
        sample1,
        sample2,
        sample3;
   float fStep = u_blurStep / 100.0;
   sample0 = texture2D ( renderTexture, 
                         vec2 ( v_texCoord.x - fStep, v_texCoord.y - fStep ) );
   sample1 = texture2D ( renderTexture, 
                         vec2 ( v_texCoord.x + fStep, v_texCoord.y + fStep ) );
   sample2 = texture2D ( renderTexture, 
                         vec2 ( v_texCoord.x + fStep, v_texCoord.y - fStep ) );
   sample3 = texture2D ( renderTexture, 
                         vec2 ( v_texCoord.x - fStep, v_texCoord.y + fStep) );
   outColor = (sample0 + sample1 + sample2 + sample3) / 4.0;
}	

眩光

较暗的表面生成比较明亮的光线,处理步骤如下供参考:

1.清除屏幕外渲染目标 rt0 绘制黑色物体

2.模糊步长 1.0 将屏幕外渲染目标 rt0 模糊到另一个渲染目标 rt1

3.模糊步长 1.0 将 rt1 模糊到 rt0

4.将对象渲染到后台缓冲区

5.将加光照的渲染目标与后台缓冲区混合

投影纹理

14_6_3_ProjectiveSpotlight

使用投影纹理,可以提供更高的性能。

1.读取投影纹理:

textureProj

通俗来讲,使用投影纹理是使用 3D 纹理坐标在 2D 纹理图形中查找,(s,t) 除以 r 坐标,使用 (s/r,t/r) 读取纹素。

2.投影纹理所用的矩阵

照明矩阵 —— 使用 景深(FOV) 纵横比(aspect) 远近平面距离(zNear|zFar) 的光源投影矩阵

照明视图 —— 定义视图轴的 3个主轴方向和照明位置构造

偏置矩阵 —— 将坐标转换为投影纹理坐标,通过在照明空间中位置(x,y,z)分量上使用 3x3 偏置矩阵实现。

上述转换一般在 CPU 中实现

3.着色器解析:

vert:

#version 300	
uniform float u_time_0_X;
uniform mat4 u_matProjection;
uniform mat4 u_matViewProjection;
in vec4 a_vertex;
in vec2 a_texCoord0;
in vec3 a_normal;

out vec2 v_texCoord;
out vec3 v_projTexCoord;
out vec3 v_normal;
out vec3 v_lightDir;

void main( void )
{
  gl_Position = u_matViewProjection * a_vertex;
  v_texCoord = a_texCoord0.xy;
    
  // 根据时间计算照明位置,一般 CPU 中完成
  vec3 lightPos;
  lightPos.x = cos(u_time_0_X);
  lightPos.z = sin(u_time_0_X);
  lightPos.xz = 200.0 * normalize(lightPos.xz);
  lightPos.y = 200.0;
  
  // Compute the light coordinate axes
  vec3 look = -normalize( lightPos );
  vec3 right = cross( vec3( 0.0, 0.0, 1.0), look );
  vec3 up = cross( look, right );
    
  // Create a view matrix for the light - 照明视图矩阵
  mat4 lightView = mat4( right, dot( right, -lightPos ),
                         up,    dot( up, -lightPos ),
                         look,  dot( look, -lightPos),
                         0.0, 0.0, 0.0, 1.0 );
                         
  // Transform position into light view space                         
  vec4 objPosLight = a_vertex * lightView;
  
  // Transform position into projective light view space 利用视野矩阵,将照明空间矩阵转换到投影照明空间中国年
  objPosLight = u_matProjection * objPosLight;
  
  // Create bias matrix 变换到投影纹理矩阵
  mat3 biasMatrix = mat3( 0.5,  0.0, 0.5,
                          0.0, -0.5, 0.5, 
                          0.0,  0.0, 1.0 );
  
  // Compute projective texture coordinates
  v_projTexCoord = objPosLight.xyz * biasMatrix;
  
  v_lightDir = normalize(a_vertex.xyz - lightPos);
  v_normal = a_normal;
 
}

frag:

version 300
precision mediump float;

uniform sampler2D baseMap;
uniform sampler2D spotLight;
in vec2 v_texCoord;
in vec3 v_projTexCoord;
in vec3 v_normal;
in vec3 v_lightDir;
out vec4 outColor;

void main( void )
{
    // Projective fetch of spotlight  读取投影纹理
    vec4 spotLightColor = textureProj( spotLight, v_projTexCoord );

    // Basemap 基础材质颜色
    vec4 baseColor = texture( baseMap, v_texCoord );
    
    // Compute N.L 计算照明方向和法线的 点积,用来衰减颜色
    float nDotL = max( 0.0, -dot( v_normal, v_lightDir ) );   
    
    outColor = spotLightColor * baseColor * 2.0 * nDotL;

}