浏览代码

Add support for volumetric projector lights and cookies

/sample_game
Evgenii Golubev 7 年前
当前提交
9e666ace
共有 2 个文件被更改,包括 54 次插入17 次删除
  1. 47
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute
  2. 24
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl

47
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute


// Fetch the light.
LightData lightData = _LightDatas[punctualLightIndex];
int lightType = lightData.lightType;
float3 sampleToLight = lightData.positionWS - samplePositionWS;
float3 lightToSample = samplePositionWS - lightData.positionWS;
float distSq = dot(sampleToLight, sampleToLight);
float distSq = dot(lightToSample, lightToSample);
float3 L = sampleToLight * rsqrt(distSq);
float3 L = lightToSample * -rsqrt(distSq);
float LdotD = dot(L, ray.directionWS);
float phase = HenyeyGreensteinPhaseFunction(asymmetry, LdotD);
float3 lightT = Transmittance(OpticalDepthHomogeneous(extinction, dist));

float attenuation = (lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius) : 1;
float attenuation = GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius);
// Reminder: lights are oriented backward (-Z)
attenuation *= GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);

// TODO: make projector lights cast shadows.
float3 offset = 0; // GetShadowPosOffset(nDotL, normal);
shadow = GetPunctualShadowAttenuation(context.shadowContext, samplePositionWS + offset, 0, lightData.shadowIndex, float4(L, dist), posInput.unPositionSS);
shadow = GetPunctualShadowAttenuation(context.shadowContext, samplePositionWS + offset, 0,
lightData.shadowIndex, float4(L, dist), posInput.unPositionSS);
[branch] if (lightData.cookieIndex >= 0)
{
// Translate and rotate 'positionWS' into the light space.
// 'lightData.right' and 'lightData.up' are pre-scaled on CPU.
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
float3 positionLS = mul(lightToSample, transpose(lightToWorld));
float4 cookie;
[branch] if (lightType == GPULIGHTTYPE_POINT)
{
cookie = SampleCookieCube(context, positionLS, lightData.cookieIndex);
}
else
{
// Compute the NDC position (in [-1, 1]^2) by projecting 'positionWS' onto the plane at 1m distance.
// Box projector lights require no perspective division.
float perspectiveZ = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1;
float2 positionNDC = positionLS.xy / perspectiveZ;
bool isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1 - positionLS.z) <= 1;
// Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2.
float2 coord = positionNDC * 0.5 + 0.5;
// We let the sampler handle clamping to border.
cookie = SampleCookie2D(context, coord, lightData.cookieIndex);
cookie.a = isInBounds ? cookie.a : 0;
}
// Premultiply.
lightData.color *= cookie.rgb;
attenuation *= cookie.a;
}
// Compute the amount of in-scattered radiance.
radiance += (dt * scattering * phase * attenuation * shadow) * (lightT * sampleT) * lightData.color;
}

if (pixelCoord.x >= (uint)_ScreenSize.x || pixelCoord.y >= (uint)_ScreenSize.y) { return; }
// Idea: zenith angle based distance limiting to simulate aerial perspective?
#ifdef UNITY_REVERSED_Z
float z = max(LOAD_TEXTURE2D(_DepthTexture, pixelCoord).r, 0 + 0.001);
#else

24
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


float3 positionLS = mul(lightToSurface, transpose(lightToWorld));
float2 positionNDC = positionLS.xy;
float clipFactor;
bool isInBounds;
// Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2.
float2 coord = positionNDC * 0.5 + 0.5;

// Tile the texture if the 'repeat' wrap mode is enabled.
coord = frac(coord);
clipFactor = 1;
isInBounds = true;
bool isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1 - positionLS.z) <= 1;
clipFactor = isInBounds ? 1 : 0;
isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1 - positionLS.z) <= 1;
}
// We let the sampler handle tiling or clamping to border.

cookie.a = isInBounds ? cookie.a : 0;
cookie.a *= clipFactor;
lightData.color *= cookie.rgb;
lightData.diffuseScale *= cookie.a;
lightData.specularScale *= cookie.a;

float illuminance = saturate(NdotL);
// Note: lightData.invSqrAttenuationRadius is 0 when applyRangeAttenuation is false
float attenuation = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius) : 1;
float attenuation = GetDistanceAttenuation(distSq, lightData.invSqrAttenuationRadius);
// Reminder: lights are oriented backward (-Z)
attenuation *= GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);

float4 L_dist = { L, dist };
shadow = GetPunctualShadowAttenuation(lightLoopContext.shadowContext, positionWS + offset, bsdfData.normalWS, lightData.shadowIndex, L_dist, posInput.unPositionSS);
shadow = lerp(1.0, shadow, lightData.shadowDimmer);
illuminance *= shadow;
shadow *= Transmittance(OpticalDepthHomogeneous(preLightData.globalFogExtinction, dist));
float3 volumetricShadow = Transmittance(OpticalDepthHomogeneous(preLightData.globalFogExtinction, dist));
// Premultiply.
lightData.color *= volumetricShadow;
illuminance *= shadow;
// Projector lights always have a cookie.
[branch] if (lightData.cookieIndex >= 0)

float perspectiveZ = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1;
float2 positionNDC = positionLS.xy / perspectiveZ;
bool isInBounds = Max3(abs(positionNDC.x), abs(positionNDC.y), 1 - positionLS.z) <= 1;
float clipFactor = isInBounds ? 1 : 0;
cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
cookie.a *= clipFactor;
cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
cookie.a = isInBounds ? cookie.a : 0;
}
// Premultiply.

正在加载...
取消
保存