Jamie Greunbaum 8eaef49f2e - Added game room, including pool and skee-ball.
- Moved video screen into its own separate movie tent.
- Adjusted stable post-processing volume.
- Chickens are now at full volume.
- Added button to toggle chickens off and on.
2026-02-09 03:49:54 -05:00

359 lines
13 KiB
HLSL

#ifndef FILAMENT_SHADING_LIT
#define FILAMENT_SHADING_LIT
#include "FilamentMaterialInputs.cginc"
#include "FilamentCommonMath.cginc"
#include "FilamentCommonGraphics.cginc"
#include "FilamentCommonLighting.cginc"
#include "FilamentCommonMaterial.cginc"
#include "FilamentCommonShading.cginc"
#if defined(SHADING_MODEL_SUBSURFACE)
#include "FilamentShadingSubsurface.cginc"
#elif defined(SHADING_MODEL_CLOTH)
#include "FilamentShadingCloth.cginc"
#else
#include "FilamentShadingStandard.cginc"
#endif
#include "FilamentLightIndirect.cginc"
#include "FilamentShadingLit.cginc"
#include "FilamentLightDirectional.cginc"
#include "FilamentLightPunctual.cginc"
#include "FilamentLightLTCGI.cginc"
#include "UnityStandardInput.cginc"
//------------------------------------------------------------------------------
// Lighting
//------------------------------------------------------------------------------
#if defined(BLEND_MODE_MASKED)
float computeMaskedAlpha(float a) {
// Use derivatives to smooth alpha tested edges
return (a - getMaskThreshold()) / max(fwidth(a), 1e-3) + 0.5;
}
float computeDiffuseAlpha(float a) {
// If we reach this point in the code, we already know that the fragment is not discarded due
// to the threshold factor. Therefore we can just output 1.0, which prevents a "punch through"
// effect from occuring. We do this only for TRANSLUCENT views in order to prevent breakage
// of ALPHA_TO_COVERAGE.
return (NEEDS_ALPHA_CHANNEL == 1.0) ? 1.0 : a;
}
void applyAlphaMask(inout float4 baseColor) {
baseColor.a = computeMaskedAlpha(baseColor.a);
if (baseColor.a <= 0.0) {
discard;
}
}
#else // not masked
float computeDiffuseAlpha(float a) {
#if defined(BLEND_MODE_TRANSPARENT) || defined(BLEND_MODE_FADE)
return a;
#else
return 1.0;
#endif
}
void applyAlphaMask(inout float4 baseColor) {}
#endif
#if defined(GEOMETRIC_SPECULAR_AA)
float normalFiltering(float perceptualRoughness, const float3 worldNormal) {
// Kaplanyan 2016, "Stable specular highlights"
// Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing"
// Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing"
// This implementation is meant for deferred rendering in the original paper but
// we use it in forward rendering as well (as discussed in Tokuyoshi and Kaplanyan
// 2019). The main reason is that the forward version requires an expensive transform
// of the half vector by the tangent frame for every light. This is therefore an
// approximation but it works well enough for our needs and provides an improvement
// over our original implementation based on Vlachos 2015, "Advanced VR Rendering".
float3 du = ddx(worldNormal);
float3 dv = ddy(worldNormal);
float variance = _specularAntiAliasingVariance * (dot(du, du) + dot(dv, dv));
float roughness = perceptualRoughnessToRoughness(perceptualRoughness);
float kernelRoughness = min(2.0 * variance, _specularAntiAliasingThreshold);
float squareRoughness = saturate(roughness * roughness + kernelRoughness);
return roughnessToPerceptualRoughness(sqrt(squareRoughness));
}
#endif
void getCommonPixelParams(const MaterialInputs material, inout PixelParams pixel) {
float4 baseColor = material.baseColor;
applyAlphaMask(baseColor);
#if defined(BLEND_MODE_FADE) && !defined(SHADING_MODEL_UNLIT)
// Since we work in premultiplied alpha mode, we need to un-premultiply
// in fade mode so we can apply alpha to both the specular and diffuse
// components at the end
unpremultiply(baseColor);
#endif
#if defined(SHADING_MODEL_SPECULAR_GLOSSINESS)
// This is from KHR_materials_pbrSpecularGlossiness.
float3 specularColor = material.specularColor;
float metallic = computeMetallicFromSpecularColor(specularColor);
pixel.diffuseColor = computeDiffuseColor(baseColor, metallic);
pixel.f0 = specularColor;
#elif !defined(SHADING_MODEL_CLOTH)
pixel.diffuseColor = computeDiffuseColor(baseColor, material.metallic);
#if !defined(SHADING_MODEL_SUBSURFACE) && (!defined(MATERIAL_HAS_REFLECTANCE) && defined(MATERIAL_HAS_IOR))
float reflectance = iorToF0(max(1.0, material.ior), 1.0);
#else
// Assumes an interface from air to an IOR of 1.5 for dielectrics
float reflectance = computeDielectricF0(material.reflectance);
#endif
pixel.f0 = computeF0(baseColor, material.metallic, reflectance);
#else
pixel.diffuseColor = baseColor.rgb;
pixel.f0 = material.sheenColor;
#if defined(MATERIAL_HAS_SUBSURFACE_COLOR)
pixel.subsurfaceColor = material.subsurfaceColor;
#endif
#endif
#if !defined(SHADING_MODEL_CLOTH) && !defined(SHADING_MODEL_SUBSURFACE)
#if defined(HAS_REFRACTION)
// Air's Index of refraction is 1.000277 at STP but everybody uses 1.0
const float airIor = 1.0;
#if !defined(MATERIAL_HAS_IOR)
// [common case] ior is not set in the material, deduce it from F0
float materialor = f0ToIor(pixel.f0.g);
#else
// if ior is set in the material, use it (can lead to unrealistic materials)
float materialor = max(1.0, material.ior);
#endif
pixel.etaIR = airIor / materialor; // air -> material
pixel.etaRI = materialor / airIor; // material -> air
#if defined(MATERIAL_HAS_TRANSMISSION)
pixel.transmission = saturate(material.transmission);
#else
pixel.transmission = 1.0;
#endif
#if defined(MATERIAL_HAS_ABSORPTION)
#if defined(MATERIAL_HAS_THICKNESS) || defined(MATERIAL_HAS_MICRO_THICKNESS)
pixel.absorption = max(0.0, material.absorption);
#else
pixel.absorption = saturate(material.absorption);
#endif
#else
pixel.absorption = 0.0;
#endif
#if defined(MATERIAL_HAS_THICKNESS)
pixel.thickness = max(0.0, material.thickness);
#endif
#if defined(MATERIAL_HAS_MICRO_THICKNESS) && (REFRACTION_TYPE == REFRACTION_TYPE_THIN)
pixel.uThickness = max(0.0, material.microThickness);
#else
pixel.uThickness = 0.0;
#endif
#endif
#endif
}
void getSheenPixelParams(const ShadingParams shading, const MaterialInputs material, inout PixelParams pixel) {
#if defined(MATERIAL_HAS_SHEEN_COLOR) && !defined(SHADING_MODEL_CLOTH) && !defined(SHADING_MODEL_SUBSURFACE)
pixel.sheenColor = material.sheenColor;
float sheenPerceptualRoughness = material.sheenRoughness;
sheenPerceptualRoughness = clamp(sheenPerceptualRoughness, MIN_PERCEPTUAL_ROUGHNESS, 1.0);
#if defined(GEOMETRIC_SPECULAR_AA)
sheenPerceptualRoughness =
normalFiltering(sheenPerceptualRoughness, shading.geometricNormal);
#endif
pixel.sheenPerceptualRoughness = sheenPerceptualRoughness;
pixel.sheenRoughness = perceptualRoughnessToRoughness(sheenPerceptualRoughness);
#endif
}
void getClearCoatPixelParams(const ShadingParams shading, const MaterialInputs material, inout PixelParams pixel) {
#if defined(MATERIAL_HAS_CLEAR_COAT)
pixel.clearCoat = material.clearCoat;
// Clamp the clear coat roughness to avoid divisions by 0
float clearCoatPerceptualRoughness = material.clearCoatRoughness;
clearCoatPerceptualRoughness =
clamp(clearCoatPerceptualRoughness, MIN_PERCEPTUAL_ROUGHNESS, 1.0);
#if defined(GEOMETRIC_SPECULAR_AA)
clearCoatPerceptualRoughness =
normalFiltering(clearCoatPerceptualRoughness, shading.geometricNormal);
#endif
pixel.clearCoatPerceptualRoughness = clearCoatPerceptualRoughness;
pixel.clearCoatRoughness = perceptualRoughnessToRoughness(clearCoatPerceptualRoughness);
#if defined(CLEAR_COAT_IOR_CHANGE)
// The base layer's f0 is computed assuming an interface from air to an IOR
// of 1.5, but the clear coat layer forms an interface from IOR 1.5 to IOR
// 1.5. We recompute f0 by first computing its IOR, then reconverting to f0
// by using the correct interface
pixel.f0 = lerp(pixel.f0, f0ClearCoatToSurface(pixel.f0), pixel.clearCoat);
#endif
#endif
}
void getRoughnessPixelParams(const ShadingParams shading, const MaterialInputs material, inout PixelParams pixel) {
#if defined(SHADING_MODEL_SPECULAR_GLOSSINESS)
float perceptualRoughness = computeRoughnessFromGlossiness(material.glossiness);
#else
float perceptualRoughness = material.roughness;
#endif
// This is used by the refraction code and must be saved before we apply specular AA
pixel.perceptualRoughnessUnclamped = perceptualRoughness;
#if defined(GEOMETRIC_SPECULAR_AA)
perceptualRoughness = normalFiltering(perceptualRoughness, shading.geometricNormal);
#endif
#if defined(MATERIAL_HAS_CLEAR_COAT) && defined(MATERIAL_HAS_CLEAR_COAT_ROUGHNESS)
// This is a hack but it will do: the base layer must be at least as rough
// as the clear coat layer to take into account possible diffusion by the
// top layer
float basePerceptualRoughness = max(perceptualRoughness, pixel.clearCoatPerceptualRoughness);
perceptualRoughness = lerp(perceptualRoughness, basePerceptualRoughness, pixel.clearCoat);
#endif
// Clamp the roughness to a minimum value to avoid divisions by 0 during lighting
pixel.perceptualRoughness = clamp(perceptualRoughness, MIN_PERCEPTUAL_ROUGHNESS, 1.0);
// Remaps the roughness to a perceptually linear roughness (roughness^2)
pixel.roughness = perceptualRoughnessToRoughness(pixel.perceptualRoughness);
}
void getSubsurfacePixelParams(const MaterialInputs material, inout PixelParams pixel) {
#if defined(SHADING_MODEL_SUBSURFACE)
pixel.subsurfacePower = material.subsurfacePower;
pixel.subsurfaceColor = material.subsurfaceColor;
pixel.thickness = saturate(material.thickness);
#endif
}
void getAnisotropyPixelParams(const ShadingParams shading, const MaterialInputs material, inout PixelParams pixel) {
#if defined(MATERIAL_HAS_ANISOTROPY)
float3 direction = material.anisotropyDirection;
pixel.anisotropy = material.anisotropy;
pixel.anisotropicT = normalize(mul(shading.tangentToWorld, direction));
pixel.anisotropicB = normalize(cross(shading.geometricNormal, pixel.anisotropicT));
#endif
}
void getEnergyCompensationPixelParams(const ShadingParams shading, inout PixelParams pixel) {
// Pre-filtered DFG term used for image-based lighting
pixel.dfg = prefilteredDFG(pixel.perceptualRoughness, shading.NoV);
#if !defined(SHADING_MODEL_CLOTH)
// Energy compensation for multiple scattering in a microfacet model
// See "Multiple-Scattering Microfacet BSDFs with the Smith Model"
pixel.energyCompensation = 1.0 + pixel.f0 * (1.0 / pixel.dfg.yyy - 1.0);
#else
pixel.energyCompensation = (1.0);
#endif
#if !defined(SHADING_MODEL_CLOTH)
#if defined(MATERIAL_HAS_SHEEN_COLOR)
pixel.sheenDFG = prefilteredDFG(pixel.sheenPerceptualRoughness, shading.NoV).z;
pixel.sheenScaling = 1.0 - max3(pixel.sheenColor) * pixel.sheenDFG;
#endif
#endif
}
/**
* Computes all the parameters required to shade the current pixel/fragment.
* These parameters are derived from the MaterialInputs structure computed
* by the user's material code.
*
* This function is also responsible for discarding the fragment when alpha
* testing fails.
*/
void getPixelParams(const ShadingParams shading, const MaterialInputs material, out PixelParams pixel) {
pixel = (PixelParams)0;
getCommonPixelParams(material, pixel);
getSheenPixelParams(shading, material, pixel);
getClearCoatPixelParams(shading, material, pixel);
getRoughnessPixelParams(shading, material, pixel);
getSubsurfacePixelParams(material, pixel);
getAnisotropyPixelParams(shading, material, pixel);
getEnergyCompensationPixelParams(shading, pixel);
}
/**
* This function evaluates all lights one by one:
* - Image based lights (IBL)
* - Directional lights
* - Punctual lights
*
* Area lights are currently not supported.
*
* Returns a pre-exposed HDR RGBA color in linear space.
*/
float4 evaluateLights(const ShadingParams shading, const MaterialInputs material) {
PixelParams pixel;
getPixelParams(shading, material, pixel);
// Ideally we would keep the diffuse and specular components separate
// until the very end but it costs more ALUs on mobile. The gains are
// currently not worth the extra operations
float3 color = 0.0;
// We always evaluate the IBL as not having one is going to be uncommon,
// it also saves 1 shader variant
#if defined(UNITY_PASS_FORWARDBASE)
evaluateIBL(shading, material, pixel, color);
#endif
#if defined(HAS_DIRECTIONAL_LIGHTING)
evaluateDirectionalLight(shading, material, pixel, color);
#endif
#if defined(HAS_DYNAMIC_LIGHTING)
evaluatePunctualLights(shading, pixel, color);
#endif
#if defined(BLEND_MODE_FADE) && !defined(SHADING_MODEL_UNLIT)
// In fade mode we un-premultiply baseColor early on, so we need to
// premultiply again at the end (affects diffuse and specular lighting)
color *= material.baseColor.a;
#endif
return float4(color, computeDiffuseAlpha(material.baseColor.a));
}
void addEmissive(const MaterialInputs material, inout float4 color) {
#if defined(MATERIAL_HAS_EMISSIVE)
float4 emissive = material.emissive;
//float attenuation = lerp(1.0, frameUniforms.exposure, emissive.w);
// Exposure not supported yet
float attenuation = emissive.w;
color.rgb += emissive.rgb * (attenuation * color.a);
#endif
}
/**
* Evaluate lit materials. The actual shading model used to do so is defined
* by the function surfaceShading() found in shading_model_*.fs.
*
* Returns a pre-exposed HDR RGBA color in linear space.
*/
float4 evaluateMaterial(const ShadingParams shading, const MaterialInputs material) {
float4 color = evaluateLights(shading, material);
addEmissive(material, color);
return color;
}
#endif // FILAMENT_SHADING_LIT