📄 macros.vsh
字号:
;------------------------------------
; RULES FOR AUTHORING VERTEX SHADERS:
;------------------------------------
; - never use "def" . . .set constants in code instead. . our constant shadowing will break otherwise.
; (same goes for pixel shaders)
; - use cN notation instead of c[N] notation. .makes grepping for registers easier.
; The only exception is c[a0.x+blah] where you have no choice.
$g_NumRegisters = 12;
# NOTE: These must match the same values in vsh_prep.pl!
$vPos = "v0";
$vBoneWeights = "v1";
$vBoneIndices = "v2";
$vNormal = "v3";
$vColor = "v5";
$vSpecular = "v6";
$vTexCoord0 = "v7";
$vTexCoord1 = "v8";
$vTexCoord2 = "v9";
$vTexCoord3 = "v10";
$vTangentS = "v11";
$vTangentT = "v12";
$vUserData = "v14";
if( $g_dx9 )
{
if( $g_usesPos )
{
dcl_position $vPos;
}
if( $g_usesBoneWeights )
{
dcl_blendweight $vBoneWeights;
}
if( $g_usesBoneIndices )
{
dcl_blendindices $vBoneIndices;
}
if( $g_usesNormal )
{
dcl_normal $vNormal;
}
if( $g_usesColor )
{
dcl_color0 $vColor;
}
if( $g_usesSpecular )
{
dcl_color1 $vSpecular;
}
if( $g_usesTexCoord0 )
{
dcl_texcoord0 $vTexCoord0;
}
if( $g_usesTexCoord1 )
{
dcl_texcoord1 $vTexCoord1;
}
if( $g_usesTexCoord2 )
{
dcl_texcoord2 $vTexCoord2;
}
if( $g_usesTexCoord3 )
{
dcl_texcoord3 $vTexCoord3;
}
if( $g_usesTangentS )
{
dcl_tangent $vTangentS;
}
if( $g_usesTangentT )
{
dcl_binormal0 $vTangentT;
}
if( $g_usesUserData )
{
dcl_tangent $vUserData;
}
}
$cConstants0 = "c0";
$cZero = "c0.x";
$cOne = "c0.y";
$cTwo = "c0.z";
$cHalf = "c0.w";
$cConstants1 = "c1";
$cOOGamma = "c1.x";
#$cThree = "c1.y"; # NOTE NOTE NOTE: This is overbright now!!!! Don't use $cThree!!!
$cOneThird = "c1.z";
$cOverbrightFactor = "c1.w";
$cEyePos = "c2";
$cWaterZ = "c2.w";
$cEyePosWaterZ = "c2";
$cLightIndex = "c3";
$cLight0Offset = "c3.x"; # 27
$cLight1Offset = "c3.y"; # 32
$cColorToIntScale = "c3.z"; # 3.0f * 255.0f ~= 765.01
$cModel0Index = "c3.w"; # 42
# NOTE: These must match the same values in vsh_prep.pl!
$cModelViewProj0 = "c4";
$cModelViewProj1 = "c5";
$cModelViewProj2 = "c6";
$cModelViewProj3 = "c7";
$cViewProj0 = "c8";
$cViewProj1 = "c9";
$cViewProj2 = "c10";
$cViewProj3 = "c11";
# NOTE: These must match the same values in vsh_prep.pl!
$cModelView0 = "c12";
$cModelView1 = "c13";
$cModelView2 = "c14";
$cModelView3 = "c15";
$cFogParams = "c16";
$cFogEndOverFogRange = "c16.x";
$cFogOne = "c16.y";
$cHeightClipZ = "c16.z";
$cOOFogRange = "c16.w"; # (1/(fogEnd-fogStart))
$cViewModel0 = "c17";
$cViewModel1 = "c18";
$cViewModel2 = "c19";
$cViewModel3 = "c20";
$cAmbientColorPosX = "c21";
$cAmbientColorNegX = "c22";
$cAmbientColorPosY = "c23";
$cAmbientColorNegY = "c24";
$cAmbientColorPosZ = "c25";
$cAmbientColorNegZ = "c26";
$cAmbientColorPosXOffset = "21";
$cAmbientColorPosYOffset = "23";
$cAmbientColorPosZOffset = "25";
$cLight0DiffColor = "c27";
$cLight0Dir = "c28";
$cLight0Pos = "c29";
$cLight0SpotParams = "c30"; # [ exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
$cLight0Atten = "c31"; # [ constant, linear, quadratic, 0.0f ]
$cLight1DiffColor = "c32";
$cLight1Dir = "c33";
$cLight1Pos = "c34";
$cLight1SpotParams = "c35"; # [ exponent, stopdot, stopdot2, 1 / (stopdot - stopdot2)
$cLight1Atten = "c36"; # [ constant, linear, quadratic, 0.0f ]
# c37-c41 unused! (would be used for a third light if we had one)
$cClipDirection = "c37.x";
$cClipDirectionTimesHeightClipZ = "c37.y";
$cModulationColor = "c38";
$cThree = "c39.x";
# There are 16 model matrices for skinning
# NOTE: These must match the same values in vsh_prep.pl!
$cModel0 = "c42";
$cModel1 = "c43";
$cModel2 = "c44";
# the last cmodel is c89
# c90-c95 are reserved for shader specific constants
sub OutputUsedRegisters
{
local( $i );
; USED REGISTERS
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( $g_allocated[$i] )
{
; $g_allocatedname[$i] = r$i
}
}
;
}
sub AllocateRegister
{
local( *reg ) = shift;
local( $regname ) = shift;
local( $i );
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( !$g_allocated[$i] )
{
$g_allocated[$i] = 1;
$g_allocatedname[$i] = $regname;
; AllocateRegister $regname = r$i
$reg = "r$i";
&OutputUsedRegisters();
return;
}
}
; Out of registers allocating $regname!
$reg = "rERROR_OUT_OF_REGISTERS";
&OutputUsedRegisters();
}
# pass in a reference to a var that contains a register. . ie \$var where var will constain "r1", etc
sub FreeRegister
{
local( *reg ) = shift;
local( $regname ) = shift;
; FreeRegister $regname = $reg
if( $reg =~ m/rERROR_DEALLOCATED/ )
{
; $regname already deallocated
; $reg = "rALREADY_DEALLOCATED";
&OutputUsedRegisters();
return;
}
# if( $regname ne g_allocatedname[$reg] )
# {
# ; Error freeing $reg
# mov compileerror, freed unallocated register $regname
# }
if( ( $reg =~ m/r(.*)/ ) )
{
$g_allocated[$1] = 0;
}
$reg = "rERROR_DEALLOCATED";
&OutputUsedRegisters();
}
sub CheckUnfreedRegisters()
{
local( $i );
for( $i = 0; $i < $g_NumRegisters; $i++ )
{
if( $g_allocated[$i] )
{
print "ERROR: r$i allocated to $g_allocatedname[$i] at end of program\n";
$g_allocated[$i] = 0;
}
}
}
sub Normalize
{
local( $r ) = shift;
dp3 $r.w, $r, $r
rsq $r.w, $r.w
mul $r, $r, $r.w
}
sub Cross
{
local( $result ) = shift;
local( $a ) = shift;
local( $b ) = shift;
mul $result.xyz, $a.yzx, $b.zxy
mad $result.xyz, -$b.yzx, $a.zxy, $result
}
sub RangeFog
{
; Can either be viewPos or projPos since z should be the same for both.
local( $viewPos ) = shift;
;------------------------------
; Regular range fog
;------------------------------
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; compute fog factor f = (fog_end - dist)*(1/(fog_end-fog_start))
; this is == to: (fog_end/(fog_end-fog_start) - dist/(fog_end-fog_start)
; which can be expressed with a single mad instruction!
if( $g_dx9 )
{
mad oFog, -$viewPos.z, $cOOFogRange, $cFogEndOverFogRange
}
else
{
mad oFog.x, -$viewPos.z, $cOOFogRange, $cFogEndOverFogRange
}
}
sub WaterFog
{
; oFog.x = 1.0f = no fog
; oFog.x = 0.0f = full fog
; mov oFog.x, $cOne
; return;
; only $worldPos.z is used out of worldPos
local( $worldPos ) = shift;
local( $viewPos ) = shift;
; $viewPos.z is the distance from the eye to the vertex
local( $tmp );
&AllocateRegister( \$tmp );
; Calculate the ratio of the line of sight integral through the water to the total line
; integral
; These could both be done in a single add if cWaterZ and cEyePos.z were in the same constant
; add $tmp.x, $cWaterZ, -$worldPos.z
; add $tmp.y, $cEyePos.z, -$worldPos.z
add $tmp.xy, $cEyePosWaterZ.wz, -$worldPos.z
; $tmp.x is the distance from the water surface to the vert
; $tmp.y is the distance from the eye position to the vert
; if $tmp.x < 0, then set it to 0
; This is the equivalent of moving the vert to the water surface if it's above the water surface
max $tmp.x, $tmp.x, $cZero
; $tmp.w = $tmp.x / $tmp.y
rcp $tmp.z, $tmp.y
mul $tmp.w, $tmp.x, $tmp.z
; If the eye is under water, then always use the whole fog amount
; Duh, if the eye is under water, use regular fog!
; sge $tmp.z, $tmp.y, $cZero
; $tmp.z = 0 if the eye is underwater, otherwise $tmp.z = 1
; mul $tmp.w, $tmp.w, $tmp.z
; add $tmp.z, $cOne, -$tmp.z
; add $tmp.w, $tmp.w, $tmp.z
mul $tmp.w, $tmp.w, $viewPos.z
; $tmp.w is now the distance that we see through water.
if( $g_dx9 )
{
mad oFog, -$tmp.w, $cOOFogRange, $cFogOne
}
else
{
mad oFog.x, -$tmp.w, $cOOFogRange, $cFogOne
}
&FreeRegister( \$tmp );
}
#------------------------------------------------------------------------------
# Main fogging routine
#------------------------------------------------------------------------------
sub CalcFog
{
; CalcFog
local( $worldPos ) = shift;
local( $projPos ) = shift;
if( $g_fogType eq "rangefog" )
{
&RangeFog( $projPos );
}
elsif( $g_fogType eq "heightfog" )
{
&WaterFog( $worldPos, $projPos );
}
else
{
die;
}
}
sub DoHeightClip
{
; DoHeightClip
; $texReg = $cClipDirection * ( $cHeightClipZ - $worldPos.z )
; $texReg = $cClipDirection * $cHeightClipZ - $cClipDirection * $worldPos.z
; $const = $cClipDirection * $cHeightClipZ;
; $texReg = $const - $cClipDirection * $worldPos.z
; $texReg = ( - $cClipDirection * $worldPos.z ) + $const
local( $worldPos ) = shift;
local( $texReg ) = shift;
local( $tmp );
# Do a user clip plan using texkill in the case that we don't have
# a detail texture.
# optimize! Can probably do an arbitrary plane in one or two instructions.
if( 0 )
{
&AllocateRegister( \$tmp );
add $tmp, -$worldPos.z, $cHeightClipZ
# This determines which side we are clipping on.
mul $texReg, $tmp, $cClipDirection
&FreeRegister( \$tmp );
}
else
{
mad $texReg, -$cClipDirection, $worldPos.z, $cClipDirectionTimesHeightClipZ
}
}
sub GammaToLinear
{
local( $gamma ) = shift;
local( $linear ) = shift;
local( $tmp );
&AllocateRegister( \$tmp );
; Is rcp more expensive than just storing 2.2 somewhere and doing a mov?
rcp $gamma.w, $cOOGamma ; $gamma.w = 2.2
lit $linear.z, $gamma.zzzw ; r0.z = linear blue
lit $tmp.z, $gamma.yyyw ; r2.z = linear green
mov $linear.y, $tmp.z ; r0.y = linear green
lit $tmp.z, $gamma.xxxw ; r2.z = linear red
mov $linear.x, $tmp.z ; r0.x = linear red
&FreeRegister( \$tmp );
}
sub LinearToGamma
{
local( $linear ) = shift;
local( $gamma ) = shift;
local( $tmp );
&AllocateRegister( \$tmp );
mov $linear.w, $cOOGamma ; $linear.w = 1.0/2.2
lit $gamma.z, $linear.zzzw ; r0.z = gamma blue
lit $tmp.z, $linear.yyyw ; r2.z = gamma green
mov $gamma.y, $tmp.z ; r0.y = gamma green
lit $tmp.z, $linear.xxxw ; r2.z = gamma red
mov $gamma.x, $tmp.z ; r0.x = gamma red
&FreeRegister( \$tmp );
}
sub ComputeReflectionVector
{
local( $worldPos ) = shift;
local( $worldNormal ) = shift;
local( $reflectionVector ) = shift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -