So I tried to create an unlit shader in unity using the built-in render pipeline and blit it to the screen using the function: OnRenderImage(RenderTexture src, RenderTexture dest)
in my C# code. I have been kind of loosely following this video:
(https://www.youtube.com/watch?v=DxfEbulyFcY&t=1138s)
among other things because my goal is to create a volumetric atmosphere shader. However, I seem to have multiple problems.
- The shader draws an oval shape, not a sphere (I suspect that this has something to do with the aspect ratio of the window, it's still not welcome though)
- The "sphere" is only drawn when the camera is at a certain angle or position. Meaning that if I tried to look at it from the back that it would just disappear
- The position seems to be way off from what the position and radius of the volume sphere seems too not be correct
I have done my best to read up and do my research on volumetric rendering, but I still don't quite understand what's going on here.
C# code (Attached to camera)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode, ImageEffectAllowedInSceneView]
public class ImageEffectManager : MonoBehaviour
{
public Shader effectShader;
public Transform volume;
Material mat;
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (mat == null && effectShader != null)
{
mat = new Material(effectShader);
}
//Set shader properties here:
mat.SetVector("_SphereCenter", volume.position);
mat.SetFloat("_SphereRadius", volume.GetComponent<SphereCollider>().radius);
//Draw the shader to the screen
Graphics.Blit(src, dest, mat);
}
}
HLSL Shader (goes into property effectShader
)
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '\_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unlit/ImageEffectTest"
{
Properties
{
\_MainTex ("Texture", 2D) = "white" {}
\_SphereCenter ("Sphere Center", Vector) = (0, 0, 0, 0) // editor's note: I dont know why the '\' got put at the beginning of each property when I copy+pasted the code, but I guess it's there now.
\_SphereRadius ("Sphere Radius", Float) = 1
}
SubShader
{
Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
Blend One Zero
Cull Off Lighting Off ZWrite Off
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float3 _SphereCenter;
float _SphereRadius;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
float2 raySphere(float3 sphereCenter, float sphereRadius, float3 rayOrigin, float3 rayDir)
{
float3 offset = rayOrigin - sphereCenter;
float a = 1;
float b = 2 * dot(offset, rayDir);
float c = dot(offset, offset) - sphereRadius * sphereRadius;
float d = b * b - 4 * a * c;
if (d > 0)
{
float s = sqrt(d);
float dstToSphereNear = max(0, (-b - s) / (2 * a));
float dstToSphereFar = (-b + s) / (2 * a);
if (dstToSphereFar >= 0)
{
return float2(dstToSphereNear, dstToSphereFar - dstToSphereNear);
}
}
return float2(3.402823466e+38, 0);
}
float4 frag (v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
float3 rayOrigin = _WorldSpaceCameraPos;
float3 rayDir = normalize(i.worldPos - _WorldSpaceCameraPos);
float2 hitInfo = raySphere(_SphereCenter, _SphereRadius, rayOrigin, rayDir);
float dstToAtmosphere = hitInfo.x;
float dstThroughAtmosphere = hitInfo.y;
return dstThroughAtmosphere / (_SphereRadius * 2);
}
ENDCG
}
}
}
Here's what I was trying to describe above
Here's an unlisted video I uploaded to make it easier to understand what's happening
I tried to switch some operators in the shader code, some macros, along with double-checking my work across some different sources such as this pretty helpful article: (https://www.alanzucconi.com/2016/07/01/volumetric-rendering/)
However, none of these made any kind of significant difference on the result that I was getting, so I finally decided to make this post.