@babylonjs/viewer
Version:
The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.
154 lines (152 loc) • 6.25 kB
JavaScript
const STAGE_FRAGMENT = 2;
const PBR2_HAS_ANISO_TEX = 1 << 27;
const ANISO_BRDF_FUNCTIONS = `
const RECIPROCAL_PI: f32 = 0.3183098861837907;
fn getAnisotropicRoughness(alphaG: f32, anisotropy: f32) -> vec2<f32> {
let aT = max(mix(alphaG, 1.0, anisotropy * anisotropy), 0.0005);
let aB = max(alphaG, 0.0005);
return vec2<f32>(aT, aB);
}
fn D_GGX_Anisotropic(NdotH: f32, TdotH: f32, BdotH: f32, alphaTB: vec2<f32>) -> f32 {
let a2 = alphaTB.x * alphaTB.y;
let v = vec3<f32>(alphaTB.y * TdotH, alphaTB.x * BdotH, a2 * NdotH);
let v2 = dot(v, v);
let w2 = a2 / v2;
return a2 * w2 * w2 * RECIPROCAL_PI;
}
fn V_GGXCorrelated_Anisotropic(NdotL: f32, NdotV: f32, TdotV: f32, BdotV: f32, TdotL: f32, BdotL: f32, alphaTB: vec2<f32>) -> f32 {
let lambdaV = NdotL * length(vec3<f32>(alphaTB.x * TdotV, alphaTB.y * BdotV, NdotV));
let lambdaL = NdotV * length(vec3<f32>(alphaTB.x * TdotL, alphaTB.y * BdotL, NdotL));
return 0.5 / (lambdaV + lambdaL);
}
`;
function makeAnisotropyTBBlock(hasNormal, hasTexture = false) {
const texSample = hasTexture ? `let anisoUV = vec2<f32>(dot(material.anisotropyUVm.xy, input.uv), dot(material.anisotropyUVm.zw, input.uv)) + material.anisotropyUVt.xy;
let anisoTexData = textureSample(anisotropyTexture_, anisotropySampler_, anisoUV).rgb;
anisoIntensityF = anisoIntensityF * anisoTexData.b;
let anisoNdir = normalize(anisoTexData.rg * 2.0 - vec2<f32>(1.0));
anisoDir2 = vec2<f32>(anisoDir2.x * anisoNdir.x - anisoDir2.y * anisoNdir.y, anisoDir2.y * anisoNdir.x + anisoDir2.x * anisoNdir.y);
` : "";
const pre = `var anisoIntensityF = material.anisotropyParams.x;
var anisoDir2 = vec2<f32>(material.anisotropyParams.y, material.anisotropyParams.z);
${texSample}`;
if (hasNormal) {
return `${pre}var anisoT = normalize(input.worldTangent);
var anisoB = normalize(input.worldBitangent);
{
let anisoDir = normalize(anisoDir2);
anisoT = normalize(anisoT * anisoDir.x + anisoB * anisoDir.y);
anisoB = normalize(cross(N, anisoT));
}`;
}
return `${pre}var anisoT: vec3<f32>;
var anisoB: vec3<f32>;
{
let aniso_Ngeom = normalize(input.worldNormal);
let aniso_dp1 = dpdx(input.worldPos);
let aniso_dp2 = dpdy(input.worldPos);
let aniso_duv1 = dpdx(input.uv);
let aniso_duv2 = dpdy(input.uv);
let aniso_dp2perp = cross(aniso_dp2, aniso_Ngeom);
let aniso_dp1perp = cross(aniso_Ngeom, aniso_dp1);
let aniso_tct = aniso_dp2perp * aniso_duv1.x + aniso_dp1perp * aniso_duv2.x;
let aniso_bct = -(aniso_dp2perp * aniso_duv1.y + aniso_dp1perp * aniso_duv2.y);
let aniso_det = max(dot(aniso_tct, aniso_tct), dot(aniso_bct, aniso_bct));
let aniso_inv = select(inverseSqrt(aniso_det), 0.0, aniso_det == 0.0);
let anisoTBN = mat3x3<f32>(normalize(aniso_tct * aniso_inv), normalize(aniso_bct * aniso_inv), N);
let anisoDir = vec3<f32>(anisoDir2.x, anisoDir2.y, 0.0);
anisoT = normalize(anisoTBN * anisoDir);
anisoB = normalize(cross(anisoTBN[2], anisoT));
}`;
}
const ANISO_DIRECT_DG = `let aniso_alphaTB = getAnisotropicRoughness(directAlphaG, anisoIntensityF);
let dl_TdotH = dot(anisoT, H); let dl_BdotH = dot(anisoB, H);
let dl_TdotV = dot(anisoT, V); let dl_BdotV = dot(anisoB, V);
let dl_TdotL = dot(anisoT, L); let dl_BdotL = dot(anisoB, L);
let D = D_GGX_Anisotropic(NdotH, dl_TdotH, dl_BdotH, aniso_alphaTB);
let G = V_GGXCorrelated_Anisotropic(NdotL, NdotV, dl_TdotV, dl_BdotV, dl_TdotL, dl_BdotL, aniso_alphaTB);`;
const ANISO_BENT_NORMAL = `var anisoBentNormal = cross(anisoB, V);
anisoBentNormal = normalize(cross(anisoBentNormal, anisoB));
let anisoSq = 1.0 - anisoIntensityF * (1.0 - roughness);
let anisoA = anisoSq * anisoSq * anisoSq * anisoSq;
anisoBentNormal = normalize(mix(anisoBentNormal, N, anisoA));
let R_raw = reflect(-V, anisoBentNormal);`;
const pbrExt = {
id: "anisotropy",
phase: "fragment",
detect(mat) {
const aniso = mat.anisotropy;
return { f: 0, f2: aniso?.isEnabled && aniso.texture ? PBR2_HAS_ANISO_TEX : 0 };
},
frag(ctx) {
if ((ctx._features2 & PBR2_HAS_ANISO_TEX) === 0) {
return null;
}
const bindings = [
{ _name: "anisotropyTexture_", _type: { _kind: "texture", _textureType: "texture_2d<f32>" }, _visibility: STAGE_FRAGMENT },
{ _name: "anisotropySampler_", _type: { _kind: "sampler", _samplerType: "sampler" }, _visibility: STAGE_FRAGMENT }
];
const uboFields = [
{ _name: "anisotropyUVm", _type: "vec4<f32>" },
{ _name: "anisotropyUVt", _type: "vec4<f32>" }
];
const frag = { _id: "anisotropy-tex", _bindings: bindings, _uboFields: uboFields };
return frag;
},
writeUbo(data, material, offsets) {
const aniso = material.anisotropy;
if (!aniso?.isEnabled || !offsets.has("anisotropyParams")) {
return;
}
const off = offsets.get("anisotropyParams") / 4;
const dir = aniso.direction ?? [1, 0];
data[off] = aniso.intensity ?? 1;
data[off + 1] = dir[0];
data[off + 2] = dir[1];
const mOff = offsets.get("anisotropyUVm");
const tOff = offsets.get("anisotropyUVt");
if (mOff === void 0 || tOff === void 0) {
return;
}
const tex = aniso.texture;
const sx = tex?.uScale ?? 1;
const sy = tex?.vScale ?? 1;
const ang = tex?.uAng ?? 0;
const mi = mOff / 4;
const ti = tOff / 4;
if (ang === 0) {
data[mi] = sx;
data[mi + 1] = 0;
data[mi + 2] = 0;
data[mi + 3] = sy;
} else {
const c = Math.cos(ang);
const s = Math.sin(ang);
data[mi] = c * sx;
data[mi + 1] = s * sy;
data[mi + 2] = -s * sx;
data[mi + 3] = c * sy;
}
data[ti] = tex?.uOffset ?? 0;
data[ti + 1] = tex?.vOffset ?? 0;
data[ti + 2] = 0;
data[ti + 3] = 0;
},
bind(ctx, entries, b) {
const aniso = ctx._material.anisotropy;
if ((ctx._features2 & PBR2_HAS_ANISO_TEX) === 0 || !aniso?.texture) {
return b;
}
entries.push({ binding: b++, resource: aniso.texture.view });
entries.push({ binding: b++, resource: aniso.texture.sampler });
return b;
},
textures(mat, out) {
const aniso = mat.anisotropy;
if (aniso?.texture) {
out.push(aniso.texture);
}
}
};
export { ANISO_BENT_NORMAL, ANISO_BRDF_FUNCTIONS, ANISO_DIRECT_DG, PBR2_HAS_ANISO_TEX, makeAnisotropyTBBlock, pbrExt };
//# sourceMappingURL=anisotropy-fragment-BG-zt_tV.esm.js.map