@openhps/core
Version:
Open Hybrid Positioning System - Core component
233 lines (221 loc) • 6.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LTC_Uv = exports.LTC_Evaluate_Volume = exports.LTC_Evaluate = void 0;
var _TSLBase = require("../../tsl/TSLBase.js");
var _MathNode = require("../../math/MathNode.js");
// Rect Area Light
// Real-Time Polygonal-Light Shading with Linearly Transformed Cosines
// by Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt
// code: https://github.com/selfshadow/ltc_code/
const LTC_Uv = exports.LTC_Uv = /*@__PURE__*/(0, _TSLBase.Fn)(({
N,
V,
roughness
}) => {
const LUT_SIZE = 64.0;
const LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;
const LUT_BIAS = 0.5 / LUT_SIZE;
const dotNV = N.dot(V).saturate();
// texture parameterized by sqrt( GGX alpha ) and sqrt( 1 - cos( theta ) )
const uv = (0, _TSLBase.vec2)(roughness, dotNV.oneMinus().sqrt());
uv.assign(uv.mul(LUT_SCALE).add(LUT_BIAS));
return uv;
}).setLayout({
name: 'LTC_Uv',
type: 'vec2',
inputs: [{
name: 'N',
type: 'vec3'
}, {
name: 'V',
type: 'vec3'
}, {
name: 'roughness',
type: 'float'
}]
});
const LTC_ClippedSphereFormFactor = /*@__PURE__*/(0, _TSLBase.Fn)(({
f
}) => {
// Real-Time Area Lighting: a Journey from Research to Production (p.102)
// An approximation of the form factor of a horizon-clipped rectangle.
const l = f.length();
return (0, _MathNode.max)(l.mul(l).add(f.z).div(l.add(1.0)), 0);
}).setLayout({
name: 'LTC_ClippedSphereFormFactor',
type: 'float',
inputs: [{
name: 'f',
type: 'vec3'
}]
});
const LTC_EdgeVectorFormFactor = /*@__PURE__*/(0, _TSLBase.Fn)(({
v1,
v2
}) => {
const x = v1.dot(v2);
const y = x.abs().toVar();
// rational polynomial approximation to theta / sin( theta ) / 2PI
const a = y.mul(0.0145206).add(0.4965155).mul(y).add(0.8543985).toVar();
const b = y.add(4.1616724).mul(y).add(3.4175940).toVar();
const v = a.div(b);
const theta_sintheta = x.greaterThan(0.0).select(v, (0, _MathNode.max)(x.mul(x).oneMinus(), 1e-7).inverseSqrt().mul(0.5).sub(v));
return v1.cross(v2).mul(theta_sintheta);
}).setLayout({
name: 'LTC_EdgeVectorFormFactor',
type: 'vec3',
inputs: [{
name: 'v1',
type: 'vec3'
}, {
name: 'v2',
type: 'vec3'
}]
});
const LTC_Evaluate = exports.LTC_Evaluate = /*@__PURE__*/(0, _TSLBase.Fn)(({
N,
V,
P,
mInv,
p0,
p1,
p2,
p3
}) => {
// bail if point is on back side of plane of light
// assumes ccw winding order of light vertices
const v1 = p1.sub(p0).toVar();
const v2 = p3.sub(p0).toVar();
const lightNormal = v1.cross(v2);
const result = (0, _TSLBase.vec3)().toVar();
(0, _TSLBase.If)(lightNormal.dot(P.sub(p0)).greaterThanEqual(0.0), () => {
// construct orthonormal basis around N
const T1 = V.sub(N.mul(V.dot(N))).normalize();
const T2 = N.cross(T1).negate(); // negated from paper; possibly due to a different handedness of world coordinate system
// compute transform
const mat = mInv.mul((0, _TSLBase.mat3)(T1, T2, N).transpose()).toVar();
// transform rect
// & project rect onto sphere
const coords0 = mat.mul(p0.sub(P)).normalize().toVar();
const coords1 = mat.mul(p1.sub(P)).normalize().toVar();
const coords2 = mat.mul(p2.sub(P)).normalize().toVar();
const coords3 = mat.mul(p3.sub(P)).normalize().toVar();
// calculate vector form factor
const vectorFormFactor = (0, _TSLBase.vec3)(0).toVar();
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords0,
v2: coords1
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords1,
v2: coords2
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords2,
v2: coords3
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords3,
v2: coords0
}));
// adjust for horizon clipping
result.assign((0, _TSLBase.vec3)(LTC_ClippedSphereFormFactor({
f: vectorFormFactor
})));
});
return result;
}).setLayout({
name: 'LTC_Evaluate',
type: 'vec3',
inputs: [{
name: 'N',
type: 'vec3'
}, {
name: 'V',
type: 'vec3'
}, {
name: 'P',
type: 'vec3'
}, {
name: 'mInv',
type: 'mat3'
}, {
name: 'p0',
type: 'vec3'
}, {
name: 'p1',
type: 'vec3'
}, {
name: 'p2',
type: 'vec3'
}, {
name: 'p3',
type: 'vec3'
}]
});
const LTC_Evaluate_Volume = exports.LTC_Evaluate_Volume = /*@__PURE__*/(0, _TSLBase.Fn)(({
P,
p0,
p1,
p2,
p3
}) => {
// bail if point is on back side of plane of light
// assumes ccw winding order of light vertices
const v1 = p1.sub(p0).toVar();
const v2 = p3.sub(p0).toVar();
const lightNormal = v1.cross(v2);
const result = (0, _TSLBase.vec3)().toVar();
(0, _TSLBase.If)(lightNormal.dot(P.sub(p0)).greaterThanEqual(0.0), () => {
// transform rect
// & project rect onto sphere
const coords0 = p0.sub(P).normalize().toVar();
const coords1 = p1.sub(P).normalize().toVar();
const coords2 = p2.sub(P).normalize().toVar();
const coords3 = p3.sub(P).normalize().toVar();
// calculate vector form factor
const vectorFormFactor = (0, _TSLBase.vec3)(0).toVar();
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords0,
v2: coords1
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords1,
v2: coords2
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords2,
v2: coords3
}));
vectorFormFactor.addAssign(LTC_EdgeVectorFormFactor({
v1: coords3,
v2: coords0
}));
// adjust for horizon clipping
result.assign((0, _TSLBase.vec3)(LTC_ClippedSphereFormFactor({
f: vectorFormFactor.abs()
})));
});
return result;
}).setLayout({
name: 'LTC_Evaluate',
type: 'vec3',
inputs: [{
name: 'P',
type: 'vec3'
}, {
name: 'p0',
type: 'vec3'
}, {
name: 'p1',
type: 'vec3'
}, {
name: 'p2',
type: 'vec3'
}, {
name: 'p3',
type: 'vec3'
}]
});