How can I get Z-depth from unlit shader? - unity3d

Currently, I try to make z depth effect as Image Effect, but result image is not correctly rendered. something wrong...
If I use standard shader (unity 5), result image was correctly rendered(z depth image is ok), but not unlit shader.
what happen? if you have any idea, tell me why.
shader
Shader "Custom/RenderDepth"
{
Properties
{
_DepthLevel ("Depth Level", Range(1, 3)) = 2
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform sampler2D_float _CameraDepthTexture;
uniform fixed _DepthLevel;
uniform half4 _MainTex_TexelSize;
struct uinput
{
float4 pos : POSITION;
half2 uv : TEXCOORD0;
};
struct uoutput
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
uoutput vert(uinput i)
{
uoutput o;
o.pos = mul(UNITY_MATRIX_MVP, i.pos);
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, i.uv);
return o;
}
fixed4 frag(uoutput o) : COLOR
{
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
depth = pow(Linear01Depth(depth), _DepthLevel);
return depth;
}
ENDCG
}
}
}
CS
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class Test : MonoBehaviour
{
public Camera _cam;
public Material mat;
public float DepthLevel = 1.0F;
void Start ()
{
_cam.depthTextureMode |= DepthTextureMode.Depth;
}
void Update ()
{
}
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
mat.SetFloat("_DepthLevel", DepthLevel);
Graphics.Blit(source, destination, mat);
}
}

I've found this solution. I use the SHADOWCASTER pass from the VertexLit legacy shader prior to render my unlit object.
Then your shader would look like this:
Shader "Custom/RenderDepth"
{
Properties
{
_DepthLevel ("Depth Level", Range(1, 3)) = 2
}
SubShader
{
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform sampler2D_float _CameraDepthTexture;
uniform fixed _DepthLevel;
uniform half4 _MainTex_TexelSize;
struct uinput
{
float4 pos : POSITION;
half2 uv : TEXCOORD0;
};
struct uoutput
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
uoutput vert(uinput i)
{
uoutput o;
o.pos = mul(UNITY_MATRIX_MVP, i.pos);
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, i.uv);
return o;
}
fixed4 frag(uoutput o) : COLOR
{
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
depth = pow(Linear01Depth(depth), _DepthLevel);
return depth;
}
ENDCG
}
}
}

You need to provide a fallback option in the unlit shader so it can use the other needed passes (depth/shadow/etc) from this fallback shader.
Adding the following line to your unlit shader should help.
Fallback "Diffuse"

Related

Object is only visible to the left eye

I have a Unity project using MRTK.
After I changed the MRTK/Standard shader with the following shader, it only renders the object to the left eye.
How can I render the object to both eyes?
Shader "HoloUS/BrightnessContrast"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Width("Width", Float) = 1
_Center("Center", Float) = 0.5
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct VInp
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct VOut
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Center;
float _Width;
VOut vert(VInp inp)
{
VOut o;
o.vertex = UnityObjectToClipPos(inp.vertex);
o.uv = TRANSFORM_TEX(inp.uv, _MainTex);
return o;
}
fixed4 frag(VOut inp) : SV_Target
{
float min = _Center - _Width / 2;
return tex2D(_MainTex, inp.uv) * _Width + min;
}
ENDCG
}
}
}
For shaders with Hololens and MRTK2, there is an upgrade path perhaps that needs to be clicked through:
https://learn.microsoft.com/en-us/windows/mixed-reality/mrtk-unity/mrtk2/features/rendering/mrtk-standard-shader?q=shader&view=mrtkunity-2022-05
Also, Unity defines following on stereo rendering for HoloLens for shader script requirements:
https://docs.unity3d.com/Manual/SinglePassStereoRenderingHoloLens.html
From version of Unity, could not tell the specific version and MRTK version using in sample above. If have further details, perhaps can assist further too with community.
If you are using single pass vr, there are few changes in shader declaration, in order to recognise stereo texture input in single pass.
//add this in struct appdata
UNITY_VERTEX_INPUT_INSTANCE_ID
//add this in struct v2f
UNITY_VERTEX_OUTPUT_STEREO
//replace sampler2D
UNITY_DECLARE_SCREENSPACE_TEXTURE(_MainTex);
//add these inside v2f vert()
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
Additional link: Single Pass Instanced rendering

I can't implement the so-called pixel lighting in the 2d game on unity

I am creating a 2D unity game and my idea was to make pixel lighting. that is, as you approach the lantern, the objects will change color (according to the color palette).
the effect I want to get is shown below (this is a drawing so far).
I have no idea how such "lighting" can be implemented, at first I thought to do it using shader graph, but out of my stupidity I could not do it. (I tried many more options, but I never managed to implement my plans) for this, I ask for help from those who know.
I haven't worked with 2d lighting, so I'm not certain, but I have an old post processing shader that can pixelize and use a limited color pallet for the default render pipeline that might work for you.
Shader:
Shader "Custom/PixelPallet"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_ColorTheme("Theme", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D _ColorTheme;
float4 _MainTex_ST;
int _PixelDensity;
float2 _ScreenAspectRatioMultiplier;
float2 _SpriteAspectRatioMultiplier;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float2 pixelScaling = _PixelDensity * _ScreenAspectRatioMultiplier;
float2 pixelCoord = round(i.uv * pixelScaling)/ pixelScaling;
fixed4 value = tex2D(_MainTex, pixelCoord);
float2 coord = float2(value.r,value.g);
return tex2D(_ColorTheme, coord);
}
ENDCG
}
}
}
Post Process Script:
using UnityEngine;
public class PostEfect : MonoBehaviour
{
private Material mat;
public Texture texture;
public int pixelDensity = 80;
void Start()
{
mat = new Material(Shader.Find("Custom/PixelPallet"));
mat.SetTexture("_ColorTheme", texture);
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Vector2 aspectRatioData;
if (Screen.height > Screen.width)
aspectRatioData = new Vector2((float)Screen.width / Screen.height, 1);
else
aspectRatioData = new Vector2(1, (float)Screen.height / Screen.width);
mat.SetVector("_ScreenAspectRatioMultiplier", aspectRatioData);
mat.SetInt("_PixelDensity", pixelDensity);
// Read pixels from the source RenderTexture, apply the material, copy the updated results to the destination RenderTexture
Graphics.Blit(src, dest, mat);
}
}
Just drop the script on the camera and select a color pallet sprite with point filter. Adjust the pixel Density according to your needs.

