UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

150 lines (134 loc) 5.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _LightingModel = _interopRequireDefault(require("../core/LightingModel.js")); var _PropertyNode = require("../core/PropertyNode.js"); var _TSLBase = require("../tsl/TSLBase.js"); var _Position = require("../accessors/Position.js"); var _Camera = require("../accessors/Camera.js"); var _LoopNode = require("../utils/LoopNode.js"); var _ViewportDepthNode = require("../display/ViewportDepthNode.js"); var _ModelNode = require("../accessors/ModelNode.js"); var _LTC = require("./BSDF/LTC.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const scatteringDensity = (0, _PropertyNode.property)('vec3'); const linearDepthRay = (0, _PropertyNode.property)('vec3'); const outgoingRayLight = (0, _PropertyNode.property)('vec3'); /** * VolumetricLightingModel class extends the LightingModel to implement volumetric lighting effects. * This model calculates the scattering and transmittance of light through a volumetric medium. * It dynamically adjusts the direction of the ray based on the camera and object positions. * The model supports custom scattering and depth nodes to enhance the lighting effects. * * @augments LightingModel */ class VolumetricLightingModel extends _LightingModel.default { constructor() { super(); } start(builder) { const { material, context } = builder; const startPos = (0, _PropertyNode.property)('vec3'); const endPos = (0, _PropertyNode.property)('vec3'); // This approach dynamically changes the direction of the ray, // prioritizing the ray from the camera to the object if it is inside the mesh, and from the object to the camera if it is far away. (0, _TSLBase.If)(_Camera.cameraPosition.sub(_Position.positionWorld).length().greaterThan(_ModelNode.modelRadius.mul(2)), () => { startPos.assign(_Camera.cameraPosition); endPos.assign(_Position.positionWorld); }).Else(() => { startPos.assign(_Position.positionWorld); endPos.assign(_Camera.cameraPosition); }); // const viewVector = endPos.sub(startPos); const steps = (0, _TSLBase.uniform)('int').onRenderUpdate(({ material }) => material.steps); const stepSize = viewVector.length().div(steps).toVar(); const rayDir = viewVector.normalize().toVar(); // TODO: toVar() should be automatic here ( in loop ) const distTravelled = (0, _TSLBase.float)(0.0).toVar(); const transmittance = (0, _TSLBase.vec3)(1).toVar(); if (material.offsetNode) { // reduce banding distTravelled.addAssign(material.offsetNode.mul(stepSize)); } (0, _LoopNode.Loop)(steps, () => { const positionRay = startPos.add(rayDir.mul(distTravelled)); const positionViewRay = _Camera.cameraViewMatrix.mul((0, _TSLBase.vec4)(positionRay, 1)).xyz; if (material.depthNode !== null) { linearDepthRay.assign((0, _ViewportDepthNode.linearDepth)((0, _ViewportDepthNode.viewZToPerspectiveDepth)(positionViewRay.z, _Camera.cameraNear, _Camera.cameraFar))); context.sceneDepthNode = (0, _ViewportDepthNode.linearDepth)(material.depthNode).toVar(); } context.positionWorld = positionRay; context.shadowPositionWorld = positionRay; context.positionView = positionViewRay; scatteringDensity.assign(0); let scatteringNode; if (material.scatteringNode) { scatteringNode = material.scatteringNode({ positionRay }); } super.start(builder); if (scatteringNode) { scatteringDensity.mulAssign(scatteringNode); } // beer's law const falloff = scatteringDensity.mul(.01).negate().mul(stepSize).exp(); transmittance.mulAssign(falloff); // move along the ray distTravelled.addAssign(stepSize); }); outgoingRayLight.addAssign(transmittance.saturate().oneMinus()); } scatteringLight(lightColor, builder) { const sceneDepthNode = builder.context.sceneDepthNode; if (sceneDepthNode) { (0, _TSLBase.If)(sceneDepthNode.greaterThanEqual(linearDepthRay), () => { scatteringDensity.addAssign(lightColor); }); } else { scatteringDensity.addAssign(lightColor); } } direct({ lightNode, lightColor }, builder) { // Ignore lights with infinite distance if (lightNode.light.distance === undefined) return; // TODO: We need a viewportOpaque*() ( output, depth ) to fit with modern rendering approaches const directLight = lightColor.xyz.toVar(); directLight.mulAssign(lightNode.shadowNode); // it no should be necessary if used in the same render pass this.scatteringLight(directLight, builder); } directRectArea({ lightColor, lightPosition, halfWidth, halfHeight }, builder) { const p0 = lightPosition.add(halfWidth).sub(halfHeight); // counterclockwise; light shines in local neg z direction const p1 = lightPosition.sub(halfWidth).sub(halfHeight); const p2 = lightPosition.sub(halfWidth).add(halfHeight); const p3 = lightPosition.add(halfWidth).add(halfHeight); const P = builder.context.positionView; const directLight = lightColor.xyz.mul((0, _LTC.LTC_Evaluate_Volume)({ P, p0, p1, p2, p3 })).pow(1.5); this.scatteringLight(directLight, builder); } finish(builder) { builder.context.outgoingLight.assign(outgoingRayLight); } } var _default = exports.default = VolumetricLightingModel;