Shadow Catcher?

Not sure of the TouchDesigner way of rendering a shadow without rendering the object that the shadow is on?

Maybe some way to make the object transparent but the shadow not?

Soft shadows preferably…

It’s a shader in Cinema 4D (where it is called a Shadow Catcher).

Basically want an RGBA output with objects and shadows.

Bruce

Sure is. You just have to constrain your render to only render the objects you want. In this example, the ground plane is rendered but the torus is not.

EDIT…

WAIT. I just re-read your post, let me try to wrap my head around what that would look like.
base_only_shadows.tox (2.75 KB)

Easiest to conceive of it in two passes. One is the alpha of each object, and the alpha of a shadow, the other is RGB of foreground stuff.

They just happen to end up in one RGBA movie.

I could probably hack it as two passes with a white shadow or something, just wondering if there’s a known technique.

Bruce

Using a custom GLSL shader, with TDHardShadow/TDSoftShadow you could get the shadow value for the pixel. Then you can output alpha based on that value. You can do this in a separate color buffer to avoid the need to do two passes.

Great! I’ll do that.

Bruce

Bruce, did you succeed with the shader?
I am trying to write the mentioned GLSL shader as I am looking for exactly the same, but I’m a novice…

Best, Robert

Wow, I don’t recall. Don’t have time to try it now but if you start I can maybe help?

Bruce

Yeah, long ago the last post, also realized :wink:

So, I want to create an surreal effect for a theater-show where an projector is used to “project shadow” without the physical light situation being changed.

I created a scene with a body geometry, lights and a floor geometry, where the shadows should be casted onto. The rendered image will then be projected on the stage.

Now, I want to kind-of separate the shadow of the body, keeping the rest of the lighting situation constant.
So my idea was to create a GLSL material that has either a constant color (white) when there’s no shadow on it or it’s gonna be black when there’s a shadow…

I created a simple (erroneous) pixel shader with sth like that (here with red and green):

[code]
out vec4 outColor;

void main()
{
if(TDHardShadow(0, uTDLights[0].direction)==1.0)
outColor = vec4(0,1,0,1);
else
outColor = vec4(1,0,0,1);
}[/code]

Of course uTDLights[0].direction is incorrect…

My problem now is that I am confused with

 float TDHardShadow(int lightIndex, vec3 camSpaceVert);

What exactly does

camSpaceVert refer to? :question:

Best, Robert

Sounds like fun!

camSpaceVert refers to a position (vert as in vertex position) in the ‘camera space’, meaning that position and scale etc is based on the camera properties as opposed to the world space, which is how vertices will arrive in a vertex shader.

There are TD functions to convert a vertex position between different spaces - essentially converting from an absolute position to a position relative to the cameras.

Had a quick look - this is the bible: [url]https://docs.derivative.ca/index.php?title=Write_a_GLSL_Material[/url]

And there’s a clue here:

// For example you'd transform the vertex in SOP space into camera space with this line of code // vec4 camSpaceVert = uTDMats[TDCameraIndex()].worldCam * vec4(P, 1.0);

But in 099, it looks like a worldspace position would work:

float TDHardShadow(int lightIndex, vec3 worldSpacePos);<br> // This one will apply soft shadows with both 25 search steps done, and 25 filter samples. float TDSoftShadow(int lightIndex, vec3 worldSpacePos);<br> // Allows for control of search steps and filter samples. float TDSoftShadow(int lightIndex, vec3 worldSpacePos, int samples, int searchSteps);

OK, sounds reasonable.
So, the vertex in camera space also refers to the currently processed pixel, just in a different space?
So I would have to figure the current pixel and find the corresponding vertex in camera space?

I was also looking in these transformation function but was wondering that they all return vec4… I seem to be looking for some vec3

I think it may be the light? Pixel probably already in camspace, I think?

To get a vec3 from vec4 use myVertex.xyz

Hmm, does not seem to be working :frowning:

Changed the vertex to the light position in cam space:

[code]
out vec4 outColor;

void main()
{
if(TDHardShadow(0, uTDLights[0].position.xyz)>0.5)
outColor = vec4(0,1,0,1);
else
outColor = vec4(1,0,0,1);

}[/code]

Here’s the rendering without material:
[url]https://ibb.co/dRh9d8[/url]

And here with material:
[url]https://ibb.co/j2HWrT[/url]

Edit:

If I change the light source to “distant light”, the material changes to completely green… So at least sth is happening :wink:

OK, I think the problem is obviously I am lacking some basic understanding of how shaders work.

In the “Writing GLSL material” tut, I stumbled upon:

So, I think I have to somehow pass the vertex in cam space from the vertex shader to the pixel shader and then pass it to TDHardShadow()…

SOLVED:

That actually was the right path and it was quite easy to solve:

Vertex shader:

[code]
out vec3 vertex;

void main()
{

vertex = P.xyz;

// P is the position of the current vertex
// TDDeform() will return the deformed P position, in world space.
// Transform it from world space to projection space so it can be rasterized
gl_Position = TDWorldToProj(TDDeform(P));

}[/code]

Pixel shader:

[code]
out vec4 outColor;
in vec3 vertex;

void main()
{

if(TDHardShadow(0, vertex )>0)

	outColor = vec4(0,1,0,1);
else
	outColor = vec4(1,0,0,1);

}[/code]

Render result:
[url]https://ibb.co/mnzTo8[/url]

Nice work! Before you solved it, I was going to say that the pixel position in a fragment shader should already be in camera space, so it may just work. But yes, you need some sort of minimum code in vertex shader too.

What I would have replied to your previous question is that the vertex shader runs once per vertex in your model, but shadowing happens in the fragment shader, per pixel, so your answer probably laid there.

I always try to start a shader from the phong material, with as many elements I need all fleshed out, so there’s no custom TD stuff missed off in my custom shader.

Bruce

Thanks a lot for all the advice! I’m really happy it works now (and that I learned the very very basics of how shaders work haha).

Hmm, moved it to a new project and got strange results,
had to change it to

vertex =TDDeform(P).xyz

which would convert the vertex to world space if I understood correct - strange…

Wasn’t it that in the docs of 088 the param was requested in world, in 099 in camera space. Maybe a bug in the docs?

Can you post your whole code that you had to change it to?

I changed it to:
Vertex:

 out vec3 vertex;
 
 void main()
 {
 	vertex =TDDeform(P).xyz;
 
    // P is the position of the current vertex
    // TDDeform() will return the deformed P position, in world space.
    // Transform it from world space to projection space so it can be rasterized
    gl_Position = TDWorldToProj(TDDeform(P));
 }

Pixel:

[code]
out vec4 outColor;
in vec3 vertex;

void main()
{

if(TDHardShadow(0,vertex )>0)  
	outColor = vec4(0,0,0,1);
else
	outColor = vec4(1,1,1,1);

}[/code]

Then shadows looked right.

(with the initial “vertex = P.xyz” they were completely odd and different from the shadow rendered without the GLSL material).

As I found this line in the “Write GLSL Material” docs

I even changed

vertex =TDDeform(P).xyz;

to

vertex =TDDeform(vec4(P, 1.0)).xyz;

but it didn’t change the outcome and everything looked still correct…