Nice use of dot! I'll definitely remember that trick from now on for distance comparisons.
Let me just quickly note that I don't have DarkShader, and I am running a dual-boot computer with Linux and Windows. Windows can't connect to the internet because of drivers, so I'm writing this from my Linux boot.
Anyway, I have RenderMonkey installed on Windows, and modified the code a little so it works. I cannot guarantee it works straight away in DarkShader because I can't test it, I did however make the necessary modifications for it to theoretically work.
Quote: "The latter should make it white (which is what you wanted I think) whereas the original makes that bit black and/or transparent or something else other than white."
Black was my intention, because the parts outside of the clip sphere need to be invisible. If you made it white, you'd just see a distinct line across the object where the texture suddenly transitions into white. I think your intention was to "fill" the object with a colour so the cut off parts reveal it? It turns out this was a little more involved, but I got a solution below.
I had to change it so the distance check is performed in world space and not in projection space. I also added a way to colour the cut off parts of the object.
Here's the shader (again, although I made the necessary modifications for it to work in DarkShader, I can't test it myself):
// ------------------------------------------------
// A method to render only a certain part of an
// object within a defined sphere ("clip sphere")
// ------------------------------------------------
// author(s): TheComet, Green Gandalf
// version : 1.1.0
// ------------------------------------------------
// == Developer Comments ==
// [TheComet][2/25/13 - 00:32] The vertex shader and pixel shader currently both
// perform distance checks, which may be a little inefficient. If the model has
// a high poly-count, you might be able to get away with flagging the vertices
// outside of the clipsphere from within the vertex shader, and let the pixel
// shader use that information for colouring the cut off parts. If the model has
// a low poly-count, however, the colouring of cut off parts will look ugly and jagged.
// An idea for a future version would be to add a technique for high poly models,
// and a techhnique for low poly models.
//
//
// ------------------------------------------------
// ------------------------------------------------
// un-tweaks
// ------------------------------------------------
float4x4 matWorld : WORLD;
float4x4 matViewProjection : VIEWPROJECTION;
// ------------------------------------------------
// user variables
// ------------------------------------------------
float3 clipSpherePosition = {0.0f, 0.0f, 0.0f};
float3 clipSphereColour = {1.0f, 0.0f, 0.0f};
float clipSphereRadius
<
string UIWidget = "slider";
float UIMax = 100.0f;
float UIMin = 0.0f;
float UIStep = 0.5f;
> = 10.0f;
// ------------------------------------------------
// define textures
// ------------------------------------------------
texture diffuseTexture
<
string Name = "";
>;
// ------------------------------------------------
// define samplers
// ------------------------------------------------
sampler2D diffuseSampler = sampler_state
{
texture = <diffuseTexture>;
};
// ------------------------------------------------
// structs
// ------------------------------------------------
struct VS_INPUT
{
float4 position : POSITION;
float2 texCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 position : POSITION;
float2 texCoord : TEXCOORD0;
float3 transformedClipSpherePosition : TEXCOORD1;
float3 transformedPixelPosition : TEXCOORD2;
};
struct PS_INPUT
{
float2 texCoord : TEXCOORD0;
float3 transformedClipSpherePosition : TEXCOORD1;
float3 transformedPixelPosition : TEXCOORD2;
};
struct PS_OUTPUT
{
float4 finalColour : COLOR0;
};
// ------------------------------------------------
// vertex shader
// ------------------------------------------------
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
// transform vertex and clip sphere into world space (for distance check)
Output.transformedPixelPosition = mul( Input.position, matWorld );
Output.transformedClipSpherePosition = mul( clipSpherePosition, matWorld );
// check if vertex is outside of clip sphere
float3 difference = Output.transformedPixelPosition - Output.transformedClipSpherePosition;
if( dot(difference, difference) > clipSphereRadius*clipSphereRadius )
{
// position vertex onto surface of clip sphere
// NOTE: added a 0.01 bias factor so pixel shader
// can tell if it's within the clip sphere for colouring
Output.transformedPixelPosition = normalize(difference)*clipSphereRadius*1.01 + Output.transformedClipSpherePosition;
}
// transform vertex into projection space
Output.position = mul( float4(Output.transformedPixelPosition, 1.0f), matViewProjection );
// forward texture coordinates
Output.texCoord = Input.texCoord;
return( Output );
}
// ------------------------------------------------
// pixel shader
// ------------------------------------------------
PS_OUTPUT ps_main( PS_INPUT Input )
{
PS_OUTPUT Output;
// check if current pixel is within clip-sphere
float3 difference = Input.transformedPixelPosition - Input.transformedClipSpherePosition;
if( dot( difference, difference ) < clipSphereRadius*clipSphereRadius )
{
// sample output colour
Output.finalColour = tex2D( diffuseSampler, Input.texCoord );
// make pixel invisible (it is outside of clip-sphere)
}else{
Output.finalColour = float4( clipSphereColour, 1.0f );
}
return( Output );
}
// ------------------------------------------------
// techniques
// ------------------------------------------------
technique defaultTechnique
{
pass p0
{
vertexShader = compile vs_1_1 vs_main();
pixelShader = compile ps_2_0 ps_main();
}
}
Here's how to use it:
null = make vector4(1)
rem apply effect
load effect "the_above.fx", 1, 0
set object effect ObjectToClip, 1
rem -- snip --
rem in your main loop
rem the shader has 3 values you can change:
` clipSpherePosition (the position of the clip sphere in 3D space)
` clipSphereRadius (how large the clip sphere is)
` clipSphereColour (what colour the clipped areas of the object should have)
set vector4 1, character_pos_x, character_pos_y, character_pos_z, 0
set effect constant vector 1, "clipSpherePosition", 1
radius# = character_view_radius
set effect constant float 1, "clipSphereRadius", radius#
set vector4 1, red, green, blue, 0
set effect constant vector 1, "clipSphereColour", 1
The results (pretty gruesome, if I may say so):
To answer the question you put in comments:
Quote: "//edited by GG (changed brackets) - but did you want to avoid processing this pixel entirely?"
If you don't explicitly set the output pixel to 0, the GPU will output whatever was in the buffer last, which will appear as random noise on your screen. At least this is the case with OpenGL.
TheComet