Crystal shader
From GameStudio Wiki
Contents |
[edit]
Crystal shader
based on the crystal shader used in the "Life on the Bleeding Edge" demo from nvidia, more infos: http://developer.nvidia.com/object/nvision08-DemoTeam.html
The crystal.fx file:
/******************************************
** crystal shader **
** based on the crystal shader used in **
** the "Life on the Bleeding Edge" demo **
** from nvidia **
*******************************************
** credits: **
** ChrisB **
** http://www.swollen-eyeballs.org **
** http://developer.nvidia.com/object/nvision08-DemoTeam.html **
******************************************/
// transformations
float4x4 matWorld;
float4x3 matView;
float4x4 matViewProj;
float4x3 matWorldView;
float4x4 matWorldViewProj;
float4x3 matWorldInv;
float4x3 matViewInv;
float3 vecViewPos;
float4 vecSunDir;
float4 vecSkill1;
float4 vecAmbient;
texture entSkin1;
texture mtlSkin1;
samplerCUBE EnvironmentSampler = sampler_state
{
Texture = <mtlSkin1>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
// vertex shader output structure
struct VS_OUTPUT
{
float4 Pos : POSITION;
float3 view : TEXCOORD0;
float3 normal : TEXCOORD3;
float3 vPos : TEXCOORD2;
float3 eye : TEXCOORD1;
};
VS_OUTPUT VS(
float4 InPos : POSITION,
float3 InNormal : NORMAL )
{
VS_OUTPUT Out = (VS_OUTPUT)0;
// transform the position and normal
Out.vPos = mul(InPos, matWorld).xyz; // position (view space)
Out.normal = mul(InNormal, matWorld); // normal (view space)
Out.view = vecViewPos.xyz;
Out.Pos = mul(InPos, matWorldViewProj); // position (projected)
Out.eye = Out.vPos-vecViewPos;
return Out;
}
float fresnelRefl(float3 n, float3 v, float f)
{
float base = 1.0 - dot(n,v);
float expo = pow(base, 2.0);
return expo + f*(1.0 - expo);
}
float intersectRaySphere(float3 dst, float3 dir) {
float B = dot(dst, dir);
float C = dot(dst, dst) - 1;
float D = B*B - C;
return D > 0 ? -B - sqrt(D) : 0;
}
float3 facetNormal(float3 n, float facetSize)
{
float3 scaledNormal = n*facetSize;
float3 scaleandround = float3( round(scaledNormal.x), round(scaledNormal.y), round(scaledNormal.z));
return normalize(scaleandround);
}
float4 PS ( VS_OUTPUT In) : COLOR
{
float4 OutColor=0;
float3 color = vecAmbient.rgb;
float3 normal = normalize(In.normal);//
normal = lerp(normal, facetNormal(normal, vecSkill1.y), vecSkill1.z);
float3 viewDir = normalize(In.eye);//In.vPos - In.view);
float3 reflectVec = reflect(viewDir, normal);
float4 reflectColor = texCUBE(EnvironmentSampler, reflectVec);
float diff = saturate(dot(normal, -vecSunDir.xyz));
float3 vReflectionTS = normalize( 2 * dot( viewDir, normal ) * normal - viewDir );
float fRdotL = saturate( dot( vReflectionTS, vecSunDir.xyz ));
float spec = pow(fRdotL, 10)*1;
float index=vecSkill1.x;
float f0=pow((1.0-index)/(1.0+index), 2.0);
float f0_out=pow((index-1.0)/(1.0+index), 2.0);
float fresnel = fresnelRefl(normal, -viewDir, f0);
float3 T0 = refract(viewDir, normal, 1.0/index);
float t=intersectRaySphere(normal, -T0);
float3 normal2 = facetNormal(normalize(normal-t*T0), vecSkill1.y);
float3 T1 = refract(T0, -normal2, 1.0/index);
float fresnel1 = (fresnelRefl(normal2, T0, f0_out));
float4 refractColor = texCUBE(EnvironmentSampler, T1);
float diff2 = saturate(dot(normal2, -vecSunDir.xyz));
float3 vReflectionTS2 = normalize( 2 * dot( T0, normal2 ) * normal2 - T0 );
float fRdotL2 = saturate( dot( vReflectionTS2, vecSunDir.xyz ));
float spec2 = pow(fRdotL2, 10)*1*exp(t*0.5);
float3 T2 = reflect(T0, normal2);
float t2=intersectRaySphere(normal2, -T2);
float3 normal3 = facetNormal(normalize(normal-t2*T2), vecSkill1.y);
float3 T3 = refract(T2, -normal3, 1.0/index);
float fresnel2 =(fresnelRefl(normal3, T2, f0_out));
float4 refractColor2 = texCUBE(EnvironmentSampler, T3);
OutColor.rgb += reflectColor*color*fresnel;
OutColor.rgb+=spec*color*2;
OutColor.rgb+=(1-fresnel)*exp(t*0.5)*((1-fresnel1)*refractColor*color+spec2*color*2+exp(t2*0.75)*(1-fresnel2)*refractColor2*color);
return OutColor;
}
float4 PS2 ( VS_OUTPUT In) : COLOR
{
float4 OutColor=0;
float3 color = vecAmbient.rgb;
float3 normal = normalize(In.normal);
normal = lerp(normal, facetNormal(normal, vecSkill1.y), vecSkill1.z);
float3 viewDir = normalize(In.eye);//In.vPos - In.view);
float3 reflectVec = reflect(viewDir, normal);
float4 reflectColor = texCUBE(EnvironmentSampler, reflectVec);
float diff = saturate(dot(normal, -vecSunDir.xyz));
float3 vReflectionTS = normalize( 2 * dot( viewDir, normal ) * normal - viewDir );
float fRdotL = saturate( dot( vReflectionTS, vecSunDir.xyz ));
float spec = pow(fRdotL, 10)*1;
float index=vecSkill1.x;
float f0=pow((1.0-index)/(1.0+index), 2.0);
float f0_out=pow((index-1.0)/(1.0+index), 2.0);
float fresnel = fresnelRefl(normal, -viewDir, f0)*1;
float3 T0 = refract(viewDir, normal, 1.0/index);
float4 refractColor = texCUBE(EnvironmentSampler, T0);
float spec2 =0;// pow(fRdotL2, 10)*1*exp(t*0.5);
OutColor.rgb += reflectColor*color*fresnel;
OutColor.rgb+=spec*color*2;
OutColor.rgb+=(1-fresnel)*0.5*refractColor*color+spec2*color*2;
return OutColor;
}
technique crystal
{
pass P0
{
VertexShader = compile vs_3_0 VS();
PixelShader = compile ps_3_0 PS();
}
}
technique crystal20
{
pass P0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS2();
}
}
[edit]
C-Script example:
bmap bmp_cubemap=<mysky+6.tga>;
material mat_crystal
{
effect="crystal.fx";
skin1=bmp_cubemap;
ambient_red=200;
ambient_green=180;
ambient_blue=150;
}
action earth
{
my.material=mat_crystal;
bmap_to_cubemap(bmp_cubemap);
mat_crystal.skill1=float(1.25); //vecSkill1
mat_crystal.skill2=float(5);
mat_crystal.skill3=float(0);
}
[edit]
Adjustable through:
| material parameter | meaning |
|---|---|
| mtl.ambient_xxx | color |
| mtl.skill1 | refractive index |
| mtl.skill2 | facet size |
| mtl.skill3 | facet models normals (0 or 1) |
[edit]
Remarks
First material skin is used for reflections and refraction.
| Uses ShaderModel: | 3 |
| Has fallback techniques: | yes (but not good ones) |
| Uses fog: | no |
--ChrisB 19:26, 4 April 2009 (CEST)
