I have finally succeeded in writing my first shader. I would say it's a pretty good fur shader, and does work. Since the file is over 900 lines long, I load it as a separate .fx file:
matrix matWorldViewProj;
vector mtlSkill1; // Fur color, alpha. pixel_from_vec()
float fur_depth = 0.200000;
// Doesn't translate well from mtlSkill.
texture mtlSkin1;
technique default_technique {
pass p0 {
//--------------------------------------------------------------//
// ASM Fur
//--------------------------------------------------------------//
//--------------------------------------------------------------//
// Pass 1
//--------------------------------------------------------------//
//float pass = 0.000000;
//texture base_map = <mtlSkin1>;
//sampler base_map = sampler_state
//{
// Texture = (base_map);
// MAGFILTER = LINEAR;
// MINFILTER = LINEAR;
// MIPFILTER = LINEAR;
//};
Texture[0] = <mtlSkin1>;
PixelShaderConstant[0] = <mtlSkill1>;
VertexShaderConstant[4] = <fur_depth>;
VertexShaderConstant[5] = 0.000000;
VertexShaderConstant[6] = <matWorldViewProj>;
zWriteEnable = false; // Delay writing to the z-buffer.
AlphaBlendEnable = true;
//--------------------------------------------------------------//
// Vertex Shader
//--------------------------------------------------------------//
VertexShader =
decl {
stream 0;
float v0[3];
float v3[3];
float v7[2];
}
asm {
vs.1.1
; get model space vertex
mov r0, v0
; get shell distance
mov r1, c4
; offset shell in direction of normal
mul r1.x, r1.x, c5.x
mul r1.xyz, r1.xxx, v3.xyz
add r0.xyz, r0.xyz, r1.xyz
; output transformed vertex
m4x4 oPos, r0, c6
; output texture coordinates
mov oT0, v7
};
//--------------------------------------------------------------//
// Pixel Shader
//--------------------------------------------------------------//
PixelShader = asm
{
ps.1.4
texld r0, t0 ; base map
mul r0, r0, c0
};
} pass p1 {
Texture[0] = <mtlSkin1>;
PixelShaderConstant[0] = <mtlSkill1>;
VertexShaderConstant[4] = <fur_depth>;
VertexShaderConstant[5] = 1.000000;
VertexShaderConstant[6] = <matWorldViewProj>;
//zWriteEnable = true; // Enable writing to the z-buffer.
AlphaBlendEnable = true;
//--------------------------------------------------------------//
// Pass 2
//--------------------------------------------------------------//
//float pass = 1.000000;
//--------------------------------------------------------------//
// Vertex Shader
//--------------------------------------------------------------//
VertexShader =
decl {
stream 0;
float v0[3];
float v3[3];
float v7[2];
}
asm {
vs.1.1
; get model space vertex
mov r0, v0
; get shell distance
mov r1, c4
; offset shell in direction of normal
mul r1.x, r1.x, c5.x
mul r1.xyz, r1.xxx, v3.xyz
add r0.xyz, r0.xyz, r1.xyz
; output transformed vertex
m4x4 oPos, r0, c6
; output texture coordinates
mov oT0, v7
};
PixelShader = asm
{
ps.1.4
texld r0, t0 ; base map
mul r0, r0, c0
};
} pass p2 {
Texture[0] = <mtlSkin1>;
PixelShaderConstant[0] = <mtlSkill1>;
VertexShaderConstant[4] = <fur_depth>;
VertexShaderConstant[5] = 2.000000;
VertexShaderConstant[6] = <matWorldViewProj>;
//zWriteEnable = true; // Enable writing to the z-buffer.
AlphaBlendEnable = true;
//--------------------------------------------------------------//
// Pass 3
//--------------------------------------------------------------//
//float pass = 2.000000;
//--------------------------------------------------------------//
// Vertex Shader
//--------------------------------------------------------------//
VertexShader =
decl {
stream 0;
float v0[3];
float v3[3];
float v7[2];
}
asm {
vs.1.1
; get model space vertex
mov r0, v0
; get shell distance
mov r1, c4
; offset shell in direction of normal
mul r1.x, r1.x, c5.x
mul r1.xyz, r1.xxx, v3.xyz
add r0.xyz, r0.xyz, r1.xyz
; output transformed vertex
m4x4 oPos, r0, c6
; output texture coordinates
mov oT0, v7
};
PixelShader = asm
{
ps.1.4
texld r0, t0 ; base map
mul r0, r0, c0
};
} pass p3 {
Texture[0] = <mtlSkin1>;
PixelShaderConstant[0] = <mtlSkill1>;
VertexShaderConstant[4] = <fur_depth>;
VertexShaderConstant[5] = 3.000000;
VertexShaderConstant[6] = <matWorldViewProj>;
//zWriteEnable = true; // Enable writing to the z-buffer.
AlphaBlendEnable = true;
//--------------------------------------------------------------//
// Pass 4
//--------------------------------------------------------------//
//float pass = 3.000000;
//--------------------------------------------------------------//
// Vertex Shader
//--------------------------------------------------------------//
VertexShader =
decl {
stream 0;
float v0[3];
float v3[3];
float v7[2];
}
asm {
vs.1.1
; get model space vertex
mov r0, v0
; get shell distance
mov r1, c4
; offset shell in direction of normal
mul r1.x, r1.x, c5.x
mul r1.xyz, r1.xxx, v3.xyz
add r0.xyz, r0.xyz, r1.xyz
; output transformed vertex
m4x4 oPos, r0, c6
; output texture coordinates
mov oT0, v7
};
PixelShader = asm
{
ps.1.4
texld r0, t0 ; base map
mul r0, r0, c0
};
}
(...)
My code adds another 10 passes, and as long as alpha-blending is enabled, they produce realistic fur. They produce more of a rug in 3D. I did it. I have added 2 fallback techniques as well, for graphics cards without ps.1.4 , and for graphics cards which can't even perform 6 passes.
During the last pass, I set zWriteEnable = on again.
One improvement I made, took notice of the fact that the above shader left small holes in the entity. Therefore, I now use the following pixel shader IN THE FIRST PASS ONLY:
PixelShader = asm
{
ps.1.4
texld r0, t0 ; base map
// mul r0, r0, c0
mov r0, c0 ; so can't be seen through
};
This one shader deposits a layer of solid colour, so that the entity appears to have skin under that fur, after which the remaining 13 passes deposit fur.
Dirk
Last edited by dirkmittler; 07/25/04 01:02.