Space curvature bending in Unity3D as Post Effect/Image Effect

I'm trying to archieve a chilindrical effect like this on Unity3D:
But every solution is using material based shader, sadly I must have a Post Process effect or an Image Effect, for these reasons:
One map out of 30 needs to use this effect and there are many materials that are shared between them...
Every solution is vertex based. I've done some experiments but I have models with different polygon count, this means that the effect would create visual artifacts (but this can by fixed by editing the 3d models eventually).
I'm at an advanced stage of development.
Do you think it's possible to create a simple effect (even a fake one) that moves the pixels downwards/upwards based on the distance to the camera? (I assume I need to use the depth map)
I've tried very hard but I had no success, the effect doesn't do anything or just won't compile :(
This is the best I could come up with, the grayscale in the frag method is only to check if the shader is working, but once I define the Vert function the grayscale disappears and the shader does nothing.
Shader "Hidden/Custom/WorldCurvature"
{
HLSLINCLUDE
#include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
float _Bend;
struct Attributes
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct Varyings
{
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
float4 Frag(Varyings i) : SV_Target
{
float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
float luminance = dot(color.rgb, float3(0.2126729, 0.7151522, 0.0721750));
color.rgb = lerp(color.rgb, luminance.xxx, _Bend.xxx);
return color;
}
Varyings Vert(Attributes v)
{
Varyings o;
float4 vv = mul(unity_ObjectToWorld, v.vertex );
vv.xyz -= _WorldSpaceCameraPos.xyz;
vv = float4( 0.0f, (vv.x * vv.x) * - _Bend, 0.0f, 0.0f );
v.vertex += mul(unity_WorldToCamera, vv);
o.vertex = mul(unity_WorldToCamera, vv);
o.texcoord = v.texcoord;
return o;
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
ENDHLSL
}
}
}
I've done another experiment but I think it would only work in a 2D environment, here the image stops once I activate the image effect:
Shader "Hidden/Custom/CylinderImageEffect" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Cull Off ZWrite Off ZTest Always
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert( appdata_img v )
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target {
i.uv.x = 1 - acos(i.uv.x * 2 - 1) / 3.14159265;
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
}

Use of UNITY_MATRIX_MV is detected

I took a billboard shader from the internet but I have this warning message that says "Shader warning in 'Custom/Billboard': Use of UNITY_MATRIX_MV is detected. To transform a vertex into view space, consider using UnityObjectToViewPos for better performance."
I'm not sure how to correct the code with the new function. Here is the shader:
Shader "Custom/Billboard"
{
Properties{
_MainTex("Texture Image", 2D) = "white" {}
_ScaleX("Scale X", Float) = 1.0
_ScaleY("Scale Y", Float) = 1.0
}
SubShader{
Tags{"Queue" = "Transparent" "RenderType" = "Transparent" }
Pass{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
uniform sampler2D _MainTex;
uniform float _ScaleX;
uniform float _ScaleY;
struct vertexInput {
float4 vertex : POSITION;
float4 tex : TEXCOORD0;
};
struct vertexOutput {
float4 pos : POSITION;
float4 tex : TEXCOORD0;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_P,
mul(UNITY_MATRIX_MV, float4(0,0,0,1))
+ float4(input.vertex.xyz, 0));
output.tex = input.tex;
return output;
}
float4 frag(vertexOutput input) : COLOR
{
return tex2D(_MainTex, float2(input.tex.xy));
}
ENDCG
}
}
}
You don't really need to do anything. If you do want to change it though, if nothing else just to make the warning go away, you can replace this:
mul(UNITY_MATRIX_MV, float4(0,0,0,1))
With this:
UnityObjectToViewPos((float3)0)

Saving fragment position into textures

I would like to store my fragment's world coordinates into 3 textures which respectively represent x,y,z coordinates of the coordinate. Despite the textures are in the format ARGB32, I cant seem to write a value bigger than 1.0 Here is my shader code. What is the proper way to do this?
Shader "Custom/FirstPass"
{
Properties { }
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 5.0
#include "UnityCG.cginc"
struct vertexData
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 color : COLOR;
float4 texcoord0 : TEXCOORD0;
//...
};
struct fragmentData
{
float4 positionC : SV_POSITION;
float4 positionW : TEXCOORD1;
//float4 color : COLOR;
//...
};
struct fragmentOutput
{
float Gx : SV_Target0;
float Gy : SV_Target1;
float Gz : SV_Target2;
float depth:SV_Target3;
};
fragmentData vert(vertexData v)
{
fragmentData o;
o.positionW=mul(unity_ObjectToWorld,v.vertex);
o.positionC=UnityObjectToClipPos(v.vertex);
return o;
}
fragmentOutput frag(fragmentData fragment)
{
fragmentOutput output;
output.Gx =fragment.positionW.x;
output.Gy= fragment.positionW.y;
output.Gz = fragment.positionW.z;
output.depth=fragment.positionC.z;
//... write to other renderbuffers
return output;
}
ENDCG
}
}
}