http://www.cnblogs.com/Zephyroal/archive/2011/10/10/2206530.html
一天干掉一只Monkey计划(一)——基本光照模型及RT后处理
1, 首先复习一下基本的光照模型:
Ambient Diffuse Specluar。。。不用多谈,不清楚自己复习,^_^~
然后建立一个基本的RenderMonkey工程,就可以开始着手建立一个基本的光照模型了。
2,VertexShader:
bool bViewSpace;
float4x4 matView;
float4x4 matViewProjection;
float3 vecLight;
float fSinTime0_X;
float4 vViewPosition;
struct VS_INPUT
{
float4 Position: POSITION0;
float2 TexCoord: TEXCOORD0;
float3 Normal: NORMAL0;
float3 Binormal: BINORMAL0;
float3 Tangent: TANGENT0;
};
struct VS_OUTPUT
{
float4 Position: POSITION0;
float2 TexCoord: TEXCOORD0;
float3 Normal: TEXCOORD1;
float3 Binormal: TEXCOORD2;
float3 Tangent: TEXCOORD3;
float3 Light:TEXCOORD4;
float3 View:TEXCOORD5;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
float4x4 matTransform = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
if( bViewSpace )
{
matTransform = matView;
} // end if( bViewSpace )
Output.Position = mul( Input.Position, matViewProjection );
Output.View =Output.Position-vViewPosition;
Output.TexCoord = Input.TexCoord;
Output.Normal = normalize(mul( Input.Normal, matTransform ));
Output.Binormal = ( mul( Input.Binormal, matTransform ) + 1.0f ) / 2.0f;
Output.Tangent = ( mul( Input.Tangent, matTransform ) + 1.0f ) / 2.0f;
Output.Light=normalize(vecLight);
//加上这一句可以使光源位置动态改变
//Output.Light.x+=fSinTime0_X*2;
return(Output);
}
3,PixelShader:
sampler2D my2DTexture;
struct PS_INPUT
{
float2 TexCoord: TEXCOORD0;
float3 Normal: TEXCOORD1;
float3 Binormal: TEXCOORD2;
float3 Tangent: TEXCOORD3;
float3 Light:TEXCOORD4;
float3 View:TEXCOORD5;
};
float4 ps_main( PS_INPUT Input ) : COLOR0
{
float4 color = float4( 0.0f, 0.0f, 0.0f, 0.0f );
float4 ambient = { 0.3686f, 0.3686f, 0.3686f, 1.0f};
float4 diffuse = { 0.88f, 0.88f, 0.88f, 1.0f};
float3 Normal = normalize( Input.Normal);
float3 LightDir = normalize( Input.Light);
float3 ViewDir = normalize( Input.View);
float4 diff = saturate( dot( Normal, LightDir));
float3 Reflect = normalize( 2 * diff * Normal - LightDir);
float4 specular = pow(saturate(dot(Reflect, ViewDir)), 8);
float4 fvBaseColor = tex2D( my2DTexture, Input.TexCoord );
float4 fvTotalAmbient = ambient * fvBaseColor;
float4 fvTotalDiffuse = diffuse * diff * fvBaseColor;
return fvTotalAmbient + fvTotalDiffuse + specular;
}
4,最后显示结果(先关的配置 RenderMonkey可以非常轻松地实现):
5,RenderMonkey中的后处理
RenderMonkey可以在pass中简单地建立一个RenderTarget,通过试手几个RT的处理
,可以预热下相关的屏幕空间后处理
VertexShader:
struct VS_OUTPUT
{
float4 pos : POSITION0;
float2 texCoord : TEXCOORD0;
};
VS_OUTPUT vs_main( float4 inPos: POSITION )
{
VS_OUTPUT o = (VS_OUTPUT) 0;
inPos.xy = sign( inPos.xy);
o.pos = float4( inPos.xy, 0.0f, 1.0f);
// get into range [0,1]
o.texCoord = (float2(o.pos.x, -o.pos.y) + 1.0f)/2.0f;
return o;
}
PixelShader:
sampler2D Texture0;
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
{
float4 color=tex2D( Texture0, texCoord );
//转换RGB为强度值
float intensity = color.r * 0.299 + color.g * 0.587 + color.b * 0.184;
return float4(intensity,intensity,intensity,color.a);
}
过程很简单,就是将原先的绘制结果改为输出到了一个指定RT上,然后再在将RT渲染的ps中做了灰度图处理~
6,水下效果
水下效果是游戏中水体处理的常见效果,原理很简单,只要加入一张新的tex为BumpMap,再对结果进行处理即可:
VS不变,PixelShader如下:
sampler2D Texture0;
sampler2D Texture1;
float fTime0_1;
float4 ps_main( float2 texCoord : TEXCOORD0 ) : COLOR
{
float2 bump=tex2D(Texture1,texCoord+fTime0_1*30);
float2 texel=texCoord+bump/60;
float4 color=tex2D( Texture0, texel );
return color;
}
F5,运行,神奇的效果便诞生了:
是不是太简单了,知其然而不知其所以然,是件可耻的事情:
首先来看贴图,可以从代码中发现采样出来只用了RG两个通道的颜色,打开PhotoShop,通过颜色通道面板,可以轻易地发现其中奥秘,RG两种颜色(白)交替出现,换算成float值大概是0.5f,左右,加在纹理的偏移上,即可产生一种“随波逐流”漂的效果。。。
但这里还有个问题,如何控制效果,这里使用了一个RenderMonkey预定义的float值--"Time0_1",查阅官方的SDK,(http://developer.amd.com/gpu_assets/RenderMonkey%20Documentation.pdf)
"Time0_1"
This variable provides a scaled floating point time value [0..1] which repeats itself
based on the “Cycle time” set in the RenderMonkey Preferences dialog. By
default this “Cycle time” is set to 120 seconds. This means that the value of this
variable cycles from 0 to 1 in 120 seconds and then goes back to 0 again.
可以得知其值为指定时间(默认两分钟内)从0~1的循环值,float2 bump=tex2D(Texture1,texCoord+fTime0_1*30);float2 texel=texCoord+bump/60;
尝试改变其中30,60几个值,可以明白对noise贴图上的偏移值决定了偏移的频率(速度),而加载对RT采样的实际纹理坐标texel上的除数决定了振幅,粗略理解fTime乘以一个m,则水流飘动的频率为1/( (120/m)/4 ),4为估计的寻址从0~1内出现的黑白交替数~
还有,进一步观察可以发现,有的像素由于扰动的纹理由屏幕左边被移到了屏幕有右边。
在逍遥剑客的blog中看到了相应的解决方法,直接设置RT的寻址模式为clamp,问题解决;
7,热流扰动
本来想实现下水下水纹扰动效果的,结果一时找不到合适的图,倒是意外实现了热流扰动的效果,想起多年前第一次玩到战地里边直升机出风口空气扰动的效果,当时十分震惊,以致自己从没敢想过去实现它,其实原理一模一样(真的是人有画地为牢,固步自封啊)
Noise贴图如下:
结果静态贴图看不清,可以自行实现,但结果还不够平滑,同样还是在逍遥剑客(真是pf前辈啊,学习)的blog上发现了解决方法,松柏分布,具体明天再一一详谈。
一天下来,颇为兴奋,还做了马赛克等等n多神奇的屏幕空间后处理,及预备下了延迟渲染,当然,我的目的是实践运用,到真正继承还需要克服各种问题,想各种方案和trick,额,不能想太多,博文都全写乱了,明天开始得每天专注于一个问题,好好精心思考~~
努力吧~~无止境~~~