just created something very simple but useful - a cross section shader.

its simply fill up the back face with solid color and assign the x-axis-up normal on those faces

[ sample video ]

(the framework of the building and the wall of the room has been cut out by the shader)

is it useful to you too ??

2 Likes

That is a cool effect. A few people did something similar a few months ago.

Thanks for the link Daniel ! I just learnt how to use Shader.SetGlobalMatrix() from there

Also, we seem to use the same method, except I just made everthing inside the shader. (because, I am lazy :p)

Here is the test code of mine versionâ€¦ (diffuse shading only at the moment)

``````// Fast Edition - Single Pass

{
Properties
{
section_depth ("section depth (x, y, z, depth)", vector) = (0,0,0,0.15)
section_color ("section color", color) = (0.5,0.1, 0.1, 1)

color_map ("color map", 2D) = "white" {}

}
{
Pass
{
CULL OFF

CGPROGRAM //--------------

#include "UnityCG.cginc"

uniform float4 section_depth;
uniform float4 section_color;
uniform sampler2D color_map;

float4x4 rotate(float3 r)
{
float3 c, s;
sincos(r.x, s.x, c.x);
sincos(r.y, s.y, c.y);
sincos(r.z, s.z, c.z);
return float4x4( c.y*c.z,	 -s.z,     s.y, 0,
s.z, c.x*c.z,    -s.x, 0,
-s.y,     s.x, c.x*c.y, 0,
0,       0,       0, 1 );
}

struct a2v
{
float4 vertex	: POSITION;
float4 color	: COLOR;
float2 texcoord : TEXCOORD;
float3 normal	: NORMAL;
};

struct v2f
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float3 normal	: TEXCOORD1;
float4 vertex	: TEXCOORD2;
};

{
v2f OUT;

float4 c 	 = float4(IN.vertex.xyz,1);

OUT.position = mul(glstate.matrix.mvp, IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.normal   = IN.normal;
OUT.vertex	 = IN.vertex;

return OUT;
}

out float4 finalcolor : COLOR)

{

float3 obj_view_dir = IN.vertex.xyz - _ObjectSpaceCameraPos;
float fd = dot(obj_view_dir, IN.normal);
float3 N = (fd > 0) ? float3(1,0,0) : IN.normal;

N = mul(glstate.matrix.invtrans.modelview[0], float4(N, 1));
float diffuse = saturate(dot(glstate.light[0].position, N));

finalcolor = float4(0,0,0,1);
if (fd > 0)
{
finalcolor.xyz = section_color *(diffuse *0.6 +0.4);
return;
}
finalcolor.xyz = tex2D(color_map, IN.texcoord).xyz *(diffuse *0.6 +0.4);
}
ENDCG //--------------

} // Pass
``````

(Remark: the " +_SinTime.xyz" could be deleted. Thatâ€™s just for the demo)

EDIT: The old attachment â€ścross_section_v004.shaderâ€ť has been replaced by the following one.

``````r *= float4x4(1,-1,-1, 0, -1, 1,-1, 0, -1,-1, 1, 0, 0, 0, 0, 1 );
``````

(In the â€ś004aâ€ť version, one more line is added onto it. since, the â€śsection_depth.xyzâ€ť need to be inverted before assign to the capâ€™s normal.)

1 Like

Cool shader, thanks for sharing it. How are you hollowing out the spheres in the video?

Simply model it, a small flipped-face sphere inside a bigger sphere

In fact, you bring out a very good idea, why not add a â€śthickerâ€ť function onto the shader too. so that, I donâ€™t need to touch the modeling program anymore. (â€¦ save up some time to enjoy my coffee :p)

Many Thanks !

In my version I add a simple lighting equation to the cut surface too, that way it doesnâ€™t always have to be constant shaded. Nice that you managed to get all the clipping code into the shader though, very handy for clipping different objects with different planes.

Surely, I will add this in my code later

In fact, I still looking for the way to work with intersecting closed objects, by making a real cap

I have this nowâ€¦

(2 spheres, left with â€ścross sectionâ€ť shader and right with diffuse shader)

I am working on this method nowâ€¦ re-assign the depth value, but not success when the angle of the clipping plane is changed :s

``````float4 c 	 = float4(IN.vertex.xyz,1);
OUT.vpos 	 = mul(glstate.matrix.modelview[0], c);
``````

``````float3 N = IN.normal;
float z = IN.vpos.z;

if (IN.vpos.z > section_depth.w)
{
N = float3(1,0,0);
z = section_depth.w;
}

float near = _ProjectionParams.y;
float far  = _ProjectionParams.z;

float a = -far/(far-near);
float b = -far*near/(far-near);
depth 	= (a*z+b)/(-z);
``````

Any new idea ??

I guess youâ€™d actually need to project the x,y coordinate onto the clipping plane to get the depth and then test if the object depth was behind.

This is a very interesting approach, I really need to solve the intersection problem to make this useful for what I want and what you are suggesting here is interesting. The question is how do you determine what is â€śinsideâ€ť so as to only test the depth for the bits that should be capped? When 2 objects intersect you canâ€™t rely on the normals any more.

The attached shader doesnâ€™t appear to work in Unity 3.1 - is it still under development?

because that poor guy still using unity 2.6 to do the developmentâ€¦ in fact, the development will be resumed very soon

Hello Apple_motion, your work is very interesting.

Did you updated the shader for Unity 3.3?

Hi Apple_Motion,

I second the request for a Unity 3.3 update! Anyone else interested in this?

El Diablo

bump! Unity 3.3 update, willing to pay!! Apple motion, where are you?

Yes bump here too??

Q

bump

bump

Bump

I wanted to do the same thing and I believe the problem was because Unity 3 use Surface shader (so things are handled in another way â€¦)

The instruction â€śclipâ€ť can be used in the surface function . For instance, for a plane which the equation is a.x +b.y + c.z + d = 0 :

``````Shader "Custom/ClipShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_a ("_a",Float) = 0.0
_b ("_b",Float) = 0.0
_c ("_c",Float) = 0.0
_d ("_d",Float) = 0.0
_clip ("_clip",Float) = 0
}
Tags { "RenderType" = "Opaque" }
Cull Off
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float3 worldPos;
};

