- 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.
359 lines
13 KiB
HLSL
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 |