shader学习笔记 - 水底效果

原创 2016年08月30日 18:32:01

这里写图片描述
来自:DX Samples: PIXGameDebugging.fx

包括两个部分:
1. 棋盘上所看到的水波花纹
2. 纵向的光纹

水波花纹

关键:

1. 使用32张现成的腐蚀纹理(caustic),来做水波变化的动态效果
2. 将光线、腐蚀因子、物体颜色,三者相乘

CPU部分:

1. 需要输入时间;
2. 预先加载所有纹理,利用时间(或其他)计算选取哪张腐蚀纹理,并设置。

效果代码:

VS_OUT CausticVS(VS_IN IN)   // vertex shader
{
    VS_OUT OUT;

    float2x2 rotation = {COS_0_15F, -SIN_0_15F, SIN_0_15F, COS_0_15F};     // 一个常数       
    float4 viewPosition = mul(IN.Position, WorldView);                     // 在观察空间的位置。【位置 * ( worldTrans * ViewTrans )】
    float3 viewNormal = normalize(mul(IN.Normal, WorldViewIT));            // 把法线转换到观察空间。【法线 / ( worldTrans * ViewTrans )】【这里为啥是除法,不懂】

    OUT.Position = mul(IN.Position, WorldViewProj);                        // 输出位置 = 输入位置变换到投影空间的结果

    OUT.Color = Light1Ambient + dot(viewNormal, Light1Dir);                // 输出颜色 = 环境光 + 漫反射光(此处没有使用漫反射系数)

    OUT.TexCoord0 = IN.TexCoord;                                           // 输出纹理坐标0 = 原纹理坐标0,将会被用作获取物体本身的纹理
    OUT.TexCoord1.xy = mul(viewPosition.xz, rotation);                     // 输出纹理坐标1 = 观察空间的位置 * 一个固定的旋转,将会被用作获取腐蚀纹理

    OUT.Fog = FogData.z * (FogData.y - length(viewPosition.xyz));          // 对观察空间位置到原点的距离,利用一个输入的变量进行线性变换,得到最终的雾效大小

    return OUT;
}
float4 CausticPS(VS_OUT IN) : COLOR   // pixel shader
{
    float2 movement = IN.TexCoord1.xy;

    movement.x = movement.x + cos(Time * 0.2f) * 0.3f;                     // 对vs中计算的“表征观察空间中的位置”的二维向量,加上一个时间相位
    movement.y = movement.y + sin(Time * 0.3f) * 0.2f;

    float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, movement.xy * 0.9f); // 将上述随时间和空间变化的固定值,作为纹理坐标,索引到腐蚀纹理中,然后与原有光效颜色,使用乘法进行混合
    color = color * tex2D(MeshTextureSampler, IN.TexCoord0.xy);            // 将物体本身颜色与水波花纹相乘,也使用乘法
    return float4(color, 1.0f);
}

纵向光纹 - 第一种

这里写图片描述

关键:

  1. 在CPU中多次渲染,来控制光线厚度;
  2. 使用一个两个三角形组成的长方形,来作为渲染对象,以此在ps中遍历屏幕;
  3. 使用上述长方形本身的颜色的alpha值,来控制在屏幕上的透明变化;

CPU部分:

  1. 按照light layer的值进行多次渲染;
  2. 制作一个由两个三角形组成的长方形的模型,作为渲染对象【不知道为什么要用1.1和1.5】;
LightShaftVertex g_LightVertices[] = // triangle list for lightshafts
{
    { -1.0f,  -1.1f, 0.0f, 0x0066ccff },
    {  -1.0f, 1.5f, 0.0f, 0x1166ccff  }, // x, y, z, color    
    {  1.0f,  -1.10f, 0.0f, 0x0066ccff  },
    {  -1.0f, 1.5f, 0.0f, 0x1166ccff },  
    {  1.0f,  1.5f, 0.0f, 0x1166ccff  },
    {  1.0f,  -1.1f, 0.0f, 0x0066ccff  },
};

效果部分:

VS_LIGHTSHAFT_OUT LightShaftAlternateVS(VS_LIGHTSHAFT_IN IN)  // vertex shader
{
    VS_LIGHTSHAFT_OUT OUT;

    OUT.Position = IN.Position;                                   // 输出位置依然是输入位置,因为输入已经被当做是屏幕位置了
    OUT.Position.z = OUT.Position.z + LightShaftZ;                // 由CPU控制z值平滑变化,防止重叠;在多层layer的情况下,z值还会有一个平滑的变化,从而也使得重叠显得更为有质感

    OUT.Color = IN.Color;                                         // 颜色固定

    OUT.TexCoord0.xy = OUT.Position.xz*0.9f;                      // 把屏幕坐标的x和z作为输出的纹理坐标,亦即其z值不变【不知道为什么要带一个缩放】

    return OUT;
}

