Per rendere la iluminazione delle nuvole piu convincente avevo il bisogno di un HLSL shader capace di simulare il Subsurface Scattering. Questo shader e alla fine molto semplice. Un bel esempio come si possono ottenere effetti convincenti con poche risorse.

Il video: VIDEO DIVX
In order to render the illumination of clouds more convincing I had a need of an HLSL shader able to simulate the Subsurface Scattering. This shader is quite simple. A beautiful example how a convincing effects can be obtained with a little resources.
Here you can find a complete shader code in HLSL (this shader is Virtools ready, in other programs you will probably have to change some lines):
//Subsurface scattering shader by Oliver Pavicevic (olix@iol.it)
.r{}************ TWEAKABLES **************/
half4 surfColor : Diffuse = {1.0f, 1.0f, 1.0f, 1.0f};
texture colorTexture : Texture;
.r{}************* light info **************/
half3 light1Pos <string type="entity3d";> = {100.0f, 100.0f, 100.0f};
half4 light1Color = { 1.0f, 1.0f, 1.0f, 0.0f };
half4x4
wvp : WorldViewProjection < string UIWidget = "None"; >;
half4x4
worldI : WorldInverse < string UIWidget = "None"; >;
half4x4
viewInvTrans : ViewInverse < string UIWidget = "None"; >;
half
attenuation1 <
string UIWidget = "slider";
float UIMin = 0;
float UIMax = 1000;
string UIName = "close attenuation";
> = 100;
half
attenuation2 <
string UIWidget = "slider";
float UIMin = 0;
float UIMax = 128;
string UIName = "medium attenuation";
> = 10;
half
attenuation3 <
string UIWidget = "slider";
float UIMin = 0;
float UIMax = 1;
string UIName = "far attenuation";
> = 0.3;
.r{}***************************************************/
.r{}********* HLSL SHADER FUNCTIONS *********************/
.r{}***************************************************/
// input from application
struct a2v {
half4 position : POSITION;
half2 texCoord : TEXCOORD0;
half3 tangent : TEXCOORD1;
half3 binormal : TEXCOORD2;
half3 normal : NORMAL;
};
// output to fragment program
struct
v2f {
half4 position : POSITION;
half2 texCoord : TEXCOORD0;
half3 lightVec : TEXCOORD2;
};
// blinn lighting with lit function
half4
blinn2(half3 N,
half3 L,
half3 V,
uniform half4 diffuseColor,
uniform half4 specularColor,
uniform half shininess
)
{
half3 H = normalize(V L);
half4 lighting = lit(dot(L,N), dot(H,N),0);
return diffuseColor*lighting.y ;
}
.r{}*************************************/
.r{}**** VERTEX SHADER ******************/
.r{}*************************************/
v2f v(a2v In,
uniform half4x4 worldViewProj, // object to clip space
uniform half4x4 WorldIMatrix, //world to object space
uniform half4 lightPosition,
uniform half4x4 ViewInvTrans )
{
v2f Out;
// transform vertex position to homogeneous clip space
Out.position =
mul(In.position, worldViewProj);
//pass texture coordinates
Out.texCoord = In.texCoord;
// compute the 3x3 tranform from tangent space to object space
half3x3 objTangentXf;
objTangentXf[0] = In.tangent.xyz;
objTangentXf[1] = In.binormal.xyz;
objTangentXf[2] = In.normal.xyz;
//put the world space light position in object space
half4 objSpaceLightPos = mul(lightPosition, WorldIMatrix);
half3 objLightVec = objSpaceLightPos.xyz - In.position.xyz;
// xform light vector from obj space to tangent space
Out.lightVec =
mul(objTangentXf, objLightVec );
//compute the eye vector in world space and put it in object space
half4 objSpaceEyePos = mul(ViewInvTrans[3], WorldIMatrix);
return Out;
}
.r{}*************************************/
.r{}**** FRAGMENT PROGRAM ***************/
.r{}*************************************/
float4
f(v2f In,
uniform sampler2D colorTex,
uniform half4 diffuseColor,
uniform half4 light1Color,
uniform half attenuation1,
uniform half attenuation2,
uniform half attenuation3
) :
COLOR
{
//fetch the diffuse map
half4 colorMap = tex2D(colorTex, In.texCoord.xy);
//calculate attenuation
half d = length(In.lightVec);
half attenuation = 1 / ((attenuation1) (attenuation2 * d) (attenuation3 * d * d));;
//Subsurface Scattering
half4 SS = (light1Color*1200) * blinn2(1, 0.02, 0, colorMap*diffuseColor, colorMap.a, 0) * attenuation;
return SS;
}
.r{}***************************************************/
.r{}********* SAMPLERS ********************************/
.r{}***************************************************/
sampler2D
colorTextureSampler = sampler_state
{
Texture = ;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
};
.r{}***************************************************/
.r{}********* TECHNIQUES ******************************/
.r{}***************************************************/
technique
Complete
{
pass envPass
{
VertexShader = compile vs_1_1 v(wvp,worldI,half4(light1Pos,1),viewInvTrans);
ZEnable = true;
ZWriteEnable = true;
//CullMode = CW;
PixelShader = compile ps_2_0 f(colorTextureSampler,surfColor,light1Color,attenuation1,attenuation2,attenuation3);
}
}