Hello,
I was running into this problem trying to write a volumatic shader for meta quest 3
since, normally, a ray marching shader would need to calculate the ray direction from vertex and camera position, I used _WorldSpaceCameraPos to get the camera position in my urp shader.
and it seems, it returns always the left eye camera’s position. so when looking into left eye only, everything seems fine. but the stereo works incorrectly, since the camera position didn’t change with eyes, the ray stays with the vertex, ande everything got a little transformed exactly along the geometrie itself. and the result in stereo was, it looks like the volum was a flat texture on the surface of the geometrie.
here’s what it looks
and in case I got any low level mistakes in my code, here is the shader:
Shader "Custome/volumn_cloud_simple_2"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
_Main_Texture_Scale("Main Texture Scale", Float) = 1
_HeightTex("Height Texture", 2D) = "white" {}
_Height_Texture_Scale("Height Texture Scale", Float) = 1
_TorrentTex("Torrent Texture", 2D) = "Black" {}
_Torrent_Texture_Scale("Torrent Texture Scale", Float) = 1
_TextTex_Transform("Text Texture Transform", Vector) = (1,1,0,0)
_Color("Main Color", Color) = (1,1,1,1)
_Alpha("Main Alpha", Range(0,1)) = 1
_Density("Density", Float) = 1
_Ray_Step("Ray Steps" , Int) = 10
_Trace_Back_Threashold("Trace Back Threashold", Range(0,1)) = 0.5
_Stride_Length("Stride Length", Float) = 1
_Light_Fac("Light Factor", Float) = 1
_Absorbtion_Rate("Absorbtion Rate", Float) = 1
_Height("Height", Float) = 0
_Bottom("Bottom", Float) = 0
_Velocity("Velocity", Float) = 1
_Bottom_Light_Color("Bottom Light Color", Color) = (0,0,0,1)
_Bottom_Light_Strength("Bottom Light Strength", Float) = 1
_Fade_Color("Fade Color",Color) = (1,1,1,1)
_Test_Value("Test Value", Float)= 1
[Space]
_ZWrite("Depth Write", Float) = 0.0
_ZTestMode("Z Test Mode", Float) = 4
}
SubShader
{
Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "RenderPipeline" = "UniversalPipeline" }
Blend One OneMinusSrcAlpha
Cull Back
ZWrite On
ZTest Less
Pass
{
HLSLPROGRAM
// Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct v2f members vertex_World)
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile SHAKE_UV_OFF SHAKE_UV_ON
#pragma multi_compile JELLY_UV_OFF JELLY_UV_ON
//#include "UnityCG.cginc"
#define UNIVERSAL_FORWARD_LIT_PASS_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#if defined(LOD_FADE_CROSSFADE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
#endif
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal: NORMAL;
float4 tangent : TANGENT;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float2 uv : TEXCOORD0;
//UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float4 vertex_world: TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
struct FragmentOutput
{
float4 color : SV_Target;
float depth : SV_Depth;
};
sampler2D _MainTex;
sampler2D _HeightTex;
sampler2D _TorrentTex;
sampler2D _TextTex;
float _Main_Texture_Scale;
float _Height_Texture_Scale;
float _Torrent_Texture_Scale;
float4 _TextTex_Transform;
float4 _MainTex_ST, _MainTex_TexelSize, _Color;
float _Alpha, _RandomSeed;
float _Light_Fac;
float _Density;
int _Ray_Step;
float _Trace_Back_Threashold;
float _Stride_Length;
float _Absorbtion_Rate;
float _Height;
float _Bottom;
float _Velocity;
float4 _Bottom_Light_Color;
float _Bottom_Light_Strength;
float _Text_Strength;
float4 _Fade_Color;
float _Test_Value;
float4 _HitEffectColor;
float _Thickness;
float _HitEffectGlow, _HitEffectBlend;
float _ShakeUvSpeed, _ShakeUvX, _ShakeUvY;
float _JellyUvSpeed, _JellyUvXStrength, _JellyUvYStrength, _JellyUvX, _JellyUvY;
int _Steps;
v2f vert (appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
//UNITY_INITIALIZE_OUTPUT(v2f, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex_world = mul(unity_ObjectToWorld, v.vertex);
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
return o;
}
float form_texture(sampler2D tex, float2 uv){
return tex2D(tex,uv).r;
}
float3 density_top_bottom(float3 pos, float3 true_pos){
float3 object_pos = mul(unity_WorldToObject,float4(pos,1)).xyz;
float3 true_boject_pos = mul(unity_WorldToObject,float4(true_pos,1)).xyz;
float2 flowing_torrent_uv = true_boject_pos.xz*_Torrent_Texture_Scale;
float texture_height = min(0.5,(form_texture(_HeightTex,object_pos.xz*_Height_Texture_Scale))+ _Height);
float height = texture_height;
float top = height - object_pos.y;
float bottom = object_pos.y - _Bottom;
float density = max(0,min(1,min(top,bottom)*25));
bottom = length(mul((float3x3)unity_ObjectToWorld,float3(0,bottom,0)));
top = length(mul((float3x3)unity_ObjectToWorld,float3(0,top,0)));
return float3(density,top,bottom);
}
float3 flow_pos(float3 pos){
float2 flowing_torrent_uv = mul(unity_WorldToObject,float4(pos,1)).xz;
flowing_torrent_uv.x += 0.5;
flowing_torrent_uv.y += _Time.x*_Velocity/2500000;
flowing_torrent_uv *= _Torrent_Texture_Scale;
float3 flowing_pos = pos;
flowing_pos.z += _Time.x*_Velocity;
flowing_pos.z += tex2D(_TorrentTex,flowing_torrent_uv).r*7000;
return flowing_pos;
}
float3 flowing_density_top_bottom(float3 pos){
float3 _flowing_density = 0.5*density_top_bottom(flow_pos(pos),pos);
return _flowing_density;
}
float4 density_integra_in_direction(float3 origin, float3 direction, int ray_step, float stride_length, float phase){
float result = 0;
float3 stride = normalize(direction)*stride_length;
for(int i=0;i<ray_step;i++){
result += stride_length*flowing_density_top_bottom(origin + stride * i)[0];
}
return result;
}
float4 density_integra_to_target(float3 origin, float3 target, int ray_step, float stride_length, float phase){
return density_integra_in_direction(origin, target - origin, ray_step, stride_length, phase);
}
float3 calculate_light(float3 light_color, float density_integra){
float3 color = light_color*exp(-density_integra*_Absorbtion_Rate*0.00001*pow(_Density,0.5));
return color;
}
float3 get_light_add(Light light,float3 current_pos, float current_pos_density,int ray_step, float stride_length, float phase, float density_integra){
float3 light_color = light.color.rgb*_Light_Fac*0.001;
float3 light_direction = light.direction;
return calculate_light(calculate_light(light_color,density_integra_in_direction(current_pos,light_direction,ray_step,stride_length,1)),density_integra)*current_pos_density/100;
}
float3 get_light_add_verticle(Light top_light, Light bottom_light, float top, float bottom, float current_pos_density, float density_integra){
return calculate_light(calculate_light(bottom_light.color.xyz*_Light_Fac*0.001,bottom)+calculate_light(top_light.color.xyz*_Light_Fac*0.001,top),density_integra)*current_pos_density/100;
}
bool need_traceBack(float previous, float current, float threashold){
if(abs(previous-current)>threashold){
return true;
}else{
return false;
}
}
FragmentOutput color_of_ray(float3 origin, float3 direction, int ray_step, float relative_stride_length, float background_depth, int trace_back, int trace_count){
float stride_length = length(direction)*relative_stride_length/abs(direction.y);
float3 light_accumulation = float3(0,0,0);
float density_integra = 0;
float3 stride = normalize(direction)*stride_length;
float surfaceDepth = 0;
float current_step = 0;
float3 current_pos = origin;
int trace_count_left = trace_count;
bool traced = false;
float3 current_pos_density;
float3 previous_pos_density = flowing_density_top_bottom(origin);
float3 previous_light_add = float3(0,0,0);
for(int i=0;i<ray_step;i++){ //begin marching of a ray of light
float stride_fac = 0;
current_pos_density = flowing_density_top_bottom(current_pos);
if (need_traceBack(current_pos_density[0],previous_pos_density[0],_Trace_Back_Threashold) && trace_count_left>0){
float3 first_stride = stride;
//go back for trace_back
float density_distance = current_pos_density[0]-previous_pos_density[0];
float3 trace_pos = current_pos;
float3 trace_pos_density = current_pos_density;
float3 trace_stride = -stride*0.5;
bool Previous_inCloud = true;
bool Current_inCloud = false;
for (int j=0;j<trace_back;j++){
trace_pos += trace_stride;
first_stride += trace_stride;
trace_pos_density = flowing_density_top_bottom(trace_pos);
if((trace_pos_density[0]-previous_pos_density[0])/density_distance>0.5){
Current_inCloud = true;
}else{
Current_inCloud = false;
}
if(Previous_inCloud == Current_inCloud){
trace_stride = trace_stride*0.5;
}else{
trace_stride = -trace_stride*0.5;
}
Previous_inCloud = Current_inCloud;
}
trace_count_left -= 1;
stride_fac = length(first_stride)/stride_length;
}
float current_depth = length(current_pos-_WorldSpaceCameraPos);
float depth_Fac;
if(current_depth-background_depth<0){
depth_Fac = 1;
}else{
depth_Fac = 0;
}
density_integra += stride_length*(stride_fac*previous_pos_density[0]+(1-stride_fac)*current_pos_density[0])*depth_Fac;
Light light = GetMainLight();
//float light_stride_length = length(light.direction)*relative_stride_length/abs(light.direction.y);
//light_stride_length = stride_length;
//light_accumulation += get_light_add(light,current_pos,current_pos_density[0],ray_step,light_stride_length,1,density_integra);
Light bottom_light = GetMainLight();
bottom_light.color = tex2D(_MainTex,mul(unity_WorldToObject,-float4(current_pos,1)).xz*_Main_Texture_Scale+float2(0.5,0.5)).rgb*_Bottom_Light_Strength;
bottom_light.color += _Bottom_Light_Color;
//bottom_light.color += tex2D(_TextTex,mul(unity_WorldToObject,float4(current_pos,1)).xz*_TextTex_Transform.xy+_TextTex_Transform.zw).r*_Color*70;
Light top_light = GetMainLight();
float3 light_add = get_light_add_verticle(top_light, bottom_light, current_pos_density[1],current_pos_density[2],current_pos_density[0],density_integra)*stride_length;
//light_accumulation += get_light_add(light,current_pos,current_pos_density[0],ray_step,light_stride_length,1,density_integra)*stride_length;
light_accumulation += (stride_fac*previous_light_add+(1-stride_fac)*light_add)*depth_Fac;
//light.direction = float3(0,-1,0);
//light_stride_length = length(light.direction)*relative_stride_length/abs(light.direction.y)*2;
//light_stride_length = stride_length;
//light_accumulation += get_light_add(light,current_pos,ray_step,light_stride_length,1,density_integra);
/*for (int lightIndex = 0; lightIndex < 1; ++lightIndex){
light = GetAdditionalLight(lightIndex,current_pos);
light_stride_length = length(light.direction)*relative_stride_length/abs(light.direction.y);
//light_stride_length = stride_length;
light_accumulation += get_light_add(light,current_pos,ray_step,light_stride_length,1,density_integra);
}*/
current_pos += stride;
previous_pos_density = current_pos_density;
previous_light_add = light_add;
}
float alpha = density_integra*_Density/100000;
//light_accumulation = float4(0,0,0,density_integra);
//light_accumulation *= alpha;
float fade_fac = pow(length(origin.xz)/length(origin.xyz),200);
FragmentOutput output = (FragmentOutput)0;
output.color = (1-fade_fac)*float4(light_accumulation,alpha)+fade_fac*_Fade_Color;
output.depth = surfaceDepth;
return output;
}
FragmentOutput frag (v2f i) : SV_Target
{
float2 UV = i.vertex.xy / _ScaledScreenParams.xy;
#if UNITY_REVERSED_Z
real depth = SampleSceneDepth(UV);
#else
real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
#endif
float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
float3 ray_direction = i.vertex_world.xyz - _WorldSpaceCameraPos.xyz;
float background_depth = length(worldPos-_WorldSpaceCameraPos.xyz);
FragmentOutput output = color_of_ray(i.vertex_world,ray_direction,_Ray_Step,_Stride_Length/_Ray_Step,background_depth,4,2);
return output;
}
ENDHLSL
}
}
}
did I miss anything? or did I misundertand any part of the rendering process?
if _WorldSpaceCameraPos was supposed to return the exact camera position in world space, (which should be consistent with the matrices, then it seem to be a bug that they won’t agree with each other?)
(so Actually I’m also trying some work around like recalculating the camera position from the given matrix, since the geometrie was correct. )
Thank you!