Last active
March 26, 2025 04:39
-
-
Save bshishov/3eaa056d1560584ff82c1b96ee2f20fd to your computer and use it in GitHub Desktop.
Unity3D simple screen-space decal shader. Does not support lighting. Works with LWRP. Just create a material with this shader and assign it to a cube (also disable shadows and collider). Thats it you've got a working decals.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Custom/SimpleDecal" | |
{ | |
Properties { | |
_MainTex ("Main Texture", 2D) = "white" {} | |
[HDR]_Color ("Color", Color) = (1, 1, 1, 1) | |
} | |
SubShader | |
{ | |
Tags { "RenderType"= "Transparent" "Queue" = "Transparent" } | |
Pass | |
{ | |
ZWrite Off | |
Lighting Off | |
Cull Back | |
Blend SrcAlpha OneMinusSrcAlpha | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
uniform half4 _Color; | |
uniform sampler2D _MainTex; | |
uniform sampler2D _CameraDepthTexture; | |
float4 _MainTex_ST; | |
struct VSInput | |
{ | |
float4 vertex : POSITION; | |
float3 texcoord : TEXCOORD0; | |
}; | |
struct VSOut | |
{ | |
float4 position :SV_POSITION; | |
float4 screenPos : TEXCOORD0; | |
float3 ray : TEXCOORD2; | |
}; | |
VSOut vert (VSInput v) | |
{ | |
VSOut o ; | |
o.position = UnityObjectToClipPos(v.vertex); | |
o.screenPos = ComputeScreenPos(o.position); | |
o.ray = UnityObjectToViewPos(v.vertex).xyz * float3(-1,-1,1); | |
// v.texcoord is equal to 0 when we are drawing 3D light shapes and | |
// contains a ray pointing from the camera to one of near plane's | |
// corners in camera space when we are drawing a full screen quad. | |
o.ray = lerp(o.ray, v.texcoord, v.texcoord.z != 0); | |
return o; | |
} | |
fixed4 frag(VSOut i): Color | |
{ | |
// Get correct view direction | |
i.ray = i.ray * (_ProjectionParams.z / i.ray.z); | |
// Get depth in the current pixel | |
float depth = Linear01Depth (SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.screenPos.xy / i.screenPos.w)); | |
// Get new projection coordinates. It is almost like original o.position, | |
// except that Z axis is using depth information. Such taht we are ignoring our projected object, Z values | |
float4 prjPos = float4(i.ray * depth,1); | |
float3 worldPos = mul(unity_CameraToWorld, prjPos).xyz; | |
float4 objPos = mul(unity_WorldToObject, float4(worldPos, 1)); | |
clip(float3(0.5, 0.5, 0.5) - abs(objPos.xyz)); | |
half2 uv = _MainTex_ST.xy * (objPos.xz + 0.5); | |
return tex2D(_MainTex, uv) * _Color; | |
} | |
ENDCG | |
} | |
} | |
FallBack "Unlit/Transparent" | |
} |
How would you make this work with an Orthographic camera?
@thunderawesome, I haven't test it with orthographic camera, there might be some issues with ProjectionParams, I guess. Probably some macro is missed or a special ifdef for ortho projection, not sure.
I'lll try to check the shader code later, I don't have much time right now.
This seems to have broken in Unity 2020.1.9f1 :/
Any workaround you know about for this? :)
This seems to have broken in Unity 2020.1.9f1 :/
Any workaround you know about for this? :)
Just tested it in 2019.3.10f1 - It works with default rendering settings but it seems like the default scene camera settings does not have depth rendering enabled.
Some workarounds:
- If it doesnt show up in scene view - enable lighting and postprocessing in scene view. See screenshot
- If it doesn't work in game view - make sure your camera has depth rendering enabled. You can force enable it from script by executing something like this:
Camera.main.depthTextureMode = DepthTextureMode.DepthNormals;
see DepthTextureMode docs for moe details - or switch camera rendering mode to deffered - it has depth buffer enabled by default.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How would you make this work with an Orthographic camera?