Hello wonderful wizards of the shader world!
I've seen a few tutorials featuring the use of Raymarching via the older OnRenderImage function, however, that is no longer called in the new stack (what is the correct terminology -- is it SRP? Post Processing V2? HDRP?). The intention is to eventually add depth into the rendering so the raymarched objects can be culled/occluded in object space.
Anyways, here is my attempt at rendering a simple sphere. The issue here is the sphere is not being drawn until the camera is physically touching the sphere, at which point the entire viewport is drawing the sphere's color.
Post Processing Script
using System; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.PostProcessing; [Serializable] [PostProcess(typeof(DebugRenderer), PostProcessEvent.AfterStack, "Custom/Debug")] public sealed class Debug : PostProcessEffectSettings { public IntParameter maxIterations = new IntParameter { value = 64 }; public FloatParameter maxDistance = new FloatParameter { value = 100f }; public FloatParameter minDistance = new FloatParameter { value = 0.01f }; public DepthTextureMode GetCameraFlags() { return DepthTextureMode.Depth; //| DepthTextureMode.DepthNormals; } } public sealed class DebugRenderer : PostProcessEffectRenderer<Debug> { //public override DepthTextureMode GetCameraFlags() //{ // return DepthTextureMode.Depth; //} [SerializeField] private Shader _shader; public Material _raymarchMaterial { get { if (!_raymarchMat && _shader) { _raymarchMat = new Material(_shader); _raymarchMat.hideFlags = HideFlags.HideAndDontSave; } return _raymarchMat; } } private Material _raymarchMat; public Camera _camera { get { if (!_cam) { _cam = Camera.main; } return _cam; } } private Camera _cam; public override void Render(PostProcessRenderContext context) { if (!_cam) { _cam = Camera.main; } var sheet = context.propertySheets.Get(Shader.Find("Hidden/Debug")); sheet.properties.SetMatrix("_CamFrustum", FrustumCorners(_cam)); sheet.properties.SetMatrix("_CamToWorld", _cam.cameraToWorldMatrix); sheet.properties.SetVector("_CamWorldSpace", _cam.transform.position); sheet.properties.SetInt("_MaxIterations", settings.maxIterations); sheet.properties.SetFloat("_MaxDistance", settings.maxDistance); sheet.properties.SetFloat("_MinDistance", settings.minDistance); context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0); } private Matrix4x4 FrustumCorners(Camera cam) { Transform camtr = cam.transform; Vector3[] frustumCorners = new Vector3[4]; cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), cam.farClipPlane, cam.stereoActiveEye, frustumCorners); var bottomLeft = camtr.TransformVector(frustumCorners[0]); var topLeft = camtr.TransformVector(frustumCorners[1]); var topRight = camtr.TransformVector(frustumCorners[2]); var bottomRight = camtr.TransformVector(frustumCorners[3]); Matrix4x4 frustumCornersArray = Matrix4x4.identity; frustumCornersArray.SetRow(0, bottomLeft); frustumCornersArray.SetRow(1, bottomRight); frustumCornersArray.SetRow(2, topLeft); frustumCornersArray.SetRow(3, topRight); return frustumCornersArray; } } Shader
Shader "Hidden/Debug" { SubShader { Cull Off ZWrite Off ZTest Always Pass { HLSLPROGRAM #pragma target 3.5 #pragma vertex vert #pragma fragment frag //#include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl" //#include "HLSLSupport.cginc" #include "UnityCG.cginc" //TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex); uniform sampler2D _MainTex; uniform sampler2D_float _CameraDepthTexture; half4 _MainTex_ST; uniform float4 _CamWorldSpace; uniform float4x4 _CamFrustum, _CamToWorld; uniform int _MaxIterations; uniform float _MaxDistance; uniform float _MinDistance; float4 _Tint; uniform float4 _MainTex_TexelSize; struct AttributesDefault { float3 vertex : POSITION; half2 texcoord : TEXCOORD0; }; struct VaryingsDefault { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; //float2 uvStereo : TEXCOORD1; float2 uv_depth : TEXCOORD1; float4 interpolatedRay : TEXCOORD2; }; float LinearEyeDepth135( float z ) { return LinearEyeDepth( z ); } // Vertex manipulation float2 TransformTriangleVertexToUV(float2 vertex) { float2 uv = (vertex + 1.0) * 0.5; return uv; } VaryingsDefault vert(AttributesDefault v ) { VaryingsDefault o; v.vertex.z = 0.1; o.pos = float4(v.vertex.xy, 0.0, 1.0); o.uv = TransformTriangleVertexToUV(v.vertex.xy); o.uv_depth = v.texcoord.xy; #if UNITY_UV_STARTS_AT_TOP o.uv = o.uv * float2(1.0, -1.0) + float2(0.0, 1.0); #endif //o.uvStereo = TransformStereoScreenSpaceTex(o.uv, 1.0); #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1 - o.uv.y; #endif int frustumIndex = v.texcoord.x + (2 * o.uv.y); o.interpolatedRay = _CamFrustum[frustumIndex]; o.interpolatedRay.w = frustumIndex; return o; } float sdSphere(float3 position, float3 origin, float radius) { return distance(position, origin) - radius; } fixed4 raymarching(float3 ro, float3 rd) { fixed4 result = float4(1, 1, 1, 1); float t = 0; // Distance Traveled from ray origin (ro) along the ray direction (rd) for (int i = 0; i < _MaxIterations; i++) { if (t > _MaxDistance) { result = float4(rd, 1); // color backround from ray direction for debugging break; } float3 p = ro + rd * t; // This is our current position float d = sdSphere(ro, float3(0, 0, 0), 1); // should be a sphere at (0, 0, 0) with a radius of 1 if (d <= _MinDistance) // We have hit something { // shading result = float4(1, 1, 0, 1); // yellow sphere should be drawn at (0, 0, 0) break; } t += d; } return result; } float4 frag(VaryingsDefault i) : SV_Target { float4 wsDir = normalize(i.interpolatedRay); float4 wsPos = _CamWorldSpace; fixed4 result = raymarching(wsPos, wsDir); return result; } ENDHLSL } } } For reference, I am converting the C# script and shader from Peer Play's tutorial video to the SRP.
Anyways, thanks for reading, and please let me know if I can provide any more information.
Cheers!
Edit: I think the issue may be in the vert function as I am not handling v.vertex and o.vertex the same as in the video. This clashes with my limited understanding of what is going on in the VertDefault function found in PostProcessing/StdLib.hlsl
