[
Edit Oops. I forgot I changed various things in the demo. I've attached the whole new project here. Hopefully the new version will work now.]
Here's my first attempt at implementing Diggsey's suggestion. It uses the object's normals to adjust the object's vertices for each of 32 render passes. Works reasonably well for a sphere but not for a cube. (The problem is my implementation - Diggsey's idea is fine.

)
Here's the revised .dba code:
` simple sponge shader demo - illustrates one use of a volume texture (with Diggsey's shader suggestions)
` by Green Gandalf
` created 16 May 2010, modified 16 May 2010
set display mode desktop width(), desktop height(), 32
sync on: sync rate 60: sync
autocam off
load effect "sponge v2.fx",1, 0
sphere$ = "no"
if sphere$ = "yes"
position camera 0, 80, -180
point camera 0, 0, 0
make object sphere 1, 100
scale object 1, 200, 80, 130
set object effect 1, 1
set effect constant float 1, "scale1", 0.25
else
make object cube 1, 100
position camera 0, 100, -200
point camera 0, 0, 0
set object effect 1, 1
set effect constant float 1, "scale1", 0.5
endif
load image "sponge64.dds", 1, 3
load image "perl1a.png", 2
texture object 1, 0, 1
texture object 1, 1, 2
set object transparency 1, 6
`set effect constant float 1, "scale", 0.1
`set effect constant float 1, "invScale", 10.0
`set effect constant float 1, "cubeSize", 50.1 ` slightly bigger than the max cube vertex values
set effect constant float 1, "scale2", 0.1
set effect constant float 1, "noiseScale", 5.0
set effect constant float 1, "darken", 0.93 ` should be a number slightly less than 1
`set effect constant float 1, "invVolSize", 0.0078125
repeat
text 20, 20, "fps = " + str$(screen fps())
rotate object 1, object angle x(1)+0.2, object angle y(1)+0.13, 0.0
sync
until spacekey()
end
and here's the revised shader:
// Simple shader using a volume texture to give a sponge effect - uses suggestions proposed by Diggsey
//
// Created 12 May 2010, edited 16 May 2010.
//
matrix mWVP : WorldViewProjection;
matrix mW : World;
matrix mWI : WorldInverse;
float4 eyePos : CameraPosition;
//float scale = 0.02;
//float invScale = 50.0;
float4 spongeColour = {1.0, 1.0, 0.0, 1.0};
//float cubeSize = 50.1;
//float invVolSize = 0.015625; // =1/64, i.e. assumes volume map is 64x64x64 pixels
//const int slices = 32; // this must be the same as the upper limit of the for loop counter in the pixel shader
float noiseScale = 0.2;
float darken = 0.9;
float scale1 = 1.0;
float scale2 = 0.1;
texture volumeMap
< string type = "VOLUME";
string ResourceName = "";
>;
sampler3D volumeSample = sampler_state
{ texture = <volumeMap>;
minFilter = linear;
magFilter = linear;
mipFilter = linear;
addressU = wrap;
addressV = wrap;
addressW = wrap;
};
texture noiseMap
< string ResourceName = "";
>;
sampler2D noiseSample = sampler_state
{ texture = <noiseMap>;
minFilter = linear;
magFilter = linear;
mipFilter = linear;
addressU = wrap;
addressV = wrap;
};
struct VSInput
{ float4 pos : position;
float2 UV0 : texcoord0;
float3 normal : normal;
};
struct VSOutput
{ float4 pos : position;
float2 UV0 : texcoord0;
float3 UVW : texcoord1;
// float3 oView : texcoord2;
// float3 oPos : texcoord3;
};
VSOutput VShader(VSInput In, VSOutput Out, uniform int layer)
{ float4 oPos = In.pos;
oPos.xyz -= In.normal * scale1 * layer;
// float4
// Out.oPos = In.pos.xyz;
Out.pos = mul(oPos, mWVP);
Out.UV0 = In.UV0;
Out.UVW = oPos.xyz * scale2;
// Out.oView = In.pos.xyz - mul(eyePos, mWI).xyz;
return Out;
}
struct PSOutput
{ float4 col : color;
};
PSOutput PShader(VSOutput In, PSOutput Out, uniform int layer)
{ // initialize variables
// float depthStep = 1.0;
// float depth = 0.0;
float3 holeUVW = In.UVW + tex2D(noiseSample, In.UV0.xy).r*noiseScale;
// float3 rayStep = normalize(In.oView)*invVolSize;
// float3 pos = In.oPos;
// float3 spongeStep = rayStep*invScale;
// loop through the relevant layers of the volume map to calculate the sponge effect
// for (int i=0; i<32; i++)
// { depthStep *= 1.0-tex3D(volumeSample, holeUV).r * (abs(pos.x)<cubeSize)*(abs(pos.y)<cubeSize)*(abs(pos.z)<cubeSize);
// depth += depthStep;
// holeUV += rayStep;
// pos += spongeStep;
// }
float hole = tex3D(volumeSample, holeUVW).r;
// float alpha = slices - depth + (abs(pos.x)<cubeSize)*(abs(pos.y)<cubeSize)*(abs(pos.z)<cubeSize);
Out.col = float4 (pow(darken, layer)*spongeColour.rgb, hole);
return Out;
}
technique volumeTest
{ pass p0
{ VertexShader = compile vs_2_0 VShader(0);
PixelShader = compile ps_2_0 PShader(0);
}
pass p1
{ VertexShader = compile vs_2_0 VShader(1);
PixelShader = compile ps_2_0 PShader(1);
}
pass p2
{ VertexShader = compile vs_2_0 VShader(2);
PixelShader = compile ps_2_0 PShader(2);
}
pass p3
{ VertexShader = compile vs_2_0 VShader(3);
PixelShader = compile ps_2_0 PShader(3);
}
pass p4
{ VertexShader = compile vs_2_0 VShader(4);
PixelShader = compile ps_2_0 PShader(4);
}
pass p5
{ VertexShader = compile vs_2_0 VShader(5);
PixelShader = compile ps_2_0 PShader(5);
}
pass p6
{ VertexShader = compile vs_2_0 VShader(6);
PixelShader = compile ps_2_0 PShader(6);
}
pass p7
{ VertexShader = compile vs_2_0 VShader(7);
PixelShader = compile ps_2_0 PShader(7);
}
pass p8
{ VertexShader = compile vs_2_0 VShader(8);
PixelShader = compile ps_2_0 PShader(8);
}
pass p9
{ VertexShader = compile vs_2_0 VShader(9);
PixelShader = compile ps_2_0 PShader(9);
}
pass p10
{ VertexShader = compile vs_2_0 VShader(10);
PixelShader = compile ps_2_0 PShader(10);
}
pass p11
{ VertexShader = compile vs_2_0 VShader(11);
PixelShader = compile ps_2_0 PShader(11);
}
pass p12
{ VertexShader = compile vs_2_0 VShader(12);
PixelShader = compile ps_2_0 PShader(12);
}
pass p13
{ VertexShader = compile vs_2_0 VShader(13);
PixelShader = compile ps_2_0 PShader(13);
}
pass p14
{ VertexShader = compile vs_2_0 VShader(14);
PixelShader = compile ps_2_0 PShader(14);
}
pass p15
{ VertexShader = compile vs_2_0 VShader(15);
PixelShader = compile ps_2_0 PShader(15);
}
pass p16
{ VertexShader = compile vs_2_0 VShader(16);
PixelShader = compile ps_2_0 PShader(16);
}
pass p17
{ VertexShader = compile vs_2_0 VShader(17);
PixelShader = compile ps_2_0 PShader(17);
}
pass p18
{ VertexShader = compile vs_2_0 VShader(18);
PixelShader = compile ps_2_0 PShader(18);
}
pass p19
{ VertexShader = compile vs_2_0 VShader(19);
PixelShader = compile ps_2_0 PShader(19);
}
pass p20
{ VertexShader = compile vs_2_0 VShader(20);
PixelShader = compile ps_2_0 PShader(20);
}
pass p21
{ VertexShader = compile vs_2_0 VShader(21);
PixelShader = compile ps_2_0 PShader(21);
}
pass p22
{ VertexShader = compile vs_2_0 VShader(22);
PixelShader = compile ps_2_0 PShader(22);
}
pass p23
{ VertexShader = compile vs_2_0 VShader(23);
PixelShader = compile ps_2_0 PShader(23);
}
pass p24
{ VertexShader = compile vs_2_0 VShader(24);
PixelShader = compile ps_2_0 PShader(24);
}
pass p25
{ VertexShader = compile vs_2_0 VShader(25);
PixelShader = compile ps_2_0 PShader(25);
}
pass p26
{ VertexShader = compile vs_2_0 VShader(26);
PixelShader = compile ps_2_0 PShader(26);
}
pass p27
{ VertexShader = compile vs_2_0 VShader(27);
PixelShader = compile ps_2_0 PShader(27);
}
pass p28
{ VertexShader = compile vs_2_0 VShader(28);
PixelShader = compile ps_2_0 PShader(28);
}
pass p29
{ VertexShader = compile vs_2_0 VShader(29);
PixelShader = compile ps_2_0 PShader(29);
}
pass p30
{ VertexShader = compile vs_2_0 VShader(30);
PixelShader = compile ps_2_0 PShader(30);
}
pass p31
{ VertexShader = compile vs_2_0 VShader(31);
PixelShader = compile ps_2_0 PShader(31);
}
}
This version seems to be faster as Diggsey claimed. It has the additional advantage that it compiles using PS2 which is supported by a wider range of graphics cards - and the main vertex and pixel shader codes are simpler. There are problems near the edges of the objects when viewed from certain angles - I'll see if I can fix those tomorrow. For the moment though the important thing is that Diggsey's idea works.