sampler2D _MainTex;
float _a,_b,_c,_d,_clip;

void surf (Input IN, inout SurfaceOutput o)
{
if(_clip == 1)
{
clip (_a *IN.worldPos.x +
_b *IN.worldPos.y +
_c *IN.worldPos.z +
_d > 0 ? -1 :1);
}

o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
``````

In a Unity script; you can activate the clipping plan using Shader.SetGlobalFloat(â€ś_clipâ€ť,1); and move the plan along its normal using Shader.SetGlobalFloat(â€ś_dâ€ť,d); However it seems that you must unexpose the variables from the property block if you want a Shader.SetGlobal function to work.

You can of course do a script to compute _a _b _c _d parameters according to a plan (gameobject) inside the scene to let the user create easily a clipping plane with a desired orientation;

You can rewrite other defaut Unity shaders (bump, alpha, etcâ€¦) , youâ€™ll juste have to add some properties and the clip instruction.

Tom

No, itâ€™s not an update because it doesnâ€™t work the same way.
It just uses the â€śclip(-1)â€ť function in the surface shader to exclude pixel that will be on one side of the plane for objects that use this shader so it creates a hole in the object.

I havent code the part to fill the intersected zone with a color/texture. I donâ€™t know how to do it but you can however easily change the color of a small part of the original object surface wich is near the clipping plane.

``````void surf (Input IN, inout SurfaceOutput o)
{
float dist = _a *IN.worldPos.x +_b *IN.worldPos.y +_c *IN.worldPos.z +_d;
if(_clip == 1  abs(dist) < 0.02)[COLOR="yellowgreen"]// fill the near surface in yellow[/COLOR]
{
fixed4 c = fixed4(1,1,0,1);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
else if(_clip == 1  dist < -0.02)  [COLOR="yellowgreen"]// exclude pixel outside the plane[/COLOR]
{
clip(-1);
}
else[COLOR="yellowgreen"] // normal diffuse display[/COLOR]
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
}
``````