FogShadows
Пробую сделать тени для тумана, вроде бы иду в правильном направлении, но появились артефакты при построении тени из карты теней. На первый взгляд может показаться что все нормально. Но, если поворочать камерой и посмотреть на картинку под разными углами, то можно заметить вот такую пьянку:
+ Показать
− Скрыть
static float4 WorldPosFromDepth(float depth, float2 uv, float4x4 invViewMat, bool relativeToCamera = false)
{
const float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22);
const float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23);
const float isOrtho = unity_OrthoParams.w;
const float near = _ProjectionParams.y;
const float far = _ProjectionParams.z;
float d = depth;
#if defined(UNITY_REVERSED_Z)
d = 1 - d;
#endif
float zOrtho = lerp(near, far, d);
float zPers = near * far / lerp(far, near, d);
float vz = lerp(zPers, zOrtho, isOrtho);
float3 vpos = float3((uv * 2 - 1 - p13_31) / p11_22 * lerp(vz, 1, isOrtho), -vz);
float4 wpos = mul(invViewMat, float4(vpos, relativeToCamera ? 0 : 1));
return wpos;
}
Pass
{
Name "FogShadowsInterleavePass"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
UNITY_DECLARE_SHADOWMAP(ShadowMap);
SamplerState fogShadow_point_repeat_sampler;
uniform Texture2D<float> _CameraDepthTexture;
uniform Texture2D fogShadowInterleaveTex;
//float3 volFogShadowRange;
float4x4 InverseViewMatrix;
float4x4 InverseProjectionMatrix;
struct v2f
{
float4 vertex : SV_POSITION;
float2 viewportTC : TEXCOORD;
float3 ray : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert (appdata_img v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
o.viewportTC = ComputeScreenPos(o.vertex);
float4 clipPos = float4( v.texcoord * 2.0 - 1.0, 1.0, 1.0);
float4 cameraRay = mul(InverseProjectionMatrix, clipPos);
o.ray = cameraRay / cameraRay.w;
return o;
}
fixed4 getCascadeWeights(float z)
{
float4 zNear = float4( z >= _LightSplitsNear );
float4 zFar = float4( z < _LightSplitsFar );
float4 weights = zNear * zFar;
return weights;
}
fixed4 getShadowCoord(float4 worldPos, float4 weights)
{
float3 shadowCoord = float3(0,0,0);
if(weights[0] == 1){
shadowCoord += mul(unity_WorldToShadow[0], worldPos).xyz;
}
if(weights[1] == 1){
shadowCoord += mul(unity_WorldToShadow[1], worldPos).xyz;
}
if(weights[2] == 1){
shadowCoord += mul(unity_WorldToShadow[2], worldPos).xyz;
}
if(weights[3] == 1){
shadowCoord += mul(unity_WorldToShadow[3], worldPos).xyz;
}
return float4(shadowCoord, 1);
}
float2 frag(v2f IN) : COLOR
{
float depth = _CameraDepthTexture.Sample(fogShadow_point_repeat_sampler, IN.viewportTC);
float sceneDepth = depth; //min(depth, volFogShadowRange.x);
const int numShadowSamples = 16;
const int numTotalShadowSamples = 8 * 8 * numShadowSamples;
float3 cameraToWorldPos = WorldPosFromDepth(sceneDepth, IN.viewportTC, InverseViewMatrix, true);
float lindepth = Linear01Depth(depth);
float4 viewPos = float4(IN.ray.xyz * lindepth, 0);
float3 worldPos = mul(InverseViewMatrix, viewPos).xyz;
float4 weights = getCascadeWeights(-viewPos.z);
half shadowOccl = 0;
for (int i = 0; i < numShadowSamples; i++)
{
float offset = (float)i / numShadowSamples;
float4 sampleWPos = float4(offset * cameraToWorldPos.xyz + _WorldSpaceCameraPos.xyz, 0);
float4 shadowCoord = getShadowCoord(float4(sampleWPos.xyz, 1), weights);
float shadowSample = UNITY_SAMPLE_SHADOW(ShadowMap, shadowCoord);
shadowOccl += shadowSample;
}
float refDepth = sceneDepth;// * volFogShadowRange.y;
shadowOccl /= (float)numShadowSamples;
return float2(refDepth, shadowOccl);
}
ENDCG
}
Target
> Хелп ми
Не делай тени от тумана. Слишком они лагучие.
Target
там можно делать огромное количество очень сильных оптимизаций, ты реализовал самый базовый/наивный вариант. например, эти тени можно считать в низком разрешении (x4 меньше разрешение -> x16 меньше пикселей -> x16 быстрее), далее можно апсемплить не как попало, а используя depth aware upsampling, далее можно для каждого пикселя смещать луч на случайную долю от шага (то есть прибавляешь к положению на луче шаг, помноженный на случайную величину 0..1, посчитанную для этого пикселя), далее можно эту случайную величину распределить не белым шумом, а байеровыми матрицами, либо синим шумом.
Suslik
Это понятно, что тут реализация в лоб без предварительных ласок) За направление пасибо, ну и я как бы совсем новичок в технологиях, потому все так вот простецки. Однако хотелось бы узнать, с чего такие артефакты могут вылезать?
Target
> Однако хотелось бы узнать, с чего такие артефакты могут вылезать?
очевидно, потому что ты шагаешь с каким-то конечным шагом по туману. поэтому точки с i-го шага на всех пикселях в совокупности образуют плоскости, расстояние между которыми равно шагу реймарчинга. количество плоскостей равно количеству шагов. чем меньше шаг, тем ближе будут плоскости и тем ровнее они будут сливаться в непрерывный объём, но тем дороже будет шейдер.
Suslik А, в общем, выявил проблемное место, чем меньше дальность теней - тем больше выражаются эти косяки. В общем, проблема с выборкой между каскадами, нужно учитывать дальность теней
а, у думал, ты другие артефакты имел в виду. энивей, сперва я бы советовал сделать нормально один каскад, потому уже больше прикручивать.
Suslik проблему решил просто. Для первого каскада заюзал не unity_WorldToShadow[0] а unity_WorldToShadow[1]
UPD: а хотя не, рано радовался. В общем с одним каскадом пока сделаю, так корректно хотя бы работает
Короче, увеличил дальность теней и поднастроил каскады, проблема ушла. Однако как-то не удобно это, зависеть от дальности теней и настроек дальности каскадов.
ясное дело, в общем случае туман внутри каждого каскада надо считать отдельно. считать пересечение луча с первым каскадом, интегрировать внутри него, далее со следующим, далее со следующим итд. в худшем случае (если смотришь вдоль направления источника света) придётся интегрировать по всем каскадам последовательно.
стохастически это делать не вариант что-ли со случайной длиной шага?
MrOcelot
надо не длину шага стохастически выбирать, а оффсет по лучу — он должен быть от нуля до размера одного шага, равномерно распределённый.
Suslik
как то ты странно меня поправил на синоним
Suslik та я смещение уже добавил посредством текстуры шума