REAL y = 1.5707921083647782 + x * (-0.9995697178013095 + x * (0.778026455830408 + x * (-0.6173111361273548 + x * (0.4202724111150622 + x * (-0.19452783598217288 + x * 0.04232040013661036)))));
real x = abs(V1oV2);
real y = 1.5707921083647782 + x * (-0.9995697178013095 + x * (0.778026455830408 + x * (-0.6173111361273548 + x * (0.4202724111150622 + x * (-0.19452783598217288 + x * 0.04232040013661036)))));
if (V1oV2 < 0)
{
// Not normalized by the factor of 1/TWO_PI.
// Ref: Improving radiosity solutions through the use of analytically determined form-factors.
REAL IntegrateEdge(REAL3 V1, REAL3 V2)
real IntegrateEdge(real3 V1, real3 V2)
// 'sinSqSigma' is the sine^2 of the REAL of the opening angle of the sphere as seen from the shaded point.
// 'sinSqSigma' is the sine^2 of the real of the opening angle of the sphere as seen from the shaded point.
REAL DiffuseSphereLightIrradiance(REAL sinSqSigma, REAL cosOmega)
real DiffuseSphereLightIrradiance(real sinSqSigma, real cosOmega)
REAL x = sinSqSigma;
REAL y = cosOmega;
real x = sinSqSigma;
real y = cosOmega;
// Use a numerical fit found in Mathematica. Mean absolute error: 0.00476944.
// You can use the following Mathematica code to reproduce our results:
#else
#if 0 // Ref: Area Light Sources for Real-Time Graphics, page 4 (1996).
REAL sinSqOmega = saturate(1 - cosOmega * cosOmega);
REAL cosSqSigma = saturate(1 - sinSqSigma);
REAL sinSqGamma = saturate(cosSqSigma / sinSqOmega);
REAL cosSqGamma = saturate(1 - sinSqGamma);
real sinSqOmega = saturate(1 - cosOmega * cosOmega);
real cosSqSigma = saturate(1 - sinSqSigma);
real sinSqGamma = saturate(cosSqSigma / sinSqOmega);
real cosSqGamma = saturate(1 - sinSqGamma);
REAL sinSigma = sqrt(sinSqSigma);
REAL sinGamma = sqrt(sinSqGamma);
REAL cosGamma = sqrt(cosSqGamma);
real sinSigma = sqrt(sinSqSigma);
real sinGamma = sqrt(sinSqGamma);
real cosGamma = sqrt(cosSqGamma);
REAL sigma = asin(sinSigma);
REAL omega = acos(cosOmega);
REAL gamma = asin(sinGamma);
real sigma = asin(sinSigma);
real omega = acos(cosOmega);
real gamma = asin(sinGamma);
if (omega >= HALF_PI + sigma)
{
REAL e = sinSqSigma * cosOmega;
real e = sinSqSigma * cosOmega;
[branch]
if (omega < HALF_PI - sigma)
}
else
{
REAL g = (-2 * sqrt(sinSqOmega * cosSqSigma) + sinGamma) * cosGamma + (HALF_PI - gamma);
REAL h = cosOmega * (cosGamma * sqrt(saturate(sinSqSigma - cosSqGamma)) + sinSqSigma * asin(saturate(cosGamma / sinSigma)));
real g = (-2 * sqrt(sinSqOmega * cosSqSigma) + sinGamma) * cosGamma + (HALF_PI - gamma);
real h = cosOmega * (cosGamma * sqrt(saturate(sinSqSigma - cosSqGamma)) + sinSqSigma * asin(saturate(cosGamma / sinSigma)));
if (omega < HALF_PI)
{
}
}
#else // Ref: Moving Frostbite to Physically Based Rendering, page 47 (2015, optimized).
REAL cosSqOmega = cosOmega * cosOmega; // y^2
real cosSqOmega = cosOmega * cosOmega; // y^2
[branch]
if (cosSqOmega > sinSqSigma) // (y^2)>x
else
{
REAL cotSqSigma = rcp(sinSqSigma) - 1; // 1/x-1
REAL tanSqSigma = rcp(cotSqSigma); // x/(1-x)
REAL sinSqOmega = 1 - cosSqOmega; // 1-y^2
real cotSqSigma = rcp(sinSqSigma) - 1; // 1/x-1
real tanSqSigma = rcp(cotSqSigma); // x/(1-x)
real sinSqOmega = 1 - cosSqOmega; // 1-y^2
REAL w = sinSqOmega * tanSqSigma; // (1-y^2)*(x/(1-x))
REAL x = -cosOmega * rsqrt(w); // -y*Sqrt[(1/x-1)/(1-y^2)]
REAL y = sqrt(sinSqOmega * tanSqSigma - cosSqOmega); // Sqrt[(1-y^2)*(x/(1-x))-y^2]
REAL z = y * cotSqSigma; // Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
real w = sinSqOmega * tanSqSigma; // (1-y^2)*(x/(1-x))
real x = -cosOmega * rsqrt(w); // -y*Sqrt[(1/x-1)/(1-y^2)]
real y = sqrt(sinSqOmega * tanSqSigma - cosSqOmega); // Sqrt[(1-y^2)*(x/(1-x))-y^2]
real z = y * cotSqSigma; // Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
REAL a = cosOmega * acos(x) - z; // y*ArcCos[-y*Sqrt[(1/x-1)/(1-y^2)]]-Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
REAL b = atan(y); // ArcTan[Sqrt[(1-y^2)*(x/(1-x))-y^2]]
real a = cosOmega * acos(x) - z; // y*ArcCos[-y*Sqrt[(1/x-1)/(1-y^2)]]-Sqrt[(1-y^2)*(x/(1-x))-y^2]*(1/x-1)
real b = atan(y); // ArcTan[Sqrt[(1-y^2)*(x/(1-x))-y^2]]
// The reason is that for compute shader we need to guarantee that the layout of CBs is consistent across kernels. Something that we can't control with the global namespace (uniforms get optimized out if not used, modifying the global CBuffer layout per kernel)
// Structure definition that are share between C# and hlsl.
// These structures need to be align on REAL4 to respect various packing rules from sahder language.
// These structures need to be align on real4 to respect various packing rules from sahder language.
// This mean that these structure need to be padded.
// Do not use "in", only "out" or "inout" as califier, not "inline" keyword either, useless.
// headers from ShaderLibrary do not include "common.hlsl", this should be included in the .shader using it (or Material.hlsl)
// Rules: When doing an array for constant buffer variables, we always use REAL4 to avoid any packing issue, particularly between compute shader and pixel shaders
// Rules: When doing an array for constant buffer variables, we always use real4 to avoid any packing issue, particularly between compute shader and pixel shaders
// uniform REAL4 packedArray[3];
// static REAL unpackedArray[12] = (REAL[12]packedArray;
// uniform real4 packedArray[3];
// static real unpackedArray[12] = (real[12]packedArray;
#ifndef REAL
#define REAL float
#define REAL2 float2
#define REAL3 float3
#define REAL4 float4
#ifndef real
#define real float
#define real2 float2
#define real3 float3
#define real4 float4
#define REAL2x2 float2x2
#define REAL2x3 float2x3
#define REAL3x2 float3x2
#define REAL3x3 float3x3
#define REAL3x4 float3x4
#define REAL4x3 float4x3
#define REAL4x4 float4x4
#define real2x2 float2x2
#define real2x3 float2x3
#define real3x2 float3x2
#define real3x3 float3x3
#define real3x4 float3x4
#define real4x3 float4x3
#define real4x4 float4x4
#define REAL_MIN FLT_MIN
#define REAL_MAX FLT_MAX
#ifndef INTRINSIC_CUBEMAP_FACE_ID
// TODO: implement this. Is the reference implementation of cubemapID provide by AMD the reverse of our ?
/*
REAL CubemapFaceID(REAL3 dir)
real CubemapFaceID(real3 dir)
REAL faceID;
real faceID;
if (abs(dir.z) >= abs(dir.x) && abs(dir.z) >= abs(dir.y))
REAL deviceDepth; // Depth from the depth buffer : [0, 1] (typically reversed)
REAL linearDepth; // View space Z coordinate : [Near, Far]
real deviceDepth; // Depth from the depth buffer : [0, 1] (typically reversed)
real linearDepth; // View space Z coordinate : [Near, Far]
};
// This function is use to provide an easy way to sample into a screen texture, either from a pixel or a compute shaders.
PositionInputs GetPositionInput(REAL2 positionSS, REAL2 invScreenSize, uint2 tileCoord) // Specify explicit tile coordinates so that we can easily make it lane invariant for compute evaluation.
PositionInputs GetPositionInput(real2 positionSS, real2 invScreenSize, uint2 tileCoord) // Specify explicit tile coordinates so that we can easily make it lane invariant for compute evaluation.
{
PositionInputs posInput;
ZERO_INITIALIZE(PositionInputs, posInput);
// In case of compute shader an extra REAL offset is added to the screenPos to shift the integer position to pixel center.
posInput.positionNDC.xy += REAL2(0.5, 0.5);
// In case of compute shader an extra real offset is added to the screenPos to shift the integer position to pixel center.
REAL3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
real3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
// Quadratic polynomials
res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
// TODO: the packing here is inefficient as we will fetch values far away from each other and they may not fit into the cache - Suggest we pack RGB continuously
// TODO: The calcul of texcoord could be perform with a single matrix multicplication calcualted on C++ side that will fold probeVolumeMin and probeVolumeSizeInv into it and handle the identity case, no reasons to do it in C++ (ask Ionut about it)
// It should also handle the camera relative path (if the render pipeline use it)
// which (approximately) covers the footprint of the lobe with a single texel.
// Improves the perceptual roughness distribution and adds reflection (contact) hardening.
// TODO: optimize!
REAL PerceptualRoughnessToMipmapLevel(REAL perceptualRoughness, REAL NdotR)
real PerceptualRoughnessToMipmapLevel(real perceptualRoughness, real NdotR)
REAL m = PerceptualRoughnessToRoughness(perceptualRoughness);
real m = PerceptualRoughnessToRoughness(perceptualRoughness);
REAL n = (2.0 / max(FLT_EPS, m * m)) - 2.0;
real n = (2.0 / max(FLT_EPS, m * m)) - 2.0;
// Remap from n_dot_h formulation to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html
n /= (4.0 * max(NdotR, FLT_EPS));
}
// The inverse of the *approximated* version of perceptualRoughnessToMipmapLevel().
REAL MipmapLevelToPerceptualRoughness(REAL mipmapLevel)
real MipmapLevelToPerceptualRoughness(real mipmapLevel)
REAL perceptualRoughness = saturate(mipmapLevel / UNITY_SPECCUBE_LOD_STEPS);
real perceptualRoughness = saturate(mipmapLevel / UNITY_SPECCUBE_LOD_STEPS);
// surface gradient from an on the fly TBN (deriv obtained using tspaceNormalToDerivative()) or from conventional vertex level TBN (mikktspace compliant and deriv obtained using tspaceNormalToDerivative())
REAL2 ParallaxOcclusionMapping(REAL lod, REAL lodThreshold, int numSteps, REAL3 viewDirTS, PerPixelHeightDisplacementParam ppdParam, out REAL outHeight)
real2 ParallaxOcclusionMapping(real lod, real lodThreshold, int numSteps, real3 viewDirTS, PerPixelHeightDisplacementParam ppdParam, out real outHeight)
REAL stepSize = 1.0 / (REAL)numSteps;
real stepSize = 1.0 / (real)numSteps;
// REAL parallaxLimit = -length(viewDirTS.xy) / viewDirTS.z;
REAL3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_ARGS(textureName, samplerName), UVMapping uvMapping, REAL scale, REAL param)
real3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_ARGS(textureName, samplerName), UVMapping uvMapping, real scale, real param)