您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
97 行
4.8 KiB
97 行
4.8 KiB
// this produces an orthonormal basis of the tangent and bitangent WITHOUT vertex level tangent/bitangent for any UV including procedurally generated
|
|
// method released with the demo for publication of "bump mapping unparametrized surfaces on the GPU"
|
|
// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
|
|
void SurfaceGradientGenBasisTB(float3 nrmVertexNormal, float3 sigmaX, float3 sigmaY, float flipSign, float2 texST, out float3 vT, out float3 vB)
|
|
{
|
|
float2 dSTdx = ddx_fine(texST), dSTdy = ddy_fine(texST);
|
|
|
|
float det = dot(dSTdx, float2(dSTdy.y, -dSTdy.x));
|
|
float sign_det = det < 0 ? -1 : 1;
|
|
|
|
// invC0 represents (dXds, dYds); but we don't divide by determinant (scale by sign instead)
|
|
float2 invC0 = sign_det * float2(dSTdy.y, -dSTdx.y);
|
|
vT = sigmaX * invC0.x + sigmaY * invC0.y;
|
|
if (abs(det) > 0.0)
|
|
vT = normalize(vT);
|
|
vB = (sign_det * flipSign) * cross(nrmVertexNormal, vT);
|
|
}
|
|
|
|
// 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())
|
|
float3 SurfaceGradientFromTBN(float2 deriv, float3 vT, float3 vB)
|
|
{
|
|
return deriv.x * vT + deriv.y * vB;
|
|
}
|
|
|
|
// surface gradient from an already generated "normal" such as from an object or world space normal map
|
|
// CAUTION: nrmVertexNormal and v must be in the same space. i.e world or object
|
|
// this allows us to mix the contribution together with a series of other contributions including tangent space normals
|
|
// v does not need to be unit length as long as it establishes the direction.
|
|
float3 SurfaceGradientFromPerturbedNormal(float3 nrmVertexNormal, float3 v)
|
|
{
|
|
float3 n = nrmVertexNormal;
|
|
float s = 1.0 / max(FLT_EPSILON, abs(dot(n, v)));
|
|
return s * (dot(n, v) * n - v);
|
|
}
|
|
|
|
// used to produce a surface gradient from the gradient of a volume bump function such as a volume of perlin noise.
|
|
// equation 2. in "bump mapping unparametrized surfaces on the GPU".
|
|
// Observe the difference in figure 2. between using the gradient vs. the surface gradient to do bump mapping (the original method is proved wrong in the paper!).
|
|
float3 SurfaceGradientFromVolumeGradient(float3 nrmVertexNormal, float3 grad)
|
|
{
|
|
return grad - dot(nrmVertexNormal, grad) * nrmVertexNormal;
|
|
}
|
|
|
|
// triplanar projection considered special case of volume bump map
|
|
// described here: http://mmikkelsen3d.blogspot.com/2013/10/volume-height-maps-and-triplanar-bump.html
|
|
// derivs obtained using tspaceNormalToDerivative() and weights using computeTriplanarWeights().
|
|
float3 SurfaceGradientFromTriplanarProjection(float3 nrmVertexNormal, float3 triplanarWeights, float2 deriv_xplane, float2 deriv_yplane, float2 deriv_zplane)
|
|
{
|
|
const float w0 = triplanarWeights.x, w1 = triplanarWeights.y, w2 = triplanarWeights.z;
|
|
|
|
// assume deriv_xplane, deriv_yplane and deriv_zplane sampled using (z,y), (z,x) and (x,y) respectively.
|
|
// positive scales of the look-up coordinate will work as well but for negative scales the derivative components will need to be negated accordingly.
|
|
float3 volumeGrad = float3(w2 * deriv_zplane.x + w1 * deriv_yplane.y, w2 * deriv_zplane.y + w0 * deriv_xplane.y, w0 * deriv_xplane.x + w1 * deriv_yplane.x);
|
|
|
|
return SurfaceGradientFromVolumeGradient(nrmVertexNormal, volumeGrad);
|
|
}
|
|
|
|
float3 SurfaceGradientResolveNormal(float3 nrmVertexNormal, float3 surfGrad)
|
|
{
|
|
return normalize(nrmVertexNormal - surfGrad);
|
|
}
|
|
|
|
// The 128 means the derivative will come out no greater than 128 numerically (where 1 is 45 degrees so 128 is very steap). You can increase it if u like of course
|
|
// Basically tan(angle) limited to 128
|
|
// So a max angle of 89.55 degrees ;) id argue thats close enough to the vertical limit at 90 degrees
|
|
// vT is channels.xy of a tangent space normal in[-1; 1]
|
|
// out: convert vT to a derivative
|
|
float2 UnpackDerivativeNormalAG(float4 packedNormal, float scale = 1.0)
|
|
{
|
|
const float fS = 1.0 / (128.0 * 128.0);
|
|
float2 vT = packedNormal.wy * 2.0 - 1.0;
|
|
float2 vTsq = vT * vT;
|
|
float nz_sq = 1 - vTsq.x - vTsq.y;
|
|
float maxcompxy_sq = fS * max(vTsq.x, vTsq.y);
|
|
float z_inv = rsqrt(max(nz_sq, maxcompxy_sq));
|
|
float2 deriv = -z_inv * float2(vT.x, vT.y);
|
|
return deriv * scale;
|
|
}
|
|
|
|
// Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1)
|
|
float2 UnpackDerivativeNormalRGorAG(float4 packedNormal, float scale = 1.0)
|
|
{
|
|
// This do the trick
|
|
packedNormal.w *= packedNormal.x;
|
|
return UnpackDerivativeNormalAG(packedNormal, scale);
|
|
}
|
|
|
|
float2 UnpackDerivativeNormalRGB(float4 packedNormal, float scale = 1.0)
|
|
{
|
|
const float fS = 1.0 / (128.0 * 128.0);
|
|
float3 vT = packedNormal.xyz * 2.0 - 1.0;
|
|
float3 vTsq = vT * vT;
|
|
float maxcompxy_sq = fS * max(vTsq.x, vTsq.y);
|
|
float z_inv = rsqrt(max(vTsq.z, maxcompxy_sq));
|
|
float2 deriv = -z_inv * float2(vT.x, vT.y);
|
|
return deriv * scale;
|
|
}
|