float4 LightShaftPS(VS_LIGHTSHAFT_OUT IN) : COLOR  // pixel shader
{
    float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, IN.TexCoord0.xy); // 根据上边生成出的uv坐标,在腐蚀纹理中得到颜色。将其与原有颜色相乘作为最终颜色
    return float4(color, IN.Color.a);                             // 注:本效果框架中alpha混合模式为src=srcalpha, dest=one,因而对最终颜色总是加强的
}

纵向光纹 - 第二种

这里写图片描述

关键:

  1. 在第一种的基础上,修改alpha值为一个程序输入的固定值,从而造成在y方向上光纹透明度不变

CPU部分:

效果部分:

VS_LIGHTSHAFT_OUT LightShaftVS(VS_LIGHTSHAFT_IN IN)  // vertex shader
{
    VS_LIGHTSHAFT_OUT OUT;

    float2x2 rotation = {COS_0_15F, -SIN_0_15F, SIN_0_15F, COS_0_15F};             // 固定的旋转

    OUT.Position = IN.Position;                                                    // 输出的位置为输入的位置(屏幕位置)
    float4 movement = IN.Position;
    movement.x = movement.x + cos(Time * 0.2f) * 0.3f;                             // 增加时间相位
    movement.z = movement.z + sin(Time * 0.3f) * 0.2f;

    OUT.Position.z = OUT.Position.z + LightShaftZ;                                 // z值增加一个可控变量。该值在多层layer时平滑递减
    OUT.Color = IN.Color;
    OUT.Color.a = LightShaftAlpha;                                                 // 颜色为本身颜色,alpha值为程序控制,为固定值

    OUT.TexCoord0.xy = mul(OUT.Position.xz, rotation) + movement.xz;               // 原位置的旋转 + 原位置 + 时间相位
    OUT.TexCoord0.xy = OUT.TexCoord0.xy * 0.9f + 1.0f / (1.0f - OUT.Position.z);   // 缩放后加上一个外部控制的变量LightShaftZ 【不知道为什么要加这个变量】
    return OUT;
}
float4 LightShaftPS(VS_LIGHTSHAFT_OUT IN) : COLOR  // pixel shader
{
    float3 color = IN.Color.rgb * tex2D(CausticTextureSampler, IN.TexCoord0.xy);   // 同前
    return float4(color, IN.Color.a);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

第五天,终于实现了水下模糊效果(动态挂载脚本),blur里写入shader

昨天元旦在外面浪了一天 然后现在的问题还是动态挂脚本的问题,玩的都不开心 然后现在我终于解决了 我一直以为是自己代码的问题 觉得是addcomonent这个函数自己不会用 然而并不是 我想动态...

水底3D水母(http://chrysaora.com/)

http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">   Chrysaora - WebGL  ...
  • devehe
  • devehe
  • 2011年10月22日 12:53
  • 695

使用着色器

// 将vsh与fsh装配成一个完整的Shader文件。 auto glprogram = GLProgram::createWithFilenames("gray.vsh", "gray.f...

真实感计算机图形学(一)--自然景物模拟

真实感计算机图形学(一)--自然景物模拟 作者:田景成 发布时间:2001/02/07 文章摘要:  寻求能准确地描述客观世界中各种现象与景观的数学模型,并逼真地再现这些现象与景观,是图形学的一个重要...

include包含文件查找的顺序

从microsoft网站上找到关于#include Directive (C/C++)的相关问题解释如下: The #include directive tells the preprocessor...

Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果

建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效。使用这种技术,可以为游戏画面添加更多艺术效果,例如景深、...

Unity Shader入门精要学习笔记 - 第8章 透明效果

透明是游戏中经常要使用的一种效果。在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元出了颜色值和深度值之外,它还有另一个属性——透明...

Unity Shader 学习笔记 (五) 积雪效果Shader

Unity Shader 学习笔记 (五) 积雪效果Shader Shader "Custom/jixue xiaoguo " { Properties { _MainTex ("Base (R...

shader学习笔记一中shader文件

  • 2015年12月31日 13:32
  • 2KB
  • 下载

shader学习笔记二中shader

  • 2015年12月31日 14:04
  • 3KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:shader学习笔记 - 水底效果
举报原因:
原因补充:

(最多只允许输入30个字)