shop-components 0.0.24 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/Color-RQJUDNI5-leAiB7jg.js +1 -0
- package/dist/assets/Configure-OUhXg2g0.js +173 -0
- package/dist/assets/DRACOLoader-FOpiHRUS.js +2 -0
- package/dist/assets/DocsRenderer-K4EAMTCU-wTc0yUaa.js +7 -0
- package/dist/assets/Header-Yyx952jD.css +1 -0
- package/dist/assets/Header.stories-8tnkOwSt.js +31 -0
- package/dist/assets/Page-fZ7a-HXz.css +1 -0
- package/dist/assets/Page.stories-53Crpe03.js +61 -0
- package/dist/assets/RGBELoader-re-MEsjP.js +5 -0
- package/dist/assets/SFL-CDD14-9UY62fbR.glb +0 -0
- package/dist/assets/WithTooltip-Y7J54OF7-e8Yh5ASp.js +1 -0
- package/dist/assets/_commonjsHelpers-4gQjN7DL.js +1 -0
- package/dist/assets/accessibility-Fv4dmnDm.png +0 -0
- package/dist/assets/addon-library-VlAgJsjc.png +0 -0
- package/dist/assets/bg-circle-d8WfpvaX.png +0 -0
- package/dist/assets/context-tKiKnkuP.png +0 -0
- package/dist/assets/docs-Pvr7BWzI.png +0 -0
- package/dist/assets/entry-preview-TptA_luc.js +8 -0
- package/dist/assets/entry-preview-docs-AhrJ3R4Z.js +2 -0
- package/dist/assets/figma-plugin-h9oRC4jr.png +0 -0
- package/dist/assets/formatter-B5HCVTEV-DKi3GmSv.js +58 -0
- package/dist/assets/generateMeshBVH.worker-NFSCTTDt.js +5 -0
- package/dist/assets/iframe-tlQuLR4E.js +7 -0
- package/dist/assets/img-radar-kufDNNXQ.png +0 -0
- package/dist/assets/img-radar2-1cPZO_cj.png +0 -0
- package/dist/assets/index-CXFn8OGe.js +513 -0
- package/dist/assets/index-C_uo8BdM.js +1 -0
- package/dist/assets/index-PPLHz8o0.js +6 -0
- package/dist/assets/index-jFdhmKfM.js +3 -0
- package/dist/assets/index-jtEywAqJ.js +1 -0
- package/dist/assets/index-ogXoivrg.js +1 -0
- package/dist/assets/index.stories-TVZrSYZv.js +20 -0
- package/dist/assets/index.stories-Uq0Yg-kp.js +896 -0
- package/dist/assets/index.stories-VJP6Jo4U.js +22 -0
- package/dist/assets/index.stories-VoNcNCFd.js +27 -0
- package/dist/assets/index.stories-YIFSciWI.js +1174 -0
- package/dist/assets/index.stories-iMKoZNyH.js +46 -0
- package/dist/assets/lightroom_14b-MJkJLVlP.hdr +0 -0
- package/dist/assets/lightroom_14b_512-e_XJNpR6.js +3981 -0
- package/dist/assets/lightroom_14b_512-nMVn659Q.hdr +0 -0
- package/dist/assets/lit-element-P_wTzRvl.js +19 -0
- package/dist/assets/parallelMeshBVH.worker-TP6qJGKX.js +5 -0
- package/dist/assets/preview-1q4RDNOi.js +1 -0
- package/dist/assets/preview-6iG64ELu.js +20 -0
- package/dist/assets/preview-7nNmfNVr.js +7 -0
- package/dist/assets/preview-9bpQVOkQ.js +1 -0
- package/dist/assets/preview-FnnPJHgu.js +1 -0
- package/dist/assets/preview-VI2eoWmp.js +1 -0
- package/dist/assets/preview-bEa2SesL.js +7 -0
- package/dist/assets/preview-u8M_OEO2.js +396 -0
- package/dist/assets/preview-zZA4w0lH.js +1 -0
- package/dist/assets/property-EQZXZ3dt.js +5 -0
- package/dist/assets/query-7eORIRsG.js +13 -0
- package/dist/assets/roller-8Vy8W3X_.glb +0 -0
- package/dist/assets/roller-hopper-Heae_wy5.glb +0 -0
- package/dist/assets/share-xgPlHEHy.png +0 -0
- package/dist/assets/styling-ZOs40c1G.png +0 -0
- package/dist/assets/syntaxhighlighter-JOJW2KGS-uBo08tOF.js +1 -0
- package/dist/assets/testing-HG80fZfa.png +0 -0
- package/dist/assets/theming--liSzaFj.png +0 -0
- package/dist/assets/three.module-9MfFqitO.js +3825 -0
- package/dist/assets/tiny-invariant-VyoA2Os1.js +1 -0
- package/dist/assets/worker-h5IcTUxB.js +1 -0
- package/dist/device-viewer/amr.d.ts +75 -0
- package/dist/device-viewer/assembly.d.ts +11 -0
- package/dist/device-viewer/dimension/index.d.ts +31 -0
- package/dist/device-viewer/dimension/line3.d.ts +21 -0
- package/dist/device-viewer/dimension/size-box.d.ts +39 -0
- package/dist/device-viewer/group-roller.d.ts +20 -0
- package/dist/device-viewer/index.d.ts +12 -0
- package/dist/device-viewer/mechanism/mechanism.d.ts +29 -0
- package/dist/device-viewer/outerline.d.ts +16 -0
- package/dist/device-viewer/roller.d.ts +31 -0
- package/dist/device-viewer/row.d.ts +18 -0
- package/dist/device-viewer/scene.d.ts +14 -28
- package/dist/device-viewer/slot.d.ts +10 -2
- package/dist/device-viewer/text2.d.ts +4 -0
- package/dist/device-viewer/text3.d.ts +4 -0
- package/dist/device-viewer/utils/index.d.ts +26 -1
- package/dist/favicon.svg +7 -0
- package/dist/iframe.html +495 -0
- package/dist/index.html +155 -0
- package/dist/index.json +1 -0
- package/dist/package.json +60 -0
- package/dist/project.json +1 -0
- package/dist/sb-addons/essentials-actions-3/manager-bundle.js +3 -0
- package/dist/sb-addons/essentials-actions-3/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/essentials-backgrounds-4/manager-bundle.js +12 -0
- package/dist/sb-addons/essentials-backgrounds-4/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/essentials-controls-2/manager-bundle.js +60 -0
- package/dist/sb-addons/essentials-controls-2/manager-bundle.js.LEGAL.txt +18 -0
- package/dist/sb-addons/essentials-measure-7/manager-bundle.js +3 -0
- package/dist/sb-addons/essentials-measure-7/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/essentials-outline-8/manager-bundle.js +3 -0
- package/dist/sb-addons/essentials-outline-8/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/essentials-toolbars-6/manager-bundle.js +3 -0
- package/dist/sb-addons/essentials-toolbars-6/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/essentials-viewport-5/manager-bundle.js +3 -0
- package/dist/sb-addons/essentials-viewport-5/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/links-1/manager-bundle.js +3 -0
- package/dist/sb-addons/links-1/manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +3 -0
- package/dist/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js.LEGAL.txt +0 -0
- package/dist/sb-common-assets/fonts.css +31 -0
- package/dist/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
- package/dist/sb-common-assets/nunito-sans-bold.woff2 +0 -0
- package/dist/sb-common-assets/nunito-sans-italic.woff2 +0 -0
- package/dist/sb-common-assets/nunito-sans-regular.woff2 +0 -0
- package/dist/sb-manager/WithTooltip-Y7J54OF7-3AIPQNGM.js +1 -0
- package/dist/sb-manager/chunk-I53COLQ6.js +183 -0
- package/dist/sb-manager/chunk-L35575BZ.js +234 -0
- package/dist/sb-manager/chunk-TZAR34JC.js +6 -0
- package/dist/sb-manager/chunk-UOBNU442.js +347 -0
- package/dist/sb-manager/chunk-VMGB76WP.js +9 -0
- package/dist/sb-manager/chunk-XP3HGWTR.js +1 -0
- package/dist/sb-manager/formatter-B5HCVTEV-7DCBOGO6.js +58 -0
- package/dist/sb-manager/globals-module-info.js +1 -0
- package/dist/sb-manager/globals-runtime.js +1 -0
- package/dist/sb-manager/globals.js +1 -0
- package/dist/sb-manager/index.js +1 -0
- package/dist/sb-manager/runtime.js +1 -0
- package/dist/sb-manager/syntaxhighlighter-JOJW2KGS-7BF26SBB.js +1 -0
- package/dist/sb-preview/globals.js +1 -0
- package/dist/sb-preview/runtime.js +128 -0
- package/dist/stories/cropper/index.d.ts +18 -0
- package/dist/stories/cropper/index.js +118 -0
- package/dist/stories/cropper/index.js.map +1 -0
- package/dist/stories/cropper/index.stories.d.ts +11 -0
- package/dist/stories/cropper/index.stories.js +14 -0
- package/dist/stories/cropper/index.stories.js.map +1 -0
- package/dist/stories/device-viewer/amr.d.ts +75 -0
- package/dist/stories/device-viewer/amr.js +554 -0
- package/dist/stories/device-viewer/amr.js.map +1 -0
- package/dist/stories/device-viewer/assembly.d.ts +11 -0
- package/dist/stories/device-viewer/assembly.js +47 -0
- package/dist/stories/device-viewer/assembly.js.map +1 -0
- package/dist/stories/device-viewer/asserts/fonts/type.json +1281 -0
- package/dist/stories/device-viewer/dimension/index.d.ts +31 -0
- package/dist/stories/device-viewer/dimension/index.js +131 -0
- package/dist/stories/device-viewer/dimension/index.js.map +1 -0
- package/dist/stories/device-viewer/dimension/line3.d.ts +21 -0
- package/dist/stories/device-viewer/dimension/line3.js +98 -0
- package/dist/stories/device-viewer/dimension/line3.js.map +1 -0
- package/dist/stories/device-viewer/dimension/size-box.d.ts +39 -0
- package/dist/stories/device-viewer/dimension/size-box.js +176 -0
- package/dist/stories/device-viewer/dimension/size-box.js.map +1 -0
- package/dist/stories/device-viewer/group-roller.d.ts +20 -0
- package/dist/stories/device-viewer/group-roller.js +65 -0
- package/dist/stories/device-viewer/group-roller.js.map +1 -0
- package/dist/stories/device-viewer/index.d.ts +47 -0
- package/dist/stories/device-viewer/index.js +530 -0
- package/dist/stories/device-viewer/index.js.map +1 -0
- package/dist/stories/device-viewer/index.stories.d.ts +27 -0
- package/dist/stories/device-viewer/index.stories.js +37 -0
- package/dist/stories/device-viewer/index.stories.js.map +1 -0
- package/dist/stories/device-viewer/lines.d.ts +36 -0
- package/dist/stories/device-viewer/lines.js +171 -0
- package/dist/stories/device-viewer/lines.js.map +1 -0
- package/dist/stories/device-viewer/main.d.ts +1 -0
- package/dist/stories/device-viewer/main.js +2 -0
- package/dist/stories/device-viewer/main.js.map +1 -0
- package/dist/stories/device-viewer/mechanism/mechanism.d.ts +29 -0
- package/dist/stories/device-viewer/mechanism/mechanism.js +164 -0
- package/dist/stories/device-viewer/mechanism/mechanism.js.map +1 -0
- package/dist/stories/device-viewer/outerline.d.ts +16 -0
- package/dist/stories/device-viewer/outerline.js +63 -0
- package/dist/stories/device-viewer/outerline.js.map +1 -0
- package/dist/stories/device-viewer/roller.d.ts +31 -0
- package/dist/stories/device-viewer/roller.js +121 -0
- package/dist/stories/device-viewer/roller.js.map +1 -0
- package/dist/stories/device-viewer/row.d.ts +18 -0
- package/dist/stories/device-viewer/row.js +58 -0
- package/dist/stories/device-viewer/row.js.map +1 -0
- package/dist/stories/device-viewer/scene.d.ts +101 -0
- package/dist/stories/device-viewer/scene.js +535 -0
- package/dist/stories/device-viewer/scene.js.map +1 -0
- package/dist/stories/device-viewer/slot/slot-item.d.ts +20 -0
- package/dist/stories/device-viewer/slot/slot-item.js +82 -0
- package/dist/stories/device-viewer/slot/slot-item.js.map +1 -0
- package/dist/stories/device-viewer/slot.d.ts +71 -0
- package/dist/stories/device-viewer/slot.js +272 -0
- package/dist/stories/device-viewer/slot.js.map +1 -0
- package/dist/stories/device-viewer/sound.d.ts +5 -0
- package/dist/stories/device-viewer/sound.js +13 -0
- package/dist/stories/device-viewer/sound.js.map +1 -0
- package/dist/stories/device-viewer/text2.d.ts +4 -0
- package/dist/stories/device-viewer/text2.js +12 -0
- package/dist/stories/device-viewer/text2.js.map +1 -0
- package/dist/stories/device-viewer/text3.d.ts +4 -0
- package/dist/stories/device-viewer/text3.js +14 -0
- package/dist/stories/device-viewer/text3.js.map +1 -0
- package/dist/stories/device-viewer/utils/index.d.ts +36 -0
- package/dist/stories/device-viewer/utils/index.js +166 -0
- package/dist/stories/device-viewer/utils/index.js.map +1 -0
- package/dist/stories/device-viewer/worker/generate-mesh-bvh-worker.d.ts +8 -0
- package/dist/stories/device-viewer/worker/generate-mesh-bvh-worker.js +88 -0
- package/dist/stories/device-viewer/worker/generate-mesh-bvh-worker.js.map +1 -0
- package/dist/stories/device-viewer/worker/generateAsync.worker.d.ts +1 -0
- package/dist/stories/device-viewer/worker/generateAsync.worker.js +57 -0
- package/dist/stories/device-viewer/worker/generateAsync.worker.js.map +1 -0
- package/dist/stories/device-viewer/worker/path-tracing-scene-worker.d.ts +16 -0
- package/dist/stories/device-viewer/worker/path-tracing-scene-worker.js +29 -0
- package/dist/stories/device-viewer/worker/path-tracing-scene-worker.js.map +1 -0
- package/dist/stories/main/index.d.ts +1 -0
- package/dist/stories/main/index.js +2 -0
- package/dist/stories/main/index.js.map +1 -0
- package/dist/stories/main.d.ts +4 -0
- package/dist/stories/main.js +5 -0
- package/dist/stories/main.js.map +1 -0
- package/dist/stories/plugin.d.ts +5 -0
- package/dist/stories/plugin.js +6 -0
- package/dist/stories/plugin.js.map +1 -0
- package/dist/stories/plugins/change-slot/index.d.ts +0 -0
- package/dist/stories/plugins/change-slot/index.js +2 -0
- package/dist/stories/plugins/change-slot/index.js.map +1 -0
- package/dist/stories/sglb/index.d.ts +27 -0
- package/dist/stories/sglb/index.js +151 -0
- package/dist/stories/sglb/index.js.map +1 -0
- package/dist/stories/smap-viewer/index.d.ts +14 -0
- package/dist/stories/smap-viewer/index.js +59 -0
- package/dist/stories/smap-viewer/index.js.map +1 -0
- package/dist/stories/smap-viewer/index.stories.d.ts +22 -0
- package/dist/stories/smap-viewer/index.stories.js +27 -0
- package/dist/stories/smap-viewer/index.stories.js.map +1 -0
- package/dist/stories/step-viewer/index.d.ts +17 -0
- package/dist/stories/step-viewer/index.js +109 -0
- package/dist/stories/step-viewer/index.js.map +1 -0
- package/dist/stories/step-viewer/index.stories.d.ts +20 -0
- package/dist/stories/step-viewer/index.stories.js +24 -0
- package/dist/stories/step-viewer/index.stories.js.map +1 -0
- package/dist/stories/test/index.d.ts +25 -0
- package/dist/stories/test/index.js +99 -0
- package/dist/stories/test/index.js.map +1 -0
- package/dist/stories/test/index.stories.d.ts +14 -0
- package/dist/stories/test/index.stories.js +16 -0
- package/dist/stories/test/index.stories.js.map +1 -0
- package/dist/stories/test/scene.d.ts +20 -0
- package/dist/stories/test/scene.js +86 -0
- package/dist/stories/test/scene.js.map +1 -0
- package/dist/stories/utils/index.d.ts +4 -0
- package/dist/stories/utils/index.js +28 -0
- package/dist/stories/utils/index.js.map +1 -0
- package/dist/test/index.d.ts +25 -0
- package/dist/test/index.stories.d.ts +14 -0
- package/dist/test/scene.d.ts +20 -0
- package/package.json +9 -6
- package/dist/shop-components.mjs +0 -55938
- package/dist/shop-components.umd.js +0 -9232
|
@@ -0,0 +1,3981 @@
|
|
|
1
|
+
import{n as Ss}from"./property-EQZXZ3dt.js";import{an as Ms,M as zr,B as De,aV as Qi,aU as Rs,aQ as Ii,j as Is,V as C,aW as ze,aX as Oe,Q as hi,aY as di,k as L,l as Ps,e as re,aR as xe,aS as ft,n as Cs,i as Y,m as he,aT as Or,u as Nr,az as mi,aZ as mt,a_ as ae,as as U,a$ as Xt,F as q,b0 as pi,b1 as Fs,b2 as Ji,b3 as Ds,aN as V,b4 as gi,b5 as Lr,b6 as Wt,b7 as Hr,b8 as Es,b9 as Bs,ba as Je,a7 as ks,y as qt,N as vt,v as pt,P as Ur,a as ve,H as fe,b as le,af as _e,aw as Me,aL as zs,bb as Os,C as xt,bc as Ns,bd as Ls,be as Wr,E as Vr,bf as Hs,_ as Us,f as Ws,z as Vs}from"./three.module-9MfFqitO.js";/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2017 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
+
*/function Vo(s){return Ss({...s,state:!0,attribute:!1})}class qo{constructor(){this.isPass=!0,this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}setSize(){}render(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}dispose(){}}const qs=new Ms(-1,1,1,-1,0,1);class js extends De{constructor(){super(),this.setAttribute("position",new Qi([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new Qi([0,2,0,0,2,0],2))}}const Gs=new js;class et{constructor(e){this._mesh=new zr(Gs,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,qs)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}const er={type:"change"},Kt={type:"start"},tr={type:"end"},bt=new Rs,ir=new Ii,Ys=Math.cos(70*Ps.DEG2RAD);class jo extends Is{constructor(e,i){super(),this.object=e,this.domElement=i,this.domElement.style.touchAction="none",this.enabled=!0,this.target=new C,this.cursor=new C,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minTargetRadius=0,this.maxTargetRadius=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.05,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.panSpeed=1,this.screenSpacePanning=!0,this.keyPanSpeed=7,this.zoomToCursor=!1,this.autoRotate=!1,this.autoRotateSpeed=2,this.keys={LEFT:"ArrowLeft",UP:"ArrowUp",RIGHT:"ArrowRight",BOTTOM:"ArrowDown"},this.mouseButtons={LEFT:ze.ROTATE,MIDDLE:ze.DOLLY,RIGHT:ze.PAN},this.touches={ONE:Oe.ROTATE,TWO:Oe.DOLLY_PAN},this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom,this._domElementKeyEvents=null,this.getPolarAngle=function(){return c.phi},this.getAzimuthalAngle=function(){return c.theta},this.getDistance=function(){return this.object.position.distanceTo(this.target)},this.listenToKeyEvents=function(x){x.addEventListener("keydown",$t),this._domElementKeyEvents=x},this.stopListenToKeyEvents=function(){this._domElementKeyEvents.removeEventListener("keydown",$t),this._domElementKeyEvents=null},this.saveState=function(){t.target0.copy(t.target),t.position0.copy(t.object.position),t.zoom0=t.object.zoom},this.reset=function(){t.target.copy(t.target0),t.object.position.copy(t.position0),t.object.zoom=t.zoom0,t.object.updateProjectionMatrix(),t.dispatchEvent(er),t.update(),a=n.NONE},this.update=function(){const x=new C,D=new hi().setFromUnitVectors(e.up,new C(0,1,0)),k=D.clone().invert(),O=new C,j=new hi,be=new C,ie=2*Math.PI;return function(_s=null){const Ki=t.object.position;x.copy(Ki).sub(t.target),x.applyQuaternion(D),c.setFromVector3(x),t.autoRotate&&a===n.NONE&&M(I(_s)),t.enableDamping?(c.theta+=l.theta*t.dampingFactor,c.phi+=l.phi*t.dampingFactor):(c.theta+=l.theta,c.phi+=l.phi);let de=t.minAzimuthAngle,me=t.maxAzimuthAngle;isFinite(de)&&isFinite(me)&&(de<-Math.PI?de+=ie:de>Math.PI&&(de-=ie),me<-Math.PI?me+=ie:me>Math.PI&&(me-=ie),de<=me?c.theta=Math.max(de,Math.min(me,c.theta)):c.theta=c.theta>(de+me)/2?Math.max(de,c.theta):Math.min(me,c.theta)),c.phi=Math.max(t.minPolarAngle,Math.min(t.maxPolarAngle,c.phi)),c.makeSafe(),t.enableDamping===!0?t.target.addScaledVector(f,t.dampingFactor):t.target.add(f),t.target.sub(t.cursor),t.target.clampLength(t.minTargetRadius,t.maxTargetRadius),t.target.add(t.cursor);let rt=!1;if(t.zoomToCursor&&_||t.object.isOrthographicCamera)c.radius=Ee(c.radius);else{const pe=c.radius;c.radius=Ee(c.radius*h),rt=pe!=c.radius}if(x.setFromSpherical(c),x.applyQuaternion(k),Ki.copy(t.target).add(x),t.object.lookAt(t.target),t.enableDamping===!0?(l.theta*=1-t.dampingFactor,l.phi*=1-t.dampingFactor,f.multiplyScalar(1-t.dampingFactor)):(l.set(0,0,0),f.set(0,0,0)),t.zoomToCursor&&_){let pe=null;if(t.object.isPerspectiveCamera){const st=x.length();pe=Ee(st*h);const yt=st-pe;t.object.position.addScaledVector(w,yt),t.object.updateMatrixWorld(),rt=!!yt}else if(t.object.isOrthographicCamera){const st=new C(T.x,T.y,0);st.unproject(t.object);const yt=t.object.zoom;t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/h)),t.object.updateProjectionMatrix(),rt=yt!==t.object.zoom;const Zi=new C(T.x,T.y,0);Zi.unproject(t.object),t.object.position.sub(Zi).add(st),t.object.updateMatrixWorld(),pe=x.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),t.zoomToCursor=!1;pe!==null&&(this.screenSpacePanning?t.target.set(0,0,-1).transformDirection(t.object.matrix).multiplyScalar(pe).add(t.object.position):(bt.origin.copy(t.object.position),bt.direction.set(0,0,-1).transformDirection(t.object.matrix),Math.abs(t.object.up.dot(bt.direction))<Ys?e.lookAt(t.target):(ir.setFromNormalAndCoplanarPoint(t.object.up,t.target),bt.intersectPlane(ir,t.target))))}else if(t.object.isOrthographicCamera){const pe=t.object.zoom;t.object.zoom=Math.max(t.minZoom,Math.min(t.maxZoom,t.object.zoom/h)),pe!==t.object.zoom&&(t.object.updateProjectionMatrix(),rt=!0)}return h=1,_=!1,rt||O.distanceToSquared(t.object.position)>r||8*(1-j.dot(t.object.quaternion))>r||be.distanceToSquared(t.target)>r?(t.dispatchEvent(er),O.copy(t.object.position),j.copy(t.object.quaternion),be.copy(t.target),!0):!1}}(),this.dispose=function(){t.domElement.removeEventListener("contextmenu",$i),t.domElement.removeEventListener("pointerdown",Vi),t.domElement.removeEventListener("pointercancel",it),t.domElement.removeEventListener("wheel",qi),t.domElement.removeEventListener("pointermove",Yt),t.domElement.removeEventListener("pointerup",it),t.domElement.getRootNode().removeEventListener("keydown",ji,{capture:!0}),t._domElementKeyEvents!==null&&(t._domElementKeyEvents.removeEventListener("keydown",$t),t._domElementKeyEvents=null)};const t=this,n={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6};let a=n.NONE;const r=1e-6,c=new di,l=new di;let h=1;const f=new C,u=new L,o=new L,m=new L,v=new L,b=new L,d=new L,p=new L,g=new L,y=new L,w=new C,T=new L;let _=!1;const A=[],S={};let R=!1;function I(x){return x!==null?2*Math.PI/60*t.autoRotateSpeed*x:2*Math.PI/60/60*t.autoRotateSpeed}function P(x){const D=Math.abs(x*.01);return Math.pow(.95,t.zoomSpeed*D)}function M(x){l.theta-=x}function F(x){l.phi-=x}const E=function(){const x=new C;return function(k,O){x.setFromMatrixColumn(O,0),x.multiplyScalar(-k),f.add(x)}}(),B=function(){const x=new C;return function(k,O){t.screenSpacePanning===!0?x.setFromMatrixColumn(O,1):(x.setFromMatrixColumn(O,0),x.crossVectors(t.object.up,x)),x.multiplyScalar(k),f.add(x)}}(),z=function(){const x=new C;return function(k,O){const j=t.domElement;if(t.object.isPerspectiveCamera){const be=t.object.position;x.copy(be).sub(t.target);let ie=x.length();ie*=Math.tan(t.object.fov/2*Math.PI/180),E(2*k*ie/j.clientHeight,t.object.matrix),B(2*O*ie/j.clientHeight,t.object.matrix)}else t.object.isOrthographicCamera?(E(k*(t.object.right-t.object.left)/t.object.zoom/j.clientWidth,t.object.matrix),B(O*(t.object.top-t.object.bottom)/t.object.zoom/j.clientHeight,t.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),t.enablePan=!1)}}();function X(x){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?h/=x:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function ee(x){t.object.isPerspectiveCamera||t.object.isOrthographicCamera?h*=x:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),t.enableZoom=!1)}function te(x,D){if(!t.zoomToCursor)return;_=!0;const k=t.domElement.getBoundingClientRect(),O=x-k.left,j=D-k.top,be=k.width,ie=k.height;T.x=O/be*2-1,T.y=-(j/ie)*2+1,w.set(T.x,T.y,1).unproject(t.object).sub(t.object.position).normalize()}function Ee(x){return Math.max(t.minDistance,Math.min(t.maxDistance,x))}function Be(x){u.set(x.clientX,x.clientY)}function os(x){te(x.clientX,x.clientX),p.set(x.clientX,x.clientY)}function zi(x){v.set(x.clientX,x.clientY)}function cs(x){o.set(x.clientX,x.clientY),m.subVectors(o,u).multiplyScalar(t.rotateSpeed);const D=t.domElement;M(2*Math.PI*m.x/D.clientHeight),F(2*Math.PI*m.y/D.clientHeight),u.copy(o),t.update()}function ls(x){g.set(x.clientX,x.clientY),y.subVectors(g,p),y.y>0?X(P(y.y)):y.y<0&&ee(P(y.y)),p.copy(g),t.update()}function us(x){b.set(x.clientX,x.clientY),d.subVectors(b,v).multiplyScalar(t.panSpeed),z(d.x,d.y),v.copy(b),t.update()}function fs(x){te(x.clientX,x.clientY),x.deltaY<0?ee(P(x.deltaY)):x.deltaY>0&&X(P(x.deltaY)),t.update()}function hs(x){let D=!1;switch(x.code){case t.keys.UP:x.ctrlKey||x.metaKey||x.shiftKey?F(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):z(0,t.keyPanSpeed),D=!0;break;case t.keys.BOTTOM:x.ctrlKey||x.metaKey||x.shiftKey?F(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):z(0,-t.keyPanSpeed),D=!0;break;case t.keys.LEFT:x.ctrlKey||x.metaKey||x.shiftKey?M(2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):z(t.keyPanSpeed,0),D=!0;break;case t.keys.RIGHT:x.ctrlKey||x.metaKey||x.shiftKey?M(-2*Math.PI*t.rotateSpeed/t.domElement.clientHeight):z(-t.keyPanSpeed,0),D=!0;break}D&&(x.preventDefault(),t.update())}function Oi(x){if(A.length===1)u.set(x.pageX,x.pageY);else{const D=ke(x),k=.5*(x.pageX+D.x),O=.5*(x.pageY+D.y);u.set(k,O)}}function Ni(x){if(A.length===1)v.set(x.pageX,x.pageY);else{const D=ke(x),k=.5*(x.pageX+D.x),O=.5*(x.pageY+D.y);v.set(k,O)}}function Li(x){const D=ke(x),k=x.pageX-D.x,O=x.pageY-D.y,j=Math.sqrt(k*k+O*O);p.set(0,j)}function ds(x){t.enableZoom&&Li(x),t.enablePan&&Ni(x)}function ms(x){t.enableZoom&&Li(x),t.enableRotate&&Oi(x)}function Hi(x){if(A.length==1)o.set(x.pageX,x.pageY);else{const k=ke(x),O=.5*(x.pageX+k.x),j=.5*(x.pageY+k.y);o.set(O,j)}m.subVectors(o,u).multiplyScalar(t.rotateSpeed);const D=t.domElement;M(2*Math.PI*m.x/D.clientHeight),F(2*Math.PI*m.y/D.clientHeight),u.copy(o)}function Ui(x){if(A.length===1)b.set(x.pageX,x.pageY);else{const D=ke(x),k=.5*(x.pageX+D.x),O=.5*(x.pageY+D.y);b.set(k,O)}d.subVectors(b,v).multiplyScalar(t.panSpeed),z(d.x,d.y),v.copy(b)}function Wi(x){const D=ke(x),k=x.pageX-D.x,O=x.pageY-D.y,j=Math.sqrt(k*k+O*O);g.set(0,j),y.set(0,Math.pow(g.y/p.y,t.zoomSpeed)),X(y.y),p.copy(g);const be=(x.pageX+D.x)*.5,ie=(x.pageY+D.y)*.5;te(be,ie)}function ps(x){t.enableZoom&&Wi(x),t.enablePan&&Ui(x)}function gs(x){t.enableZoom&&Wi(x),t.enableRotate&&Hi(x)}function Vi(x){t.enabled!==!1&&(A.length===0&&(t.domElement.setPointerCapture(x.pointerId),t.domElement.addEventListener("pointermove",Yt),t.domElement.addEventListener("pointerup",it)),!As(x)&&(Ts(x),x.pointerType==="touch"?Yi(x):vs(x)))}function Yt(x){t.enabled!==!1&&(x.pointerType==="touch"?bs(x):xs(x))}function it(x){switch(ws(x),A.length){case 0:t.domElement.releasePointerCapture(x.pointerId),t.domElement.removeEventListener("pointermove",Yt),t.domElement.removeEventListener("pointerup",it),t.dispatchEvent(tr),a=n.NONE;break;case 1:const D=A[0],k=S[D];Yi({pointerId:D,pageX:k.x,pageY:k.y});break}}function vs(x){let D;switch(x.button){case 0:D=t.mouseButtons.LEFT;break;case 1:D=t.mouseButtons.MIDDLE;break;case 2:D=t.mouseButtons.RIGHT;break;default:D=-1}switch(D){case ze.DOLLY:if(t.enableZoom===!1)return;os(x),a=n.DOLLY;break;case ze.ROTATE:if(x.ctrlKey||x.metaKey||x.shiftKey){if(t.enablePan===!1)return;zi(x),a=n.PAN}else{if(t.enableRotate===!1)return;Be(x),a=n.ROTATE}break;case ze.PAN:if(x.ctrlKey||x.metaKey||x.shiftKey){if(t.enableRotate===!1)return;Be(x),a=n.ROTATE}else{if(t.enablePan===!1)return;zi(x),a=n.PAN}break;default:a=n.NONE}a!==n.NONE&&t.dispatchEvent(Kt)}function xs(x){switch(a){case n.ROTATE:if(t.enableRotate===!1)return;cs(x);break;case n.DOLLY:if(t.enableZoom===!1)return;ls(x);break;case n.PAN:if(t.enablePan===!1)return;us(x);break}}function qi(x){t.enabled===!1||t.enableZoom===!1||a!==n.NONE||(x.preventDefault(),t.dispatchEvent(Kt),fs(ys(x)),t.dispatchEvent(tr))}function ys(x){const D=x.deltaMode,k={clientX:x.clientX,clientY:x.clientY,deltaY:x.deltaY};switch(D){case 1:k.deltaY*=16;break;case 2:k.deltaY*=100;break}return x.ctrlKey&&!R&&(k.deltaY*=10),k}function ji(x){x.key==="Control"&&(R=!0,t.domElement.getRootNode().addEventListener("keyup",Gi,{passive:!0,capture:!0}))}function Gi(x){x.key==="Control"&&(R=!1,t.domElement.getRootNode().removeEventListener("keyup",Gi,{passive:!0,capture:!0}))}function $t(x){t.enabled===!1||t.enablePan===!1||hs(x)}function Yi(x){switch(Xi(x),A.length){case 1:switch(t.touches.ONE){case Oe.ROTATE:if(t.enableRotate===!1)return;Oi(x),a=n.TOUCH_ROTATE;break;case Oe.PAN:if(t.enablePan===!1)return;Ni(x),a=n.TOUCH_PAN;break;default:a=n.NONE}break;case 2:switch(t.touches.TWO){case Oe.DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;ds(x),a=n.TOUCH_DOLLY_PAN;break;case Oe.DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;ms(x),a=n.TOUCH_DOLLY_ROTATE;break;default:a=n.NONE}break;default:a=n.NONE}a!==n.NONE&&t.dispatchEvent(Kt)}function bs(x){switch(Xi(x),a){case n.TOUCH_ROTATE:if(t.enableRotate===!1)return;Hi(x),t.update();break;case n.TOUCH_PAN:if(t.enablePan===!1)return;Ui(x),t.update();break;case n.TOUCH_DOLLY_PAN:if(t.enableZoom===!1&&t.enablePan===!1)return;ps(x),t.update();break;case n.TOUCH_DOLLY_ROTATE:if(t.enableZoom===!1&&t.enableRotate===!1)return;gs(x),t.update();break;default:a=n.NONE}}function $i(x){t.enabled!==!1&&x.preventDefault()}function Ts(x){A.push(x.pointerId)}function ws(x){delete S[x.pointerId];for(let D=0;D<A.length;D++)if(A[D]==x.pointerId){A.splice(D,1);return}}function As(x){for(let D=0;D<A.length;D++)if(A[D]==x.pointerId)return!0;return!1}function Xi(x){let D=S[x.pointerId];D===void 0&&(D=new L,S[x.pointerId]=D),D.set(x.pageX,x.pageY)}function ke(x){const D=x.pointerId===A[0]?A[1]:A[0];return S[D]}t.domElement.addEventListener("contextmenu",$i),t.domElement.addEventListener("pointerdown",Vi),t.domElement.addEventListener("pointercancel",it),t.domElement.addEventListener("wheel",qi,{passive:!1}),t.domElement.getRootNode().addEventListener("keydown",ji,{passive:!0,capture:!0}),this.update()}}const qr=0,$s=1,jr=2,rr=2,Zt=1.25,sr=1,Se=6*4+4+4,jt=65535,Xs=Math.pow(2,-24),Qt=Symbol("SKIP_GENERATION");function Gr(s){return s.index?s.index.count:s.attributes.position.count}function tt(s){return Gr(s)/3}function Yr(s,e=ArrayBuffer){return s>65535?new Uint32Array(new e(4*s)):new Uint16Array(new e(2*s))}function Ks(s,e){if(!s.index){const i=s.attributes.position.count,t=e.useSharedArrayBuffer?SharedArrayBuffer:ArrayBuffer,n=Yr(i,t);s.setIndex(new re(n,1));for(let a=0;a<i;a++)n[a]=a}}function $r(s){const e=tt(s),i=s.drawRange,t=i.start/3,n=(i.start+i.count)/3,a=Math.max(0,t),r=Math.min(e,n)-a;return[{offset:Math.floor(a),count:Math.floor(r)}]}function Xr(s){if(!s.groups||!s.groups.length)return $r(s);const e=[],i=new Set,t=s.drawRange,n=t.start/3,a=(t.start+t.count)/3;for(const c of s.groups){const l=c.start/3,h=(c.start+c.count)/3;i.add(Math.max(n,l)),i.add(Math.min(a,h))}const r=Array.from(i.values()).sort((c,l)=>c-l);for(let c=0;c<r.length-1;c++){const l=r[c],h=r[c+1];e.push({offset:Math.floor(l),count:Math.floor(h-l)})}return e}function Zs(s){if(s.groups.length===0)return!1;const e=tt(s),i=Xr(s).sort((a,r)=>a.offset-r.offset),t=i[i.length-1];t.count=Math.min(e-t.offset,t.count);let n=0;return i.forEach(({count:a})=>n+=a),e!==n}function Jt(s,e,i,t,n){let a=1/0,r=1/0,c=1/0,l=-1/0,h=-1/0,f=-1/0,u=1/0,o=1/0,m=1/0,v=-1/0,b=-1/0,d=-1/0;for(let p=e*6,g=(e+i)*6;p<g;p+=6){const y=s[p+0],w=s[p+1],T=y-w,_=y+w;T<a&&(a=T),_>l&&(l=_),y<u&&(u=y),y>v&&(v=y);const A=s[p+2],S=s[p+3],R=A-S,I=A+S;R<r&&(r=R),I>h&&(h=I),A<o&&(o=A),A>b&&(b=A);const P=s[p+4],M=s[p+5],F=P-M,E=P+M;F<c&&(c=F),E>f&&(f=E),P<m&&(m=P),P>d&&(d=P)}t[0]=a,t[1]=r,t[2]=c,t[3]=l,t[4]=h,t[5]=f,n[0]=u,n[1]=o,n[2]=m,n[3]=v,n[4]=b,n[5]=d}function Qs(s,e=null,i=null,t=null){const n=s.attributes.position,a=s.index?s.index.array:null,r=tt(s),c=n.normalized;let l;e===null?(l=new Float32Array(r*6*4),i=0,t=r):(l=e,i=i||0,t=t||r);const h=n.array,f=n.offset||0;let u=3;n.isInterleavedBufferAttribute&&(u=n.data.stride);const o=["getX","getY","getZ"];for(let m=i;m<i+t;m++){const v=m*3,b=m*6;let d=v+0,p=v+1,g=v+2;a&&(d=a[d],p=a[p],g=a[g]),c||(d=d*u+f,p=p*u+f,g=g*u+f);for(let y=0;y<3;y++){let w,T,_;c?(w=n[o[y]](d),T=n[o[y]](p),_=n[o[y]](g)):(w=h[d+y],T=h[p+y],_=h[g+y]);let A=w;T<A&&(A=T),_<A&&(A=_);let S=w;T>S&&(S=T),_>S&&(S=_);const R=(S-A)/2,I=y*2;l[b+I+0]=A+R,l[b+I+1]=R+(Math.abs(A)+R)*Xs}}return l}function H(s,e,i){return i.min.x=e[s],i.min.y=e[s+1],i.min.z=e[s+2],i.max.x=e[s+3],i.max.y=e[s+4],i.max.z=e[s+5],i}function nr(s){let e=-1,i=-1/0;for(let t=0;t<3;t++){const n=s[t+3]-s[t];n>i&&(i=n,e=t)}return e}function ar(s,e){e.set(s)}function or(s,e,i){let t,n;for(let a=0;a<3;a++){const r=a+3;t=s[a],n=e[a],i[a]=t<n?t:n,t=s[r],n=e[r],i[r]=t>n?t:n}}function Tt(s,e,i){for(let t=0;t<3;t++){const n=e[s+2*t],a=e[s+2*t+1],r=n-a,c=n+a;r<i[t]&&(i[t]=r),c>i[t+3]&&(i[t+3]=c)}}function nt(s){const e=s[3]-s[0],i=s[4]-s[1],t=s[5]-s[2];return 2*(e*i+i*t+t*e)}const ge=32,Js=(s,e)=>s.candidate-e.candidate,Te=new Array(ge).fill().map(()=>({count:0,bounds:new Float32Array(6),rightCacheBounds:new Float32Array(6),leftCacheBounds:new Float32Array(6),candidate:0})),wt=new Float32Array(6);function en(s,e,i,t,n,a){let r=-1,c=0;if(a===qr)r=nr(e),r!==-1&&(c=(e[r]+e[r+3])/2);else if(a===$s)r=nr(s),r!==-1&&(c=tn(i,t,n,r));else if(a===jr){const l=nt(s);let h=Zt*n;const f=t*6,u=(t+n)*6;for(let o=0;o<3;o++){const m=e[o],d=(e[o+3]-m)/ge;if(n<ge/4){const p=[...Te];p.length=n;let g=0;for(let w=f;w<u;w+=6,g++){const T=p[g];T.candidate=i[w+2*o],T.count=0;const{bounds:_,leftCacheBounds:A,rightCacheBounds:S}=T;for(let R=0;R<3;R++)S[R]=1/0,S[R+3]=-1/0,A[R]=1/0,A[R+3]=-1/0,_[R]=1/0,_[R+3]=-1/0;Tt(w,i,_)}p.sort(Js);let y=n;for(let w=0;w<y;w++){const T=p[w];for(;w+1<y&&p[w+1].candidate===T.candidate;)p.splice(w+1,1),y--}for(let w=f;w<u;w+=6){const T=i[w+2*o];for(let _=0;_<y;_++){const A=p[_];T>=A.candidate?Tt(w,i,A.rightCacheBounds):(Tt(w,i,A.leftCacheBounds),A.count++)}}for(let w=0;w<y;w++){const T=p[w],_=T.count,A=n-T.count,S=T.leftCacheBounds,R=T.rightCacheBounds;let I=0;_!==0&&(I=nt(S)/l);let P=0;A!==0&&(P=nt(R)/l);const M=sr+Zt*(I*_+P*A);M<h&&(r=o,h=M,c=T.candidate)}}else{for(let y=0;y<ge;y++){const w=Te[y];w.count=0,w.candidate=m+d+y*d;const T=w.bounds;for(let _=0;_<3;_++)T[_]=1/0,T[_+3]=-1/0}for(let y=f;y<u;y+=6){let _=~~((i[y+2*o]-m)/d);_>=ge&&(_=ge-1);const A=Te[_];A.count++,Tt(y,i,A.bounds)}const p=Te[ge-1];ar(p.bounds,p.rightCacheBounds);for(let y=ge-2;y>=0;y--){const w=Te[y],T=Te[y+1];or(w.bounds,T.rightCacheBounds,w.rightCacheBounds)}let g=0;for(let y=0;y<ge-1;y++){const w=Te[y],T=w.count,_=w.bounds,S=Te[y+1].rightCacheBounds;T!==0&&(g===0?ar(_,wt):or(_,wt,wt)),g+=T;let R=0,I=0;g!==0&&(R=nt(wt)/l);const P=n-g;P!==0&&(I=nt(S)/l);const M=sr+Zt*(R*g+I*P);M<h&&(r=o,h=M,c=w.candidate)}}}}else console.warn(`MeshBVH: Invalid build strategy value ${a} used.`);return{axis:r,pos:c}}function tn(s,e,i,t){let n=0;for(let a=e,r=e+i;a<r;a++)n+=s[a*6+t*2];return n/i}class ei{constructor(){this.boundingData=new Float32Array(6)}}function rn(s,e,i,t,n,a){let r=t,c=t+n-1;const l=a.pos,h=a.axis*2;for(;;){for(;r<=c&&i[r*6+h]<l;)r++;for(;r<=c&&i[c*6+h]>=l;)c--;if(r<c){for(let f=0;f<3;f++){let u=e[r*3+f];e[r*3+f]=e[c*3+f],e[c*3+f]=u}for(let f=0;f<6;f++){let u=i[r*6+f];i[r*6+f]=i[c*6+f],i[c*6+f]=u}r++,c--}else return r}}function sn(s,e,i,t,n,a){let r=t,c=t+n-1;const l=a.pos,h=a.axis*2;for(;;){for(;r<=c&&i[r*6+h]<l;)r++;for(;r<=c&&i[c*6+h]>=l;)c--;if(r<c){let f=s[r];s[r]=s[c],s[c]=f;for(let u=0;u<6;u++){let o=i[r*6+u];i[r*6+u]=i[c*6+u],i[c*6+u]=o}r++,c--}else return r}}function G(s,e){return e[s+15]===65535}function Z(s,e){return e[s+6]}function Q(s,e){return e[s+14]}function se(s){return s+8}function J(s,e){return e[s+6]}function Pi(s,e){return e[s+7]}let Kr,ht,Ut,Zr;const nn=Math.pow(2,32);function vi(s){return"count"in s?1:1+vi(s.left)+vi(s.right)}function an(s,e,i){return Kr=new Float32Array(i),ht=new Uint32Array(i),Ut=new Uint16Array(i),Zr=new Uint8Array(i),xi(s,e)}function xi(s,e){const i=s/4,t=s/2,n="count"in e,a=e.boundingData;for(let r=0;r<6;r++)Kr[i+r]=a[r];if(n)if(e.buffer){const r=e.buffer;Zr.set(new Uint8Array(r),s);for(let c=s,l=s+r.byteLength;c<l;c+=Se){const h=c/2;G(h,Ut)||(ht[c/4+6]+=i)}return s+r.byteLength}else{const r=e.offset,c=e.count;return ht[i+6]=r,Ut[t+14]=c,Ut[t+15]=jt,s+Se}else{const r=e.left,c=e.right,l=e.splitAxis;let h;if(h=xi(s+Se,r),h/4>nn)throw new Error("MeshBVH: Cannot store child pointer greater than 32 bits.");return ht[i+6]=h/4,h=xi(h,c),ht[i+7]=l,h}}function on(s,e){const i=(s.index?s.index.count:s.attributes.position.count)/3,t=i>2**16,n=t?4:2,a=e?new SharedArrayBuffer(i*n):new ArrayBuffer(i*n),r=t?new Uint32Array(a):new Uint16Array(a);for(let c=0,l=r.length;c<l;c++)r[c]=c;return r}function cn(s,e,i,t,n){const{maxDepth:a,verbose:r,maxLeafTris:c,strategy:l,onProgress:h,indirect:f}=n,u=s._indirectBuffer,o=s.geometry,m=o.index?o.index.array:null,v=f?sn:rn,b=tt(o),d=new Float32Array(6);let p=!1;const g=new ei;return Jt(e,i,t,g.boundingData,d),w(g,i,t,d),g;function y(T){h&&h(T/b)}function w(T,_,A,S=null,R=0){if(!p&&R>=a&&(p=!0,r&&(console.warn(`MeshBVH: Max depth of ${a} reached when generating BVH. Consider increasing maxDepth.`),console.warn(o))),A<=c||R>=a)return y(_+A),T.offset=_,T.count=A,T;const I=en(T.boundingData,S,e,_,A,l);if(I.axis===-1)return y(_+A),T.offset=_,T.count=A,T;const P=v(u,m,e,_,A,I);if(P===_||P===_+A)y(_+A),T.offset=_,T.count=A;else{T.splitAxis=I.axis;const M=new ei,F=_,E=P-_;T.left=M,Jt(e,F,E,M.boundingData,d),w(M,F,E,d,R+1);const B=new ei,z=P,X=A-E;T.right=B,Jt(e,z,X,B.boundingData,d),w(B,z,X,d,R+1)}return T}}function ln(s,e){const i=s.geometry;e.indirect&&(s._indirectBuffer=on(i,e.useSharedArrayBuffer),Zs(i)&&!e.verbose&&console.warn('MeshBVH: Provided geometry contains groups that do not fully span the vertex contents while using the "indirect" option. BVH may incorrectly report intersections on unrendered portions of the geometry.')),s._indirectBuffer||Ks(i,e);const t=e.useSharedArrayBuffer?SharedArrayBuffer:ArrayBuffer,n=Qs(i),a=e.indirect?$r(i):Xr(i);s._roots=a.map(r=>{const c=cn(s,n,r.offset,r.count,e),l=vi(c),h=new t(Se*l);return an(0,c,h),h})}class ye{constructor(){this.min=1/0,this.max=-1/0}setFromPointsField(e,i){let t=1/0,n=-1/0;for(let a=0,r=e.length;a<r;a++){const l=e[a][i];t=l<t?l:t,n=l>n?l:n}this.min=t,this.max=n}setFromPoints(e,i){let t=1/0,n=-1/0;for(let a=0,r=i.length;a<r;a++){const c=i[a],l=e.dot(c);t=l<t?l:t,n=l>n?l:n}this.min=t,this.max=n}isSeparated(e){return this.min>e.max||e.min>this.max}}ye.prototype.setFromBox=function(){const s=new C;return function(i,t){const n=t.min,a=t.max;let r=1/0,c=-1/0;for(let l=0;l<=1;l++)for(let h=0;h<=1;h++)for(let f=0;f<=1;f++){s.x=n.x*l+a.x*(1-l),s.y=n.y*h+a.y*(1-h),s.z=n.z*f+a.z*(1-f);const u=i.dot(s);r=Math.min(u,r),c=Math.max(u,c)}this.min=r,this.max=c}}();const un=function(){const s=new C,e=new C,i=new C;return function(n,a,r){const c=n.start,l=s,h=a.start,f=e;i.subVectors(c,h),s.subVectors(n.end,n.start),e.subVectors(a.end,a.start);const u=i.dot(f),o=f.dot(l),m=f.dot(f),v=i.dot(l),d=l.dot(l)*m-o*o;let p,g;d!==0?p=(u*o-v*m)/d:p=0,g=(u+p*o)/m,r.x=p,r.y=g}}(),Ci=function(){const s=new L,e=new C,i=new C;return function(n,a,r,c){un(n,a,s);let l=s.x,h=s.y;if(l>=0&&l<=1&&h>=0&&h<=1){n.at(l,r),a.at(h,c);return}else if(l>=0&&l<=1){h<0?a.at(0,c):a.at(1,c),n.closestPointToPoint(c,!0,r);return}else if(h>=0&&h<=1){l<0?n.at(0,r):n.at(1,r),a.closestPointToPoint(r,!0,c);return}else{let f;l<0?f=n.start:f=n.end;let u;h<0?u=a.start:u=a.end;const o=e,m=i;if(n.closestPointToPoint(u,!0,e),a.closestPointToPoint(f,!0,i),o.distanceToSquared(u)<=m.distanceToSquared(f)){r.copy(o),c.copy(u);return}else{r.copy(f),c.copy(m);return}}}}(),fn=function(){const s=new C,e=new C,i=new Ii,t=new xe;return function(a,r){const{radius:c,center:l}=a,{a:h,b:f,c:u}=r;if(t.start=h,t.end=f,t.closestPointToPoint(l,!0,s).distanceTo(l)<=c||(t.start=h,t.end=u,t.closestPointToPoint(l,!0,s).distanceTo(l)<=c)||(t.start=f,t.end=u,t.closestPointToPoint(l,!0,s).distanceTo(l)<=c))return!0;const b=r.getPlane(i);if(Math.abs(b.distanceToPoint(l))<=c){const p=b.projectPoint(l,e);if(r.containsPoint(p))return!0}return!1}}(),hn=1e-15;function ti(s){return Math.abs(s)<hn}class ue extends ft{constructor(...e){super(...e),this.isExtendedTriangle=!0,this.satAxes=new Array(4).fill().map(()=>new C),this.satBounds=new Array(4).fill().map(()=>new ye),this.points=[this.a,this.b,this.c],this.sphere=new Cs,this.plane=new Ii,this.needsUpdate=!0}intersectsSphere(e){return fn(e,this)}update(){const e=this.a,i=this.b,t=this.c,n=this.points,a=this.satAxes,r=this.satBounds,c=a[0],l=r[0];this.getNormal(c),l.setFromPoints(c,n);const h=a[1],f=r[1];h.subVectors(e,i),f.setFromPoints(h,n);const u=a[2],o=r[2];u.subVectors(i,t),o.setFromPoints(u,n);const m=a[3],v=r[3];m.subVectors(t,e),v.setFromPoints(m,n),this.sphere.setFromPoints(this.points),this.plane.setFromNormalAndCoplanarPoint(c,e),this.needsUpdate=!1}}ue.prototype.closestPointToSegment=function(){const s=new C,e=new C,i=new xe;return function(n,a=null,r=null){const{start:c,end:l}=n,h=this.points;let f,u=1/0;for(let o=0;o<3;o++){const m=(o+1)%3;i.start.copy(h[o]),i.end.copy(h[m]),Ci(i,n,s,e),f=s.distanceToSquared(e),f<u&&(u=f,a&&a.copy(s),r&&r.copy(e))}return this.closestPointToPoint(c,s),f=c.distanceToSquared(s),f<u&&(u=f,a&&a.copy(s),r&&r.copy(c)),this.closestPointToPoint(l,s),f=l.distanceToSquared(s),f<u&&(u=f,a&&a.copy(s),r&&r.copy(l)),Math.sqrt(u)}}();ue.prototype.intersectsTriangle=function(){const s=new ue,e=new Array(3),i=new Array(3),t=new ye,n=new ye,a=new C,r=new C,c=new C,l=new C,h=new C,f=new xe,u=new xe,o=new xe,m=new C;function v(b,d,p){const g=b.points;let y=0,w=-1;for(let T=0;T<3;T++){const{start:_,end:A}=f;_.copy(g[T]),A.copy(g[(T+1)%3]),f.delta(r);const S=ti(d.distanceToPoint(_));if(ti(d.normal.dot(r))&&S){p.copy(f),y=2;break}const R=d.intersectLine(f,m);if(!R&&S&&m.copy(_),(R||S)&&!ti(m.distanceTo(A))){if(y<=1)(y===1?p.start:p.end).copy(m),S&&(w=y);else if(y>=2){(w===1?p.start:p.end).copy(m),y=2;break}if(y++,y===2&&w===-1)break}}return y}return function(d,p=null,g=!1){this.needsUpdate&&this.update(),d.isExtendedTriangle?d.needsUpdate&&d.update():(s.copy(d),s.update(),d=s);const y=this.plane,w=d.plane;if(Math.abs(y.normal.dot(w.normal))>1-1e-10){const T=this.satBounds,_=this.satAxes;i[0]=d.a,i[1]=d.b,i[2]=d.c;for(let R=0;R<4;R++){const I=T[R],P=_[R];if(t.setFromPoints(P,i),I.isSeparated(t))return!1}const A=d.satBounds,S=d.satAxes;e[0]=this.a,e[1]=this.b,e[2]=this.c;for(let R=0;R<4;R++){const I=A[R],P=S[R];if(t.setFromPoints(P,e),I.isSeparated(t))return!1}for(let R=0;R<4;R++){const I=_[R];for(let P=0;P<4;P++){const M=S[P];if(a.crossVectors(I,M),t.setFromPoints(a,e),n.setFromPoints(a,i),t.isSeparated(n))return!1}}return p&&(g||console.warn("ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0."),p.start.set(0,0,0),p.end.set(0,0,0)),!0}else{const T=v(this,w,u);if(T===1&&d.containsPoint(u.end))return p&&(p.start.copy(u.end),p.end.copy(u.end)),!0;if(T!==2)return!1;const _=v(d,y,o);if(_===1&&this.containsPoint(o.end))return p&&(p.start.copy(o.end),p.end.copy(o.end)),!0;if(_!==2)return!1;if(u.delta(c),o.delta(l),c.dot(l)<0){let F=o.start;o.start=o.end,o.end=F}const A=u.start.dot(c),S=u.end.dot(c),R=o.start.dot(c),I=o.end.dot(c),P=S<R,M=A<I;return A!==I&&R!==S&&P===M?!1:(p&&(h.subVectors(u.start,o.start),h.dot(c)>0?p.start.copy(u.start):p.start.copy(o.start),h.subVectors(u.end,o.end),h.dot(c)<0?p.end.copy(u.end):p.end.copy(o.end)),!0)}}}();ue.prototype.distanceToPoint=function(){const s=new C;return function(i){return this.closestPointToPoint(i,s),i.distanceTo(s)}}();ue.prototype.distanceToTriangle=function(){const s=new C,e=new C,i=["a","b","c"],t=new xe,n=new xe;return function(r,c=null,l=null){const h=c||l?t:null;if(this.intersectsTriangle(r,h))return(c||l)&&(c&&h.getCenter(c),l&&h.getCenter(l)),0;let f=1/0;for(let u=0;u<3;u++){let o;const m=i[u],v=r[m];this.closestPointToPoint(v,s),o=v.distanceToSquared(s),o<f&&(f=o,c&&c.copy(s),l&&l.copy(v));const b=this[m];r.closestPointToPoint(b,s),o=b.distanceToSquared(s),o<f&&(f=o,c&&c.copy(b),l&&l.copy(s))}for(let u=0;u<3;u++){const o=i[u],m=i[(u+1)%3];t.set(this[o],this[m]);for(let v=0;v<3;v++){const b=i[v],d=i[(v+1)%3];n.set(r[b],r[d]),Ci(t,n,s,e);const p=s.distanceToSquared(e);p<f&&(f=p,c&&c.copy(s),l&&l.copy(e))}}return Math.sqrt(f)}}();class ${constructor(e,i,t){this.isOrientedBox=!0,this.min=new C,this.max=new C,this.matrix=new Y,this.invMatrix=new Y,this.points=new Array(8).fill().map(()=>new C),this.satAxes=new Array(3).fill().map(()=>new C),this.satBounds=new Array(3).fill().map(()=>new ye),this.alignedSatBounds=new Array(3).fill().map(()=>new ye),this.needsUpdate=!1,e&&this.min.copy(e),i&&this.max.copy(i),t&&this.matrix.copy(t)}set(e,i,t){this.min.copy(e),this.max.copy(i),this.matrix.copy(t),this.needsUpdate=!0}copy(e){this.min.copy(e.min),this.max.copy(e.max),this.matrix.copy(e.matrix),this.needsUpdate=!0}}$.prototype.update=function(){return function(){const e=this.matrix,i=this.min,t=this.max,n=this.points;for(let h=0;h<=1;h++)for(let f=0;f<=1;f++)for(let u=0;u<=1;u++){const o=1*h|2*f|4*u,m=n[o];m.x=h?t.x:i.x,m.y=f?t.y:i.y,m.z=u?t.z:i.z,m.applyMatrix4(e)}const a=this.satBounds,r=this.satAxes,c=n[0];for(let h=0;h<3;h++){const f=r[h],u=a[h],o=1<<h,m=n[o];f.subVectors(c,m),u.setFromPoints(f,n)}const l=this.alignedSatBounds;l[0].setFromPointsField(n,"x"),l[1].setFromPointsField(n,"y"),l[2].setFromPointsField(n,"z"),this.invMatrix.copy(this.matrix).invert(),this.needsUpdate=!1}}();$.prototype.intersectsBox=function(){const s=new ye;return function(i){this.needsUpdate&&this.update();const t=i.min,n=i.max,a=this.satBounds,r=this.satAxes,c=this.alignedSatBounds;if(s.min=t.x,s.max=n.x,c[0].isSeparated(s)||(s.min=t.y,s.max=n.y,c[1].isSeparated(s))||(s.min=t.z,s.max=n.z,c[2].isSeparated(s)))return!1;for(let l=0;l<3;l++){const h=r[l],f=a[l];if(s.setFromBox(h,i),f.isSeparated(s))return!1}return!0}}();$.prototype.intersectsTriangle=function(){const s=new ue,e=new Array(3),i=new ye,t=new ye,n=new C;return function(r){this.needsUpdate&&this.update(),r.isExtendedTriangle?r.needsUpdate&&r.update():(s.copy(r),s.update(),r=s);const c=this.satBounds,l=this.satAxes;e[0]=r.a,e[1]=r.b,e[2]=r.c;for(let o=0;o<3;o++){const m=c[o],v=l[o];if(i.setFromPoints(v,e),m.isSeparated(i))return!1}const h=r.satBounds,f=r.satAxes,u=this.points;for(let o=0;o<3;o++){const m=h[o],v=f[o];if(i.setFromPoints(v,u),m.isSeparated(i))return!1}for(let o=0;o<3;o++){const m=l[o];for(let v=0;v<4;v++){const b=f[v];if(n.crossVectors(m,b),i.setFromPoints(n,e),t.setFromPoints(n,u),i.isSeparated(t))return!1}}return!0}}();$.prototype.closestPointToPoint=function(){return function(e,i){return this.needsUpdate&&this.update(),i.copy(e).applyMatrix4(this.invMatrix).clamp(this.min,this.max).applyMatrix4(this.matrix),i}}();$.prototype.distanceToPoint=function(){const s=new C;return function(i){return this.closestPointToPoint(i,s),i.distanceTo(s)}}();$.prototype.distanceToBox=function(){const s=["x","y","z"],e=new Array(12).fill().map(()=>new xe),i=new Array(12).fill().map(()=>new xe),t=new C,n=new C;return function(r,c=0,l=null,h=null){if(this.needsUpdate&&this.update(),this.intersectsBox(r))return(l||h)&&(r.getCenter(n),this.closestPointToPoint(n,t),r.closestPointToPoint(t,n),l&&l.copy(t),h&&h.copy(n)),0;const f=c*c,u=r.min,o=r.max,m=this.points;let v=1/0;for(let d=0;d<8;d++){const p=m[d];n.copy(p).clamp(u,o);const g=p.distanceToSquared(n);if(g<v&&(v=g,l&&l.copy(p),h&&h.copy(n),g<f))return Math.sqrt(g)}let b=0;for(let d=0;d<3;d++)for(let p=0;p<=1;p++)for(let g=0;g<=1;g++){const y=(d+1)%3,w=(d+2)%3,T=p<<y|g<<w,_=1<<d|p<<y|g<<w,A=m[T],S=m[_];e[b].set(A,S);const I=s[d],P=s[y],M=s[w],F=i[b],E=F.start,B=F.end;E[I]=u[I],E[P]=p?u[P]:o[P],E[M]=g?u[M]:o[P],B[I]=o[I],B[P]=p?u[P]:o[P],B[M]=g?u[M]:o[P],b++}for(let d=0;d<=1;d++)for(let p=0;p<=1;p++)for(let g=0;g<=1;g++){n.x=d?o.x:u.x,n.y=p?o.y:u.y,n.z=g?o.z:u.z,this.closestPointToPoint(n,t);const y=n.distanceToSquared(t);if(y<v&&(v=y,l&&l.copy(t),h&&h.copy(n),y<f))return Math.sqrt(y)}for(let d=0;d<12;d++){const p=e[d];for(let g=0;g<12;g++){const y=i[g];Ci(p,y,t,n);const w=t.distanceToSquared(n);if(w<v&&(v=w,l&&l.copy(t),h&&h.copy(n),w<f))return Math.sqrt(w)}}return Math.sqrt(v)}}();class Fi{constructor(e){this._getNewPrimitive=e,this._primitives=[]}getPrimitive(){const e=this._primitives;return e.length===0?this._getNewPrimitive():e.pop()}releasePrimitive(e){this._primitives.push(e)}}class dn extends Fi{constructor(){super(()=>new ue)}}const ne=new dn;class mn{constructor(){this.float32Array=null,this.uint16Array=null,this.uint32Array=null;const e=[];let i=null;this.setBuffer=t=>{i&&e.push(i),i=t,this.float32Array=new Float32Array(t),this.uint16Array=new Uint16Array(t),this.uint32Array=new Uint32Array(t)},this.clearBuffer=()=>{i=null,this.float32Array=null,this.uint16Array=null,this.uint32Array=null,e.length!==0&&this.setBuffer(e.pop())}}}const N=new mn;let Ae,Qe;const Ne=[],At=new Fi(()=>new he);function pn(s,e,i,t,n,a){Ae=At.getPrimitive(),Qe=At.getPrimitive(),Ne.push(Ae,Qe),N.setBuffer(s._roots[e]);const r=yi(0,s.geometry,i,t,n,a);N.clearBuffer(),At.releasePrimitive(Ae),At.releasePrimitive(Qe),Ne.pop(),Ne.pop();const c=Ne.length;return c>0&&(Qe=Ne[c-1],Ae=Ne[c-2]),r}function yi(s,e,i,t,n=null,a=0,r=0){const{float32Array:c,uint16Array:l,uint32Array:h}=N;let f=s*2;if(G(f,l)){const o=Z(s,h),m=Q(f,l);return H(s,c,Ae),t(o,m,!1,r,a+s,Ae)}else{let I=function(M){const{uint16Array:F,uint32Array:E}=N;let B=M*2;for(;!G(B,F);)M=se(M),B=M*2;return Z(M,E)},P=function(M){const{uint16Array:F,uint32Array:E}=N;let B=M*2;for(;!G(B,F);)M=J(M,E),B=M*2;return Z(M,E)+Q(B,F)};const o=se(s),m=J(s,h);let v=o,b=m,d,p,g,y;if(n&&(g=Ae,y=Qe,H(v,c,g),H(b,c,y),d=n(g),p=n(y),p<d)){v=m,b=o;const M=d;d=p,p=M,g=y}g||(g=Ae,H(v,c,g));const w=G(v*2,l),T=i(g,w,d,r+1,a+v);let _;if(T===rr){const M=I(v),E=P(v)-M;_=t(M,E,!0,r+1,a+v,g)}else _=T&&yi(v,e,i,t,n,a,r+1);if(_)return!0;y=Qe,H(b,c,y);const A=G(b*2,l),S=i(y,A,p,r+1,a+b);let R;if(S===rr){const M=I(b),E=P(b)-M;R=t(M,E,!0,r+1,a+b,y)}else R=S&&yi(b,e,i,t,n,a,r+1);return!!R}}const at=new C,ii=new C;function gn(s,e,i={},t=0,n=1/0){const a=t*t,r=n*n;let c=1/0,l=null;if(s.shapecast({boundsTraverseOrder:f=>(at.copy(e).clamp(f.min,f.max),at.distanceToSquared(e)),intersectsBounds:(f,u,o)=>o<c&&o<r,intersectsTriangle:(f,u)=>{f.closestPointToPoint(e,at);const o=e.distanceToSquared(at);return o<c&&(ii.copy(at),c=o,l=u),o<a}}),c===1/0)return null;const h=Math.sqrt(c);return i.point?i.point.copy(ii):i.point=ii.clone(),i.distance=h,i.faceIndex=l,i}const Le=new C,He=new C,Ue=new C,_t=new L,St=new L,Mt=new L,cr=new C,lr=new C,ur=new C,Rt=new C;function vn(s,e,i,t,n,a,r,c){let l;if(a===Or?l=s.intersectTriangle(t,i,e,!0,n):l=s.intersectTriangle(e,i,t,a!==Nr,n),l===null)return null;const h=s.origin.distanceTo(n);return h<r||h>c?null:{distance:h,point:n.clone()}}function xn(s,e,i,t,n,a,r,c,l,h,f){Le.fromBufferAttribute(e,a),He.fromBufferAttribute(e,r),Ue.fromBufferAttribute(e,c);const u=vn(s,Le,He,Ue,Rt,l,h,f);if(u){t&&(_t.fromBufferAttribute(t,a),St.fromBufferAttribute(t,r),Mt.fromBufferAttribute(t,c),u.uv=ft.getInterpolation(Rt,Le,He,Ue,_t,St,Mt,new L)),n&&(_t.fromBufferAttribute(n,a),St.fromBufferAttribute(n,r),Mt.fromBufferAttribute(n,c),u.uv1=ft.getInterpolation(Rt,Le,He,Ue,_t,St,Mt,new L)),i&&(cr.fromBufferAttribute(i,a),lr.fromBufferAttribute(i,r),ur.fromBufferAttribute(i,c),u.normal=ft.getInterpolation(Rt,Le,He,Ue,cr,lr,ur,new C),u.normal.dot(s.direction)>0&&u.normal.multiplyScalar(-1));const o={a,b:r,c,normal:new C,materialIndex:0};ft.getNormal(Le,He,Ue,o.normal),u.face=o,u.faceIndex=a}return u}function Gt(s,e,i,t,n,a,r){const c=t*3;let l=c+0,h=c+1,f=c+2;const u=s.index;s.index&&(l=u.getX(l),h=u.getX(h),f=u.getX(f));const{position:o,normal:m,uv:v,uv1:b}=s.attributes,d=xn(i,o,m,v,b,l,h,f,e,a,r);return d?(d.faceIndex=t,n&&n.push(d),d):null}function W(s,e,i,t){const n=s.a,a=s.b,r=s.c;let c=e,l=e+1,h=e+2;i&&(c=i.getX(c),l=i.getX(l),h=i.getX(h)),n.x=t.getX(c),n.y=t.getY(c),n.z=t.getZ(c),a.x=t.getX(l),a.y=t.getY(l),a.z=t.getZ(l),r.x=t.getX(h),r.y=t.getY(h),r.z=t.getZ(h)}function yn(s,e,i,t,n,a,r,c){const{geometry:l,_indirectBuffer:h}=s;for(let f=t,u=t+n;f<u;f++)Gt(l,e,i,f,a,r,c)}function bn(s,e,i,t,n,a,r){const{geometry:c,_indirectBuffer:l}=s;let h=1/0,f=null;for(let u=t,o=t+n;u<o;u++){let m;m=Gt(c,e,i,u,null,a,r),m&&m.distance<h&&(f=m,h=m.distance)}return f}function Tn(s,e,i,t,n,a,r){const{geometry:c}=i,{index:l}=c,h=c.attributes.position;for(let f=s,u=e+s;f<u;f++){let o;if(o=f,W(r,o*3,l,h),r.needsUpdate=!0,t(r,o,n,a))return!0}return!1}function wn(s,e=null){e&&Array.isArray(e)&&(e=new Set(e));const i=s.geometry,t=i.index?i.index.array:null,n=i.attributes.position;let a,r,c,l,h=0;const f=s._roots;for(let o=0,m=f.length;o<m;o++)a=f[o],r=new Uint32Array(a),c=new Uint16Array(a),l=new Float32Array(a),u(0,h),h+=a.byteLength;function u(o,m,v=!1){const b=o*2;if(c[b+15]===jt){const p=r[o+6],g=c[b+14];let y=1/0,w=1/0,T=1/0,_=-1/0,A=-1/0,S=-1/0;for(let R=3*p,I=3*(p+g);R<I;R++){let P=t[R];const M=n.getX(P),F=n.getY(P),E=n.getZ(P);M<y&&(y=M),M>_&&(_=M),F<w&&(w=F),F>A&&(A=F),E<T&&(T=E),E>S&&(S=E)}return l[o+0]!==y||l[o+1]!==w||l[o+2]!==T||l[o+3]!==_||l[o+4]!==A||l[o+5]!==S?(l[o+0]=y,l[o+1]=w,l[o+2]=T,l[o+3]=_,l[o+4]=A,l[o+5]=S,!0):!1}else{const p=o+8,g=r[o+6],y=p+m,w=g+m;let T=v,_=!1,A=!1;e?T||(_=e.has(y),A=e.has(w),T=!_&&!A):(_=!0,A=!0);const S=T||_,R=T||A;let I=!1;S&&(I=u(p,m,T));let P=!1;R&&(P=u(g,m,T));const M=I||P;if(M)for(let F=0;F<3;F++){const E=p+F,B=g+F,z=l[E],X=l[E+3],ee=l[B],te=l[B+3];l[o+F]=z<ee?z:ee,l[o+F+3]=X>te?X:te}return M}}}function Re(s,e,i,t,n){let a,r,c,l,h,f;const u=1/i.direction.x,o=1/i.direction.y,m=1/i.direction.z,v=i.origin.x,b=i.origin.y,d=i.origin.z;let p=e[s],g=e[s+3],y=e[s+1],w=e[s+3+1],T=e[s+2],_=e[s+3+2];return u>=0?(a=(p-v)*u,r=(g-v)*u):(a=(g-v)*u,r=(p-v)*u),o>=0?(c=(y-b)*o,l=(w-b)*o):(c=(w-b)*o,l=(y-b)*o),a>l||c>r||((c>a||isNaN(a))&&(a=c),(l<r||isNaN(r))&&(r=l),m>=0?(h=(T-d)*m,f=(_-d)*m):(h=(_-d)*m,f=(T-d)*m),a>f||h>r)?!1:((h>a||a!==a)&&(a=h),(f<r||r!==r)&&(r=f),a<=n&&r>=t)}function An(s,e,i,t,n,a,r,c){const{geometry:l,_indirectBuffer:h}=s;for(let f=t,u=t+n;f<u;f++){let o=h?h[f]:f;Gt(l,e,i,o,a,r,c)}}function _n(s,e,i,t,n,a,r){const{geometry:c,_indirectBuffer:l}=s;let h=1/0,f=null;for(let u=t,o=t+n;u<o;u++){let m;m=Gt(c,e,i,l?l[u]:u,null,a,r),m&&m.distance<h&&(f=m,h=m.distance)}return f}function Sn(s,e,i,t,n,a,r){const{geometry:c}=i,{index:l}=c,h=c.attributes.position;for(let f=s,u=e+s;f<u;f++){let o;if(o=i.resolveTriangleIndex(f),W(r,o*3,l,h),r.needsUpdate=!0,t(r,o,n,a))return!0}return!1}function Mn(s,e,i,t,n,a,r){N.setBuffer(s._roots[e]),bi(0,s,i,t,n,a,r),N.clearBuffer()}function bi(s,e,i,t,n,a,r){const{float32Array:c,uint16Array:l,uint32Array:h}=N,f=s*2;if(G(f,l)){const o=Z(s,h),m=Q(f,l);yn(e,i,t,o,m,n,a,r)}else{const o=se(s);Re(o,c,t,a,r)&&bi(o,e,i,t,n,a,r);const m=J(s,h);Re(m,c,t,a,r)&&bi(m,e,i,t,n,a,r)}}const Rn=["x","y","z"];function In(s,e,i,t,n,a){N.setBuffer(s._roots[e]);const r=Ti(0,s,i,t,n,a);return N.clearBuffer(),r}function Ti(s,e,i,t,n,a){const{float32Array:r,uint16Array:c,uint32Array:l}=N;let h=s*2;if(G(h,c)){const u=Z(s,l),o=Q(h,c);return bn(e,i,t,u,o,n,a)}else{const u=Pi(s,l),o=Rn[u],v=t.direction[o]>=0;let b,d;v?(b=se(s),d=J(s,l)):(b=J(s,l),d=se(s));const g=Re(b,r,t,n,a)?Ti(b,e,i,t,n,a):null;if(g){const T=g.point[o];if(v?T<=r[d+u]:T>=r[d+u+3])return g}const w=Re(d,r,t,n,a)?Ti(d,e,i,t,n,a):null;return g&&w?g.distance<=w.distance?g:w:g||w||null}}const It=new he,We=new ue,Ve=new ue,ot=new Y,fr=new $,Pt=new $;function Pn(s,e,i,t){N.setBuffer(s._roots[e]);const n=wi(0,s,i,t);return N.clearBuffer(),n}function wi(s,e,i,t,n=null){const{float32Array:a,uint16Array:r,uint32Array:c}=N;let l=s*2;if(n===null&&(i.boundingBox||i.computeBoundingBox(),fr.set(i.boundingBox.min,i.boundingBox.max,t),n=fr),G(l,r)){const f=e.geometry,u=f.index,o=f.attributes.position,m=i.index,v=i.attributes.position,b=Z(s,c),d=Q(l,r);if(ot.copy(t).invert(),i.boundsTree)return H(s,a,Pt),Pt.matrix.copy(ot),Pt.needsUpdate=!0,i.boundsTree.shapecast({intersectsBounds:g=>Pt.intersectsBox(g),intersectsTriangle:g=>{g.a.applyMatrix4(t),g.b.applyMatrix4(t),g.c.applyMatrix4(t),g.needsUpdate=!0;for(let y=b*3,w=(d+b)*3;y<w;y+=3)if(W(Ve,y,u,o),Ve.needsUpdate=!0,g.intersectsTriangle(Ve))return!0;return!1}});for(let p=b*3,g=(d+b)*3;p<g;p+=3){W(We,p,u,o),We.a.applyMatrix4(ot),We.b.applyMatrix4(ot),We.c.applyMatrix4(ot),We.needsUpdate=!0;for(let y=0,w=m.count;y<w;y+=3)if(W(Ve,y,m,v),Ve.needsUpdate=!0,We.intersectsTriangle(Ve))return!0}}else{const f=s+8,u=c[s+6];return H(f,a,It),!!(n.intersectsBox(It)&&wi(f,e,i,t,n)||(H(u,a,It),n.intersectsBox(It)&&wi(u,e,i,t,n)))}}const Ct=new Y,ri=new $,ct=new $,Cn=new C,Fn=new C,Dn=new C,En=new C;function Bn(s,e,i,t={},n={},a=0,r=1/0){e.boundingBox||e.computeBoundingBox(),ri.set(e.boundingBox.min,e.boundingBox.max,i),ri.needsUpdate=!0;const c=s.geometry,l=c.attributes.position,h=c.index,f=e.attributes.position,u=e.index,o=ne.getPrimitive(),m=ne.getPrimitive();let v=Cn,b=Fn,d=null,p=null;n&&(d=Dn,p=En);let g=1/0,y=null,w=null;return Ct.copy(i).invert(),ct.matrix.copy(Ct),s.shapecast({boundsTraverseOrder:T=>ri.distanceToBox(T),intersectsBounds:(T,_,A)=>A<g&&A<r?(_&&(ct.min.copy(T.min),ct.max.copy(T.max),ct.needsUpdate=!0),!0):!1,intersectsRange:(T,_)=>{if(e.boundsTree)return e.boundsTree.shapecast({boundsTraverseOrder:S=>ct.distanceToBox(S),intersectsBounds:(S,R,I)=>I<g&&I<r,intersectsRange:(S,R)=>{for(let I=S,P=S+R;I<P;I++){W(m,3*I,u,f),m.a.applyMatrix4(i),m.b.applyMatrix4(i),m.c.applyMatrix4(i),m.needsUpdate=!0;for(let M=T,F=T+_;M<F;M++){W(o,3*M,h,l),o.needsUpdate=!0;const E=o.distanceToTriangle(m,v,d);if(E<g&&(b.copy(v),p&&p.copy(d),g=E,y=M,w=I),E<a)return!0}}}});{const A=tt(e);for(let S=0,R=A;S<R;S++){W(m,3*S,u,f),m.a.applyMatrix4(i),m.b.applyMatrix4(i),m.c.applyMatrix4(i),m.needsUpdate=!0;for(let I=T,P=T+_;I<P;I++){W(o,3*I,h,l),o.needsUpdate=!0;const M=o.distanceToTriangle(m,v,d);if(M<g&&(b.copy(v),p&&p.copy(d),g=M,y=I,w=S),M<a)return!0}}}}}),ne.releasePrimitive(o),ne.releasePrimitive(m),g===1/0?null:(t.point?t.point.copy(b):t.point=b.clone(),t.distance=g,t.faceIndex=y,n&&(n.point?n.point.copy(p):n.point=p.clone(),n.point.applyMatrix4(Ct),b.applyMatrix4(Ct),n.distance=b.sub(n.point).length(),n.faceIndex=w),t)}function kn(s,e=null){e&&Array.isArray(e)&&(e=new Set(e));const i=s.geometry,t=i.index?i.index.array:null,n=i.attributes.position;let a,r,c,l,h=0;const f=s._roots;for(let o=0,m=f.length;o<m;o++)a=f[o],r=new Uint32Array(a),c=new Uint16Array(a),l=new Float32Array(a),u(0,h),h+=a.byteLength;function u(o,m,v=!1){const b=o*2;if(c[b+15]===jt){const p=r[o+6],g=c[b+14];let y=1/0,w=1/0,T=1/0,_=-1/0,A=-1/0,S=-1/0;for(let R=p,I=p+g;R<I;R++){const P=3*s.resolveTriangleIndex(R);for(let M=0;M<3;M++){let F=P+M;F=t?t[F]:F;const E=n.getX(F),B=n.getY(F),z=n.getZ(F);E<y&&(y=E),E>_&&(_=E),B<w&&(w=B),B>A&&(A=B),z<T&&(T=z),z>S&&(S=z)}}return l[o+0]!==y||l[o+1]!==w||l[o+2]!==T||l[o+3]!==_||l[o+4]!==A||l[o+5]!==S?(l[o+0]=y,l[o+1]=w,l[o+2]=T,l[o+3]=_,l[o+4]=A,l[o+5]=S,!0):!1}else{const p=o+8,g=r[o+6],y=p+m,w=g+m;let T=v,_=!1,A=!1;e?T||(_=e.has(y),A=e.has(w),T=!_&&!A):(_=!0,A=!0);const S=T||_,R=T||A;let I=!1;S&&(I=u(p,m,T));let P=!1;R&&(P=u(g,m,T));const M=I||P;if(M)for(let F=0;F<3;F++){const E=p+F,B=g+F,z=l[E],X=l[E+3],ee=l[B],te=l[B+3];l[o+F]=z<ee?z:ee,l[o+F+3]=X>te?X:te}return M}}}function zn(s,e,i,t,n,a,r){N.setBuffer(s._roots[e]),Ai(0,s,i,t,n,a,r),N.clearBuffer()}function Ai(s,e,i,t,n,a,r){const{float32Array:c,uint16Array:l,uint32Array:h}=N,f=s*2;if(G(f,l)){const o=Z(s,h),m=Q(f,l);An(e,i,t,o,m,n,a,r)}else{const o=se(s);Re(o,c,t,a,r)&&Ai(o,e,i,t,n,a,r);const m=J(s,h);Re(m,c,t,a,r)&&Ai(m,e,i,t,n,a,r)}}const On=["x","y","z"];function Nn(s,e,i,t,n,a){N.setBuffer(s._roots[e]);const r=_i(0,s,i,t,n,a);return N.clearBuffer(),r}function _i(s,e,i,t,n,a){const{float32Array:r,uint16Array:c,uint32Array:l}=N;let h=s*2;if(G(h,c)){const u=Z(s,l),o=Q(h,c);return _n(e,i,t,u,o,n,a)}else{const u=Pi(s,l),o=On[u],v=t.direction[o]>=0;let b,d;v?(b=se(s),d=J(s,l)):(b=J(s,l),d=se(s));const g=Re(b,r,t,n,a)?_i(b,e,i,t,n,a):null;if(g){const T=g.point[o];if(v?T<=r[d+u]:T>=r[d+u+3])return g}const w=Re(d,r,t,n,a)?_i(d,e,i,t,n,a):null;return g&&w?g.distance<=w.distance?g:w:g||w||null}}const Ft=new he,qe=new ue,je=new ue,lt=new Y,hr=new $,Dt=new $;function Ln(s,e,i,t){N.setBuffer(s._roots[e]);const n=Si(0,s,i,t);return N.clearBuffer(),n}function Si(s,e,i,t,n=null){const{float32Array:a,uint16Array:r,uint32Array:c}=N;let l=s*2;if(n===null&&(i.boundingBox||i.computeBoundingBox(),hr.set(i.boundingBox.min,i.boundingBox.max,t),n=hr),G(l,r)){const f=e.geometry,u=f.index,o=f.attributes.position,m=i.index,v=i.attributes.position,b=Z(s,c),d=Q(l,r);if(lt.copy(t).invert(),i.boundsTree)return H(s,a,Dt),Dt.matrix.copy(lt),Dt.needsUpdate=!0,i.boundsTree.shapecast({intersectsBounds:g=>Dt.intersectsBox(g),intersectsTriangle:g=>{g.a.applyMatrix4(t),g.b.applyMatrix4(t),g.c.applyMatrix4(t),g.needsUpdate=!0;for(let y=b,w=d+b;y<w;y++)if(W(je,3*e.resolveTriangleIndex(y),u,o),je.needsUpdate=!0,g.intersectsTriangle(je))return!0;return!1}});for(let p=b,g=d+b;p<g;p++){const y=e.resolveTriangleIndex(p);W(qe,3*y,u,o),qe.a.applyMatrix4(lt),qe.b.applyMatrix4(lt),qe.c.applyMatrix4(lt),qe.needsUpdate=!0;for(let w=0,T=m.count;w<T;w+=3)if(W(je,w,m,v),je.needsUpdate=!0,qe.intersectsTriangle(je))return!0}}else{const f=s+8,u=c[s+6];return H(f,a,Ft),!!(n.intersectsBox(Ft)&&Si(f,e,i,t,n)||(H(u,a,Ft),n.intersectsBox(Ft)&&Si(u,e,i,t,n)))}}const Et=new Y,si=new $,ut=new $,Hn=new C,Un=new C,Wn=new C,Vn=new C;function qn(s,e,i,t={},n={},a=0,r=1/0){e.boundingBox||e.computeBoundingBox(),si.set(e.boundingBox.min,e.boundingBox.max,i),si.needsUpdate=!0;const c=s.geometry,l=c.attributes.position,h=c.index,f=e.attributes.position,u=e.index,o=ne.getPrimitive(),m=ne.getPrimitive();let v=Hn,b=Un,d=null,p=null;n&&(d=Wn,p=Vn);let g=1/0,y=null,w=null;return Et.copy(i).invert(),ut.matrix.copy(Et),s.shapecast({boundsTraverseOrder:T=>si.distanceToBox(T),intersectsBounds:(T,_,A)=>A<g&&A<r?(_&&(ut.min.copy(T.min),ut.max.copy(T.max),ut.needsUpdate=!0),!0):!1,intersectsRange:(T,_)=>{if(e.boundsTree){const A=e.boundsTree;return A.shapecast({boundsTraverseOrder:S=>ut.distanceToBox(S),intersectsBounds:(S,R,I)=>I<g&&I<r,intersectsRange:(S,R)=>{for(let I=S,P=S+R;I<P;I++){const M=A.resolveTriangleIndex(I);W(m,3*M,u,f),m.a.applyMatrix4(i),m.b.applyMatrix4(i),m.c.applyMatrix4(i),m.needsUpdate=!0;for(let F=T,E=T+_;F<E;F++){const B=s.resolveTriangleIndex(F);W(o,3*B,h,l),o.needsUpdate=!0;const z=o.distanceToTriangle(m,v,d);if(z<g&&(b.copy(v),p&&p.copy(d),g=z,y=F,w=I),z<a)return!0}}}})}else{const A=tt(e);for(let S=0,R=A;S<R;S++){W(m,3*S,u,f),m.a.applyMatrix4(i),m.b.applyMatrix4(i),m.c.applyMatrix4(i),m.needsUpdate=!0;for(let I=T,P=T+_;I<P;I++){const M=s.resolveTriangleIndex(I);W(o,3*M,h,l),o.needsUpdate=!0;const F=o.distanceToTriangle(m,v,d);if(F<g&&(b.copy(v),p&&p.copy(d),g=F,y=I,w=S),F<a)return!0}}}}}),ne.releasePrimitive(o),ne.releasePrimitive(m),g===1/0?null:(t.point?t.point.copy(b):t.point=b.clone(),t.distance=g,t.faceIndex=y,n&&(n.point?n.point.copy(p):n.point=p.clone(),n.point.applyMatrix4(Et),b.applyMatrix4(Et),n.distance=b.sub(n.point).length(),n.faceIndex=w),t)}function jn(){return typeof SharedArrayBuffer<"u"}const gt=new N.constructor,Vt=new N.constructor,we=new Fi(()=>new he),Ge=new he,Ye=new he,ni=new he,ai=new he;let oi=!1;function Gn(s,e,i,t){if(oi)throw new Error("MeshBVH: Recursive calls to bvhcast not supported.");oi=!0;const n=s._roots,a=e._roots;let r,c=0,l=0;const h=new Y().copy(i).invert();for(let f=0,u=n.length;f<u;f++){gt.setBuffer(n[f]),l=0;const o=we.getPrimitive();H(0,gt.float32Array,o),o.applyMatrix4(h);for(let m=0,v=a.length;m<v&&(Vt.setBuffer(a[f]),r=ce(0,0,i,h,t,c,l,0,0,o),Vt.clearBuffer(),l+=a[m].length,!r);m++);if(we.releasePrimitive(o),gt.clearBuffer(),c+=n[f].length,r)break}return oi=!1,r}function ce(s,e,i,t,n,a=0,r=0,c=0,l=0,h=null,f=!1){let u,o;f?(u=Vt,o=gt):(u=gt,o=Vt);const m=u.float32Array,v=u.uint32Array,b=u.uint16Array,d=o.float32Array,p=o.uint32Array,g=o.uint16Array,y=s*2,w=e*2,T=G(y,b),_=G(w,g);let A=!1;if(_&&T)f?A=n(Z(e,p),Q(e*2,g),Z(s,v),Q(s*2,b),l,r+e,c,a+s):A=n(Z(s,v),Q(s*2,b),Z(e,p),Q(e*2,g),c,a+s,l,r+e);else if(_){const S=we.getPrimitive();H(e,d,S),S.applyMatrix4(i);const R=se(s),I=J(s,v);H(R,m,Ge),H(I,m,Ye);const P=S.intersectsBox(Ge),M=S.intersectsBox(Ye);A=P&&ce(e,R,t,i,n,r,a,l,c+1,S,!f)||M&&ce(e,I,t,i,n,r,a,l,c+1,S,!f),we.releasePrimitive(S)}else{const S=se(e),R=J(e,p);H(S,d,ni),H(R,d,ai);const I=h.intersectsBox(ni),P=h.intersectsBox(ai);if(I&&P)A=ce(s,S,i,t,n,a,r,c,l+1,h,f)||ce(s,R,i,t,n,a,r,c,l+1,h,f);else if(I)if(T)A=ce(s,S,i,t,n,a,r,c,l+1,h,f);else{const M=we.getPrimitive();M.copy(ni).applyMatrix4(i);const F=se(s),E=J(s,v);H(F,m,Ge),H(E,m,Ye);const B=M.intersectsBox(Ge),z=M.intersectsBox(Ye);A=B&&ce(S,F,t,i,n,r,a,l,c+1,M,!f)||z&&ce(S,E,t,i,n,r,a,l,c+1,M,!f),we.releasePrimitive(M)}else if(P)if(T)A=ce(s,R,i,t,n,a,r,c,l+1,h,f);else{const M=we.getPrimitive();M.copy(ai).applyMatrix4(i);const F=se(s),E=J(s,v);H(F,m,Ge),H(E,m,Ye);const B=M.intersectsBox(Ge),z=M.intersectsBox(Ye);A=B&&ce(R,F,t,i,n,r,a,l,c+1,M,!f)||z&&ce(R,E,t,i,n,r,a,l,c+1,M,!f),we.releasePrimitive(M)}}return A}const Bt=new $,dr=new he,Yn={strategy:qr,maxDepth:40,maxLeafTris:10,useSharedArrayBuffer:!1,setBoundingBox:!0,onProgress:null,indirect:!1,verbose:!0};class Di{static serialize(e,i={}){i={cloneBuffers:!0,...i};const t=e.geometry,n=e._roots,a=e._indirectBuffer,r=t.getIndex();let c;return i.cloneBuffers?c={roots:n.map(l=>l.slice()),index:r?r.array.slice():null,indirectBuffer:a?a.slice():null}:c={roots:n,index:r?r.array:null,indirectBuffer:a},c}static deserialize(e,i,t={}){t={setIndex:!0,indirect:!!e.indirectBuffer,...t};const{index:n,roots:a,indirectBuffer:r}=e,c=new Di(i,{...t,[Qt]:!0});if(c._roots=a,c._indirectBuffer=r||null,t.setIndex){const l=i.getIndex();if(l===null){const h=new re(e.index,1,!1);i.setIndex(h)}else l.array!==n&&(l.array.set(n),l.needsUpdate=!0)}return c}get indirect(){return!!this._indirectBuffer}constructor(e,i={}){if(e.isBufferGeometry){if(e.index&&e.index.isInterleavedBufferAttribute)throw new Error("MeshBVH: InterleavedBufferAttribute is not supported for the index attribute.")}else throw new Error("MeshBVH: Only BufferGeometries are supported.");if(i=Object.assign({...Yn,[Qt]:!1},i),i.useSharedArrayBuffer&&!jn())throw new Error("MeshBVH: SharedArrayBuffer is not available.");this.geometry=e,this._roots=null,this._indirectBuffer=null,i[Qt]||(ln(this,i),!e.boundingBox&&i.setBoundingBox&&(e.boundingBox=this.getBoundingBox(new he))),this.resolveTriangleIndex=i.indirect?t=>this._indirectBuffer[t]:t=>t}refit(e=null){return(this.indirect?kn:wn)(this,e)}traverse(e,i=0){const t=this._roots[i],n=new Uint32Array(t),a=new Uint16Array(t);r(0);function r(c,l=0){const h=c*2,f=a[h+15]===jt;if(f){const u=n[c+6],o=a[h+14];e(l,f,new Float32Array(t,c*4,6),u,o)}else{const u=c+Se/4,o=n[c+6],m=n[c+7];e(l,f,new Float32Array(t,c*4,6),m)||(r(u,l+1),r(o,l+1))}}}raycast(e,i=mi,t=0,n=1/0){const a=this._roots,r=this.geometry,c=[],l=i.isMaterial,h=Array.isArray(i),f=r.groups,u=l?i.side:i,o=this.indirect?zn:Mn;for(let m=0,v=a.length;m<v;m++){const b=h?i[f[m].materialIndex].side:u,d=c.length;if(o(this,m,b,e,c,t,n),h){const p=f[m].materialIndex;for(let g=d,y=c.length;g<y;g++)c[g].face.materialIndex=p}}return c}raycastFirst(e,i=mi,t=0,n=1/0){const a=this._roots,r=this.geometry,c=i.isMaterial,l=Array.isArray(i);let h=null;const f=r.groups,u=c?i.side:i,o=this.indirect?Nn:In;for(let m=0,v=a.length;m<v;m++){const b=l?i[f[m].materialIndex].side:u,d=o(this,m,b,e,t,n);d!=null&&(h==null||d.distance<h.distance)&&(h=d,l&&(d.face.materialIndex=f[m].materialIndex))}return h}intersectsGeometry(e,i){let t=!1;const n=this._roots,a=this.indirect?Ln:Pn;for(let r=0,c=n.length;r<c&&(t=a(this,r,e,i),!t);r++);return t}shapecast(e){const i=ne.getPrimitive(),t=this.indirect?Sn:Tn;let{boundsTraverseOrder:n,intersectsBounds:a,intersectsRange:r,intersectsTriangle:c}=e;if(r&&c){const u=r;r=(o,m,v,b,d)=>u(o,m,v,b,d)?!0:t(o,m,this,c,v,b,i)}else r||(c?r=(u,o,m,v)=>t(u,o,this,c,m,v,i):r=(u,o,m)=>m);let l=!1,h=0;const f=this._roots;for(let u=0,o=f.length;u<o;u++){const m=f[u];if(l=pn(this,u,a,r,n,h),l)break;h+=m.byteLength}return ne.releasePrimitive(i),l}bvhcast(e,i,t){let{intersectsRanges:n,intersectsTriangles:a}=t;const r=ne.getPrimitive(),c=this.geometry.index,l=this.geometry.attributes.position,h=this.indirect?v=>{const b=this.resolveTriangleIndex(v);W(r,b*3,c,l)}:v=>{W(r,v*3,c,l)},f=ne.getPrimitive(),u=e.geometry.index,o=e.geometry.attributes.position,m=e.indirect?v=>{const b=e.resolveTriangleIndex(v);W(f,b*3,u,o)}:v=>{W(f,v*3,u,o)};if(a){const v=(b,d,p,g,y,w,T,_)=>{for(let A=p,S=p+g;A<S;A++){m(A),f.a.applyMatrix4(i),f.b.applyMatrix4(i),f.c.applyMatrix4(i),f.needsUpdate=!0;for(let R=b,I=b+d;R<I;R++)if(h(R),r.needsUpdate=!0,a(r,f,R,A,y,w,T,_))return!0}return!1};if(n){const b=n;n=function(d,p,g,y,w,T,_,A){return b(d,p,g,y,w,T,_,A)?!0:v(d,p,g,y,w,T,_,A)}}else n=v}return Gn(this,e,i,n)}intersectsBox(e,i){return Bt.set(e.min,e.max,i),Bt.needsUpdate=!0,this.shapecast({intersectsBounds:t=>Bt.intersectsBox(t),intersectsTriangle:t=>Bt.intersectsTriangle(t)})}intersectsSphere(e){return this.shapecast({intersectsBounds:i=>e.intersectsBox(i),intersectsTriangle:i=>i.intersectsSphere(e)})}closestPointToGeometry(e,i,t={},n={},a=0,r=1/0){return(this.indirect?qn:Bn)(this,e,i,t,n,a,r)}closestPointToPoint(e,i={},t=0,n=1/0){return gn(this,e,i,t,n)}getBoundingBox(e){return e.makeEmpty(),this._roots.forEach(t=>{H(0,new Float32Array(t),dr),e.union(dr)}),e}}function $n(s){switch(s){case 1:return"R";case 2:return"RG";case 3:return"RGBA";case 4:return"RGBA"}throw new Error}function Xn(s){switch(s){case 1:return Wt;case 2:return Lr;case 3:return V;case 4:return V}}function mr(s){switch(s){case 1:return Es;case 2:return Hr;case 3:return gi;case 4:return gi}}class Qr extends ae{constructor(){super(),this.minFilter=U,this.magFilter=U,this.generateMipmaps=!1,this.overrideItemSize=null,this._forcedType=null}updateFrom(e){const i=this.overrideItemSize,t=e.itemSize,n=e.count;if(i!==null){if(t*n%i!==0)throw new Error("VertexAttributeTexture: overrideItemSize must divide evenly into buffer length.");e.itemSize=i,e.count=n*t/i}const a=e.itemSize,r=e.count,c=e.normalized,l=e.array.constructor,h=l.BYTES_PER_ELEMENT;let f=this._forcedType,u=a;if(f===null)switch(l){case Float32Array:f=q;break;case Uint8Array:case Uint16Array:case Uint32Array:f=mt;break;case Int8Array:case Int16Array:case Int32Array:f=Xt;break}let o,m,v,b,d=$n(a);switch(f){case q:v=1,m=Xn(a),c&&h===1?(b=l,d+="8",l===Uint8Array?o=pi:(o=Ji,d+="_SNORM")):(b=Float32Array,d+="32F",o=q);break;case Xt:d+=h*8+"I",v=c?Math.pow(2,l.BYTES_PER_ELEMENT*8-1):1,m=mr(a),h===1?(b=Int8Array,o=Ji):h===2?(b=Int16Array,o=Ds):(b=Int32Array,o=Xt);break;case mt:d+=h*8+"UI",v=c?Math.pow(2,l.BYTES_PER_ELEMENT*8-1):1,m=mr(a),h===1?(b=Uint8Array,o=pi):h===2?(b=Uint16Array,o=Fs):(b=Uint32Array,o=mt);break}u===3&&(m===V||m===gi)&&(u=4);const p=Math.ceil(Math.sqrt(r))||1,g=u*p*p,y=new b(g),w=e.normalized;e.normalized=!1;for(let T=0;T<r;T++){const _=u*T;y[_]=e.getX(T)/v,a>=2&&(y[_+1]=e.getY(T)/v),a>=3&&(y[_+2]=e.getZ(T)/v,u===4&&(y[_+3]=1)),a>=4&&(y[_+3]=e.getW(T)/v)}e.normalized=w,this.internalFormat=d,this.format=m,this.type=o,this.image.width=p,this.image.height=p,this.image.data=y,this.needsUpdate=!0,this.dispose(),e.itemSize=t,e.count=n}}class Jr extends Qr{constructor(){super(),this._forcedType=mt}}class es extends Qr{constructor(){super(),this._forcedType=q}}class Kn{constructor(){this.index=new Jr,this.position=new es,this.bvhBounds=new ae,this.bvhContents=new ae,this._cachedIndexAttr=null,this.index.overrideItemSize=3}updateFrom(e){const{geometry:i}=e;if(Qn(e,this.bvhBounds,this.bvhContents),this.position.updateFrom(i.attributes.position),e.indirect){const t=e._indirectBuffer;if(this._cachedIndexAttr===null||this._cachedIndexAttr.count!==t.length)if(i.index)this._cachedIndexAttr=i.index.clone();else{const n=Yr(Gr(i));this._cachedIndexAttr=new re(n,1,!1)}Zn(i,t,this._cachedIndexAttr),this.index.updateFrom(this._cachedIndexAttr)}else this.index.updateFrom(i.index)}dispose(){const{index:e,position:i,bvhBounds:t,bvhContents:n}=this;e&&e.dispose(),i&&i.dispose(),t&&t.dispose(),n&&n.dispose()}}function Zn(s,e,i){const t=i.array,n=s.index?s.index.array:null;for(let a=0,r=e.length;a<r;a++){const c=3*a,l=3*e[a];for(let h=0;h<3;h++)t[c+h]=n?n[l+h]:l+h}}function Qn(s,e,i){const t=s._roots;if(t.length!==1)throw new Error("MeshBVHUniformStruct: Multi-root BVHs not supported.");const n=t[0],a=new Uint16Array(n),r=new Uint32Array(n),c=new Float32Array(n),l=n.byteLength/Se,h=2*Math.ceil(Math.sqrt(l/2)),f=new Float32Array(4*h*h),u=Math.ceil(Math.sqrt(l)),o=new Uint32Array(2*u*u);for(let m=0;m<l;m++){const v=m*Se/4,b=v*2,d=v;for(let p=0;p<3;p++)f[8*m+0+p]=c[d+0+p],f[8*m+4+p]=c[d+3+p];if(G(b,a)){const p=Q(b,a),g=Z(v,r),y=4294901760|p;o[m*2+0]=y,o[m*2+1]=g}else{const p=4*J(v,r)/Se,g=Pi(v,r);o[m*2+0]=g,o[m*2+1]=p}}e.image.data=f,e.image.width=h,e.image.height=h,e.format=V,e.type=q,e.internalFormat="RGBA32F",e.minFilter=U,e.magFilter=U,e.generateMipmaps=!1,e.needsUpdate=!0,e.dispose(),i.image.data=o,i.image.width=u,i.image.height=u,i.format=Hr,i.type=mt,i.internalFormat="RG32UI",i.minFilter=U,i.magFilter=U,i.generateMipmaps=!1,i.needsUpdate=!0,i.dispose()}const Jn=`
|
|
6
|
+
|
|
7
|
+
// A stack of uint32 indices can can store the indices for
|
|
8
|
+
// a perfectly balanced tree with a depth up to 31. Lower stack
|
|
9
|
+
// depth gets higher performance.
|
|
10
|
+
//
|
|
11
|
+
// However not all trees are balanced. Best value to set this to
|
|
12
|
+
// is the trees max depth.
|
|
13
|
+
#ifndef BVH_STACK_DEPTH
|
|
14
|
+
#define BVH_STACK_DEPTH 60
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
#ifndef INFINITY
|
|
18
|
+
#define INFINITY 1e20
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
// Utilities
|
|
22
|
+
uvec4 uTexelFetch1D( usampler2D tex, uint index ) {
|
|
23
|
+
|
|
24
|
+
uint width = uint( textureSize( tex, 0 ).x );
|
|
25
|
+
uvec2 uv;
|
|
26
|
+
uv.x = index % width;
|
|
27
|
+
uv.y = index / width;
|
|
28
|
+
|
|
29
|
+
return texelFetch( tex, ivec2( uv ), 0 );
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
ivec4 iTexelFetch1D( isampler2D tex, uint index ) {
|
|
34
|
+
|
|
35
|
+
uint width = uint( textureSize( tex, 0 ).x );
|
|
36
|
+
uvec2 uv;
|
|
37
|
+
uv.x = index % width;
|
|
38
|
+
uv.y = index / width;
|
|
39
|
+
|
|
40
|
+
return texelFetch( tex, ivec2( uv ), 0 );
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
vec4 texelFetch1D( sampler2D tex, uint index ) {
|
|
45
|
+
|
|
46
|
+
uint width = uint( textureSize( tex, 0 ).x );
|
|
47
|
+
uvec2 uv;
|
|
48
|
+
uv.x = index % width;
|
|
49
|
+
uv.y = index / width;
|
|
50
|
+
|
|
51
|
+
return texelFetch( tex, ivec2( uv ), 0 );
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
vec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {
|
|
56
|
+
|
|
57
|
+
return
|
|
58
|
+
barycoord.x * texelFetch1D( tex, faceIndices.x ) +
|
|
59
|
+
barycoord.y * texelFetch1D( tex, faceIndices.y ) +
|
|
60
|
+
barycoord.z * texelFetch1D( tex, faceIndices.z );
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
void ndcToCameraRay(
|
|
65
|
+
vec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,
|
|
66
|
+
out vec3 rayOrigin, out vec3 rayDirection
|
|
67
|
+
) {
|
|
68
|
+
|
|
69
|
+
// get camera look direction and near plane for camera clipping
|
|
70
|
+
vec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );
|
|
71
|
+
vec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );
|
|
72
|
+
float near = abs( nearVector.z / nearVector.w );
|
|
73
|
+
|
|
74
|
+
// get the camera direction and position from camera matrices
|
|
75
|
+
vec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );
|
|
76
|
+
vec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );
|
|
77
|
+
direction /= direction.w;
|
|
78
|
+
direction = cameraWorld * direction - origin;
|
|
79
|
+
|
|
80
|
+
// slide the origin along the ray until it sits at the near clip plane position
|
|
81
|
+
origin.xyz += direction.xyz * near / dot( direction, lookDirection );
|
|
82
|
+
|
|
83
|
+
rayOrigin = origin.xyz;
|
|
84
|
+
rayDirection = direction.xyz;
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
`,ea=`
|
|
88
|
+
|
|
89
|
+
#ifndef TRI_INTERSECT_EPSILON
|
|
90
|
+
#define TRI_INTERSECT_EPSILON 1e-5
|
|
91
|
+
#endif
|
|
92
|
+
|
|
93
|
+
// Raycasting
|
|
94
|
+
bool intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax, out float dist ) {
|
|
95
|
+
|
|
96
|
+
// https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/
|
|
97
|
+
// https://tavianator.com/2011/ray_box.html
|
|
98
|
+
vec3 invDir = 1.0 / rayDirection;
|
|
99
|
+
|
|
100
|
+
// find intersection distances for each plane
|
|
101
|
+
vec3 tMinPlane = invDir * ( boundsMin - rayOrigin );
|
|
102
|
+
vec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );
|
|
103
|
+
|
|
104
|
+
// get the min and max distances from each intersection
|
|
105
|
+
vec3 tMinHit = min( tMaxPlane, tMinPlane );
|
|
106
|
+
vec3 tMaxHit = max( tMaxPlane, tMinPlane );
|
|
107
|
+
|
|
108
|
+
// get the furthest hit distance
|
|
109
|
+
vec2 t = max( tMinHit.xx, tMinHit.yz );
|
|
110
|
+
float t0 = max( t.x, t.y );
|
|
111
|
+
|
|
112
|
+
// get the minimum hit distance
|
|
113
|
+
t = min( tMaxHit.xx, tMaxHit.yz );
|
|
114
|
+
float t1 = min( t.x, t.y );
|
|
115
|
+
|
|
116
|
+
// set distance to 0.0 if the ray starts inside the box
|
|
117
|
+
dist = max( t0, 0.0 );
|
|
118
|
+
|
|
119
|
+
return t1 >= dist;
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
bool intersectsTriangle(
|
|
124
|
+
vec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,
|
|
125
|
+
out vec3 barycoord, out vec3 norm, out float dist, out float side
|
|
126
|
+
) {
|
|
127
|
+
|
|
128
|
+
// https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d
|
|
129
|
+
vec3 edge1 = b - a;
|
|
130
|
+
vec3 edge2 = c - a;
|
|
131
|
+
norm = cross( edge1, edge2 );
|
|
132
|
+
|
|
133
|
+
float det = - dot( rayDirection, norm );
|
|
134
|
+
float invdet = 1.0 / det;
|
|
135
|
+
|
|
136
|
+
vec3 AO = rayOrigin - a;
|
|
137
|
+
vec3 DAO = cross( AO, rayDirection );
|
|
138
|
+
|
|
139
|
+
vec4 uvt;
|
|
140
|
+
uvt.x = dot( edge2, DAO ) * invdet;
|
|
141
|
+
uvt.y = - dot( edge1, DAO ) * invdet;
|
|
142
|
+
uvt.z = dot( AO, norm ) * invdet;
|
|
143
|
+
uvt.w = 1.0 - uvt.x - uvt.y;
|
|
144
|
+
|
|
145
|
+
// set the hit information
|
|
146
|
+
barycoord = uvt.wxy; // arranged in A, B, C order
|
|
147
|
+
dist = uvt.z;
|
|
148
|
+
side = sign( det );
|
|
149
|
+
norm = side * normalize( norm );
|
|
150
|
+
|
|
151
|
+
// add an epsilon to avoid misses between triangles
|
|
152
|
+
uvt += vec4( TRI_INTERSECT_EPSILON );
|
|
153
|
+
|
|
154
|
+
return all( greaterThanEqual( uvt, vec4( 0.0 ) ) );
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
bool intersectTriangles(
|
|
159
|
+
// geometry info and triangle range
|
|
160
|
+
sampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,
|
|
161
|
+
|
|
162
|
+
// ray
|
|
163
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
164
|
+
|
|
165
|
+
// outputs
|
|
166
|
+
inout float minDistance, inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,
|
|
167
|
+
inout float side, inout float dist
|
|
168
|
+
) {
|
|
169
|
+
|
|
170
|
+
bool found = false;
|
|
171
|
+
vec3 localBarycoord, localNormal;
|
|
172
|
+
float localDist, localSide;
|
|
173
|
+
for ( uint i = offset, l = offset + count; i < l; i ++ ) {
|
|
174
|
+
|
|
175
|
+
uvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;
|
|
176
|
+
vec3 a = texelFetch1D( positionAttr, indices.x ).rgb;
|
|
177
|
+
vec3 b = texelFetch1D( positionAttr, indices.y ).rgb;
|
|
178
|
+
vec3 c = texelFetch1D( positionAttr, indices.z ).rgb;
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
intersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )
|
|
182
|
+
&& localDist < minDistance
|
|
183
|
+
) {
|
|
184
|
+
|
|
185
|
+
found = true;
|
|
186
|
+
minDistance = localDist;
|
|
187
|
+
|
|
188
|
+
faceIndices = uvec4( indices.xyz, i );
|
|
189
|
+
faceNormal = localNormal;
|
|
190
|
+
|
|
191
|
+
side = localSide;
|
|
192
|
+
barycoord = localBarycoord;
|
|
193
|
+
dist = localDist;
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return found;
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
bool intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, sampler2D bvhBounds, uint currNodeIndex, out float dist ) {
|
|
204
|
+
|
|
205
|
+
uint cni2 = currNodeIndex * 2u;
|
|
206
|
+
vec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;
|
|
207
|
+
vec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;
|
|
208
|
+
return intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax, dist );
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// use a macro to hide the fact that we need to expand the struct into separate fields
|
|
213
|
+
#define bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ) _bvhIntersectFirstHit( bvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist )
|
|
214
|
+
|
|
215
|
+
bool _bvhIntersectFirstHit(
|
|
216
|
+
// bvh info
|
|
217
|
+
sampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,
|
|
218
|
+
|
|
219
|
+
// ray
|
|
220
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
221
|
+
|
|
222
|
+
// output variables split into separate variables due to output precision
|
|
223
|
+
inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,
|
|
224
|
+
inout float side, inout float dist
|
|
225
|
+
) {
|
|
226
|
+
|
|
227
|
+
// stack needs to be twice as long as the deepest tree we expect because
|
|
228
|
+
// we push both the left and right child onto the stack every traversal
|
|
229
|
+
int ptr = 0;
|
|
230
|
+
uint stack[ BVH_STACK_DEPTH ];
|
|
231
|
+
stack[ 0 ] = 0u;
|
|
232
|
+
|
|
233
|
+
float triangleDistance = INFINITY;
|
|
234
|
+
bool found = false;
|
|
235
|
+
while ( ptr > - 1 && ptr < BVH_STACK_DEPTH ) {
|
|
236
|
+
|
|
237
|
+
uint currNodeIndex = stack[ ptr ];
|
|
238
|
+
ptr --;
|
|
239
|
+
|
|
240
|
+
// check if we intersect the current bounds
|
|
241
|
+
float boundsHitDistance;
|
|
242
|
+
if (
|
|
243
|
+
! intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh_bvhBounds, currNodeIndex, boundsHitDistance )
|
|
244
|
+
|| boundsHitDistance > triangleDistance
|
|
245
|
+
) {
|
|
246
|
+
|
|
247
|
+
continue;
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
uvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;
|
|
252
|
+
bool isLeaf = bool( boundsInfo.x & 0xffff0000u );
|
|
253
|
+
|
|
254
|
+
if ( isLeaf ) {
|
|
255
|
+
|
|
256
|
+
uint count = boundsInfo.x & 0x0000ffffu;
|
|
257
|
+
uint offset = boundsInfo.y;
|
|
258
|
+
|
|
259
|
+
found = intersectTriangles(
|
|
260
|
+
bvh_position, bvh_index, offset, count,
|
|
261
|
+
rayOrigin, rayDirection, triangleDistance,
|
|
262
|
+
faceIndices, faceNormal, barycoord, side, dist
|
|
263
|
+
) || found;
|
|
264
|
+
|
|
265
|
+
} else {
|
|
266
|
+
|
|
267
|
+
uint leftIndex = currNodeIndex + 1u;
|
|
268
|
+
uint splitAxis = boundsInfo.x & 0x0000ffffu;
|
|
269
|
+
uint rightIndex = boundsInfo.y;
|
|
270
|
+
|
|
271
|
+
bool leftToRight = rayDirection[ splitAxis ] >= 0.0;
|
|
272
|
+
uint c1 = leftToRight ? leftIndex : rightIndex;
|
|
273
|
+
uint c2 = leftToRight ? rightIndex : leftIndex;
|
|
274
|
+
|
|
275
|
+
// set c2 in the stack so we traverse it later. We need to keep track of a pointer in
|
|
276
|
+
// the stack while we traverse. The second pointer added is the one that will be
|
|
277
|
+
// traversed first
|
|
278
|
+
ptr ++;
|
|
279
|
+
stack[ ptr ] = c2;
|
|
280
|
+
|
|
281
|
+
ptr ++;
|
|
282
|
+
stack[ ptr ] = c1;
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return found;
|
|
289
|
+
|
|
290
|
+
}
|
|
291
|
+
`,ta=`
|
|
292
|
+
struct BVH {
|
|
293
|
+
|
|
294
|
+
usampler2D index;
|
|
295
|
+
sampler2D position;
|
|
296
|
+
|
|
297
|
+
sampler2D bvhBounds;
|
|
298
|
+
usampler2D bvhContents;
|
|
299
|
+
|
|
300
|
+
};
|
|
301
|
+
`;function ts(s,e,i=0){if(s.isInterleavedBufferAttribute){const t=s.itemSize;for(let n=0,a=s.count;n<a;n++){const r=n+i;e.setX(r,s.getX(n)),t>=2&&e.setY(r,s.getY(n)),t>=3&&e.setZ(r,s.getZ(n)),t>=4&&e.setW(r,s.getW(n))}}else{const t=e.array,n=t.constructor,a=t.BYTES_PER_ELEMENT*s.itemSize*i;new n(t.buffer,a,s.array.length).set(s.array)}}function dt(s,e=null){const i=s.array.constructor,t=s.normalized,n=s.itemSize,a=e===null?s.count:e;return new re(new i(n*a),n,t)}function Ze(s,e){if(!s&&!e)return!0;if(!!s!=!!e)return!1;const i=s.count===e.count,t=s.normalized===e.normalized,n=s.array.constructor===e.array.constructor,a=s.itemSize===e.itemSize;return!(!i||!t||!n||!a)}function ia(s){const e=s[0].index!==null,i=new Set(Object.keys(s[0].attributes));if(!s[0].getAttribute("position"))throw new Error("StaticGeometryGenerator: position attribute is required.");for(let t=0;t<s.length;++t){const n=s[t];let a=0;if(e!==(n.index!==null))throw new Error("StaticGeometryGenerator: All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.");for(const r in n.attributes){if(!i.has(r))throw new Error('StaticGeometryGenerator: All geometries must have compatible attributes; make sure "'+r+'" attribute exists among all geometries, or in none of them.');a++}if(a!==i.size)throw new Error("StaticGeometryGenerator: All geometries must have the same number of attributes.")}}function ra(s){let e=0;for(let i=0,t=s.length;i<t;i++)e+=s[i].getIndex().count;return e}function sa(s){let e=0;for(let i=0,t=s.length;i<t;i++)e+=s[i].getAttribute("position").count;return e}function na(s,e,i){s.index&&s.index.count!==e&&s.setIndex(null);const t=s.attributes;for(const n in t)t[n].count!==i&&s.deleteAttribute(n)}function aa(s,e={},i=new De){const{useGroups:t=!1,forceUpdate:n=!1,skipAssigningAttributes:a=[],overwriteIndex:r=!0}=e;ia(s);const c=s[0].index!==null,l=c?ra(s):-1,h=sa(s);if(na(i,l,h),t){let u=0;for(let o=0,m=s.length;o<m;o++){const v=s[o];let b;c?b=v.getIndex().count:b=v.getAttribute("position").count,i.addGroup(u,b,o),u+=b}}if(c){let u=!1;if(i.index||(i.setIndex(new re(new Uint32Array(l),1,!1)),u=!0),u||r){let o=0,m=0;const v=i.getIndex();for(let b=0,d=s.length;b<d;b++){const p=s[b],g=p.getIndex();if(!(!n&&!u&&a[b]))for(let w=0;w<g.count;++w)v.setX(o+w,g.getX(w)+m);o+=g.count,m+=p.getAttribute("position").count}}}const f=Object.keys(s[0].attributes);for(let u=0,o=f.length;u<o;u++){let m=!1;const v=f[u];if(!i.getAttribute(v)){const p=s[0].getAttribute(v);i.setAttribute(v,dt(p,h)),m=!0}let b=0;const d=i.getAttribute(v);for(let p=0,g=s.length;p<g;p++){const y=s[p],w=!n&&!m&&a[p],T=y.getAttribute(v);w||ts(T,d,b),b+=T.count}}}function oa(s,e,i){const t=s.index,a=s.attributes.position.count,r=t?t.count:a;let c=s.groups;c.length===0&&(c=[{count:r,start:0,materialIndex:0}]);let l=s.getAttribute("materialIndex");if(!l||l.count!==a){let f;i.length<=255?f=new Uint8Array(a):f=new Uint16Array(a),l=new re(f,1,!1),s.deleteAttribute("materialIndex"),s.setAttribute("materialIndex",l)}const h=l.array;for(let f=0;f<c.length;f++){const u=c[f],o=u.start,m=u.count,v=Math.min(m,r-o),b=Array.isArray(e)?e[u.materialIndex]:e,d=i.indexOf(b);for(let p=0;p<v;p++){let g=o+p;t&&(g=t.getX(g)),h[g]=d}}}function ca(s,e){if(!s.index){const i=s.attributes.position.count,t=new Array(i);for(let n=0;n<i;n++)t[n]=n;s.setIndex(t)}if(!s.attributes.normal&&e&&e.includes("normal")&&s.computeVertexNormals(),!s.attributes.uv&&e&&e.includes("uv")){const i=s.attributes.position.count;s.setAttribute("uv",new re(new Float32Array(i*2),2,!1))}if(!s.attributes.uv2&&e&&e.includes("uv2")){const i=s.attributes.position.count;s.setAttribute("uv2",new re(new Float32Array(i*2),2,!1))}if(!s.attributes.tangent&&e&&e.includes("tangent"))if(s.attributes.uv&&s.attributes.normal)s.computeTangents();else{const i=s.attributes.position.count;s.setAttribute("tangent",new re(new Float32Array(i*4),4,!1))}if(!s.attributes.color&&e&&e.includes("color")){const i=s.attributes.position.count,t=new Float32Array(i*4);t.fill(1),s.setAttribute("color",new re(t,4))}}function Ei(s){let e=0;if(s.byteLength!==0){const i=new Uint8Array(s);for(let t=0;t<s.byteLength;t++){const n=i[t];e=(e<<5)-e+n,e|=0}}return e}function pr(s){let e=s.uuid;const i=Object.values(s.attributes);s.index&&(i.push(s.index),e+=`index|${s.index.version}`);const t=Object.keys(i).sort();for(const n of t){const a=i[n];e+=`${n}_${a.version}|`}return e}function gr(s){const e=s.skeleton;return e?(e.boneTexture||e.computeBoneTexture(),`${Ei(e.boneTexture.image.data.buffer)}_${e.boneTexture.uuid}`):null}class la{constructor(e=null){this.matrixWorld=new Y,this.geometryHash=null,this.skeletonHash=null,this.primitiveCount=-1,e!==null&&this.updateFrom(e)}updateFrom(e){const i=e.geometry,t=(i.index?i.index.count:i.attributes.position.count)/3;this.matrixWorld.copy(e.matrixWorld),this.geometryHash=pr(i),this.primitiveCount=t,this.skeletonHash=gr(e)}didChange(e){const i=e.geometry,t=(i.index?i.index.count:i.attributes.position.count)/3;return!(this.matrixWorld.equals(e.matrixWorld)&&this.geometryHash===pr(i)&&this.skeletonHash===gr(e)&&this.primitiveCount===t)}}const Ie=new C,Pe=new C,Ce=new C,vr=new Je,kt=new C,ci=new C,xr=new Je,yr=new Je,zt=new Y,br=new Y;function Tr(s,e,i){const t=s.skeleton,n=s.geometry,a=t.bones,r=t.boneInverses;xr.fromBufferAttribute(n.attributes.skinIndex,e),yr.fromBufferAttribute(n.attributes.skinWeight,e),zt.elements.fill(0);for(let c=0;c<4;c++){const l=yr.getComponent(c);if(l!==0){const h=xr.getComponent(c);br.multiplyMatrices(a[h].matrixWorld,r[h]),ua(zt,br,l)}}return zt.multiply(s.bindMatrix).premultiply(s.bindMatrixInverse),i.transformDirection(zt),i}function li(s,e,i,t,n){kt.set(0,0,0);for(let a=0,r=s.length;a<r;a++){const c=e[a],l=s[a];c!==0&&(ci.fromBufferAttribute(l,t),i?kt.addScaledVector(ci,c):kt.addScaledVector(ci.sub(n),c))}n.add(kt)}function ua(s,e,i){const t=s.elements,n=e.elements;for(let a=0,r=n.length;a<r;a++)t[a]+=n[a]*i}function fa(s){const{index:e,attributes:i}=s;if(e)for(let t=0,n=e.count;t<n;t+=3){const a=e.getX(t),r=e.getX(t+2);e.setX(t,r),e.setX(t+2,a)}else for(const t in i){const n=i[t],a=n.itemSize;for(let r=0,c=n.count;r<c;r+=3)for(let l=0;l<a;l++){const h=n.getComponent(r,l),f=n.getComponent(r+2,l);n.setComponent(r,l,f),n.setComponent(r+2,l,h)}}return s}function ha(s,e={},i=new De){e={applyWorldTransforms:!0,attributes:[],...e};const t=s.geometry,n=e.applyWorldTransforms,a=e.attributes.includes("normal"),r=e.attributes.includes("tangent"),c=t.attributes,l=i.attributes;for(const g in i.attributes)(!e.attributes.includes(g)||!(g in t.attributes))&&i.deleteAttribute(g);!i.index&&t.index&&(i.index=t.index.clone()),l.position||i.setAttribute("position",dt(c.position)),a&&!l.normal&&c.normal&&i.setAttribute("normal",dt(c.normal)),r&&!l.tangent&&c.tangent&&i.setAttribute("tangent",dt(c.tangent)),Ze(t.index,i.index),Ze(c.position,l.position),a&&Ze(c.normal,l.normal),r&&Ze(c.tangent,l.tangent);const h=c.position,f=a?c.normal:null,u=r?c.tangent:null,o=t.morphAttributes.position,m=t.morphAttributes.normal,v=t.morphAttributes.tangent,b=t.morphTargetsRelative,d=s.morphTargetInfluences,p=new Bs;p.getNormalMatrix(s.matrixWorld),t.index&&i.index.array.set(t.index.array);for(let g=0,y=c.position.count;g<y;g++)Ie.fromBufferAttribute(h,g),f&&Pe.fromBufferAttribute(f,g),u&&(vr.fromBufferAttribute(u,g),Ce.fromBufferAttribute(u,g)),d&&(o&&li(o,d,b,g,Ie),m&&li(m,d,b,g,Pe),v&&li(v,d,b,g,Ce)),s.isSkinnedMesh&&(s.applyBoneTransform(g,Ie),f&&Tr(s,g,Pe),u&&Tr(s,g,Ce)),n&&Ie.applyMatrix4(s.matrixWorld),l.position.setXYZ(g,Ie.x,Ie.y,Ie.z),f&&(n&&Pe.applyNormalMatrix(p),l.normal.setXYZ(g,Pe.x,Pe.y,Pe.z)),u&&(n&&Ce.transformDirection(s.matrixWorld),l.tangent.setXYZW(g,Ce.x,Ce.y,Ce.z,vr.w));for(const g in e.attributes){const y=e.attributes[g];y==="position"||y==="tangent"||y==="normal"||!(y in c)||(l[y]||i.setAttribute(y,dt(c[y])),Ze(c[y],l[y]),ts(c[y],l[y]))}return s.matrixWorld.determinant()<0&&fa(i),i}class da extends De{constructor(){super(),this.version=0,this.hash=null,this._diff=new la}isCompatible(e,i){const t=e.geometry;for(let n=0;n<i.length;n++){const a=i[n],r=t.attributes[a],c=this.attributes[a];if(r&&!Ze(r,c))return!1}return!0}updateFrom(e,i){const t=this._diff;return t.didChange(e)?(ha(e,i,this),t.updateFrom(e),this.version++,this.hash=`${this.uuid}_${this.version}`,!0):!1}}const Mi=0,is=1,rs=2;function ma(s,e){for(let i=0,t=s.length;i<t;i++)s[i].traverseVisible(a=>{a.isMesh&&e(a)})}function pa(s){const e=[];for(let i=0,t=s.length;i<t;i++){const n=s[i];Array.isArray(n.material)?e.push(...n.material):e.push(n.material)}return e}function ga(s,e,i){if(s.length===0){e.setIndex(null);const t=e.attributes;for(const n in t)e.deleteAttribute(n);for(const n in i.attributes)e.setAttribute(i.attributes[n],new re(new Float32Array(0),4,!1))}else aa(s,i,e);for(const t in e.attributes)e.attributes[t].needsUpdate=!0}class va{constructor(e){this.objects=null,this.useGroups=!0,this.applyWorldTransforms=!0,this.generateMissingAttributes=!0,this.overwriteIndex=!0,this.attributes=["position","normal","color","tangent","uv","uv2"],this._intermediateGeometry=new Map,this._geometryMergeSets=new WeakMap,this._mergeOrder=[],this._dummyMesh=null,this.setObjects(e||[])}_getDummyMesh(){if(!this._dummyMesh){const e=new ks,i=new De;i.setAttribute("position",new re(new Float32Array(9),3)),this._dummyMesh=new zr(i,e)}return this._dummyMesh}_getMeshes(){const e=[];return ma(this.objects,i=>{e.push(i)}),e.sort((i,t)=>i.uuid>t.uuid?1:i.uuid<t.uuid?-1:0),e.length===0&&e.push(this._getDummyMesh()),e}_updateIntermediateGeometries(){const{_intermediateGeometry:e}=this,i=this._getMeshes(),t=new Set(e.keys()),n={attributes:this.attributes,applyWorldTransforms:this.applyWorldTransforms};for(let a=0,r=i.length;a<r;a++){const c=i[a],l=c.uuid;t.delete(l);let h=e.get(l);(!h||!h.isCompatible(c,this.attributes))&&(h&&h.dispose(),h=new da,e.set(l,h)),h.updateFrom(c,n)&&this.generateMissingAttributes&&ca(h,this.attributes)}t.forEach(a=>{e.delete(a)})}setObjects(e){Array.isArray(e)?this.objects=[...e]:this.objects=[e]}generate(e=new De){const{useGroups:i,overwriteIndex:t,_intermediateGeometry:n,_geometryMergeSets:a}=this,r=this._getMeshes(),c=[],l=[],h=a.get(e)||[];this._updateIntermediateGeometries();let f=!1;r.length!==h.length&&(f=!0);for(let o=0,m=r.length;o<m;o++){const v=r[o],b=n.get(v.uuid);l.push(b);const d=h[o];!d||d.uuid!==b.uuid?(c.push(!1),f=!0):d.version!==b.version?c.push(!1):c.push(!0)}ga(l,e,{useGroups:i,forceUpdate:f,skipAssigningAttributes:c,overwriteIndex:t}),f&&e.dispose(),a.set(e,l.map(o=>({version:o.version,uuid:o.uuid})));let u=Mi;return f?u=rs:c.includes(!1)&&(u=is),{changeType:u,materials:pa(r),geometry:e}}}function xa(s){const e=new Set;for(let i=0,t=s.length;i<t;i++){const n=s[i];for(const a in n){const r=n[a];r&&r.isTexture&&e.add(r)}}return Array.from(e)}function ya(s){const e=[],i=new Set;for(let n=0,a=s.length;n<a;n++)s[n].traverse(r=>{r.visible&&(r.isRectAreaLight||r.isSpotLight||r.isPointLight||r.isDirectionalLight)&&(e.push(r),r.iesMap&&i.add(r.iesMap))});const t=Array.from(i).sort((n,a)=>n.uuid<a.uuid?1:n.uuid>a.uuid?-1:0);return{lights:e,iesTextures:t}}class ba{get initialized(){return!!this.bvh}constructor(e){this.bvhOptions={},this.attributes=["position","normal","tangent","color","uv","uv2"],this.generateBVH=!0,this.bvh=null,this.geometry=new De,this.staticGeometryGenerator=new va(e),this._bvhWorker=null,this._pendingGenerate=null,this._buildAsync=!1}setObjects(e){this.staticGeometryGenerator.setObjects(e)}setBVHWorker(e){this._bvhWorker=e}async generateAsync(e=null){if(!this._bvhWorker)throw new Error('PathTracingSceneGenerator: "setBVHWorker" must be called before "generateAsync" can be called.');if(this.bvh instanceof Promise)return this._pendingGenerate||(this._pendingGenerate=new Promise(async()=>(await this.bvh,this._pendingGenerate=null,this.generateAsync(e)))),this._pendingGenerate;{this._buildAsync=!0;const i=this.generate(e);return this._buildAsync=!1,i.bvh=this.bvh=await i.bvh,i}}generate(e=null){const{staticGeometryGenerator:i,geometry:t,attributes:n}=this,a=i.objects;i.attributes=n,a.forEach(u=>{u.traverse(o=>{o.isSkinnedMesh&&o.skeleton&&o.skeleton.update()})});const r=i.generate(t),c=r.materials,l=xa(c),{lights:h,iesTextures:f}=ya(a);if(r.changeType!==Mi&&oa(t,c,c),this.generateBVH){if(this.bvh instanceof Promise)throw new Error("PathTracingSceneGenerator: BVH is already building asynchronously.");if(r.changeType===rs){const u={strategy:jr,maxLeafTris:1,indirect:!0,onProgress:e,...this.bvhOptions};this._buildAsync?this.bvh=this._bvhWorker.generate(t,u):this.bvh=new Di(t,u)}else r.changeType===is&&this.bvh.refit()}return{bvhChanged:r.changeType!==Mi,bvh:this.bvh,lights:h,iesTextures:f,geometry:t,materials:c,textures:l,objects:a}}}class Bi extends qt{set needsUpdate(e){super.needsUpdate=!0,this.dispatchEvent({type:"recompilation"})}constructor(e){super(e);for(const i in this.uniforms)Object.defineProperty(this,i,{get(){return this.uniforms[i].value},set(t){this.uniforms[i].value=t}})}setDefine(e,i=void 0){if(i==null){if(e in this.defines)return delete this.defines[e],this.needsUpdate=!0,!0}else if(this.defines[e]!==i)return this.defines[e]=i,this.needsUpdate=!0,!0;return!1}}class Ta extends Bi{constructor(e){super({blending:vt,uniforms:{target1:{value:null},target2:{value:null},opacity:{value:1}},vertexShader:`
|
|
302
|
+
|
|
303
|
+
varying vec2 vUv;
|
|
304
|
+
|
|
305
|
+
void main() {
|
|
306
|
+
|
|
307
|
+
vUv = uv;
|
|
308
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
309
|
+
|
|
310
|
+
}`,fragmentShader:`
|
|
311
|
+
|
|
312
|
+
uniform float opacity;
|
|
313
|
+
|
|
314
|
+
uniform sampler2D target1;
|
|
315
|
+
uniform sampler2D target2;
|
|
316
|
+
|
|
317
|
+
varying vec2 vUv;
|
|
318
|
+
|
|
319
|
+
void main() {
|
|
320
|
+
|
|
321
|
+
vec4 color1 = texture2D( target1, vUv );
|
|
322
|
+
vec4 color2 = texture2D( target2, vUv );
|
|
323
|
+
|
|
324
|
+
float invOpacity = 1.0 - opacity;
|
|
325
|
+
float totalAlpha = color1.a * invOpacity + color2.a * opacity;
|
|
326
|
+
|
|
327
|
+
if ( color1.a != 0.0 || color2.a != 0.0 ) {
|
|
328
|
+
|
|
329
|
+
gl_FragColor.rgb = color1.rgb * ( invOpacity * color1.a / totalAlpha ) + color2.rgb * ( opacity * color2.a / totalAlpha );
|
|
330
|
+
gl_FragColor.a = totalAlpha;
|
|
331
|
+
|
|
332
|
+
} else {
|
|
333
|
+
|
|
334
|
+
gl_FragColor = vec4( 0.0 );
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
}`}),this.setValues(e)}}function Ot(s=1){let e="uint";return s>1&&(e="uvec"+s),`
|
|
339
|
+
${e} sobolReverseBits( ${e} x ) {
|
|
340
|
+
|
|
341
|
+
x = ( ( ( x & 0xaaaaaaaau ) >> 1 ) | ( ( x & 0x55555555u ) << 1 ) );
|
|
342
|
+
x = ( ( ( x & 0xccccccccu ) >> 2 ) | ( ( x & 0x33333333u ) << 2 ) );
|
|
343
|
+
x = ( ( ( x & 0xf0f0f0f0u ) >> 4 ) | ( ( x & 0x0f0f0f0fu ) << 4 ) );
|
|
344
|
+
x = ( ( ( x & 0xff00ff00u ) >> 8 ) | ( ( x & 0x00ff00ffu ) << 8 ) );
|
|
345
|
+
return ( ( x >> 16 ) | ( x << 16 ) );
|
|
346
|
+
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
${e} sobolHashCombine( uint seed, ${e} v ) {
|
|
350
|
+
|
|
351
|
+
return seed ^ ( v + ${e}( ( seed << 6 ) + ( seed >> 2 ) ) );
|
|
352
|
+
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
${e} sobolLaineKarrasPermutation( ${e} x, ${e} seed ) {
|
|
356
|
+
|
|
357
|
+
x += seed;
|
|
358
|
+
x ^= x * 0x6c50b47cu;
|
|
359
|
+
x ^= x * 0xb82f1e52u;
|
|
360
|
+
x ^= x * 0xc7afe638u;
|
|
361
|
+
x ^= x * 0x8d22f6e6u;
|
|
362
|
+
return x;
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
${e} nestedUniformScrambleBase2( ${e} x, ${e} seed ) {
|
|
367
|
+
|
|
368
|
+
x = sobolLaineKarrasPermutation( x, seed );
|
|
369
|
+
x = sobolReverseBits( x );
|
|
370
|
+
return x;
|
|
371
|
+
|
|
372
|
+
}
|
|
373
|
+
`}function Nt(s=1){let e="uint",i="float",t="",n=".r",a="1u";return s>1&&(e="uvec"+s,i="vec"+s,t=s+"",s===2?(n=".rg",a="uvec2( 1u, 2u )"):s===3?(n=".rgb",a="uvec3( 1u, 2u, 3u )"):(n="",a="uvec4( 1u, 2u, 3u, 4u )")),`
|
|
374
|
+
|
|
375
|
+
${i} sobol${t}( int effect ) {
|
|
376
|
+
|
|
377
|
+
uint seed = sobolGetSeed( sobolBounceIndex, uint( effect ) );
|
|
378
|
+
uint index = sobolPathIndex;
|
|
379
|
+
|
|
380
|
+
uint shuffle_seed = sobolHashCombine( seed, 0u );
|
|
381
|
+
uint shuffled_index = nestedUniformScrambleBase2( sobolReverseBits( index ), shuffle_seed );
|
|
382
|
+
${i} sobol_pt = sobolGetTexturePoint( shuffled_index )${n};
|
|
383
|
+
${e} result = ${e}( sobol_pt * 16777216.0 );
|
|
384
|
+
|
|
385
|
+
${e} seed2 = sobolHashCombine( seed, ${a} );
|
|
386
|
+
result = nestedUniformScrambleBase2( result, seed2 );
|
|
387
|
+
|
|
388
|
+
return SOBOL_FACTOR * ${i}( result >> 8 );
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
`}const ss=`
|
|
392
|
+
|
|
393
|
+
// Utils
|
|
394
|
+
const float SOBOL_FACTOR = 1.0 / 16777216.0;
|
|
395
|
+
const uint SOBOL_MAX_POINTS = 256u * 256u;
|
|
396
|
+
|
|
397
|
+
${Ot(1)}
|
|
398
|
+
${Ot(2)}
|
|
399
|
+
${Ot(3)}
|
|
400
|
+
${Ot(4)}
|
|
401
|
+
|
|
402
|
+
uint sobolHash( uint x ) {
|
|
403
|
+
|
|
404
|
+
// finalizer from murmurhash3
|
|
405
|
+
x ^= x >> 16;
|
|
406
|
+
x *= 0x85ebca6bu;
|
|
407
|
+
x ^= x >> 13;
|
|
408
|
+
x *= 0xc2b2ae35u;
|
|
409
|
+
x ^= x >> 16;
|
|
410
|
+
return x;
|
|
411
|
+
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
`,wa=`
|
|
415
|
+
|
|
416
|
+
const uint SOBOL_DIRECTIONS_1[ 32 ] = uint[ 32 ](
|
|
417
|
+
0x80000000u, 0xc0000000u, 0xa0000000u, 0xf0000000u,
|
|
418
|
+
0x88000000u, 0xcc000000u, 0xaa000000u, 0xff000000u,
|
|
419
|
+
0x80800000u, 0xc0c00000u, 0xa0a00000u, 0xf0f00000u,
|
|
420
|
+
0x88880000u, 0xcccc0000u, 0xaaaa0000u, 0xffff0000u,
|
|
421
|
+
0x80008000u, 0xc000c000u, 0xa000a000u, 0xf000f000u,
|
|
422
|
+
0x88008800u, 0xcc00cc00u, 0xaa00aa00u, 0xff00ff00u,
|
|
423
|
+
0x80808080u, 0xc0c0c0c0u, 0xa0a0a0a0u, 0xf0f0f0f0u,
|
|
424
|
+
0x88888888u, 0xccccccccu, 0xaaaaaaaau, 0xffffffffu
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const uint SOBOL_DIRECTIONS_2[ 32 ] = uint[ 32 ](
|
|
428
|
+
0x80000000u, 0xc0000000u, 0x60000000u, 0x90000000u,
|
|
429
|
+
0xe8000000u, 0x5c000000u, 0x8e000000u, 0xc5000000u,
|
|
430
|
+
0x68800000u, 0x9cc00000u, 0xee600000u, 0x55900000u,
|
|
431
|
+
0x80680000u, 0xc09c0000u, 0x60ee0000u, 0x90550000u,
|
|
432
|
+
0xe8808000u, 0x5cc0c000u, 0x8e606000u, 0xc5909000u,
|
|
433
|
+
0x6868e800u, 0x9c9c5c00u, 0xeeee8e00u, 0x5555c500u,
|
|
434
|
+
0x8000e880u, 0xc0005cc0u, 0x60008e60u, 0x9000c590u,
|
|
435
|
+
0xe8006868u, 0x5c009c9cu, 0x8e00eeeeu, 0xc5005555u
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const uint SOBOL_DIRECTIONS_3[ 32 ] = uint[ 32 ](
|
|
439
|
+
0x80000000u, 0xc0000000u, 0x20000000u, 0x50000000u,
|
|
440
|
+
0xf8000000u, 0x74000000u, 0xa2000000u, 0x93000000u,
|
|
441
|
+
0xd8800000u, 0x25400000u, 0x59e00000u, 0xe6d00000u,
|
|
442
|
+
0x78080000u, 0xb40c0000u, 0x82020000u, 0xc3050000u,
|
|
443
|
+
0x208f8000u, 0x51474000u, 0xfbea2000u, 0x75d93000u,
|
|
444
|
+
0xa0858800u, 0x914e5400u, 0xdbe79e00u, 0x25db6d00u,
|
|
445
|
+
0x58800080u, 0xe54000c0u, 0x79e00020u, 0xb6d00050u,
|
|
446
|
+
0x800800f8u, 0xc00c0074u, 0x200200a2u, 0x50050093u
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
const uint SOBOL_DIRECTIONS_4[ 32 ] = uint[ 32 ](
|
|
450
|
+
0x80000000u, 0x40000000u, 0x20000000u, 0xb0000000u,
|
|
451
|
+
0xf8000000u, 0xdc000000u, 0x7a000000u, 0x9d000000u,
|
|
452
|
+
0x5a800000u, 0x2fc00000u, 0xa1600000u, 0xf0b00000u,
|
|
453
|
+
0xda880000u, 0x6fc40000u, 0x81620000u, 0x40bb0000u,
|
|
454
|
+
0x22878000u, 0xb3c9c000u, 0xfb65a000u, 0xddb2d000u,
|
|
455
|
+
0x78022800u, 0x9c0b3c00u, 0x5a0fb600u, 0x2d0ddb00u,
|
|
456
|
+
0xa2878080u, 0xf3c9c040u, 0xdb65a020u, 0x6db2d0b0u,
|
|
457
|
+
0x800228f8u, 0x400b3cdcu, 0x200fb67au, 0xb00ddb9du
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
uint getMaskedSobol( uint index, uint directions[ 32 ] ) {
|
|
461
|
+
|
|
462
|
+
uint X = 0u;
|
|
463
|
+
for ( int bit = 0; bit < 32; bit ++ ) {
|
|
464
|
+
|
|
465
|
+
uint mask = ( index >> bit ) & 1u;
|
|
466
|
+
X ^= mask * directions[ bit ];
|
|
467
|
+
|
|
468
|
+
}
|
|
469
|
+
return X;
|
|
470
|
+
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
vec4 generateSobolPoint( uint index ) {
|
|
474
|
+
|
|
475
|
+
if ( index >= SOBOL_MAX_POINTS ) {
|
|
476
|
+
|
|
477
|
+
return vec4( 0.0 );
|
|
478
|
+
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// NOTE: this sobol "direction" is also available but we can't write out 5 components
|
|
482
|
+
// uint x = index & 0x00ffffffu;
|
|
483
|
+
uint x = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_1 ) ) & 0x00ffffffu;
|
|
484
|
+
uint y = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_2 ) ) & 0x00ffffffu;
|
|
485
|
+
uint z = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_3 ) ) & 0x00ffffffu;
|
|
486
|
+
uint w = sobolReverseBits( getMaskedSobol( index, SOBOL_DIRECTIONS_4 ) ) & 0x00ffffffu;
|
|
487
|
+
|
|
488
|
+
return vec4( x, y, z, w ) * SOBOL_FACTOR;
|
|
489
|
+
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
`,Aa=`
|
|
493
|
+
|
|
494
|
+
// Seeds
|
|
495
|
+
uniform sampler2D sobolTexture;
|
|
496
|
+
uint sobolPixelIndex = 0u;
|
|
497
|
+
uint sobolPathIndex = 0u;
|
|
498
|
+
uint sobolBounceIndex = 0u;
|
|
499
|
+
|
|
500
|
+
uint sobolGetSeed( uint bounce, uint effect ) {
|
|
501
|
+
|
|
502
|
+
return sobolHash(
|
|
503
|
+
sobolHashCombine(
|
|
504
|
+
sobolHashCombine(
|
|
505
|
+
sobolHash( bounce ),
|
|
506
|
+
sobolPixelIndex
|
|
507
|
+
),
|
|
508
|
+
effect
|
|
509
|
+
)
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
vec4 sobolGetTexturePoint( uint index ) {
|
|
515
|
+
|
|
516
|
+
if ( index >= SOBOL_MAX_POINTS ) {
|
|
517
|
+
|
|
518
|
+
index = index % SOBOL_MAX_POINTS;
|
|
519
|
+
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
uvec2 dim = uvec2( textureSize( sobolTexture, 0 ).xy );
|
|
523
|
+
uint y = index / dim.x;
|
|
524
|
+
uint x = index - y * dim.x;
|
|
525
|
+
vec2 uv = vec2( x, y ) / vec2( dim );
|
|
526
|
+
return texture( sobolTexture, uv );
|
|
527
|
+
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
${Nt(1)}
|
|
531
|
+
${Nt(2)}
|
|
532
|
+
${Nt(3)}
|
|
533
|
+
${Nt(4)}
|
|
534
|
+
|
|
535
|
+
`;class _a extends Bi{constructor(){super({blending:vt,uniforms:{resolution:{value:new L}},vertexShader:`
|
|
536
|
+
|
|
537
|
+
varying vec2 vUv;
|
|
538
|
+
void main() {
|
|
539
|
+
|
|
540
|
+
vUv = uv;
|
|
541
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
542
|
+
|
|
543
|
+
}
|
|
544
|
+
`,fragmentShader:`
|
|
545
|
+
|
|
546
|
+
${ss}
|
|
547
|
+
${wa}
|
|
548
|
+
|
|
549
|
+
varying vec2 vUv;
|
|
550
|
+
uniform vec2 resolution;
|
|
551
|
+
void main() {
|
|
552
|
+
|
|
553
|
+
uint index = uint( gl_FragCoord.y ) * uint( resolution.x ) + uint( gl_FragCoord.x );
|
|
554
|
+
gl_FragColor = generateSobolPoint( index );
|
|
555
|
+
|
|
556
|
+
}
|
|
557
|
+
`})}}class Sa{generate(e,i=256){const t=new pt(i,i,{type:q,format:V,minFilter:U,magFilter:U,generateMipmaps:!1}),n=e.getRenderTarget();e.setRenderTarget(t);const a=new et(new _a);return a.material.resolution.set(i,i),a.render(e),e.setRenderTarget(n),a.dispose(),t}}class Ma extends Ur{set bokehSize(e){this.fStop=this.getFocalLength()/e}get bokehSize(){return this.getFocalLength()/this.fStop}constructor(...e){super(...e),this.fStop=1.4,this.apertureBlades=0,this.apertureRotation=0,this.focusDistance=25,this.anamorphicRatio=1}copy(e,i){return super.copy(e,i),this.fStop=e.fStop,this.apertureBlades=e.apertureBlades,this.apertureRotation=e.apertureRotation,this.focusDistance=e.focusDistance,this.anamorphicRatio=e.anamorphicRatio,this}}class Ra{constructor(){this.bokehSize=0,this.apertureBlades=0,this.apertureRotation=0,this.focusDistance=10,this.anamorphicRatio=1}updateFrom(e){e instanceof Ma?(this.bokehSize=e.bokehSize,this.apertureBlades=e.apertureBlades,this.apertureRotation=e.apertureRotation,this.focusDistance=e.focusDistance,this.anamorphicRatio=e.anamorphicRatio):(this.bokehSize=0,this.apertureRotation=0,this.apertureBlades=0,this.focusDistance=10,this.anamorphicRatio=1)}}function ui(s){const e=new Uint16Array(s.length);for(let i=0,t=s.length;i<t;++i)e[i]=ve.toHalfFloat(s[i]);return e}function wr(s,e,i=0,t=s.length){let n=i,a=i+t-1;for(;n<a;){const r=n+a>>1;s[r]<e?n=r+1:a=r}return n-i}function Ia(s,e,i){return .2126*s+.7152*e+.0722*i}function Pa(s,e=fe){const i=s.clone();i.source=new zs({...i.image});const{width:t,height:n,data:a}=i.image;let r=a;if(i.type!==e){e===fe?r=new Uint16Array(a.length):r=new Float32Array(a.length);let c;a instanceof Int8Array||a instanceof Int16Array||a instanceof Int32Array?c=2**(8*a.BYTES_PER_ELEMENT-1)-1:c=2**(8*a.BYTES_PER_ELEMENT)-1;for(let l=0,h=a.length;l<h;l++){let f=a[l];i.type===fe&&(f=ve.fromHalfFloat(a[l])),i.type!==q&&i.type!==fe&&(f/=c),e===fe&&(r[l]=ve.toHalfFloat(f))}i.image.data=r,i.type=e}if(i.flipY){const c=r;r=r.slice();for(let l=0;l<n;l++)for(let h=0;h<t;h++){const f=n-l-1,u=4*(l*t+h),o=4*(f*t+h);r[o+0]=c[u+0],r[o+1]=c[u+1],r[o+2]=c[u+2],r[o+3]=c[u+3]}i.flipY=!1,i.image.data=r}return i}class Ca{constructor(){const e=new ae(ui(new Float32Array([0,0,0,0])),1,1);e.type=fe,e.format=V,e.minFilter=le,e.magFilter=le,e.wrapS=_e,e.wrapT=_e,e.generateMipmaps=!1,e.needsUpdate=!0;const i=new ae(ui(new Float32Array([0,1])),1,2);i.type=fe,i.format=Wt,i.minFilter=le,i.magFilter=le,i.generateMipmaps=!1,i.needsUpdate=!0;const t=new ae(ui(new Float32Array([0,0,1,1])),2,2);t.type=fe,t.format=Wt,t.minFilter=le,t.magFilter=le,t.generateMipmaps=!1,t.needsUpdate=!0,this.map=e,this.marginalWeights=i,this.conditionalWeights=t,this.totalSum=0}dispose(){this.marginalWeights.dispose(),this.conditionalWeights.dispose(),this.map.dispose()}updateFrom(e){const i=Pa(e);i.wrapS=_e,i.wrapT=Me;const{width:t,height:n,data:a}=i.image,r=new Float32Array(t*n),c=new Float32Array(t*n),l=new Float32Array(n),h=new Float32Array(n);let f=0,u=0;for(let d=0;d<n;d++){let p=0;for(let g=0;g<t;g++){const y=d*t+g,w=ve.fromHalfFloat(a[4*y+0]),T=ve.fromHalfFloat(a[4*y+1]),_=ve.fromHalfFloat(a[4*y+2]),A=Ia(w,T,_);p+=A,f+=A,r[y]=A,c[y]=p}if(p!==0)for(let g=d*t,y=d*t+t;g<y;g++)r[g]/=p,c[g]/=p;u+=p,l[d]=p,h[d]=u}if(u!==0)for(let d=0,p=l.length;d<p;d++)l[d]/=u,h[d]/=u;const o=new Uint16Array(n),m=new Uint16Array(t*n);for(let d=0;d<n;d++){const p=(d+1)/n,g=wr(h,p);o[d]=ve.toHalfFloat((g+.5)/n)}for(let d=0;d<n;d++)for(let p=0;p<t;p++){const g=d*t+p,y=(p+1)/t,w=wr(c,y,d*t,t);m[g]=ve.toHalfFloat((w+.5)/t)}this.dispose();const{marginalWeights:v,conditionalWeights:b}=this;v.image={width:n,height:1,data:o},v.needsUpdate=!0,b.image={width:t,height:n,data:m},b.needsUpdate=!0,this.totalSum=f,this.map=i}}const fi=6,Fa=0,Da=1,Ea=2,Ba=3,ka=4,oe=new C,K=new C,Ar=new Y,$e=new hi,_r=new C,Xe=new C,za=new C(0,1,0);class Oa{constructor(){const e=new ae(new Float32Array(4),1,1);e.format=V,e.type=q,e.wrapS=Me,e.wrapT=Me,e.generateMipmaps=!1,e.minFilter=U,e.magFilter=U,this.tex=e,this.count=0}updateFrom(e,i=[]){const t=this.tex,n=Math.max(e.length*fi,1),a=Math.ceil(Math.sqrt(n));t.image.width!==a&&(t.dispose(),t.image.data=new Float32Array(a*a*4),t.image.width=a,t.image.height=a);const r=t.image.data;for(let l=0,h=e.length;l<h;l++){const f=e[l],u=l*fi*4;let o=0;for(let v=0;v<fi*4;v++)r[u+v]=0;f.getWorldPosition(K),r[u+o++]=K.x,r[u+o++]=K.y,r[u+o++]=K.z;let m=Fa;if(f.isRectAreaLight&&f.isCircular?m=Da:f.isSpotLight?m=Ea:f.isDirectionalLight?m=Ba:f.isPointLight&&(m=ka),r[u+o++]=m,r[u+o++]=f.color.r,r[u+o++]=f.color.g,r[u+o++]=f.color.b,r[u+o++]=f.intensity,f.getWorldQuaternion($e),f.isRectAreaLight)oe.set(f.width,0,0).applyQuaternion($e),r[u+o++]=oe.x,r[u+o++]=oe.y,r[u+o++]=oe.z,o++,K.set(0,f.height,0).applyQuaternion($e),r[u+o++]=K.x,r[u+o++]=K.y,r[u+o++]=K.z,r[u+o++]=oe.cross(K).length()*(f.isCircular?Math.PI/4:1);else if(f.isSpotLight){const v=f.radius||0;_r.setFromMatrixPosition(f.matrixWorld),Xe.setFromMatrixPosition(f.target.matrixWorld),Ar.lookAt(_r,Xe,za),$e.setFromRotationMatrix(Ar),oe.set(1,0,0).applyQuaternion($e),r[u+o++]=oe.x,r[u+o++]=oe.y,r[u+o++]=oe.z,o++,K.set(0,1,0).applyQuaternion($e),r[u+o++]=K.x,r[u+o++]=K.y,r[u+o++]=K.z,r[u+o++]=Math.PI*v*v,r[u+o++]=v,r[u+o++]=f.decay,r[u+o++]=f.distance,r[u+o++]=Math.cos(f.angle),r[u+o++]=Math.cos(f.angle*(1-f.penumbra)),r[u+o++]=f.iesMap?i.indexOf(f.iesMap):-1}else if(f.isPointLight){const v=oe.setFromMatrixPosition(f.matrixWorld);r[u+o++]=v.x,r[u+o++]=v.y,r[u+o++]=v.z,o++,o+=4,o+=1,r[u+o++]=f.decay,r[u+o++]=f.distance}else if(f.isDirectionalLight){const v=oe.setFromMatrixPosition(f.matrixWorld),b=K.setFromMatrixPosition(f.target.matrixWorld);Xe.subVectors(v,b).normalize(),r[u+o++]=Xe.x,r[u+o++]=Xe.y,r[u+o++]=Xe.z}}this.count=e.length;const c=Ei(r.buffer);return this.hash!==c?(this.hash=c,t.needsUpdate=!0,!0):!1}}function Sr(s,e,i,t,n){if(e>t)throw new Error;const a=s.length/e,r=s.constructor.BYTES_PER_ELEMENT*8;let c=1;switch(s.constructor){case Uint8Array:case Uint16Array:case Uint32Array:c=2**r-1;break;case Int8Array:case Int16Array:case Int32Array:c=2**(r-1)-1;break}for(let l=0;l<a;l++){const h=4*l,f=e*l;for(let u=0;u<t;u++)i[n+h+u]=e>=u+1?s[f+u]/c:0}}class Na extends Os{constructor(){super(),this._textures=[],this.type=q,this.format=V,this.internalFormat="RGBA32F"}updateAttribute(e,i){const t=this._textures[e];t.updateFrom(i);const n=t.image,a=this.image;if(n.width!==a.width||n.height!==a.height)throw new Error("FloatAttributeTextureArray: Attribute must be the same dimensions when updating single layer.");const{width:r,height:c,data:l}=a,f=r*c*4*e;let u=i.itemSize;u===3&&(u=4),Sr(t.image.data,u,l,4,f),this.dispose(),this.needsUpdate=!0}setAttributes(e){const i=e[0].count,t=e.length;for(let u=0,o=t;u<o;u++)if(e[u].count!==i)throw new Error("FloatAttributeTextureArray: All attributes must have the same item count.");const n=this._textures;for(;n.length<t;){const u=new es;n.push(u)}for(;n.length>t;)n.pop();for(let u=0,o=t;u<o;u++)n[u].updateFrom(e[u]);const r=n[0].image,c=this.image;(r.width!==c.width||r.height!==c.height||r.depth!==t)&&(c.width=r.width,c.height=r.height,c.depth=t,c.data=new Float32Array(c.width*c.height*c.depth*4));const{data:l,width:h,height:f}=c;for(let u=0,o=t;u<o;u++){const m=n[u],b=h*f*4*u;let d=e[u].itemSize;d===3&&(d=4),Sr(m.image.data,d,l,4,b)}this.dispose(),this.needsUpdate=!0}}class La extends Na{updateNormalAttribute(e){this.updateAttribute(0,e)}updateTangentAttribute(e){this.updateAttribute(1,e)}updateUvAttribute(e){this.updateAttribute(2,e)}updateColorAttribute(e){this.updateAttribute(3,e)}updateFrom(e,i,t,n){this.setAttributes([e,i,t,n])}}function ki(s,e){return s.uuid<e.uuid?1:s.uuid>e.uuid?-1:0}function Ri(s){return`${s.source.uuid}:${s.colorSpace}`}function Ha(s){const e=new Set,i=[];for(let t=0,n=s.length;t<n;t++){const a=s[t],r=Ri(a);e.has(r)||(e.add(r),i.push(a))}return i}function Ua(s){const e=s.map(t=>t.iesMap||null).filter(t=>t),i=new Set(e);return Array.from(i).sort(ki)}function Wa(s){const e=new Set;for(let t=0,n=s.length;t<n;t++){const a=s[t];for(const r in a){const c=a[r];c&&c.isTexture&&e.add(c)}}const i=Array.from(e);return Ha(i).sort(ki)}function Va(s){const e=[];return s.traverse(i=>{i.visible&&(i.isRectAreaLight||i.isSpotLight||i.isPointLight||i.isDirectionalLight)&&e.push(i)}),e.sort(ki)}const ns=45,Mr=ns*4;class qa{constructor(){this._features={}}isUsed(e){return e in this._features}setUsed(e,i=!0){i===!1?delete this._features[e]:this._features[e]=!0}reset(){this._features={}}}class ja extends ae{constructor(){super(new Float32Array(4),1,1),this.format=V,this.type=q,this.wrapS=Me,this.wrapT=Me,this.minFilter=U,this.magFilter=U,this.generateMipmaps=!1,this.features=new qa}updateFrom(e,i){function t(v,b,d=-1){if(b in v&&v[b]){const p=Ri(v[b]);return u[p]}else return d}function n(v,b,d){return b in v?v[b]:d}function a(v,b,d,p){const g=v[b]&&v[b].isTexture?v[b]:null;if(g){g.matrixAutoUpdate&&g.updateMatrix();const y=g.matrix.elements;let w=0;d[p+w++]=y[0],d[p+w++]=y[3],d[p+w++]=y[6],w++,d[p+w++]=y[1],d[p+w++]=y[4],d[p+w++]=y[7],w++}return 8}let r=0;const c=e.length*ns,l=Math.ceil(Math.sqrt(c))||1,{image:h,features:f}=this,u={};for(let v=0,b=i.length;v<b;v++)u[Ri(i[v])]=v;h.width!==l&&(this.dispose(),h.data=new Float32Array(l*l*4),h.width=l,h.height=l);const o=h.data;f.reset();for(let v=0,b=e.length;v<b;v++){const d=e[v];if(d.isFogVolumeMaterial){f.setUsed("FOG");for(let y=0;y<Mr;y++)o[r+y]=0;o[r+0*4+0]=d.color.r,o[r+0*4+1]=d.color.g,o[r+0*4+2]=d.color.b,o[r+2*4+3]=n(d,"emissiveIntensity",0),o[r+3*4+0]=d.emissive.r,o[r+3*4+1]=d.emissive.g,o[r+3*4+2]=d.emissive.b,o[r+13*4+1]=d.density,o[r+13*4+3]=0,o[r+14*4+2]=4,r+=Mr;continue}o[r++]=d.color.r,o[r++]=d.color.g,o[r++]=d.color.b,o[r++]=t(d,"map"),o[r++]=n(d,"metalness",0),o[r++]=t(d,"metalnessMap"),o[r++]=n(d,"roughness",0),o[r++]=t(d,"roughnessMap"),o[r++]=n(d,"ior",1.5),o[r++]=n(d,"transmission",0),o[r++]=t(d,"transmissionMap"),o[r++]=n(d,"emissiveIntensity",0),"emissive"in d?(o[r++]=d.emissive.r,o[r++]=d.emissive.g,o[r++]=d.emissive.b):(o[r++]=0,o[r++]=0,o[r++]=0),o[r++]=t(d,"emissiveMap"),o[r++]=t(d,"normalMap"),"normalScale"in d?(o[r++]=d.normalScale.x,o[r++]=d.normalScale.y):(o[r++]=1,o[r++]=1),o[r++]=n(d,"clearcoat",0),o[r++]=t(d,"clearcoatMap"),o[r++]=n(d,"clearcoatRoughness",0),o[r++]=t(d,"clearcoatRoughnessMap"),o[r++]=t(d,"clearcoatNormalMap"),"clearcoatNormalScale"in d?(o[r++]=d.clearcoatNormalScale.x,o[r++]=d.clearcoatNormalScale.y):(o[r++]=1,o[r++]=1),r++,o[r++]=n(d,"sheen",0),"sheenColor"in d?(o[r++]=d.sheenColor.r,o[r++]=d.sheenColor.g,o[r++]=d.sheenColor.b):(o[r++]=0,o[r++]=0,o[r++]=0),o[r++]=t(d,"sheenColorMap"),o[r++]=n(d,"sheenRoughness",0),o[r++]=t(d,"sheenRoughnessMap"),o[r++]=t(d,"iridescenceMap"),o[r++]=t(d,"iridescenceThicknessMap"),o[r++]=n(d,"iridescence",0),o[r++]=n(d,"iridescenceIOR",1.3);const p=n(d,"iridescenceThicknessRange",[100,400]);o[r++]=p[0],o[r++]=p[1],"specularColor"in d?(o[r++]=d.specularColor.r,o[r++]=d.specularColor.g,o[r++]=d.specularColor.b):(o[r++]=1,o[r++]=1,o[r++]=1),o[r++]=t(d,"specularColorMap"),o[r++]=n(d,"specularIntensity",1),o[r++]=t(d,"specularIntensityMap");const g=n(d,"thickness",0)===0&&n(d,"attenuationDistance",1/0)===1/0;if(o[r++]=Number(g),r++,"attenuationColor"in d?(o[r++]=d.attenuationColor.r,o[r++]=d.attenuationColor.g,o[r++]=d.attenuationColor.b):(o[r++]=1,o[r++]=1,o[r++]=1),o[r++]=n(d,"attenuationDistance",1/0),o[r++]=t(d,"alphaMap"),o[r++]=d.opacity,o[r++]=d.alphaTest,!g&&d.transmission>0)o[r++]=0;else switch(d.side){case mi:o[r++]=1;break;case Or:o[r++]=-1;break;case Nr:o[r++]=0;break}o[r++]=Number(n(d,"matte",!1)),o[r++]=Number(n(d,"castShadow",!0)),o[r++]=Number(d.vertexColors)|Number(d.flatShading)<<1,o[r++]=Number(d.transparent),r+=a(d,"map",o,r),r+=a(d,"metalnessMap",o,r),r+=a(d,"roughnessMap",o,r),r+=a(d,"transmissionMap",o,r),r+=a(d,"emissiveMap",o,r),r+=a(d,"normalMap",o,r),r+=a(d,"clearcoatMap",o,r),r+=a(d,"clearcoatNormalMap",o,r),r+=a(d,"clearcoatRoughnessMap",o,r),r+=a(d,"sheenColorMap",o,r),r+=a(d,"sheenRoughnessMap",o,r),r+=a(d,"iridescenceMap",o,r),r+=a(d,"iridescenceThicknessMap",o,r),r+=a(d,"specularColorMap",o,r),r+=a(d,"specularIntensityMap",o,r)}const m=Ei(o.buffer);return this.hash!==m?(this.hash=m,this.needsUpdate=!0,!0):!1}}const Rr=new xt;function Ga(s){return s?`${s.uuid}:${s.version}`:null}function Ya(s,e){for(const i in e)i in s&&(s[i]=e[i])}class Ir extends Ns{constructor(e,i,t){const n={format:V,type:pi,minFilter:le,magFilter:le,wrapS:_e,wrapT:_e,generateMipmaps:!1,...t};super(e,i,1,n),Ya(this.texture,n),this.texture.setTextures=(...r)=>{this.setTextures(...r)},this.hashes=[null];const a=new et(new $a);this.fsQuad=a}setTextures(e,i,t=this.width,n=this.height){const a=e.getRenderTarget(),r=e.toneMapping,c=e.getClearAlpha();e.getClearColor(Rr);const l=i.length||1;(t!==this.width||n!==this.height||this.depth!==l)&&(this.setSize(t,n,l),this.hashes=new Array(l).fill(null)),e.setClearColor(0,0),e.toneMapping=Ls;const h=this.fsQuad,f=this.hashes;let u=!1;for(let o=0,m=l;o<m;o++){const v=i[o],b=Ga(v);v&&(f[o]!==b||v.isWebGLRenderTarget)&&(v.matrixAutoUpdate=!1,v.matrix.identity(),h.material.map=v,e.setRenderTarget(this,o),h.render(e),v.updateMatrix(),v.matrixAutoUpdate=!0,f[o]=b,u=!0)}return h.material.map=null,e.setClearColor(Rr,c),e.setRenderTarget(a),e.toneMapping=r,u}dispose(){super.dispose(),this.fsQuad.dispose()}}class $a extends qt{get map(){return this.uniforms.map.value}set map(e){this.uniforms.map.value=e}constructor(){super({uniforms:{map:{value:null}},vertexShader:`
|
|
558
|
+
varying vec2 vUv;
|
|
559
|
+
void main() {
|
|
560
|
+
|
|
561
|
+
vUv = uv;
|
|
562
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
563
|
+
|
|
564
|
+
}
|
|
565
|
+
`,fragmentShader:`
|
|
566
|
+
uniform sampler2D map;
|
|
567
|
+
varying vec2 vUv;
|
|
568
|
+
void main() {
|
|
569
|
+
|
|
570
|
+
gl_FragColor = texture2D( map, vUv );
|
|
571
|
+
|
|
572
|
+
}
|
|
573
|
+
`})}}function Xa(s,e=Math.random()){for(let i=s.length-1;i>0;i--){const t=Math.floor(e()*(i+1)),n=s[i];s[i]=s[t],s[t]=n}return s}class Ka{constructor(e,i,t=Math.random){const n=e**i,a=new Uint16Array(n);let r=n;for(let c=0;c<n;c++)a[c]=c;this.samples=new Float32Array(i),this.strataCount=e,this.reset=function(){for(let c=0;c<n;c++)a[c]=c;r=0},this.reshuffle=function(){r=0},this.next=function(){const{samples:c}=this;r>=a.length&&(Xa(a,t),this.reshuffle());let l=a[r++];for(let h=0;h<i;h++)c[h]=(l%e+t())/e,l=Math.floor(l/e);return c}}}class Za{constructor(e,i,t=Math.random){let n=0;for(const l of i)n+=l;const a=new Float32Array(n),r=[];let c=0;for(const l of i){const h=new Ka(e,l,t);h.samples=new Float32Array(a.buffer,c,h.samples.length),c+=h.samples.length*4,r.push(h)}this.samples=a,this.strataCount=e,this.next=function(){for(const l of r)l.next();return a},this.reshuffle=function(){for(const l of r)l.reshuffle()},this.reset=function(){for(const l of r)l.reset()}}}class Qa{constructor(e=0){this.m=2147483648,this.a=1103515245,this.c=12345,this.seed=e}nextInt(){return this.seed=(this.a*this.seed+this.c)%this.m,this.seed}nextFloat(){return this.nextInt()/(this.m-1)}}class Ja extends ae{constructor(e=1,i=1,t=8){super(new Float32Array(1),1,1,V,q),this.minFilter=U,this.magFilter=U,this.strata=t,this.sampler=null,this.generator=new Qa,this.stableNoise=!1,this.random=()=>this.stableNoise?this.generator.nextFloat():Math.random(),this.init(e,i,t)}init(e=this.image.height,i=this.image.width,t=this.strata){const{image:n}=this;if(n.width===i&&n.height===e&&this.sampler!==null)return;const a=new Array(e*i).fill(4),r=new Za(t,a,this.random);n.width=i,n.height=e,n.data=r.samples,this.sampler=r,this.dispose(),this.next()}next(){this.sampler.next(),this.needsUpdate=!0}reset(){this.sampler.reset(),this.generator.seed=0}}function eo(s,e=Math.random){for(let i=s.length-1;i>0;i--){const t=~~((e()-1e-6)*i),n=s[i];s[i]=s[t],s[t]=n}}function to(s,e){s.fill(0);for(let i=0;i<e;i++)s[i]=1}class Pr{constructor(e){this.count=0,this.size=-1,this.sigma=-1,this.radius=-1,this.lookupTable=null,this.score=null,this.binaryPattern=null,this.resize(e),this.setSigma(1.5)}findVoid(){const{score:e,binaryPattern:i}=this;let t=1/0,n=-1;for(let a=0,r=i.length;a<r;a++){if(i[a]!==0)continue;const c=e[a];c<t&&(t=c,n=a)}return n}findCluster(){const{score:e,binaryPattern:i}=this;let t=-1/0,n=-1;for(let a=0,r=i.length;a<r;a++){if(i[a]!==1)continue;const c=e[a];c>t&&(t=c,n=a)}return n}setSigma(e){if(e===this.sigma)return;const i=~~(Math.sqrt(10*2*e**2)+1),t=2*i+1,n=new Float32Array(t*t),a=e*e;for(let r=-i;r<=i;r++)for(let c=-i;c<=i;c++){const l=(i+c)*t+r+i,h=r*r+c*c;n[l]=Math.E**(-h/(2*a))}this.lookupTable=n,this.sigma=e,this.radius=i}resize(e){this.size!==e&&(this.size=e,this.score=new Float32Array(e*e),this.binaryPattern=new Uint8Array(e*e))}invert(){const{binaryPattern:e,score:i,size:t}=this;i.fill(0);for(let n=0,a=e.length;n<a;n++)if(e[n]===0){const r=~~(n/t),c=n-r*t;this.updateScore(c,r,1),e[n]=1}else e[n]=0}updateScore(e,i,t){const{size:n,score:a,lookupTable:r}=this,c=this.radius,l=2*c+1;for(let h=-c;h<=c;h++)for(let f=-c;f<=c;f++){const u=(c+f)*l+h+c,o=r[u];let m=e+h;m=m<0?n+m:m%n;let v=i+f;v=v<0?n+v:v%n;const b=v*n+m;a[b]+=t*o}}addPointIndex(e){this.binaryPattern[e]=1;const i=this.size,t=~~(e/i),n=e-t*i;this.updateScore(n,t,1),this.count++}removePointIndex(e){this.binaryPattern[e]=0;const i=this.size,t=~~(e/i),n=e-t*i;this.updateScore(n,t,-1),this.count--}copy(e){this.resize(e.size),this.score.set(e.score),this.binaryPattern.set(e.binaryPattern),this.setSigma(e.sigma),this.count=e.count}}class io{constructor(){this.random=Math.random,this.sigma=1.5,this.size=64,this.majorityPointsRatio=.1,this.samples=new Pr(1),this.savedSamples=new Pr(1)}generate(){const{samples:e,savedSamples:i,sigma:t,majorityPointsRatio:n,size:a}=this;e.resize(a),e.setSigma(t);const r=Math.floor(a*a*n),c=e.binaryPattern;to(c,r),eo(c,this.random);for(let u=0,o=c.length;u<o;u++)c[u]===1&&e.addPointIndex(u);for(;;){const u=e.findCluster();e.removePointIndex(u);const o=e.findVoid();if(u===o){e.addPointIndex(u);break}e.addPointIndex(o)}const l=new Uint32Array(a*a);i.copy(e);let h;for(h=e.count-1;h>=0;){const u=e.findCluster();e.removePointIndex(u),l[u]=h,h--}const f=a*a;for(h=i.count;h<f/2;){const u=i.findVoid();i.addPointIndex(u),l[u]=h,h++}for(i.invert();h<f;){const u=i.findCluster();i.removePointIndex(u),l[u]=h,h++}return{data:l,maxValue:f}}}function ro(s){return s>=3?4:s}function so(s){switch(s){case 1:return Wt;case 2:return Lr;default:return V}}class no extends ae{constructor(e=64,i=1){super(new Float32Array(4),1,1,V,q),this.minFilter=U,this.magFilter=U,this.size=e,this.channels=i,this.update()}update(){const e=this.channels,i=this.size,t=new io;t.channels=e,t.size=i;const n=ro(e),a=so(n);(this.image.width!==i||a!==this.format)&&(this.image.width=i,this.image.height=i,this.image.data=new Float32Array(i**2*n),this.format=a,this.dispose());const r=this.image.data;for(let c=0,l=e;c<l;c++){const h=t.generate(),f=h.data,u=h.maxValue;for(let o=0,m=f.length;o<m;o++){const v=f[o]/u;r[o*n+c]=v}}this.needsUpdate=!0}}const ao=`
|
|
574
|
+
|
|
575
|
+
struct PhysicalCamera {
|
|
576
|
+
|
|
577
|
+
float focusDistance;
|
|
578
|
+
float anamorphicRatio;
|
|
579
|
+
float bokehSize;
|
|
580
|
+
int apertureBlades;
|
|
581
|
+
float apertureRotation;
|
|
582
|
+
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
`,oo=`
|
|
586
|
+
|
|
587
|
+
struct EquirectHdrInfo {
|
|
588
|
+
|
|
589
|
+
sampler2D marginalWeights;
|
|
590
|
+
sampler2D conditionalWeights;
|
|
591
|
+
sampler2D map;
|
|
592
|
+
|
|
593
|
+
float totalSum;
|
|
594
|
+
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
`,co=`
|
|
598
|
+
|
|
599
|
+
#define RECT_AREA_LIGHT_TYPE 0
|
|
600
|
+
#define CIRC_AREA_LIGHT_TYPE 1
|
|
601
|
+
#define SPOT_LIGHT_TYPE 2
|
|
602
|
+
#define DIR_LIGHT_TYPE 3
|
|
603
|
+
#define POINT_LIGHT_TYPE 4
|
|
604
|
+
|
|
605
|
+
struct LightsInfo {
|
|
606
|
+
|
|
607
|
+
sampler2D tex;
|
|
608
|
+
uint count;
|
|
609
|
+
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
struct Light {
|
|
613
|
+
|
|
614
|
+
vec3 position;
|
|
615
|
+
int type;
|
|
616
|
+
|
|
617
|
+
vec3 color;
|
|
618
|
+
float intensity;
|
|
619
|
+
|
|
620
|
+
vec3 u;
|
|
621
|
+
vec3 v;
|
|
622
|
+
float area;
|
|
623
|
+
|
|
624
|
+
// spot light fields
|
|
625
|
+
float radius;
|
|
626
|
+
float near;
|
|
627
|
+
float decay;
|
|
628
|
+
float distance;
|
|
629
|
+
float coneCos;
|
|
630
|
+
float penumbraCos;
|
|
631
|
+
int iesProfile;
|
|
632
|
+
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
Light readLightInfo( sampler2D tex, uint index ) {
|
|
636
|
+
|
|
637
|
+
uint i = index * 6u;
|
|
638
|
+
|
|
639
|
+
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
640
|
+
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
641
|
+
vec4 s2 = texelFetch1D( tex, i + 2u );
|
|
642
|
+
vec4 s3 = texelFetch1D( tex, i + 3u );
|
|
643
|
+
|
|
644
|
+
Light l;
|
|
645
|
+
l.position = s0.rgb;
|
|
646
|
+
l.type = int( round( s0.a ) );
|
|
647
|
+
|
|
648
|
+
l.color = s1.rgb;
|
|
649
|
+
l.intensity = s1.a;
|
|
650
|
+
|
|
651
|
+
l.u = s2.rgb;
|
|
652
|
+
l.v = s3.rgb;
|
|
653
|
+
l.area = s3.a;
|
|
654
|
+
|
|
655
|
+
if ( l.type == SPOT_LIGHT_TYPE || l.type == POINT_LIGHT_TYPE ) {
|
|
656
|
+
|
|
657
|
+
vec4 s4 = texelFetch1D( tex, i + 4u );
|
|
658
|
+
vec4 s5 = texelFetch1D( tex, i + 5u );
|
|
659
|
+
l.radius = s4.r;
|
|
660
|
+
l.decay = s4.g;
|
|
661
|
+
l.distance = s4.b;
|
|
662
|
+
l.coneCos = s4.a;
|
|
663
|
+
|
|
664
|
+
l.penumbraCos = s5.r;
|
|
665
|
+
l.iesProfile = int( round( s5.g ) );
|
|
666
|
+
|
|
667
|
+
} else {
|
|
668
|
+
|
|
669
|
+
l.radius = 0.0;
|
|
670
|
+
l.decay = 0.0;
|
|
671
|
+
l.distance = 0.0;
|
|
672
|
+
|
|
673
|
+
l.coneCos = 0.0;
|
|
674
|
+
l.penumbraCos = 0.0;
|
|
675
|
+
l.iesProfile = - 1;
|
|
676
|
+
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return l;
|
|
680
|
+
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
`,lo=`
|
|
684
|
+
|
|
685
|
+
struct Material {
|
|
686
|
+
|
|
687
|
+
vec3 color;
|
|
688
|
+
int map;
|
|
689
|
+
|
|
690
|
+
float metalness;
|
|
691
|
+
int metalnessMap;
|
|
692
|
+
|
|
693
|
+
float roughness;
|
|
694
|
+
int roughnessMap;
|
|
695
|
+
|
|
696
|
+
float ior;
|
|
697
|
+
float transmission;
|
|
698
|
+
int transmissionMap;
|
|
699
|
+
|
|
700
|
+
float emissiveIntensity;
|
|
701
|
+
vec3 emissive;
|
|
702
|
+
int emissiveMap;
|
|
703
|
+
|
|
704
|
+
int normalMap;
|
|
705
|
+
vec2 normalScale;
|
|
706
|
+
|
|
707
|
+
float clearcoat;
|
|
708
|
+
int clearcoatMap;
|
|
709
|
+
int clearcoatNormalMap;
|
|
710
|
+
vec2 clearcoatNormalScale;
|
|
711
|
+
float clearcoatRoughness;
|
|
712
|
+
int clearcoatRoughnessMap;
|
|
713
|
+
|
|
714
|
+
int iridescenceMap;
|
|
715
|
+
int iridescenceThicknessMap;
|
|
716
|
+
float iridescence;
|
|
717
|
+
float iridescenceIor;
|
|
718
|
+
float iridescenceThicknessMinimum;
|
|
719
|
+
float iridescenceThicknessMaximum;
|
|
720
|
+
|
|
721
|
+
vec3 specularColor;
|
|
722
|
+
int specularColorMap;
|
|
723
|
+
|
|
724
|
+
float specularIntensity;
|
|
725
|
+
int specularIntensityMap;
|
|
726
|
+
bool thinFilm;
|
|
727
|
+
|
|
728
|
+
vec3 attenuationColor;
|
|
729
|
+
float attenuationDistance;
|
|
730
|
+
|
|
731
|
+
int alphaMap;
|
|
732
|
+
|
|
733
|
+
bool castShadow;
|
|
734
|
+
float opacity;
|
|
735
|
+
float alphaTest;
|
|
736
|
+
|
|
737
|
+
float side;
|
|
738
|
+
bool matte;
|
|
739
|
+
|
|
740
|
+
float sheen;
|
|
741
|
+
vec3 sheenColor;
|
|
742
|
+
int sheenColorMap;
|
|
743
|
+
float sheenRoughness;
|
|
744
|
+
int sheenRoughnessMap;
|
|
745
|
+
|
|
746
|
+
bool vertexColors;
|
|
747
|
+
bool flatShading;
|
|
748
|
+
bool transparent;
|
|
749
|
+
bool fogVolume;
|
|
750
|
+
|
|
751
|
+
mat3 mapTransform;
|
|
752
|
+
mat3 metalnessMapTransform;
|
|
753
|
+
mat3 roughnessMapTransform;
|
|
754
|
+
mat3 transmissionMapTransform;
|
|
755
|
+
mat3 emissiveMapTransform;
|
|
756
|
+
mat3 normalMapTransform;
|
|
757
|
+
mat3 clearcoatMapTransform;
|
|
758
|
+
mat3 clearcoatNormalMapTransform;
|
|
759
|
+
mat3 clearcoatRoughnessMapTransform;
|
|
760
|
+
mat3 sheenColorMapTransform;
|
|
761
|
+
mat3 sheenRoughnessMapTransform;
|
|
762
|
+
mat3 iridescenceMapTransform;
|
|
763
|
+
mat3 iridescenceThicknessMapTransform;
|
|
764
|
+
mat3 specularColorMapTransform;
|
|
765
|
+
mat3 specularIntensityMapTransform;
|
|
766
|
+
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
mat3 readTextureTransform( sampler2D tex, uint index ) {
|
|
770
|
+
|
|
771
|
+
mat3 textureTransform;
|
|
772
|
+
|
|
773
|
+
vec4 row1 = texelFetch1D( tex, index );
|
|
774
|
+
vec4 row2 = texelFetch1D( tex, index + 1u );
|
|
775
|
+
|
|
776
|
+
textureTransform[0] = vec3(row1.r, row2.r, 0.0);
|
|
777
|
+
textureTransform[1] = vec3(row1.g, row2.g, 0.0);
|
|
778
|
+
textureTransform[2] = vec3(row1.b, row2.b, 1.0);
|
|
779
|
+
|
|
780
|
+
return textureTransform;
|
|
781
|
+
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
Material readMaterialInfo( sampler2D tex, uint index ) {
|
|
785
|
+
|
|
786
|
+
uint i = index * 45u;
|
|
787
|
+
|
|
788
|
+
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
789
|
+
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
790
|
+
vec4 s2 = texelFetch1D( tex, i + 2u );
|
|
791
|
+
vec4 s3 = texelFetch1D( tex, i + 3u );
|
|
792
|
+
vec4 s4 = texelFetch1D( tex, i + 4u );
|
|
793
|
+
vec4 s5 = texelFetch1D( tex, i + 5u );
|
|
794
|
+
vec4 s6 = texelFetch1D( tex, i + 6u );
|
|
795
|
+
vec4 s7 = texelFetch1D( tex, i + 7u );
|
|
796
|
+
vec4 s8 = texelFetch1D( tex, i + 8u );
|
|
797
|
+
vec4 s9 = texelFetch1D( tex, i + 9u );
|
|
798
|
+
vec4 s10 = texelFetch1D( tex, i + 10u );
|
|
799
|
+
vec4 s11 = texelFetch1D( tex, i + 11u );
|
|
800
|
+
vec4 s12 = texelFetch1D( tex, i + 12u );
|
|
801
|
+
vec4 s13 = texelFetch1D( tex, i + 13u );
|
|
802
|
+
vec4 s14 = texelFetch1D( tex, i + 14u );
|
|
803
|
+
|
|
804
|
+
Material m;
|
|
805
|
+
m.color = s0.rgb;
|
|
806
|
+
m.map = int( round( s0.a ) );
|
|
807
|
+
|
|
808
|
+
m.metalness = s1.r;
|
|
809
|
+
m.metalnessMap = int( round( s1.g ) );
|
|
810
|
+
m.roughness = s1.b;
|
|
811
|
+
m.roughnessMap = int( round( s1.a ) );
|
|
812
|
+
|
|
813
|
+
m.ior = s2.r;
|
|
814
|
+
m.transmission = s2.g;
|
|
815
|
+
m.transmissionMap = int( round( s2.b ) );
|
|
816
|
+
m.emissiveIntensity = s2.a;
|
|
817
|
+
|
|
818
|
+
m.emissive = s3.rgb;
|
|
819
|
+
m.emissiveMap = int( round( s3.a ) );
|
|
820
|
+
|
|
821
|
+
m.normalMap = int( round( s4.r ) );
|
|
822
|
+
m.normalScale = s4.gb;
|
|
823
|
+
|
|
824
|
+
m.clearcoat = s4.a;
|
|
825
|
+
m.clearcoatMap = int( round( s5.r ) );
|
|
826
|
+
m.clearcoatRoughness = s5.g;
|
|
827
|
+
m.clearcoatRoughnessMap = int( round( s5.b ) );
|
|
828
|
+
m.clearcoatNormalMap = int( round( s5.a ) );
|
|
829
|
+
m.clearcoatNormalScale = s6.rg;
|
|
830
|
+
|
|
831
|
+
m.sheen = s6.a;
|
|
832
|
+
m.sheenColor = s7.rgb;
|
|
833
|
+
m.sheenColorMap = int( round( s7.a ) );
|
|
834
|
+
m.sheenRoughness = s8.r;
|
|
835
|
+
m.sheenRoughnessMap = int( round( s8.g ) );
|
|
836
|
+
|
|
837
|
+
m.iridescenceMap = int( round( s8.b ) );
|
|
838
|
+
m.iridescenceThicknessMap = int( round( s8.a ) );
|
|
839
|
+
m.iridescence = s9.r;
|
|
840
|
+
m.iridescenceIor = s9.g;
|
|
841
|
+
m.iridescenceThicknessMinimum = s9.b;
|
|
842
|
+
m.iridescenceThicknessMaximum = s9.a;
|
|
843
|
+
|
|
844
|
+
m.specularColor = s10.rgb;
|
|
845
|
+
m.specularColorMap = int( round( s10.a ) );
|
|
846
|
+
|
|
847
|
+
m.specularIntensity = s11.r;
|
|
848
|
+
m.specularIntensityMap = int( round( s11.g ) );
|
|
849
|
+
m.thinFilm = bool( s11.b );
|
|
850
|
+
|
|
851
|
+
m.attenuationColor = s12.rgb;
|
|
852
|
+
m.attenuationDistance = s12.a;
|
|
853
|
+
|
|
854
|
+
m.alphaMap = int( round( s13.r ) );
|
|
855
|
+
|
|
856
|
+
m.opacity = s13.g;
|
|
857
|
+
m.alphaTest = s13.b;
|
|
858
|
+
m.side = s13.a;
|
|
859
|
+
|
|
860
|
+
m.matte = bool( s14.r );
|
|
861
|
+
m.castShadow = bool( s14.g );
|
|
862
|
+
m.vertexColors = bool( int( s14.b ) & 1 );
|
|
863
|
+
m.flatShading = bool( int( s14.b ) & 2 );
|
|
864
|
+
m.fogVolume = bool( int( s14.b ) & 4 );
|
|
865
|
+
m.transparent = bool( s14.a );
|
|
866
|
+
|
|
867
|
+
uint firstTextureTransformIdx = i + 15u;
|
|
868
|
+
|
|
869
|
+
// mat3( 1.0 ) is an identity matrix
|
|
870
|
+
m.mapTransform = m.map == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx );
|
|
871
|
+
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
872
|
+
m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );
|
|
873
|
+
m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );
|
|
874
|
+
m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );
|
|
875
|
+
m.normalMapTransform = m.normalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );
|
|
876
|
+
m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );
|
|
877
|
+
m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );
|
|
878
|
+
m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );
|
|
879
|
+
m.sheenColorMapTransform = m.sheenColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 18u );
|
|
880
|
+
m.sheenRoughnessMapTransform = m.sheenRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 20u );
|
|
881
|
+
m.iridescenceMapTransform = m.iridescenceMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 22u );
|
|
882
|
+
m.iridescenceThicknessMapTransform = m.iridescenceThicknessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 24u );
|
|
883
|
+
m.specularColorMapTransform = m.specularColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 26u );
|
|
884
|
+
m.specularIntensityMapTransform = m.specularIntensityMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 28u );
|
|
885
|
+
|
|
886
|
+
return m;
|
|
887
|
+
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
`,uo=`
|
|
891
|
+
|
|
892
|
+
struct SurfaceRecord {
|
|
893
|
+
|
|
894
|
+
// surface type
|
|
895
|
+
bool volumeParticle;
|
|
896
|
+
|
|
897
|
+
// geometry
|
|
898
|
+
vec3 faceNormal;
|
|
899
|
+
bool frontFace;
|
|
900
|
+
vec3 normal;
|
|
901
|
+
mat3 normalBasis;
|
|
902
|
+
mat3 normalInvBasis;
|
|
903
|
+
|
|
904
|
+
// cached properties
|
|
905
|
+
float eta;
|
|
906
|
+
float f0;
|
|
907
|
+
|
|
908
|
+
// material
|
|
909
|
+
float roughness;
|
|
910
|
+
float filteredRoughness;
|
|
911
|
+
float metalness;
|
|
912
|
+
vec3 color;
|
|
913
|
+
vec3 emission;
|
|
914
|
+
|
|
915
|
+
// transmission
|
|
916
|
+
float ior;
|
|
917
|
+
float transmission;
|
|
918
|
+
bool thinFilm;
|
|
919
|
+
vec3 attenuationColor;
|
|
920
|
+
float attenuationDistance;
|
|
921
|
+
|
|
922
|
+
// clearcoat
|
|
923
|
+
vec3 clearcoatNormal;
|
|
924
|
+
mat3 clearcoatBasis;
|
|
925
|
+
mat3 clearcoatInvBasis;
|
|
926
|
+
float clearcoat;
|
|
927
|
+
float clearcoatRoughness;
|
|
928
|
+
float filteredClearcoatRoughness;
|
|
929
|
+
|
|
930
|
+
// sheen
|
|
931
|
+
float sheen;
|
|
932
|
+
vec3 sheenColor;
|
|
933
|
+
float sheenRoughness;
|
|
934
|
+
|
|
935
|
+
// iridescence
|
|
936
|
+
float iridescence;
|
|
937
|
+
float iridescenceIor;
|
|
938
|
+
float iridescenceThickness;
|
|
939
|
+
|
|
940
|
+
// specular
|
|
941
|
+
vec3 specularColor;
|
|
942
|
+
float specularIntensity;
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
struct ScatterRecord {
|
|
946
|
+
float specularPdf;
|
|
947
|
+
float pdf;
|
|
948
|
+
vec3 direction;
|
|
949
|
+
vec3 color;
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
`,fo=`
|
|
953
|
+
|
|
954
|
+
// samples the the given environment map in the given direction
|
|
955
|
+
vec3 sampleEquirectColor( sampler2D envMap, vec3 direction ) {
|
|
956
|
+
|
|
957
|
+
return texture2D( envMap, equirectDirectionToUv( direction ) ).rgb;
|
|
958
|
+
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// gets the pdf of the given direction to sample
|
|
962
|
+
float equirectDirectionPdf( vec3 direction ) {
|
|
963
|
+
|
|
964
|
+
vec2 uv = equirectDirectionToUv( direction );
|
|
965
|
+
float theta = uv.y * PI;
|
|
966
|
+
float sinTheta = sin( theta );
|
|
967
|
+
if ( sinTheta == 0.0 ) {
|
|
968
|
+
|
|
969
|
+
return 0.0;
|
|
970
|
+
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return 1.0 / ( 2.0 * PI * PI * sinTheta );
|
|
974
|
+
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// samples the color given env map with CDF and returns the pdf of the direction
|
|
978
|
+
float sampleEquirect( vec3 direction, inout vec3 color ) {
|
|
979
|
+
|
|
980
|
+
float totalSum = envMapInfo.totalSum;
|
|
981
|
+
if ( totalSum == 0.0 ) {
|
|
982
|
+
|
|
983
|
+
color = vec3( 0.0 );
|
|
984
|
+
return 1.0;
|
|
985
|
+
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
vec2 uv = equirectDirectionToUv( direction );
|
|
989
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
990
|
+
|
|
991
|
+
float lum = luminance( color );
|
|
992
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
993
|
+
float pdf = lum / totalSum;
|
|
994
|
+
|
|
995
|
+
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
996
|
+
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// samples a direction of the envmap with color and retrieves pdf
|
|
1000
|
+
float sampleEquirectProbability( vec2 r, inout vec3 color, inout vec3 direction ) {
|
|
1001
|
+
|
|
1002
|
+
// sample env map cdf
|
|
1003
|
+
float v = texture2D( envMapInfo.marginalWeights, vec2( r.x, 0.0 ) ).x;
|
|
1004
|
+
float u = texture2D( envMapInfo.conditionalWeights, vec2( r.y, v ) ).x;
|
|
1005
|
+
vec2 uv = vec2( u, v );
|
|
1006
|
+
|
|
1007
|
+
vec3 derivedDirection = equirectUvToDirection( uv );
|
|
1008
|
+
direction = derivedDirection;
|
|
1009
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
1010
|
+
|
|
1011
|
+
float totalSum = envMapInfo.totalSum;
|
|
1012
|
+
float lum = luminance( color );
|
|
1013
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
1014
|
+
float pdf = lum / totalSum;
|
|
1015
|
+
|
|
1016
|
+
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
1017
|
+
|
|
1018
|
+
}
|
|
1019
|
+
`,ho=`
|
|
1020
|
+
|
|
1021
|
+
float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {
|
|
1022
|
+
|
|
1023
|
+
return smoothstep( coneCosine, penumbraCosine, angleCosine );
|
|
1024
|
+
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
|
|
1028
|
+
|
|
1029
|
+
// based upon Frostbite 3 Moving to Physically-based Rendering
|
|
1030
|
+
// page 32, equation 26: E[window1]
|
|
1031
|
+
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
|
1032
|
+
float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );
|
|
1033
|
+
|
|
1034
|
+
if ( cutoffDistance > 0.0 ) {
|
|
1035
|
+
|
|
1036
|
+
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );
|
|
1037
|
+
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return distanceFalloff;
|
|
1041
|
+
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {
|
|
1045
|
+
|
|
1046
|
+
float cosTheta = dot( posToLight, lightDir );
|
|
1047
|
+
float angle = acos( cosTheta ) / PI;
|
|
1048
|
+
|
|
1049
|
+
return texture2D( iesProfiles, vec3( angle, 0.0, iesProfile ) ).r;
|
|
1050
|
+
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
struct LightRecord {
|
|
1054
|
+
|
|
1055
|
+
float dist;
|
|
1056
|
+
vec3 direction;
|
|
1057
|
+
float pdf;
|
|
1058
|
+
vec3 emission;
|
|
1059
|
+
int type;
|
|
1060
|
+
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
bool intersectLightAtIndex( sampler2D lights, vec3 rayOrigin, vec3 rayDirection, uint l, inout LightRecord lightRec ) {
|
|
1064
|
+
|
|
1065
|
+
bool didHit = false;
|
|
1066
|
+
Light light = readLightInfo( lights, l );
|
|
1067
|
+
|
|
1068
|
+
vec3 u = light.u;
|
|
1069
|
+
vec3 v = light.v;
|
|
1070
|
+
|
|
1071
|
+
// check for backface
|
|
1072
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
1073
|
+
if ( dot( normal, rayDirection ) > 0.0 ) {
|
|
1074
|
+
|
|
1075
|
+
u *= 1.0 / dot( u, u );
|
|
1076
|
+
v *= 1.0 / dot( v, v );
|
|
1077
|
+
|
|
1078
|
+
float dist;
|
|
1079
|
+
|
|
1080
|
+
// MIS / light intersection is not supported for punctual lights.
|
|
1081
|
+
if(
|
|
1082
|
+
( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
|
|
1083
|
+
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
1084
|
+
) {
|
|
1085
|
+
|
|
1086
|
+
float cosTheta = dot( rayDirection, normal );
|
|
1087
|
+
didHit = true;
|
|
1088
|
+
lightRec.dist = dist;
|
|
1089
|
+
lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
1090
|
+
lightRec.emission = light.color * light.intensity;
|
|
1091
|
+
lightRec.direction = rayDirection;
|
|
1092
|
+
lightRec.type = light.type;
|
|
1093
|
+
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
return didHit;
|
|
1099
|
+
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
|
|
1103
|
+
|
|
1104
|
+
vec3 randomPos;
|
|
1105
|
+
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
1106
|
+
|
|
1107
|
+
// rectangular area light
|
|
1108
|
+
randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
|
|
1109
|
+
|
|
1110
|
+
} else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
|
|
1111
|
+
|
|
1112
|
+
// circular area light
|
|
1113
|
+
float r = 0.5 * sqrt( ruv.x );
|
|
1114
|
+
float theta = ruv.y * 2.0 * PI;
|
|
1115
|
+
float x = r * cos( theta );
|
|
1116
|
+
float y = r * sin( theta );
|
|
1117
|
+
|
|
1118
|
+
randomPos = light.position + light.u * x + light.v * y;
|
|
1119
|
+
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
vec3 toLight = randomPos - rayOrigin;
|
|
1123
|
+
float lightDistSq = dot( toLight, toLight );
|
|
1124
|
+
float dist = sqrt( lightDistSq );
|
|
1125
|
+
vec3 direction = toLight / dist;
|
|
1126
|
+
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
1127
|
+
|
|
1128
|
+
LightRecord lightRec;
|
|
1129
|
+
lightRec.type = light.type;
|
|
1130
|
+
lightRec.emission = light.color * light.intensity;
|
|
1131
|
+
lightRec.dist = dist;
|
|
1132
|
+
lightRec.direction = direction;
|
|
1133
|
+
|
|
1134
|
+
// TODO: the denominator is potentially zero
|
|
1135
|
+
lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
1136
|
+
|
|
1137
|
+
return lightRec;
|
|
1138
|
+
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
LightRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {
|
|
1142
|
+
|
|
1143
|
+
float radius = light.radius * sqrt( ruv.x );
|
|
1144
|
+
float theta = ruv.y * 2.0 * PI;
|
|
1145
|
+
float x = radius * cos( theta );
|
|
1146
|
+
float y = radius * sin( theta );
|
|
1147
|
+
|
|
1148
|
+
vec3 u = light.u;
|
|
1149
|
+
vec3 v = light.v;
|
|
1150
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
1151
|
+
|
|
1152
|
+
float angle = acos( light.coneCos );
|
|
1153
|
+
float angleTan = tan( angle );
|
|
1154
|
+
float startDistance = light.radius / max( angleTan, EPSILON );
|
|
1155
|
+
|
|
1156
|
+
vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
|
|
1157
|
+
vec3 toLight = randomPos - rayOrigin;
|
|
1158
|
+
float lightDistSq = dot( toLight, toLight );
|
|
1159
|
+
float dist = sqrt( lightDistSq );
|
|
1160
|
+
|
|
1161
|
+
vec3 direction = toLight / max( dist, EPSILON );
|
|
1162
|
+
float cosTheta = dot( direction, normal );
|
|
1163
|
+
|
|
1164
|
+
float spotAttenuation = light.iesProfile != - 1 ?
|
|
1165
|
+
getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
|
|
1166
|
+
getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
|
|
1167
|
+
|
|
1168
|
+
float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
|
|
1169
|
+
LightRecord lightRec;
|
|
1170
|
+
lightRec.type = light.type;
|
|
1171
|
+
lightRec.dist = dist;
|
|
1172
|
+
lightRec.direction = direction;
|
|
1173
|
+
lightRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;
|
|
1174
|
+
lightRec.pdf = 1.0;
|
|
1175
|
+
|
|
1176
|
+
return lightRec;
|
|
1177
|
+
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
|
|
1181
|
+
|
|
1182
|
+
LightRecord result;
|
|
1183
|
+
|
|
1184
|
+
// pick a random light
|
|
1185
|
+
uint l = uint( ruv.x * float( lightCount ) );
|
|
1186
|
+
Light light = readLightInfo( lights, l );
|
|
1187
|
+
|
|
1188
|
+
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
1189
|
+
|
|
1190
|
+
result = randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
1191
|
+
|
|
1192
|
+
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
1193
|
+
|
|
1194
|
+
vec3 lightRay = light.u - rayOrigin;
|
|
1195
|
+
float lightDist = length( lightRay );
|
|
1196
|
+
float cutoffDistance = light.distance;
|
|
1197
|
+
float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
|
|
1198
|
+
if ( cutoffDistance > 0.0 ) {
|
|
1199
|
+
|
|
1200
|
+
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
|
|
1201
|
+
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
LightRecord rec;
|
|
1205
|
+
rec.direction = normalize( lightRay );
|
|
1206
|
+
rec.dist = length( lightRay );
|
|
1207
|
+
rec.pdf = 1.0;
|
|
1208
|
+
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
1209
|
+
rec.type = light.type;
|
|
1210
|
+
result = rec;
|
|
1211
|
+
|
|
1212
|
+
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
1213
|
+
|
|
1214
|
+
LightRecord rec;
|
|
1215
|
+
rec.dist = 1e10;
|
|
1216
|
+
rec.direction = light.u;
|
|
1217
|
+
rec.pdf = 1.0;
|
|
1218
|
+
rec.emission = light.color * light.intensity;
|
|
1219
|
+
rec.type = light.type;
|
|
1220
|
+
|
|
1221
|
+
result = rec;
|
|
1222
|
+
|
|
1223
|
+
} else {
|
|
1224
|
+
|
|
1225
|
+
// sample the light
|
|
1226
|
+
result = randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
1227
|
+
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
return result;
|
|
1231
|
+
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
`,mo=`
|
|
1235
|
+
|
|
1236
|
+
vec3 sampleHemisphere( vec3 n, vec2 uv ) {
|
|
1237
|
+
|
|
1238
|
+
// https://www.rorydriscoll.com/2009/01/07/better-sampling/
|
|
1239
|
+
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
1240
|
+
float sign = n.z == 0.0 ? 1.0 : sign( n.z );
|
|
1241
|
+
float a = - 1.0 / ( sign + n.z );
|
|
1242
|
+
float b = n.x * n.y * a;
|
|
1243
|
+
vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
|
|
1244
|
+
vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
|
|
1245
|
+
|
|
1246
|
+
float r = sqrt( uv.x );
|
|
1247
|
+
float theta = 2.0 * PI * uv.y;
|
|
1248
|
+
float x = r * cos( theta );
|
|
1249
|
+
float y = r * sin( theta );
|
|
1250
|
+
return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
|
|
1251
|
+
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {
|
|
1255
|
+
|
|
1256
|
+
// get the edges of the triangle and the diagonal across the
|
|
1257
|
+
// center of the parallelogram
|
|
1258
|
+
vec2 e1 = a - b;
|
|
1259
|
+
vec2 e2 = c - b;
|
|
1260
|
+
vec2 diag = normalize( e1 + e2 );
|
|
1261
|
+
|
|
1262
|
+
// pick the point in the parallelogram
|
|
1263
|
+
if ( r.x + r.y > 1.0 ) {
|
|
1264
|
+
|
|
1265
|
+
r = vec2( 1.0 ) - r;
|
|
1266
|
+
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
return e1 * r.x + e2 * r.y;
|
|
1270
|
+
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
vec2 sampleCircle( vec2 uv ) {
|
|
1274
|
+
|
|
1275
|
+
float angle = 2.0 * PI * uv.x;
|
|
1276
|
+
float radius = sqrt( uv.y );
|
|
1277
|
+
return vec2( cos( angle ), sin( angle ) ) * radius;
|
|
1278
|
+
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
vec3 sampleSphere( vec2 uv ) {
|
|
1282
|
+
|
|
1283
|
+
float u = ( uv.x - 0.5 ) * 2.0;
|
|
1284
|
+
float t = uv.y * PI * 2.0;
|
|
1285
|
+
float f = sqrt( 1.0 - u * u );
|
|
1286
|
+
|
|
1287
|
+
return vec3( f * cos( t ), f * sin( t ), u );
|
|
1288
|
+
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
vec2 sampleRegularPolygon( int sides, vec3 uvw ) {
|
|
1292
|
+
|
|
1293
|
+
sides = max( sides, 3 );
|
|
1294
|
+
|
|
1295
|
+
vec3 r = uvw;
|
|
1296
|
+
float anglePerSegment = 2.0 * PI / float( sides );
|
|
1297
|
+
float segment = floor( float( sides ) * r.x );
|
|
1298
|
+
|
|
1299
|
+
float angle1 = anglePerSegment * segment;
|
|
1300
|
+
float angle2 = angle1 + anglePerSegment;
|
|
1301
|
+
vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
|
|
1302
|
+
vec2 b = vec2( 0.0, 0.0 );
|
|
1303
|
+
vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
|
|
1304
|
+
|
|
1305
|
+
return sampleTriangle( a, b, c, r.yz );
|
|
1306
|
+
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// samples an aperture shape with the given number of sides. 0 means circle
|
|
1310
|
+
vec2 sampleAperture( int blades, vec3 uvw ) {
|
|
1311
|
+
|
|
1312
|
+
return blades == 0 ?
|
|
1313
|
+
sampleCircle( uvw.xy ) :
|
|
1314
|
+
sampleRegularPolygon( blades, uvw );
|
|
1315
|
+
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
|
|
1319
|
+
`,po=`
|
|
1320
|
+
|
|
1321
|
+
bool totalInternalReflection( float cosTheta, float eta ) {
|
|
1322
|
+
|
|
1323
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
1324
|
+
return eta * sinTheta > 1.0;
|
|
1325
|
+
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
|
|
1329
|
+
float schlickFresnel( float cosine, float f0 ) {
|
|
1330
|
+
|
|
1331
|
+
return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
|
|
1332
|
+
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
vec3 schlickFresnel( float cosine, vec3 f0 ) {
|
|
1336
|
+
|
|
1337
|
+
return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
|
|
1338
|
+
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
vec3 schlickFresnel( float cosine, vec3 f0, vec3 f90 ) {
|
|
1342
|
+
|
|
1343
|
+
return f0 + ( f90 - f0 ) * pow( 1.0 - cosine, 5.0 );
|
|
1344
|
+
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
float dielectricFresnel( float cosThetaI, float eta ) {
|
|
1348
|
+
|
|
1349
|
+
// https://schuttejoe.github.io/post/disneybsdf/
|
|
1350
|
+
float ni = eta;
|
|
1351
|
+
float nt = 1.0;
|
|
1352
|
+
|
|
1353
|
+
// Check for total internal reflection
|
|
1354
|
+
float sinThetaISq = 1.0f - cosThetaI * cosThetaI;
|
|
1355
|
+
float sinThetaTSq = eta * eta * sinThetaISq;
|
|
1356
|
+
if( sinThetaTSq >= 1.0 ) {
|
|
1357
|
+
|
|
1358
|
+
return 1.0;
|
|
1359
|
+
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
float sinThetaT = sqrt( sinThetaTSq );
|
|
1363
|
+
|
|
1364
|
+
float cosThetaT = sqrt( max( 0.0, 1.0f - sinThetaT * sinThetaT ) );
|
|
1365
|
+
float rParallel = ( ( nt * cosThetaI ) - ( ni * cosThetaT ) ) / ( ( nt * cosThetaI ) + ( ni * cosThetaT ) );
|
|
1366
|
+
float rPerpendicular = ( ( ni * cosThetaI ) - ( nt * cosThetaT ) ) / ( ( ni * cosThetaI ) + ( nt * cosThetaT ) );
|
|
1367
|
+
return ( rParallel * rParallel + rPerpendicular * rPerpendicular ) / 2.0;
|
|
1368
|
+
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation
|
|
1372
|
+
float iorRatioToF0( float eta ) {
|
|
1373
|
+
|
|
1374
|
+
return pow( ( 1.0 - eta ) / ( 1.0 + eta ), 2.0 );
|
|
1375
|
+
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
vec3 evaluateFresnel( float cosTheta, float eta, vec3 f0, vec3 f90 ) {
|
|
1379
|
+
|
|
1380
|
+
if ( totalInternalReflection( cosTheta, eta ) ) {
|
|
1381
|
+
|
|
1382
|
+
return f90;
|
|
1383
|
+
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
return schlickFresnel( cosTheta, f0, f90 );
|
|
1387
|
+
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
// TODO: disney fresnel was removed and replaced with this fresnel function to better align with
|
|
1391
|
+
// the glTF but is causing blown out pixels. Should be revisited
|
|
1392
|
+
// float evaluateFresnelWeight( float cosTheta, float eta, float f0 ) {
|
|
1393
|
+
|
|
1394
|
+
// if ( totalInternalReflection( cosTheta, eta ) ) {
|
|
1395
|
+
|
|
1396
|
+
// return 1.0;
|
|
1397
|
+
|
|
1398
|
+
// }
|
|
1399
|
+
|
|
1400
|
+
// return schlickFresnel( cosTheta, f0 );
|
|
1401
|
+
|
|
1402
|
+
// }
|
|
1403
|
+
|
|
1404
|
+
// https://schuttejoe.github.io/post/disneybsdf/
|
|
1405
|
+
float disneyFresnel( vec3 wo, vec3 wi, vec3 wh, float f0, float eta, float metalness ) {
|
|
1406
|
+
|
|
1407
|
+
float dotHV = dot( wo, wh );
|
|
1408
|
+
if ( totalInternalReflection( dotHV, eta ) ) {
|
|
1409
|
+
|
|
1410
|
+
return 1.0;
|
|
1411
|
+
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
float dotHL = dot( wi, wh );
|
|
1415
|
+
float dielectricFresnel = dielectricFresnel( abs( dotHV ), eta );
|
|
1416
|
+
float metallicFresnel = schlickFresnel( dotHL, f0 );
|
|
1417
|
+
|
|
1418
|
+
return mix( dielectricFresnel, metallicFresnel, metalness );
|
|
1419
|
+
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
`,go=`
|
|
1423
|
+
|
|
1424
|
+
// Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.
|
|
1425
|
+
// This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].
|
|
1426
|
+
// For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248
|
|
1427
|
+
float acosApprox( float x ) {
|
|
1428
|
+
|
|
1429
|
+
x = clamp( x, -1.0, 1.0 );
|
|
1430
|
+
return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;
|
|
1431
|
+
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// An acos with input values bound to the range [-1, 1].
|
|
1435
|
+
float acosSafe( float x ) {
|
|
1436
|
+
|
|
1437
|
+
return acos( clamp( x, -1.0, 1.0 ) );
|
|
1438
|
+
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
float saturateCos( float val ) {
|
|
1442
|
+
|
|
1443
|
+
return clamp( val, 0.001, 1.0 );
|
|
1444
|
+
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
float square( float t ) {
|
|
1448
|
+
|
|
1449
|
+
return t * t;
|
|
1450
|
+
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
vec2 square( vec2 t ) {
|
|
1454
|
+
|
|
1455
|
+
return t * t;
|
|
1456
|
+
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
vec3 square( vec3 t ) {
|
|
1460
|
+
|
|
1461
|
+
return t * t;
|
|
1462
|
+
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
vec4 square( vec4 t ) {
|
|
1466
|
+
|
|
1467
|
+
return t * t;
|
|
1468
|
+
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
vec2 rotateVector( vec2 v, float t ) {
|
|
1472
|
+
|
|
1473
|
+
float ac = cos( t );
|
|
1474
|
+
float as = sin( t );
|
|
1475
|
+
return vec2(
|
|
1476
|
+
v.x * ac - v.y * as,
|
|
1477
|
+
v.x * as + v.y * ac
|
|
1478
|
+
);
|
|
1479
|
+
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// forms a basis with the normal vector as Z
|
|
1483
|
+
mat3 getBasisFromNormal( vec3 normal ) {
|
|
1484
|
+
|
|
1485
|
+
vec3 other;
|
|
1486
|
+
if ( abs( normal.x ) > 0.5 ) {
|
|
1487
|
+
|
|
1488
|
+
other = vec3( 0.0, 1.0, 0.0 );
|
|
1489
|
+
|
|
1490
|
+
} else {
|
|
1491
|
+
|
|
1492
|
+
other = vec3( 1.0, 0.0, 0.0 );
|
|
1493
|
+
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
vec3 ortho = normalize( cross( normal, other ) );
|
|
1497
|
+
vec3 ortho2 = normalize( cross( normal, ortho ) );
|
|
1498
|
+
return mat3( ortho2, ortho, normal );
|
|
1499
|
+
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
`,vo=`
|
|
1503
|
+
|
|
1504
|
+
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
1505
|
+
// falls in the bounds of the rectangle on that same plane.
|
|
1506
|
+
// Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
|
|
1507
|
+
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
|
|
1508
|
+
|
|
1509
|
+
float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
1510
|
+
|
|
1511
|
+
if ( t > EPSILON ) {
|
|
1512
|
+
|
|
1513
|
+
vec3 p = rayOrigin + rayDirection * t;
|
|
1514
|
+
vec3 vi = p - center;
|
|
1515
|
+
|
|
1516
|
+
// check if p falls inside the rectangle
|
|
1517
|
+
float a1 = dot( u, vi );
|
|
1518
|
+
if ( abs( a1 ) <= 0.5 ) {
|
|
1519
|
+
|
|
1520
|
+
float a2 = dot( v, vi );
|
|
1521
|
+
if ( abs( a2 ) <= 0.5 ) {
|
|
1522
|
+
|
|
1523
|
+
dist = t;
|
|
1524
|
+
return true;
|
|
1525
|
+
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
return false;
|
|
1533
|
+
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
1537
|
+
// falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.
|
|
1538
|
+
bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
|
|
1539
|
+
|
|
1540
|
+
float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
1541
|
+
|
|
1542
|
+
if ( t > EPSILON ) {
|
|
1543
|
+
|
|
1544
|
+
vec3 hit = rayOrigin + rayDirection * t;
|
|
1545
|
+
vec3 vi = hit - position;
|
|
1546
|
+
|
|
1547
|
+
float a1 = dot( u, vi );
|
|
1548
|
+
float a2 = dot( v, vi );
|
|
1549
|
+
|
|
1550
|
+
if( length( vec2( a1, a2 ) ) <= 0.5 ) {
|
|
1551
|
+
|
|
1552
|
+
dist = t;
|
|
1553
|
+
return true;
|
|
1554
|
+
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
return false;
|
|
1560
|
+
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
`,xo=`
|
|
1564
|
+
|
|
1565
|
+
// add texel fetch functions for texture arrays
|
|
1566
|
+
vec4 texelFetch1D( sampler2DArray tex, int layer, uint index ) {
|
|
1567
|
+
|
|
1568
|
+
uint width = uint( textureSize( tex, 0 ).x );
|
|
1569
|
+
uvec2 uv;
|
|
1570
|
+
uv.x = index % width;
|
|
1571
|
+
uv.y = index / width;
|
|
1572
|
+
|
|
1573
|
+
return texelFetch( tex, ivec3( uv, layer ), 0 );
|
|
1574
|
+
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
vec4 textureSampleBarycoord( sampler2DArray tex, int layer, vec3 barycoord, uvec3 faceIndices ) {
|
|
1578
|
+
|
|
1579
|
+
return
|
|
1580
|
+
barycoord.x * texelFetch1D( tex, layer, faceIndices.x ) +
|
|
1581
|
+
barycoord.y * texelFetch1D( tex, layer, faceIndices.y ) +
|
|
1582
|
+
barycoord.z * texelFetch1D( tex, layer, faceIndices.z );
|
|
1583
|
+
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
`,as=`
|
|
1587
|
+
|
|
1588
|
+
// TODO: possibly this should be renamed something related to material or path tracing logic
|
|
1589
|
+
|
|
1590
|
+
#ifndef RAY_OFFSET
|
|
1591
|
+
#define RAY_OFFSET 1e-4
|
|
1592
|
+
#endif
|
|
1593
|
+
|
|
1594
|
+
// adjust the hit point by the surface normal by a factor of some offset and the
|
|
1595
|
+
// maximum component-wise value of the current point to accommodate floating point
|
|
1596
|
+
// error as values increase.
|
|
1597
|
+
vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {
|
|
1598
|
+
|
|
1599
|
+
vec3 point = rayOrigin + rayDirection * dist;
|
|
1600
|
+
vec3 absPoint = abs( point );
|
|
1601
|
+
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
1602
|
+
return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;
|
|
1603
|
+
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
|
|
1607
|
+
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
|
|
1608
|
+
|
|
1609
|
+
vec3 ot = - log( attColor ) / attDist;
|
|
1610
|
+
return exp( - ot * dist );
|
|
1611
|
+
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
vec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {
|
|
1615
|
+
|
|
1616
|
+
// get the half vector - assuming if the light incident vector is on the other side
|
|
1617
|
+
// of the that it's transmissive.
|
|
1618
|
+
vec3 h;
|
|
1619
|
+
if ( wi.z > 0.0 ) {
|
|
1620
|
+
|
|
1621
|
+
h = normalize( wi + wo );
|
|
1622
|
+
|
|
1623
|
+
} else {
|
|
1624
|
+
|
|
1625
|
+
// Scale by the ior ratio to retrieve the appropriate half vector
|
|
1626
|
+
// From Section 2.2 on computing the transmission half vector:
|
|
1627
|
+
// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
|
|
1628
|
+
h = normalize( wi + wo * eta );
|
|
1629
|
+
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
h *= sign( h.z );
|
|
1633
|
+
return h;
|
|
1634
|
+
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
vec3 getHalfVector( vec3 a, vec3 b ) {
|
|
1638
|
+
|
|
1639
|
+
return normalize( a + b );
|
|
1640
|
+
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray
|
|
1644
|
+
// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If
|
|
1645
|
+
// we find a ray like that we ignore it to avoid artifacts.
|
|
1646
|
+
// This function returns if the direction is on the same side of both planes.
|
|
1647
|
+
bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {
|
|
1648
|
+
|
|
1649
|
+
bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;
|
|
1650
|
+
bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;
|
|
1651
|
+
return aboveSurfaceNormal == aboveGeometryNormal;
|
|
1652
|
+
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// ray sampling x and z are swapped to align with expected background view
|
|
1656
|
+
vec2 equirectDirectionToUv( vec3 direction ) {
|
|
1657
|
+
|
|
1658
|
+
// from Spherical.setFromCartesianCoords
|
|
1659
|
+
vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );
|
|
1660
|
+
uv /= vec2( 2.0 * PI, PI );
|
|
1661
|
+
|
|
1662
|
+
// apply adjustments to get values in range [0, 1] and y right side up
|
|
1663
|
+
uv.x += 0.5;
|
|
1664
|
+
uv.y = 1.0 - uv.y;
|
|
1665
|
+
return uv;
|
|
1666
|
+
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
vec3 equirectUvToDirection( vec2 uv ) {
|
|
1670
|
+
|
|
1671
|
+
// undo above adjustments
|
|
1672
|
+
uv.x -= 0.5;
|
|
1673
|
+
uv.y = 1.0 - uv.y;
|
|
1674
|
+
|
|
1675
|
+
// from Vector3.setFromSphericalCoords
|
|
1676
|
+
float theta = uv.x * 2.0 * PI;
|
|
1677
|
+
float phi = uv.y * PI;
|
|
1678
|
+
|
|
1679
|
+
float sinPhi = sin( phi );
|
|
1680
|
+
|
|
1681
|
+
return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );
|
|
1682
|
+
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// power heuristic for multiple importance sampling
|
|
1686
|
+
float misHeuristic( float a, float b ) {
|
|
1687
|
+
|
|
1688
|
+
float aa = a * a;
|
|
1689
|
+
float bb = b * b;
|
|
1690
|
+
return aa / ( aa + bb );
|
|
1691
|
+
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
// tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60
|
|
1695
|
+
// erichlof/THREE.js-PathTracing-Renderer/
|
|
1696
|
+
float tentFilter( float x ) {
|
|
1697
|
+
|
|
1698
|
+
return x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );
|
|
1699
|
+
|
|
1700
|
+
}
|
|
1701
|
+
`,Cr=`
|
|
1702
|
+
|
|
1703
|
+
// https://www.shadertoy.com/view/wltcRS
|
|
1704
|
+
uvec4 WHITE_NOISE_SEED;
|
|
1705
|
+
|
|
1706
|
+
void rng_initialize( vec2 p, int frame ) {
|
|
1707
|
+
|
|
1708
|
+
// white noise seed
|
|
1709
|
+
WHITE_NOISE_SEED = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );
|
|
1710
|
+
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
// https://www.pcg-random.org/
|
|
1714
|
+
void pcg4d( inout uvec4 v ) {
|
|
1715
|
+
|
|
1716
|
+
v = v * 1664525u + 1013904223u;
|
|
1717
|
+
v.x += v.y * v.w;
|
|
1718
|
+
v.y += v.z * v.x;
|
|
1719
|
+
v.z += v.x * v.y;
|
|
1720
|
+
v.w += v.y * v.z;
|
|
1721
|
+
v = v ^ ( v >> 16u );
|
|
1722
|
+
v.x += v.y*v.w;
|
|
1723
|
+
v.y += v.z*v.x;
|
|
1724
|
+
v.z += v.x*v.y;
|
|
1725
|
+
v.w += v.y*v.z;
|
|
1726
|
+
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// returns [ 0, 1 ]
|
|
1730
|
+
float pcgRand() {
|
|
1731
|
+
|
|
1732
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
1733
|
+
return float( WHITE_NOISE_SEED.x ) / float( 0xffffffffu );
|
|
1734
|
+
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
vec2 pcgRand2() {
|
|
1738
|
+
|
|
1739
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
1740
|
+
return vec2( WHITE_NOISE_SEED.xy ) / float(0xffffffffu);
|
|
1741
|
+
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
vec3 pcgRand3() {
|
|
1745
|
+
|
|
1746
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
1747
|
+
return vec3( WHITE_NOISE_SEED.xyz ) / float( 0xffffffffu );
|
|
1748
|
+
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
vec4 pcgRand4() {
|
|
1752
|
+
|
|
1753
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
1754
|
+
return vec4( WHITE_NOISE_SEED ) / float( 0xffffffffu );
|
|
1755
|
+
|
|
1756
|
+
}
|
|
1757
|
+
`,yo=`
|
|
1758
|
+
|
|
1759
|
+
uniform sampler2D stratifiedTexture;
|
|
1760
|
+
uniform sampler2D stratifiedOffsetTexture;
|
|
1761
|
+
|
|
1762
|
+
uint sobolPixelIndex = 0u;
|
|
1763
|
+
uint sobolPathIndex = 0u;
|
|
1764
|
+
uint sobolBounceIndex = 0u;
|
|
1765
|
+
vec4 pixelSeed = vec4( 0 );
|
|
1766
|
+
|
|
1767
|
+
vec4 rand4( int v ) {
|
|
1768
|
+
|
|
1769
|
+
ivec2 uv = ivec2( v, sobolBounceIndex );
|
|
1770
|
+
vec4 stratifiedSample = texelFetch( stratifiedTexture, uv, 0 );
|
|
1771
|
+
return fract( stratifiedSample + pixelSeed.r ); // blue noise + stratified samples
|
|
1772
|
+
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
vec3 rand3( int v ) {
|
|
1776
|
+
|
|
1777
|
+
return rand4( v ).xyz;
|
|
1778
|
+
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
vec2 rand2( int v ) {
|
|
1782
|
+
|
|
1783
|
+
return rand4( v ).xy;
|
|
1784
|
+
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
float rand( int v ) {
|
|
1788
|
+
|
|
1789
|
+
return rand4( v ).x;
|
|
1790
|
+
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
void rng_initialize( vec2 screenCoord, int frame ) {
|
|
1794
|
+
|
|
1795
|
+
// tile the small noise texture across the entire screen
|
|
1796
|
+
ivec2 noiseSize = ivec2( textureSize( stratifiedOffsetTexture, 0 ) );
|
|
1797
|
+
ivec2 pixel = ivec2( screenCoord.xy ) % noiseSize;
|
|
1798
|
+
vec2 pixelWidth = 1.0 / vec2( noiseSize );
|
|
1799
|
+
vec2 uv = vec2( pixel ) * pixelWidth + pixelWidth * 0.5;
|
|
1800
|
+
|
|
1801
|
+
// note that using "texelFetch" here seems to break Android for some reason
|
|
1802
|
+
pixelSeed = texture( stratifiedOffsetTexture, uv );
|
|
1803
|
+
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
`,bo=`
|
|
1807
|
+
|
|
1808
|
+
// diffuse
|
|
1809
|
+
float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
1810
|
+
|
|
1811
|
+
// https://schuttejoe.github.io/post/disneybsdf/
|
|
1812
|
+
float fl = schlickFresnel( wi.z, 0.0 );
|
|
1813
|
+
float fv = schlickFresnel( wo.z, 0.0 );
|
|
1814
|
+
|
|
1815
|
+
float metalFactor = ( 1.0 - surf.metalness );
|
|
1816
|
+
float transFactor = ( 1.0 - surf.transmission );
|
|
1817
|
+
float rr = 0.5 + 2.0 * surf.roughness * fl * fl;
|
|
1818
|
+
float retro = rr * ( fl + fv + fl * fv * ( rr - 1.0f ) );
|
|
1819
|
+
float lambert = ( 1.0f - 0.5f * fl ) * ( 1.0f - 0.5f * fv );
|
|
1820
|
+
|
|
1821
|
+
// TODO: subsurface approx?
|
|
1822
|
+
|
|
1823
|
+
// float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );
|
|
1824
|
+
float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );
|
|
1825
|
+
color = ( 1.0 - F ) * transFactor * metalFactor * wi.z * surf.color * ( retro + lambert ) / PI;
|
|
1826
|
+
|
|
1827
|
+
return wi.z / PI;
|
|
1828
|
+
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
vec3 diffuseDirection( vec3 wo, SurfaceRecord surf ) {
|
|
1832
|
+
|
|
1833
|
+
vec3 lightDirection = sampleSphere( rand2( 11 ) );
|
|
1834
|
+
lightDirection.z += 1.0;
|
|
1835
|
+
lightDirection = normalize( lightDirection );
|
|
1836
|
+
|
|
1837
|
+
return lightDirection;
|
|
1838
|
+
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
// specular
|
|
1842
|
+
float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
1843
|
+
|
|
1844
|
+
// if roughness is set to 0 then D === NaN which results in black pixels
|
|
1845
|
+
float metalness = surf.metalness;
|
|
1846
|
+
float roughness = surf.filteredRoughness;
|
|
1847
|
+
|
|
1848
|
+
float eta = surf.eta;
|
|
1849
|
+
float f0 = surf.f0;
|
|
1850
|
+
|
|
1851
|
+
vec3 f0Color = mix( f0 * surf.specularColor * surf.specularIntensity, surf.color, surf.metalness );
|
|
1852
|
+
vec3 f90Color = vec3( mix( surf.specularIntensity, 1.0, surf.metalness ) );
|
|
1853
|
+
vec3 F = evaluateFresnel( dot( wo, wh ), eta, f0Color, f90Color );
|
|
1854
|
+
|
|
1855
|
+
vec3 iridescenceF = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, wh ), surf.iridescenceThickness, f0Color );
|
|
1856
|
+
F = mix( F, iridescenceF, surf.iridescence );
|
|
1857
|
+
|
|
1858
|
+
// PDF
|
|
1859
|
+
// See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/
|
|
1860
|
+
float incidentTheta = acos( wo.z );
|
|
1861
|
+
float G = ggxShadowMaskG2( wi, wo, roughness );
|
|
1862
|
+
float D = ggxDistribution( wh, roughness );
|
|
1863
|
+
float G1 = ggxShadowMaskG1( incidentTheta, roughness );
|
|
1864
|
+
float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs ( wo.z );
|
|
1865
|
+
|
|
1866
|
+
color = wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );
|
|
1867
|
+
return ggxPdf / ( 4.0 * dot( wo, wh ) );
|
|
1868
|
+
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
vec3 specularDirection( vec3 wo, SurfaceRecord surf ) {
|
|
1872
|
+
|
|
1873
|
+
// sample ggx vndf distribution which gives a new normal
|
|
1874
|
+
float roughness = surf.filteredRoughness;
|
|
1875
|
+
vec3 halfVector = ggxDirection(
|
|
1876
|
+
wo,
|
|
1877
|
+
vec2( roughness ),
|
|
1878
|
+
rand2( 12 )
|
|
1879
|
+
);
|
|
1880
|
+
|
|
1881
|
+
// apply to new ray by reflecting off the new normal
|
|
1882
|
+
return - reflect( wo, halfVector );
|
|
1883
|
+
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
|
|
1887
|
+
// transmission
|
|
1888
|
+
/*
|
|
1889
|
+
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
1890
|
+
|
|
1891
|
+
// See section 4.2 in https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
|
|
1892
|
+
|
|
1893
|
+
float filteredRoughness = surf.filteredRoughness;
|
|
1894
|
+
float eta = surf.eta;
|
|
1895
|
+
bool frontFace = surf.frontFace;
|
|
1896
|
+
bool thinFilm = surf.thinFilm;
|
|
1897
|
+
|
|
1898
|
+
color = surf.transmission * surf.color;
|
|
1899
|
+
|
|
1900
|
+
float denom = pow( eta * dot( wi, wh ) + dot( wo, wh ), 2.0 );
|
|
1901
|
+
return ggxPDF( wo, wh, filteredRoughness ) / denom;
|
|
1902
|
+
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {
|
|
1906
|
+
|
|
1907
|
+
float filteredRoughness = surf.filteredRoughness;
|
|
1908
|
+
float eta = surf.eta;
|
|
1909
|
+
bool frontFace = surf.frontFace;
|
|
1910
|
+
|
|
1911
|
+
// sample ggx vndf distribution which gives a new normal
|
|
1912
|
+
vec3 halfVector = ggxDirection(
|
|
1913
|
+
wo,
|
|
1914
|
+
vec2( filteredRoughness ),
|
|
1915
|
+
rand2( 13 )
|
|
1916
|
+
);
|
|
1917
|
+
|
|
1918
|
+
vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );
|
|
1919
|
+
if ( surf.thinFilm ) {
|
|
1920
|
+
|
|
1921
|
+
lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );
|
|
1922
|
+
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
return normalize( lightDirection );
|
|
1926
|
+
|
|
1927
|
+
}
|
|
1928
|
+
*/
|
|
1929
|
+
|
|
1930
|
+
// TODO: This is just using a basic cosine-weighted specular distribution with an
|
|
1931
|
+
// incorrect PDF value at the moment. Update it to correctly use a GGX distribution
|
|
1932
|
+
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
1933
|
+
|
|
1934
|
+
color = surf.transmission * surf.color;
|
|
1935
|
+
|
|
1936
|
+
// PDF
|
|
1937
|
+
// float F = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );
|
|
1938
|
+
// float F = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );
|
|
1939
|
+
// if ( F >= 1.0 ) {
|
|
1940
|
+
|
|
1941
|
+
// return 0.0;
|
|
1942
|
+
|
|
1943
|
+
// }
|
|
1944
|
+
|
|
1945
|
+
// return 1.0 / ( 1.0 - F );
|
|
1946
|
+
|
|
1947
|
+
// reverted to previous to transmission. The above was causing black pixels
|
|
1948
|
+
float eta = surf.eta;
|
|
1949
|
+
float f0 = surf.f0;
|
|
1950
|
+
float cosTheta = min( wo.z, 1.0 );
|
|
1951
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
1952
|
+
float reflectance = schlickFresnel( cosTheta, f0 );
|
|
1953
|
+
bool cannotRefract = eta * sinTheta > 1.0;
|
|
1954
|
+
if ( cannotRefract ) {
|
|
1955
|
+
|
|
1956
|
+
return 0.0;
|
|
1957
|
+
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
return 1.0 / ( 1.0 - reflectance );
|
|
1961
|
+
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
vec3 transmissionDirection( vec3 wo, SurfaceRecord surf ) {
|
|
1965
|
+
|
|
1966
|
+
float roughness = surf.filteredRoughness;
|
|
1967
|
+
float eta = surf.eta;
|
|
1968
|
+
vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + sampleSphere( rand2( 13 ) ) * roughness );
|
|
1969
|
+
vec3 lightDirection = refract( normalize( - wo ), halfVector, eta );
|
|
1970
|
+
|
|
1971
|
+
if ( surf.thinFilm ) {
|
|
1972
|
+
|
|
1973
|
+
lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / eta );
|
|
1974
|
+
|
|
1975
|
+
}
|
|
1976
|
+
return normalize( lightDirection );
|
|
1977
|
+
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
// clearcoat
|
|
1981
|
+
float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
1982
|
+
|
|
1983
|
+
float ior = 1.5;
|
|
1984
|
+
float f0 = iorRatioToF0( ior );
|
|
1985
|
+
bool frontFace = surf.frontFace;
|
|
1986
|
+
float roughness = surf.filteredClearcoatRoughness;
|
|
1987
|
+
|
|
1988
|
+
float eta = frontFace ? 1.0 / ior : ior;
|
|
1989
|
+
float G = ggxShadowMaskG2( wi, wo, roughness );
|
|
1990
|
+
float D = ggxDistribution( wh, roughness );
|
|
1991
|
+
float F = schlickFresnel( dot( wi, wh ), f0 );
|
|
1992
|
+
|
|
1993
|
+
float fClearcoat = F * D * G / ( 4.0 * abs( wi.z * wo.z ) );
|
|
1994
|
+
color = color * ( 1.0 - surf.clearcoat * F ) + fClearcoat * surf.clearcoat * wi.z;
|
|
1995
|
+
|
|
1996
|
+
// PDF
|
|
1997
|
+
// See equation (27) in http://jcgt.org/published/0003/02/03/
|
|
1998
|
+
return ggxPDF( wo, wh, roughness ) / ( 4.0 * dot( wi, wh ) );
|
|
1999
|
+
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
vec3 clearcoatDirection( vec3 wo, SurfaceRecord surf ) {
|
|
2003
|
+
|
|
2004
|
+
// sample ggx vndf distribution which gives a new normal
|
|
2005
|
+
float roughness = surf.filteredClearcoatRoughness;
|
|
2006
|
+
vec3 halfVector = ggxDirection(
|
|
2007
|
+
wo,
|
|
2008
|
+
vec2( roughness ),
|
|
2009
|
+
rand2( 14 )
|
|
2010
|
+
);
|
|
2011
|
+
|
|
2012
|
+
// apply to new ray by reflecting off the new normal
|
|
2013
|
+
return - reflect( wo, halfVector );
|
|
2014
|
+
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
// sheen
|
|
2018
|
+
vec3 sheenColor( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf ) {
|
|
2019
|
+
|
|
2020
|
+
float cosThetaO = saturateCos( wo.z );
|
|
2021
|
+
float cosThetaI = saturateCos( wi.z );
|
|
2022
|
+
float cosThetaH = wh.z;
|
|
2023
|
+
|
|
2024
|
+
float D = velvetD( cosThetaH, surf.sheenRoughness );
|
|
2025
|
+
float G = velvetG( cosThetaO, cosThetaI, surf.sheenRoughness );
|
|
2026
|
+
|
|
2027
|
+
// See equation (1) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
2028
|
+
vec3 color = surf.sheenColor;
|
|
2029
|
+
color *= D * G / ( 4.0 * abs( cosThetaO * cosThetaI ) );
|
|
2030
|
+
color *= wi.z;
|
|
2031
|
+
|
|
2032
|
+
return color;
|
|
2033
|
+
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// bsdf
|
|
2037
|
+
void getLobeWeights(
|
|
2038
|
+
vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRecord surf,
|
|
2039
|
+
inout float diffuseWeight, inout float specularWeight, inout float transmissionWeight, inout float clearcoatWeight
|
|
2040
|
+
) {
|
|
2041
|
+
|
|
2042
|
+
float metalness = surf.metalness;
|
|
2043
|
+
float transmission = surf.transmission;
|
|
2044
|
+
// float fEstimate = evaluateFresnelWeight( dot( wo, wh ), surf.eta, surf.f0 );
|
|
2045
|
+
float fEstimate = disneyFresnel( wo, wi, wh, surf.f0, surf.eta, surf.metalness );
|
|
2046
|
+
|
|
2047
|
+
float transSpecularProb = mix( max( 0.25, fEstimate ), 1.0, metalness );
|
|
2048
|
+
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
2049
|
+
|
|
2050
|
+
diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb );
|
|
2051
|
+
specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb;
|
|
2052
|
+
transmissionWeight = transmission * ( 1.0 - transSpecularProb );
|
|
2053
|
+
clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );
|
|
2054
|
+
|
|
2055
|
+
float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;
|
|
2056
|
+
diffuseWeight /= totalWeight;
|
|
2057
|
+
specularWeight /= totalWeight;
|
|
2058
|
+
transmissionWeight /= totalWeight;
|
|
2059
|
+
clearcoatWeight /= totalWeight;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
float bsdfEval(
|
|
2063
|
+
vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRecord surf,
|
|
2064
|
+
float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, inout float specularPdf, inout vec3 color
|
|
2065
|
+
) {
|
|
2066
|
+
|
|
2067
|
+
float metalness = surf.metalness;
|
|
2068
|
+
float transmission = surf.transmission;
|
|
2069
|
+
|
|
2070
|
+
float spdf = 0.0;
|
|
2071
|
+
float dpdf = 0.0;
|
|
2072
|
+
float tpdf = 0.0;
|
|
2073
|
+
float cpdf = 0.0;
|
|
2074
|
+
color = vec3( 0.0 );
|
|
2075
|
+
|
|
2076
|
+
vec3 halfVector = getHalfVector( wi, wo, surf.eta );
|
|
2077
|
+
|
|
2078
|
+
// diffuse
|
|
2079
|
+
if ( diffuseWeight > 0.0 && wi.z > 0.0 ) {
|
|
2080
|
+
|
|
2081
|
+
dpdf = diffuseEval( wo, wi, halfVector, surf, color );
|
|
2082
|
+
color *= 1.0 - surf.transmission;
|
|
2083
|
+
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
// ggx specular
|
|
2087
|
+
if ( specularWeight > 0.0 && wi.z > 0.0 ) {
|
|
2088
|
+
|
|
2089
|
+
vec3 outColor;
|
|
2090
|
+
spdf = specularEval( wo, wi, getHalfVector( wi, wo ), surf, outColor );
|
|
2091
|
+
color += outColor;
|
|
2092
|
+
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// transmission
|
|
2096
|
+
if ( transmissionWeight > 0.0 && wi.z < 0.0 ) {
|
|
2097
|
+
|
|
2098
|
+
tpdf = transmissionEval( wo, wi, halfVector, surf, color );
|
|
2099
|
+
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
// sheen
|
|
2103
|
+
color *= mix( 1.0, sheenAlbedoScaling( wo, wi, surf ), surf.sheen );
|
|
2104
|
+
color += sheenColor( wo, wi, halfVector, surf ) * surf.sheen;
|
|
2105
|
+
|
|
2106
|
+
// clearcoat
|
|
2107
|
+
if ( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
2108
|
+
|
|
2109
|
+
vec3 clearcoatHalfVector = getHalfVector( clearcoatWo, clearcoatWi );
|
|
2110
|
+
cpdf = clearcoatEval( clearcoatWo, clearcoatWi, clearcoatHalfVector, surf, color );
|
|
2111
|
+
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
float pdf =
|
|
2115
|
+
dpdf * diffuseWeight
|
|
2116
|
+
+ spdf * specularWeight
|
|
2117
|
+
+ tpdf * transmissionWeight
|
|
2118
|
+
+ cpdf * clearcoatWeight;
|
|
2119
|
+
|
|
2120
|
+
// retrieve specular rays for the shadows flag
|
|
2121
|
+
specularPdf = spdf * specularWeight + cpdf * clearcoatWeight;
|
|
2122
|
+
|
|
2123
|
+
return pdf;
|
|
2124
|
+
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, inout vec3 color ) {
|
|
2128
|
+
|
|
2129
|
+
if ( surf.volumeParticle ) {
|
|
2130
|
+
|
|
2131
|
+
color = surf.color / ( 4.0 * PI );
|
|
2132
|
+
return 1.0 / ( 4.0 * PI );
|
|
2133
|
+
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
vec3 wo = normalize( surf.normalInvBasis * worldWo );
|
|
2137
|
+
vec3 wi = normalize( surf.normalInvBasis * worldWi );
|
|
2138
|
+
|
|
2139
|
+
vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );
|
|
2140
|
+
vec3 clearcoatWi = normalize( surf.clearcoatInvBasis * worldWi );
|
|
2141
|
+
|
|
2142
|
+
vec3 wh = getHalfVector( wo, wi, surf.eta );
|
|
2143
|
+
float diffuseWeight;
|
|
2144
|
+
float specularWeight;
|
|
2145
|
+
float transmissionWeight;
|
|
2146
|
+
float clearcoatWeight;
|
|
2147
|
+
getLobeWeights( wo, wi, wh, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
2148
|
+
|
|
2149
|
+
float specularPdf;
|
|
2150
|
+
return bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, specularPdf, color );
|
|
2151
|
+
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
ScatterRecord bsdfSample( vec3 worldWo, SurfaceRecord surf ) {
|
|
2155
|
+
|
|
2156
|
+
if ( surf.volumeParticle ) {
|
|
2157
|
+
|
|
2158
|
+
ScatterRecord sampleRec;
|
|
2159
|
+
sampleRec.specularPdf = 0.0;
|
|
2160
|
+
sampleRec.pdf = 1.0 / ( 4.0 * PI );
|
|
2161
|
+
sampleRec.direction = sampleSphere( rand2( 16 ) );
|
|
2162
|
+
sampleRec.color = surf.color / ( 4.0 * PI );
|
|
2163
|
+
return sampleRec;
|
|
2164
|
+
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
vec3 wo = normalize( surf.normalInvBasis * worldWo );
|
|
2168
|
+
vec3 clearcoatWo = normalize( surf.clearcoatInvBasis * worldWo );
|
|
2169
|
+
mat3 normalBasis = surf.normalBasis;
|
|
2170
|
+
mat3 invBasis = surf.normalInvBasis;
|
|
2171
|
+
mat3 clearcoatNormalBasis = surf.clearcoatBasis;
|
|
2172
|
+
mat3 clearcoatInvBasis = surf.clearcoatInvBasis;
|
|
2173
|
+
|
|
2174
|
+
float diffuseWeight;
|
|
2175
|
+
float specularWeight;
|
|
2176
|
+
float transmissionWeight;
|
|
2177
|
+
float clearcoatWeight;
|
|
2178
|
+
// using normal and basically-reflected ray since we don't have proper half vector here
|
|
2179
|
+
getLobeWeights( wo, wo, vec3( 0, 0, 1 ), clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
2180
|
+
|
|
2181
|
+
float pdf[4];
|
|
2182
|
+
pdf[0] = diffuseWeight;
|
|
2183
|
+
pdf[1] = specularWeight;
|
|
2184
|
+
pdf[2] = transmissionWeight;
|
|
2185
|
+
pdf[3] = clearcoatWeight;
|
|
2186
|
+
|
|
2187
|
+
float cdf[4];
|
|
2188
|
+
cdf[0] = pdf[0];
|
|
2189
|
+
cdf[1] = pdf[1] + cdf[0];
|
|
2190
|
+
cdf[2] = pdf[2] + cdf[1];
|
|
2191
|
+
cdf[3] = pdf[3] + cdf[2];
|
|
2192
|
+
|
|
2193
|
+
if( cdf[3] != 0.0 ) {
|
|
2194
|
+
|
|
2195
|
+
float invMaxCdf = 1.0 / cdf[3];
|
|
2196
|
+
cdf[0] *= invMaxCdf;
|
|
2197
|
+
cdf[1] *= invMaxCdf;
|
|
2198
|
+
cdf[2] *= invMaxCdf;
|
|
2199
|
+
cdf[3] *= invMaxCdf;
|
|
2200
|
+
|
|
2201
|
+
} else {
|
|
2202
|
+
|
|
2203
|
+
cdf[0] = 1.0;
|
|
2204
|
+
cdf[1] = 0.0;
|
|
2205
|
+
cdf[2] = 0.0;
|
|
2206
|
+
cdf[3] = 0.0;
|
|
2207
|
+
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
vec3 wi;
|
|
2211
|
+
vec3 clearcoatWi;
|
|
2212
|
+
|
|
2213
|
+
float r = rand( 15 );
|
|
2214
|
+
if ( r <= cdf[0] ) { // diffuse
|
|
2215
|
+
|
|
2216
|
+
wi = diffuseDirection( wo, surf );
|
|
2217
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
2218
|
+
|
|
2219
|
+
} else if ( r <= cdf[1] ) { // specular
|
|
2220
|
+
|
|
2221
|
+
wi = specularDirection( wo, surf );
|
|
2222
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
2223
|
+
|
|
2224
|
+
} else if ( r <= cdf[2] ) { // transmission / refraction
|
|
2225
|
+
|
|
2226
|
+
wi = transmissionDirection( wo, surf );
|
|
2227
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
2228
|
+
|
|
2229
|
+
} else if ( r <= cdf[3] ) { // clearcoat
|
|
2230
|
+
|
|
2231
|
+
clearcoatWi = clearcoatDirection( clearcoatWo, surf );
|
|
2232
|
+
wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );
|
|
2233
|
+
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
ScatterRecord result;
|
|
2237
|
+
result.pdf = bsdfEval( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight, result.specularPdf, result.color );
|
|
2238
|
+
result.direction = normalize( surf.normalBasis * wi );
|
|
2239
|
+
|
|
2240
|
+
return result;
|
|
2241
|
+
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
`,To=`
|
|
2245
|
+
|
|
2246
|
+
// returns the hit distance given the material density
|
|
2247
|
+
float intersectFogVolume( Material material, float u ) {
|
|
2248
|
+
|
|
2249
|
+
// https://raytracing.github.io/books/RayTracingTheNextWeek.html#volumes/constantdensitymediums
|
|
2250
|
+
return material.opacity == 0.0 ? INFINITY : ( - 1.0 / material.opacity ) * log( u );
|
|
2251
|
+
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
ScatterRecord sampleFogVolume( SurfaceRecord surf, vec2 uv ) {
|
|
2255
|
+
|
|
2256
|
+
ScatterRecord sampleRec;
|
|
2257
|
+
sampleRec.specularPdf = 0.0;
|
|
2258
|
+
sampleRec.pdf = 1.0 / ( 2.0 * PI );
|
|
2259
|
+
sampleRec.direction = sampleSphere( uv );
|
|
2260
|
+
sampleRec.color = surf.color;
|
|
2261
|
+
return sampleRec;
|
|
2262
|
+
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
`,wo=`
|
|
2266
|
+
|
|
2267
|
+
// The GGX functions provide sampling and distribution information for normals as output so
|
|
2268
|
+
// in order to get probability of scatter direction the half vector must be computed and provided.
|
|
2269
|
+
// [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
|
|
2270
|
+
// [1] https://hal.archives-ouvertes.fr/hal-01509746/document
|
|
2271
|
+
// [2] http://jcgt.org/published/0007/04/01/
|
|
2272
|
+
// [4] http://jcgt.org/published/0003/02/03/
|
|
2273
|
+
|
|
2274
|
+
// trowbridge-reitz === GGX === GTR
|
|
2275
|
+
|
|
2276
|
+
vec3 ggxDirection( vec3 incidentDir, vec2 roughness, vec2 uv ) {
|
|
2277
|
+
|
|
2278
|
+
// TODO: try GGXVNDF implementation from reference [2], here. Needs to update ggxDistribution
|
|
2279
|
+
// function below, as well
|
|
2280
|
+
|
|
2281
|
+
// Implementation from reference [1]
|
|
2282
|
+
// stretch view
|
|
2283
|
+
vec3 V = normalize( vec3( roughness * incidentDir.xy, incidentDir.z ) );
|
|
2284
|
+
|
|
2285
|
+
// orthonormal basis
|
|
2286
|
+
vec3 T1 = ( V.z < 0.9999 ) ? normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) ) : vec3( 1.0, 0.0, 0.0 );
|
|
2287
|
+
vec3 T2 = cross( T1, V );
|
|
2288
|
+
|
|
2289
|
+
// sample point with polar coordinates (r, phi)
|
|
2290
|
+
float a = 1.0 / ( 1.0 + V.z );
|
|
2291
|
+
float r = sqrt( uv.x );
|
|
2292
|
+
float phi = ( uv.y < a ) ? uv.y / a * PI : PI + ( uv.y - a ) / ( 1.0 - a ) * PI;
|
|
2293
|
+
float P1 = r * cos( phi );
|
|
2294
|
+
float P2 = r * sin( phi ) * ( ( uv.y < a ) ? 1.0 : V.z );
|
|
2295
|
+
|
|
2296
|
+
// compute normal
|
|
2297
|
+
vec3 N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );
|
|
2298
|
+
|
|
2299
|
+
// unstretch
|
|
2300
|
+
N = normalize( vec3( roughness * N.xy, max( 0.0, N.z ) ) );
|
|
2301
|
+
|
|
2302
|
+
return N;
|
|
2303
|
+
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
// Below are PDF and related functions for use in a Monte Carlo path tracer
|
|
2307
|
+
// as specified in Appendix B of the following paper
|
|
2308
|
+
// See equation (34) from reference [0]
|
|
2309
|
+
float ggxLamda( float theta, float roughness ) {
|
|
2310
|
+
|
|
2311
|
+
float tanTheta = tan( theta );
|
|
2312
|
+
float tanTheta2 = tanTheta * tanTheta;
|
|
2313
|
+
float alpha2 = roughness * roughness;
|
|
2314
|
+
|
|
2315
|
+
float numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );
|
|
2316
|
+
return numerator / 2.0;
|
|
2317
|
+
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
// See equation (34) from reference [0]
|
|
2321
|
+
float ggxShadowMaskG1( float theta, float roughness ) {
|
|
2322
|
+
|
|
2323
|
+
return 1.0 / ( 1.0 + ggxLamda( theta, roughness ) );
|
|
2324
|
+
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
// See equation (125) from reference [4]
|
|
2328
|
+
float ggxShadowMaskG2( vec3 wi, vec3 wo, float roughness ) {
|
|
2329
|
+
|
|
2330
|
+
float incidentTheta = acos( wi.z );
|
|
2331
|
+
float scatterTheta = acos( wo.z );
|
|
2332
|
+
return 1.0 / ( 1.0 + ggxLamda( incidentTheta, roughness ) + ggxLamda( scatterTheta, roughness ) );
|
|
2333
|
+
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
// See equation (33) from reference [0]
|
|
2337
|
+
float ggxDistribution( vec3 halfVector, float roughness ) {
|
|
2338
|
+
|
|
2339
|
+
float a2 = roughness * roughness;
|
|
2340
|
+
a2 = max( EPSILON, a2 );
|
|
2341
|
+
float cosTheta = halfVector.z;
|
|
2342
|
+
float cosTheta4 = pow( cosTheta, 4.0 );
|
|
2343
|
+
|
|
2344
|
+
if ( cosTheta == 0.0 ) return 0.0;
|
|
2345
|
+
|
|
2346
|
+
float theta = acosSafe( halfVector.z );
|
|
2347
|
+
float tanTheta = tan( theta );
|
|
2348
|
+
float tanTheta2 = pow( tanTheta, 2.0 );
|
|
2349
|
+
|
|
2350
|
+
float denom = PI * cosTheta4 * pow( a2 + tanTheta2, 2.0 );
|
|
2351
|
+
return ( a2 / denom );
|
|
2352
|
+
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
// See equation (3) from reference [2]
|
|
2356
|
+
float ggxPDF( vec3 wi, vec3 halfVector, float roughness ) {
|
|
2357
|
+
|
|
2358
|
+
float incidentTheta = acos( wi.z );
|
|
2359
|
+
float D = ggxDistribution( halfVector, roughness );
|
|
2360
|
+
float G1 = ggxShadowMaskG1( incidentTheta, roughness );
|
|
2361
|
+
|
|
2362
|
+
return D * G1 * max( 0.0, dot( wi, halfVector ) ) / wi.z;
|
|
2363
|
+
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
`,Ao=`
|
|
2367
|
+
|
|
2368
|
+
// XYZ to sRGB color space
|
|
2369
|
+
const mat3 XYZ_TO_REC709 = mat3(
|
|
2370
|
+
3.2404542, -0.9692660, 0.0556434,
|
|
2371
|
+
-1.5371385, 1.8760108, -0.2040259,
|
|
2372
|
+
-0.4985314, 0.0415560, 1.0572252
|
|
2373
|
+
);
|
|
2374
|
+
|
|
2375
|
+
vec3 fresnel0ToIor( vec3 fresnel0 ) {
|
|
2376
|
+
|
|
2377
|
+
vec3 sqrtF0 = sqrt( fresnel0 );
|
|
2378
|
+
return ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );
|
|
2379
|
+
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
// Conversion FO/IOR
|
|
2383
|
+
vec3 iorToFresnel0( vec3 transmittedIor, float incidentIor ) {
|
|
2384
|
+
|
|
2385
|
+
return square( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );
|
|
2386
|
+
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// ior is a value between 1.0 and 3.0. 1.0 is air interface
|
|
2390
|
+
float iorToFresnel0( float transmittedIor, float incidentIor ) {
|
|
2391
|
+
|
|
2392
|
+
return square( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ) );
|
|
2393
|
+
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
// Fresnel equations for dielectric/dielectric interfaces. See https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html
|
|
2397
|
+
vec3 evalSensitivity( float OPD, vec3 shift ) {
|
|
2398
|
+
|
|
2399
|
+
float phase = 2.0 * PI * OPD * 1.0e-9;
|
|
2400
|
+
|
|
2401
|
+
vec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );
|
|
2402
|
+
vec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );
|
|
2403
|
+
vec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );
|
|
2404
|
+
|
|
2405
|
+
vec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - square( phase ) * var );
|
|
2406
|
+
xyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * square( phase ) );
|
|
2407
|
+
xyz /= 1.0685e-7;
|
|
2408
|
+
|
|
2409
|
+
vec3 srgb = XYZ_TO_REC709 * xyz;
|
|
2410
|
+
return srgb;
|
|
2411
|
+
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// See Section 4. Analytic Spectral Integration, A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence, https://hal.archives-ouvertes.fr/hal-01518344/document
|
|
2415
|
+
vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {
|
|
2416
|
+
|
|
2417
|
+
vec3 I;
|
|
2418
|
+
|
|
2419
|
+
// Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0
|
|
2420
|
+
float iridescenceIor = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );
|
|
2421
|
+
|
|
2422
|
+
// Evaluate the cosTheta on the base layer (Snell law)
|
|
2423
|
+
float sinTheta2Sq = square( outsideIOR / iridescenceIor ) * ( 1.0 - square( cosTheta1 ) );
|
|
2424
|
+
|
|
2425
|
+
// Handle TIR:
|
|
2426
|
+
float cosTheta2Sq = 1.0 - sinTheta2Sq;
|
|
2427
|
+
if ( cosTheta2Sq < 0.0 ) {
|
|
2428
|
+
|
|
2429
|
+
return vec3( 1.0 );
|
|
2430
|
+
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
float cosTheta2 = sqrt( cosTheta2Sq );
|
|
2434
|
+
|
|
2435
|
+
// First interface
|
|
2436
|
+
float R0 = iorToFresnel0( iridescenceIor, outsideIOR );
|
|
2437
|
+
float R12 = schlickFresnel( cosTheta1, R0 );
|
|
2438
|
+
float R21 = R12;
|
|
2439
|
+
float T121 = 1.0 - R12;
|
|
2440
|
+
float phi12 = 0.0;
|
|
2441
|
+
if ( iridescenceIor < outsideIOR ) {
|
|
2442
|
+
|
|
2443
|
+
phi12 = PI;
|
|
2444
|
+
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
float phi21 = PI - phi12;
|
|
2448
|
+
|
|
2449
|
+
// Second interface
|
|
2450
|
+
vec3 baseIOR = fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) ); // guard against 1.0
|
|
2451
|
+
vec3 R1 = iorToFresnel0( baseIOR, iridescenceIor );
|
|
2452
|
+
vec3 R23 = schlickFresnel( cosTheta2, R1 );
|
|
2453
|
+
vec3 phi23 = vec3( 0.0 );
|
|
2454
|
+
if ( baseIOR[0] < iridescenceIor ) {
|
|
2455
|
+
|
|
2456
|
+
phi23[ 0 ] = PI;
|
|
2457
|
+
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
if ( baseIOR[1] < iridescenceIor ) {
|
|
2461
|
+
|
|
2462
|
+
phi23[ 1 ] = PI;
|
|
2463
|
+
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
if ( baseIOR[2] < iridescenceIor ) {
|
|
2467
|
+
|
|
2468
|
+
phi23[ 2 ] = PI;
|
|
2469
|
+
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
// Phase shift
|
|
2473
|
+
float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2;
|
|
2474
|
+
vec3 phi = vec3( phi21 ) + phi23;
|
|
2475
|
+
|
|
2476
|
+
// Compound terms
|
|
2477
|
+
vec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );
|
|
2478
|
+
vec3 r123 = sqrt( R123 );
|
|
2479
|
+
vec3 Rs = square( T121 ) * R23 / ( vec3( 1.0 ) - R123 );
|
|
2480
|
+
|
|
2481
|
+
// Reflectance term for m = 0 (DC term amplitude)
|
|
2482
|
+
vec3 C0 = R12 + Rs;
|
|
2483
|
+
I = C0;
|
|
2484
|
+
|
|
2485
|
+
// Reflectance term for m > 0 (pairs of diracs)
|
|
2486
|
+
vec3 Cm = Rs - T121;
|
|
2487
|
+
for ( int m = 1; m <= 2; ++ m ) {
|
|
2488
|
+
|
|
2489
|
+
Cm *= r123;
|
|
2490
|
+
vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );
|
|
2491
|
+
I += Cm * Sm;
|
|
2492
|
+
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
// Since out of gamut colors might be produced, negative color values are clamped to 0.
|
|
2496
|
+
return max( I, vec3( 0.0 ) );
|
|
2497
|
+
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
`,_o=`
|
|
2501
|
+
|
|
2502
|
+
// See equation (2) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
2503
|
+
float velvetD( float cosThetaH, float roughness ) {
|
|
2504
|
+
|
|
2505
|
+
float alpha = max( roughness, 0.07 );
|
|
2506
|
+
alpha = alpha * alpha;
|
|
2507
|
+
|
|
2508
|
+
float invAlpha = 1.0 / alpha;
|
|
2509
|
+
|
|
2510
|
+
float sqrCosThetaH = cosThetaH * cosThetaH;
|
|
2511
|
+
float sinThetaH = max( 1.0 - sqrCosThetaH, 0.001 );
|
|
2512
|
+
|
|
2513
|
+
return ( 2.0 + invAlpha ) * pow( sinThetaH, 0.5 * invAlpha ) / ( 2.0 * PI );
|
|
2514
|
+
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
float velvetParamsInterpolate( int i, float oneMinusAlphaSquared ) {
|
|
2518
|
+
|
|
2519
|
+
const float p0[5] = float[5]( 25.3245, 3.32435, 0.16801, -1.27393, -4.85967 );
|
|
2520
|
+
const float p1[5] = float[5]( 21.5473, 3.82987, 0.19823, -1.97760, -4.32054 );
|
|
2521
|
+
|
|
2522
|
+
return mix( p1[i], p0[i], oneMinusAlphaSquared );
|
|
2523
|
+
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
float velvetL( float x, float alpha ) {
|
|
2527
|
+
|
|
2528
|
+
float oneMinusAlpha = 1.0 - alpha;
|
|
2529
|
+
float oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;
|
|
2530
|
+
|
|
2531
|
+
float a = velvetParamsInterpolate( 0, oneMinusAlphaSquared );
|
|
2532
|
+
float b = velvetParamsInterpolate( 1, oneMinusAlphaSquared );
|
|
2533
|
+
float c = velvetParamsInterpolate( 2, oneMinusAlphaSquared );
|
|
2534
|
+
float d = velvetParamsInterpolate( 3, oneMinusAlphaSquared );
|
|
2535
|
+
float e = velvetParamsInterpolate( 4, oneMinusAlphaSquared );
|
|
2536
|
+
|
|
2537
|
+
return a / ( 1.0 + b * pow( abs( x ), c ) ) + d * x + e;
|
|
2538
|
+
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
// See equation (3) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
2542
|
+
float velvetLambda( float cosTheta, float alpha ) {
|
|
2543
|
+
|
|
2544
|
+
return abs( cosTheta ) < 0.5 ? exp( velvetL( cosTheta, alpha ) ) : exp( 2.0 * velvetL( 0.5, alpha ) - velvetL( 1.0 - cosTheta, alpha ) );
|
|
2545
|
+
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
// See Section 3, Shadowing Term, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
2549
|
+
float velvetG( float cosThetaO, float cosThetaI, float roughness ) {
|
|
2550
|
+
|
|
2551
|
+
float alpha = max( roughness, 0.07 );
|
|
2552
|
+
alpha = alpha * alpha;
|
|
2553
|
+
|
|
2554
|
+
return 1.0 / ( 1.0 + velvetLambda( cosThetaO, alpha ) + velvetLambda( cosThetaI, alpha ) );
|
|
2555
|
+
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
float directionalAlbedoSheen( float cosTheta, float alpha ) {
|
|
2559
|
+
|
|
2560
|
+
cosTheta = saturate( cosTheta );
|
|
2561
|
+
|
|
2562
|
+
float c = 1.0 - cosTheta;
|
|
2563
|
+
float c3 = c * c * c;
|
|
2564
|
+
|
|
2565
|
+
return 0.65584461 * c3 + 1.0 / ( 4.16526551 + exp( -7.97291361 * sqrt( alpha ) + 6.33516894 ) );
|
|
2566
|
+
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
float sheenAlbedoScaling( vec3 wo, vec3 wi, SurfaceRecord surf ) {
|
|
2570
|
+
|
|
2571
|
+
float alpha = max( surf.sheenRoughness, 0.07 );
|
|
2572
|
+
alpha = alpha * alpha;
|
|
2573
|
+
|
|
2574
|
+
float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );
|
|
2575
|
+
|
|
2576
|
+
float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );
|
|
2577
|
+
float eWi = directionalAlbedoSheen( saturateCos( wi.z ), alpha );
|
|
2578
|
+
|
|
2579
|
+
return min( 1.0 - maxSheenColor * eWo, 1.0 - maxSheenColor * eWi );
|
|
2580
|
+
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
// See Section 5, Layering, in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
|
|
2584
|
+
float sheenAlbedoScaling( vec3 wo, SurfaceRecord surf ) {
|
|
2585
|
+
|
|
2586
|
+
float alpha = max( surf.sheenRoughness, 0.07 );
|
|
2587
|
+
alpha = alpha * alpha;
|
|
2588
|
+
|
|
2589
|
+
float maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );
|
|
2590
|
+
|
|
2591
|
+
float eWo = directionalAlbedoSheen( saturateCos( wo.z ), alpha );
|
|
2592
|
+
|
|
2593
|
+
return 1.0 - maxSheenColor * eWo;
|
|
2594
|
+
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
`,So=`
|
|
2598
|
+
|
|
2599
|
+
#ifndef FOG_CHECK_ITERATIONS
|
|
2600
|
+
#define FOG_CHECK_ITERATIONS 30
|
|
2601
|
+
#endif
|
|
2602
|
+
|
|
2603
|
+
// returns whether the given material is a fog material or not
|
|
2604
|
+
bool isMaterialFogVolume( sampler2D materials, uint materialIndex ) {
|
|
2605
|
+
|
|
2606
|
+
uint i = materialIndex * 45u;
|
|
2607
|
+
vec4 s14 = texelFetch1D( materials, i + 14u );
|
|
2608
|
+
return bool( int( s14.b ) & 4 );
|
|
2609
|
+
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
// returns true if we're within the first fog volume we hit
|
|
2613
|
+
bool bvhIntersectFogVolumeHit(
|
|
2614
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
2615
|
+
usampler2D materialIndexAttribute, sampler2D materials,
|
|
2616
|
+
inout Material material
|
|
2617
|
+
) {
|
|
2618
|
+
|
|
2619
|
+
material.fogVolume = false;
|
|
2620
|
+
|
|
2621
|
+
for ( int i = 0; i < FOG_CHECK_ITERATIONS; i ++ ) {
|
|
2622
|
+
|
|
2623
|
+
// find nearest hit
|
|
2624
|
+
uvec4 faceIndices = uvec4( 0u );
|
|
2625
|
+
vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
|
2626
|
+
vec3 barycoord = vec3( 0.0 );
|
|
2627
|
+
float side = 1.0;
|
|
2628
|
+
float dist = 0.0;
|
|
2629
|
+
bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
|
2630
|
+
if ( hit ) {
|
|
2631
|
+
|
|
2632
|
+
// if it's a fog volume return whether we hit the front or back face
|
|
2633
|
+
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
2634
|
+
if ( isMaterialFogVolume( materials, materialIndex ) ) {
|
|
2635
|
+
|
|
2636
|
+
material = readMaterialInfo( materials, materialIndex );
|
|
2637
|
+
return side == - 1.0;
|
|
2638
|
+
|
|
2639
|
+
} else {
|
|
2640
|
+
|
|
2641
|
+
// move the ray forward
|
|
2642
|
+
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
2643
|
+
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
} else {
|
|
2647
|
+
|
|
2648
|
+
return false;
|
|
2649
|
+
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
return false;
|
|
2655
|
+
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
`,Mo=`
|
|
2659
|
+
|
|
2660
|
+
// step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
|
|
2661
|
+
// returns true if a solid surface was hit
|
|
2662
|
+
bool attenuateHit(
|
|
2663
|
+
RenderState state,
|
|
2664
|
+
Ray ray, float rayDist,
|
|
2665
|
+
out vec3 color
|
|
2666
|
+
) {
|
|
2667
|
+
|
|
2668
|
+
// store the original bounce index so we can reset it after
|
|
2669
|
+
uint originalBounceIndex = sobolBounceIndex;
|
|
2670
|
+
|
|
2671
|
+
int traversals = state.traversals;
|
|
2672
|
+
int transmissiveTraversals = state.transmissiveTraversals;
|
|
2673
|
+
bool isShadowRay = state.isShadowRay;
|
|
2674
|
+
Material fogMaterial = state.fogMaterial;
|
|
2675
|
+
|
|
2676
|
+
vec3 startPoint = ray.origin;
|
|
2677
|
+
|
|
2678
|
+
// hit results
|
|
2679
|
+
SurfaceHit surfaceHit;
|
|
2680
|
+
|
|
2681
|
+
color = vec3( 1.0 );
|
|
2682
|
+
|
|
2683
|
+
bool result = true;
|
|
2684
|
+
for ( int i = 0; i < traversals; i ++ ) {
|
|
2685
|
+
|
|
2686
|
+
sobolBounceIndex ++;
|
|
2687
|
+
|
|
2688
|
+
int hitType = traceScene( ray, fogMaterial, surfaceHit );
|
|
2689
|
+
|
|
2690
|
+
if ( hitType == FOG_HIT ) {
|
|
2691
|
+
|
|
2692
|
+
result = true;
|
|
2693
|
+
break;
|
|
2694
|
+
|
|
2695
|
+
} else if ( hitType == SURFACE_HIT ) {
|
|
2696
|
+
|
|
2697
|
+
float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );
|
|
2698
|
+
if ( totalDist > rayDist ) {
|
|
2699
|
+
|
|
2700
|
+
result = false;
|
|
2701
|
+
break;
|
|
2702
|
+
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
// TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
|
|
2706
|
+
// Should be able to work using the material BSDF functions which will take into account specularity, etc.
|
|
2707
|
+
// TODO: should we account for emissive surfaces here?
|
|
2708
|
+
|
|
2709
|
+
uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;
|
|
2710
|
+
Material material = readMaterialInfo( materials, materialIndex );
|
|
2711
|
+
|
|
2712
|
+
// adjust the ray to the new surface
|
|
2713
|
+
bool isEntering = surfaceHit.side == 1.0;
|
|
2714
|
+
ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
|
|
2715
|
+
|
|
2716
|
+
#if FEATURE_FOG
|
|
2717
|
+
|
|
2718
|
+
if ( material.fogVolume ) {
|
|
2719
|
+
|
|
2720
|
+
fogMaterial = material;
|
|
2721
|
+
fogMaterial.fogVolume = surfaceHit.side == 1.0;
|
|
2722
|
+
i -= sign( transmissiveTraversals );
|
|
2723
|
+
transmissiveTraversals --;
|
|
2724
|
+
continue;
|
|
2725
|
+
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
#endif
|
|
2729
|
+
|
|
2730
|
+
if ( ! material.castShadow && isShadowRay ) {
|
|
2731
|
+
|
|
2732
|
+
continue;
|
|
2733
|
+
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;
|
|
2737
|
+
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );
|
|
2738
|
+
|
|
2739
|
+
// albedo
|
|
2740
|
+
vec4 albedo = vec4( material.color, material.opacity );
|
|
2741
|
+
if ( material.map != - 1 ) {
|
|
2742
|
+
|
|
2743
|
+
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
2744
|
+
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
2745
|
+
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
if ( material.vertexColors ) {
|
|
2749
|
+
|
|
2750
|
+
albedo *= vertexColor;
|
|
2751
|
+
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
// alphaMap
|
|
2755
|
+
if ( material.alphaMap != - 1 ) {
|
|
2756
|
+
|
|
2757
|
+
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
2758
|
+
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
// transmission
|
|
2762
|
+
float transmission = material.transmission;
|
|
2763
|
+
if ( material.transmissionMap != - 1 ) {
|
|
2764
|
+
|
|
2765
|
+
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
2766
|
+
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
2767
|
+
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
// metalness
|
|
2771
|
+
float metalness = material.metalness;
|
|
2772
|
+
if ( material.metalnessMap != - 1 ) {
|
|
2773
|
+
|
|
2774
|
+
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
2775
|
+
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
2776
|
+
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
float alphaTest = material.alphaTest;
|
|
2780
|
+
bool useAlphaTest = alphaTest != 0.0;
|
|
2781
|
+
float transmissionFactor = ( 1.0 - metalness ) * transmission;
|
|
2782
|
+
if (
|
|
2783
|
+
transmissionFactor < rand( 9 ) && ! (
|
|
2784
|
+
// material sidedness
|
|
2785
|
+
material.side != 0.0 && surfaceHit.side == material.side
|
|
2786
|
+
|
|
2787
|
+
// alpha test
|
|
2788
|
+
|| useAlphaTest && albedo.a < alphaTest
|
|
2789
|
+
|
|
2790
|
+
// opacity
|
|
2791
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand( 10 )
|
|
2792
|
+
)
|
|
2793
|
+
) {
|
|
2794
|
+
|
|
2795
|
+
result = true;
|
|
2796
|
+
break;
|
|
2797
|
+
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
if ( surfaceHit.side == 1.0 && isEntering ) {
|
|
2801
|
+
|
|
2802
|
+
// only attenuate by surface color on the way in
|
|
2803
|
+
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
|
|
2804
|
+
|
|
2805
|
+
} else if ( surfaceHit.side == - 1.0 ) {
|
|
2806
|
+
|
|
2807
|
+
// attenuate by medium once we hit the opposite side of the model
|
|
2808
|
+
color *= transmissionAttenuation( surfaceHit.dist, material.attenuationColor, material.attenuationDistance );
|
|
2809
|
+
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
bool isTransmissiveRay = dot( ray.direction, surfaceHit.faceNormal * surfaceHit.side ) < 0.0;
|
|
2813
|
+
if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {
|
|
2814
|
+
|
|
2815
|
+
i -= sign( transmissiveTraversals );
|
|
2816
|
+
transmissiveTraversals --;
|
|
2817
|
+
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
} else {
|
|
2821
|
+
|
|
2822
|
+
result = false;
|
|
2823
|
+
break;
|
|
2824
|
+
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
// reset the bounce index
|
|
2830
|
+
sobolBounceIndex = originalBounceIndex;
|
|
2831
|
+
return result;
|
|
2832
|
+
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
`,Ro=`
|
|
2836
|
+
|
|
2837
|
+
vec3 ndcToRayOrigin( vec2 coord ) {
|
|
2838
|
+
|
|
2839
|
+
vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
|
|
2840
|
+
return rayOrigin4.xyz / rayOrigin4.w;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
Ray getCameraRay() {
|
|
2844
|
+
|
|
2845
|
+
vec2 ssd = vec2( 1.0 ) / resolution;
|
|
2846
|
+
|
|
2847
|
+
// Jitter the camera ray by finding a uv coordinate at a random sample
|
|
2848
|
+
// around this pixel's UV coordinate for AA
|
|
2849
|
+
vec2 ruv = rand2( 0 );
|
|
2850
|
+
vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
|
|
2851
|
+
Ray ray;
|
|
2852
|
+
|
|
2853
|
+
#if CAMERA_TYPE == 2
|
|
2854
|
+
|
|
2855
|
+
// Equirectangular projection
|
|
2856
|
+
vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );
|
|
2857
|
+
vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );
|
|
2858
|
+
|
|
2859
|
+
rayDirection4 = cameraWorldMatrix * rayDirection4;
|
|
2860
|
+
rayOrigin4 = cameraWorldMatrix * rayOrigin4;
|
|
2861
|
+
|
|
2862
|
+
ray.direction = normalize( rayDirection4.xyz );
|
|
2863
|
+
ray.origin = rayOrigin4.xyz / rayOrigin4.w;
|
|
2864
|
+
|
|
2865
|
+
#else
|
|
2866
|
+
|
|
2867
|
+
// get [- 1, 1] normalized device coordinates
|
|
2868
|
+
vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
|
|
2869
|
+
ray.origin = ndcToRayOrigin( ndc );
|
|
2870
|
+
|
|
2871
|
+
#if CAMERA_TYPE == 1
|
|
2872
|
+
|
|
2873
|
+
// Orthographic projection
|
|
2874
|
+
ray.direction = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
|
|
2875
|
+
ray.direction = normalize( ray.direction );
|
|
2876
|
+
|
|
2877
|
+
#else
|
|
2878
|
+
|
|
2879
|
+
// Perspective projection
|
|
2880
|
+
ray.direction = normalize( mat3( cameraWorldMatrix ) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );
|
|
2881
|
+
|
|
2882
|
+
#endif
|
|
2883
|
+
|
|
2884
|
+
#endif
|
|
2885
|
+
|
|
2886
|
+
#if FEATURE_DOF
|
|
2887
|
+
{
|
|
2888
|
+
|
|
2889
|
+
// depth of field
|
|
2890
|
+
vec3 focalPoint = ray.origin + normalize( ray.direction ) * physicalCamera.focusDistance;
|
|
2891
|
+
|
|
2892
|
+
// get the aperture sample
|
|
2893
|
+
// if blades === 0 then we assume a circle
|
|
2894
|
+
vec3 shapeUVW= rand3( 1 );
|
|
2895
|
+
int blades = physicalCamera.apertureBlades;
|
|
2896
|
+
float anamorphicRatio = physicalCamera.anamorphicRatio;
|
|
2897
|
+
vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );
|
|
2898
|
+
apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;
|
|
2899
|
+
|
|
2900
|
+
// rotate the aperture shape
|
|
2901
|
+
apertureSample =
|
|
2902
|
+
rotateVector( apertureSample, physicalCamera.apertureRotation ) *
|
|
2903
|
+
saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );
|
|
2904
|
+
|
|
2905
|
+
// create the new ray
|
|
2906
|
+
ray.origin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;
|
|
2907
|
+
ray.direction = focalPoint - ray.origin;
|
|
2908
|
+
|
|
2909
|
+
}
|
|
2910
|
+
#endif
|
|
2911
|
+
|
|
2912
|
+
ray.direction = normalize( ray.direction );
|
|
2913
|
+
|
|
2914
|
+
return ray;
|
|
2915
|
+
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
`,Io=`
|
|
2919
|
+
|
|
2920
|
+
vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {
|
|
2921
|
+
|
|
2922
|
+
vec3 result = vec3( 0.0 );
|
|
2923
|
+
|
|
2924
|
+
// uniformly pick a light or environment map
|
|
2925
|
+
if( lightsDenom != 0.0 && rand( 5 ) < float( lights.count ) / lightsDenom ) {
|
|
2926
|
+
|
|
2927
|
+
// sample a light or environment
|
|
2928
|
+
LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, rand3( 6 ) );
|
|
2929
|
+
|
|
2930
|
+
bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, lightRec.direction ) < 0.0;
|
|
2931
|
+
if ( isSampleBelowSurface ) {
|
|
2932
|
+
|
|
2933
|
+
lightRec.pdf = 0.0;
|
|
2934
|
+
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// check if a ray could even reach the light area
|
|
2938
|
+
Ray lightRay;
|
|
2939
|
+
lightRay.origin = rayOrigin;
|
|
2940
|
+
lightRay.direction = lightRec.direction;
|
|
2941
|
+
vec3 attenuatedColor;
|
|
2942
|
+
if (
|
|
2943
|
+
lightRec.pdf > 0.0 &&
|
|
2944
|
+
isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&
|
|
2945
|
+
! attenuateHit( state, lightRay, lightRec.dist, attenuatedColor )
|
|
2946
|
+
) {
|
|
2947
|
+
|
|
2948
|
+
// get the material pdf
|
|
2949
|
+
vec3 sampleColor;
|
|
2950
|
+
float lightMaterialPdf = bsdfResult( worldWo, lightRec.direction, surf, sampleColor );
|
|
2951
|
+
bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
|
|
2952
|
+
if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {
|
|
2953
|
+
|
|
2954
|
+
// weight the direct light contribution
|
|
2955
|
+
float lightPdf = lightRec.pdf / lightsDenom;
|
|
2956
|
+
float misWeight = lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
|
|
2957
|
+
result = attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;
|
|
2958
|
+
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
} else if ( envMapInfo.totalSum != 0.0 && environmentIntensity != 0.0 ) {
|
|
2964
|
+
|
|
2965
|
+
// find a sample in the environment map to include in the contribution
|
|
2966
|
+
vec3 envColor, envDirection;
|
|
2967
|
+
float envPdf = sampleEquirectProbability( rand2( 7 ), envColor, envDirection );
|
|
2968
|
+
envDirection = invEnvRotation3x3 * envDirection;
|
|
2969
|
+
|
|
2970
|
+
// this env sampling is not set up for transmissive sampling and yields overly bright
|
|
2971
|
+
// results so we ignore the sample in this case.
|
|
2972
|
+
// TODO: this should be improved but how? The env samples could traverse a few layers?
|
|
2973
|
+
bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, envDirection ) < 0.0;
|
|
2974
|
+
if ( isSampleBelowSurface ) {
|
|
2975
|
+
|
|
2976
|
+
envPdf = 0.0;
|
|
2977
|
+
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
// check if a ray could even reach the surface
|
|
2981
|
+
Ray envRay;
|
|
2982
|
+
envRay.origin = rayOrigin;
|
|
2983
|
+
envRay.direction = envDirection;
|
|
2984
|
+
vec3 attenuatedColor;
|
|
2985
|
+
if (
|
|
2986
|
+
envPdf > 0.0 &&
|
|
2987
|
+
isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&
|
|
2988
|
+
! attenuateHit( state, envRay, INFINITY, attenuatedColor )
|
|
2989
|
+
) {
|
|
2990
|
+
|
|
2991
|
+
// get the material pdf
|
|
2992
|
+
vec3 sampleColor;
|
|
2993
|
+
float envMaterialPdf = bsdfResult( worldWo, envDirection, surf, sampleColor );
|
|
2994
|
+
bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
|
|
2995
|
+
if ( envMaterialPdf > 0.0 && isValidSampleColor ) {
|
|
2996
|
+
|
|
2997
|
+
// weight the direct light contribution
|
|
2998
|
+
envPdf /= lightsDenom;
|
|
2999
|
+
float misWeight = misHeuristic( envPdf, envMaterialPdf );
|
|
3000
|
+
result = attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;
|
|
3001
|
+
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
// Function changed to have a single return statement to potentially help with crashes on Mac OS.
|
|
3009
|
+
// See issue #470
|
|
3010
|
+
return result;
|
|
3011
|
+
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
`,Po=`
|
|
3015
|
+
|
|
3016
|
+
#define SKIP_SURFACE 0
|
|
3017
|
+
#define HIT_SURFACE 1
|
|
3018
|
+
int getSurfaceRecord(
|
|
3019
|
+
Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,
|
|
3020
|
+
float accumulatedRoughness,
|
|
3021
|
+
inout SurfaceRecord surf
|
|
3022
|
+
) {
|
|
3023
|
+
|
|
3024
|
+
if ( material.fogVolume ) {
|
|
3025
|
+
|
|
3026
|
+
vec3 normal = vec3( 0, 0, 1 );
|
|
3027
|
+
|
|
3028
|
+
SurfaceRecord fogSurface;
|
|
3029
|
+
fogSurface.volumeParticle = true;
|
|
3030
|
+
fogSurface.color = material.color;
|
|
3031
|
+
fogSurface.emission = material.emissiveIntensity * material.emissive;
|
|
3032
|
+
fogSurface.normal = normal;
|
|
3033
|
+
fogSurface.faceNormal = normal;
|
|
3034
|
+
fogSurface.clearcoatNormal = normal;
|
|
3035
|
+
|
|
3036
|
+
surf = fogSurface;
|
|
3037
|
+
return HIT_SURFACE;
|
|
3038
|
+
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
// uv coord for textures
|
|
3042
|
+
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;
|
|
3043
|
+
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );
|
|
3044
|
+
|
|
3045
|
+
// albedo
|
|
3046
|
+
vec4 albedo = vec4( material.color, material.opacity );
|
|
3047
|
+
if ( material.map != - 1 ) {
|
|
3048
|
+
|
|
3049
|
+
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
3050
|
+
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
3051
|
+
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
if ( material.vertexColors ) {
|
|
3055
|
+
|
|
3056
|
+
albedo *= vertexColor;
|
|
3057
|
+
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// alphaMap
|
|
3061
|
+
if ( material.alphaMap != - 1 ) {
|
|
3062
|
+
|
|
3063
|
+
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
3064
|
+
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
// possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side
|
|
3068
|
+
// and it's single sided.
|
|
3069
|
+
// - alpha test is disabled when it === 0
|
|
3070
|
+
// - the material sidedness test is complicated because we want light to pass through the back side but still
|
|
3071
|
+
// be able to see the front side. This boolean checks if the side we hit is the front side on the first ray
|
|
3072
|
+
// and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
|
|
3073
|
+
float alphaTest = material.alphaTest;
|
|
3074
|
+
bool useAlphaTest = alphaTest != 0.0;
|
|
3075
|
+
if (
|
|
3076
|
+
// material sidedness
|
|
3077
|
+
material.side != 0.0 && surfaceHit.side != material.side
|
|
3078
|
+
|
|
3079
|
+
// alpha test
|
|
3080
|
+
|| useAlphaTest && albedo.a < alphaTest
|
|
3081
|
+
|
|
3082
|
+
// opacity
|
|
3083
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand( 3 )
|
|
3084
|
+
) {
|
|
3085
|
+
|
|
3086
|
+
return SKIP_SURFACE;
|
|
3087
|
+
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
// fetch the interpolated smooth normal
|
|
3091
|
+
vec3 normal = normalize( textureSampleBarycoord(
|
|
3092
|
+
attributesArray,
|
|
3093
|
+
ATTR_NORMAL,
|
|
3094
|
+
surfaceHit.barycoord,
|
|
3095
|
+
surfaceHit.faceIndices.xyz
|
|
3096
|
+
).xyz );
|
|
3097
|
+
|
|
3098
|
+
// roughness
|
|
3099
|
+
float roughness = material.roughness;
|
|
3100
|
+
if ( material.roughnessMap != - 1 ) {
|
|
3101
|
+
|
|
3102
|
+
vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );
|
|
3103
|
+
roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;
|
|
3104
|
+
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
// metalness
|
|
3108
|
+
float metalness = material.metalness;
|
|
3109
|
+
if ( material.metalnessMap != - 1 ) {
|
|
3110
|
+
|
|
3111
|
+
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
3112
|
+
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
3113
|
+
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
// emission
|
|
3117
|
+
vec3 emission = material.emissiveIntensity * material.emissive;
|
|
3118
|
+
if ( material.emissiveMap != - 1 ) {
|
|
3119
|
+
|
|
3120
|
+
vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );
|
|
3121
|
+
emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;
|
|
3122
|
+
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
// transmission
|
|
3126
|
+
float transmission = material.transmission;
|
|
3127
|
+
if ( material.transmissionMap != - 1 ) {
|
|
3128
|
+
|
|
3129
|
+
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
3130
|
+
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
3131
|
+
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
// normal
|
|
3135
|
+
if ( material.flatShading ) {
|
|
3136
|
+
|
|
3137
|
+
// if we're rendering a flat shaded object then use the face normals - the face normal
|
|
3138
|
+
// is provided based on the side the ray hits the mesh so flip it to align with the
|
|
3139
|
+
// interpolated vertex normals.
|
|
3140
|
+
normal = surfaceHit.faceNormal * surfaceHit.side;
|
|
3141
|
+
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
vec3 baseNormal = normal;
|
|
3145
|
+
if ( material.normalMap != - 1 ) {
|
|
3146
|
+
|
|
3147
|
+
vec4 tangentSample = textureSampleBarycoord(
|
|
3148
|
+
attributesArray,
|
|
3149
|
+
ATTR_TANGENT,
|
|
3150
|
+
surfaceHit.barycoord,
|
|
3151
|
+
surfaceHit.faceIndices.xyz
|
|
3152
|
+
);
|
|
3153
|
+
|
|
3154
|
+
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
3155
|
+
// resulting in NaNs and slow path tracing.
|
|
3156
|
+
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
3157
|
+
|
|
3158
|
+
vec3 tangent = normalize( tangentSample.xyz );
|
|
3159
|
+
vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );
|
|
3160
|
+
mat3 vTBN = mat3( tangent, bitangent, normal );
|
|
3161
|
+
|
|
3162
|
+
vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );
|
|
3163
|
+
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;
|
|
3164
|
+
texNormal.xy *= material.normalScale;
|
|
3165
|
+
normal = vTBN * texNormal;
|
|
3166
|
+
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
normal *= surfaceHit.side;
|
|
3172
|
+
|
|
3173
|
+
// clearcoat
|
|
3174
|
+
float clearcoat = material.clearcoat;
|
|
3175
|
+
if ( material.clearcoatMap != - 1 ) {
|
|
3176
|
+
|
|
3177
|
+
vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );
|
|
3178
|
+
clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;
|
|
3179
|
+
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
// clearcoatRoughness
|
|
3183
|
+
float clearcoatRoughness = material.clearcoatRoughness;
|
|
3184
|
+
if ( material.clearcoatRoughnessMap != - 1 ) {
|
|
3185
|
+
|
|
3186
|
+
vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );
|
|
3187
|
+
clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;
|
|
3188
|
+
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
// clearcoatNormal
|
|
3192
|
+
vec3 clearcoatNormal = baseNormal;
|
|
3193
|
+
if ( material.clearcoatNormalMap != - 1 ) {
|
|
3194
|
+
|
|
3195
|
+
vec4 tangentSample = textureSampleBarycoord(
|
|
3196
|
+
attributesArray,
|
|
3197
|
+
ATTR_TANGENT,
|
|
3198
|
+
surfaceHit.barycoord,
|
|
3199
|
+
surfaceHit.faceIndices.xyz
|
|
3200
|
+
);
|
|
3201
|
+
|
|
3202
|
+
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
3203
|
+
// resulting in NaNs and slow path tracing.
|
|
3204
|
+
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
3205
|
+
|
|
3206
|
+
vec3 tangent = normalize( tangentSample.xyz );
|
|
3207
|
+
vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );
|
|
3208
|
+
mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
|
|
3209
|
+
|
|
3210
|
+
vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );
|
|
3211
|
+
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;
|
|
3212
|
+
texNormal.xy *= material.clearcoatNormalScale;
|
|
3213
|
+
clearcoatNormal = vTBN * texNormal;
|
|
3214
|
+
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
clearcoatNormal *= surfaceHit.side;
|
|
3220
|
+
|
|
3221
|
+
// sheenColor
|
|
3222
|
+
vec3 sheenColor = material.sheenColor;
|
|
3223
|
+
if ( material.sheenColorMap != - 1 ) {
|
|
3224
|
+
|
|
3225
|
+
vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );
|
|
3226
|
+
sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;
|
|
3227
|
+
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
// sheenRoughness
|
|
3231
|
+
float sheenRoughness = material.sheenRoughness;
|
|
3232
|
+
if ( material.sheenRoughnessMap != - 1 ) {
|
|
3233
|
+
|
|
3234
|
+
vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );
|
|
3235
|
+
sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;
|
|
3236
|
+
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
// iridescence
|
|
3240
|
+
float iridescence = material.iridescence;
|
|
3241
|
+
if ( material.iridescenceMap != - 1 ) {
|
|
3242
|
+
|
|
3243
|
+
vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );
|
|
3244
|
+
iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;
|
|
3245
|
+
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
// iridescence thickness
|
|
3249
|
+
float iridescenceThickness = material.iridescenceThicknessMaximum;
|
|
3250
|
+
if ( material.iridescenceThicknessMap != - 1 ) {
|
|
3251
|
+
|
|
3252
|
+
vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );
|
|
3253
|
+
float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;
|
|
3254
|
+
iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );
|
|
3255
|
+
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;
|
|
3259
|
+
|
|
3260
|
+
// specular color
|
|
3261
|
+
vec3 specularColor = material.specularColor;
|
|
3262
|
+
if ( material.specularColorMap != - 1 ) {
|
|
3263
|
+
|
|
3264
|
+
vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );
|
|
3265
|
+
specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;
|
|
3266
|
+
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
// specular intensity
|
|
3270
|
+
float specularIntensity = material.specularIntensity;
|
|
3271
|
+
if ( material.specularIntensityMap != - 1 ) {
|
|
3272
|
+
|
|
3273
|
+
vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );
|
|
3274
|
+
specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;
|
|
3275
|
+
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
surf.volumeParticle = false;
|
|
3279
|
+
|
|
3280
|
+
surf.faceNormal = surfaceHit.faceNormal;
|
|
3281
|
+
surf.normal = normal;
|
|
3282
|
+
|
|
3283
|
+
surf.metalness = metalness;
|
|
3284
|
+
surf.color = albedo.rgb;
|
|
3285
|
+
surf.emission = emission;
|
|
3286
|
+
|
|
3287
|
+
surf.ior = material.ior;
|
|
3288
|
+
surf.transmission = transmission;
|
|
3289
|
+
surf.thinFilm = material.thinFilm;
|
|
3290
|
+
surf.attenuationColor = material.attenuationColor;
|
|
3291
|
+
surf.attenuationDistance = material.attenuationDistance;
|
|
3292
|
+
|
|
3293
|
+
surf.clearcoatNormal = clearcoatNormal;
|
|
3294
|
+
surf.clearcoat = clearcoat;
|
|
3295
|
+
|
|
3296
|
+
surf.sheen = material.sheen;
|
|
3297
|
+
surf.sheenColor = sheenColor;
|
|
3298
|
+
|
|
3299
|
+
surf.iridescence = iridescence;
|
|
3300
|
+
surf.iridescenceIor = material.iridescenceIor;
|
|
3301
|
+
surf.iridescenceThickness = iridescenceThickness;
|
|
3302
|
+
|
|
3303
|
+
surf.specularColor = specularColor;
|
|
3304
|
+
surf.specularIntensity = specularIntensity;
|
|
3305
|
+
|
|
3306
|
+
// apply perceptual roughness factor from gltf. sheen perceptual roughness is
|
|
3307
|
+
// applied by its brdf function
|
|
3308
|
+
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
|
|
3309
|
+
surf.roughness = roughness * roughness;
|
|
3310
|
+
surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
|
|
3311
|
+
surf.sheenRoughness = sheenRoughness;
|
|
3312
|
+
|
|
3313
|
+
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
|
|
3314
|
+
// then we can just always assume this is a front face.
|
|
3315
|
+
surf.frontFace = surfaceHit.side == 1.0 || transmission == 0.0;
|
|
3316
|
+
surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;
|
|
3317
|
+
surf.f0 = iorRatioToF0( surf.eta );
|
|
3318
|
+
|
|
3319
|
+
// Compute the filtered roughness value to use during specular reflection computations.
|
|
3320
|
+
// The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
|
|
3321
|
+
// If we're exiting something transmissive then scale the factor down significantly so we can retain
|
|
3322
|
+
// sharp internal reflections
|
|
3323
|
+
surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );
|
|
3324
|
+
surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );
|
|
3325
|
+
|
|
3326
|
+
// get the normal frames
|
|
3327
|
+
surf.normalBasis = getBasisFromNormal( surf.normal );
|
|
3328
|
+
surf.normalInvBasis = inverse( surf.normalBasis );
|
|
3329
|
+
|
|
3330
|
+
surf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );
|
|
3331
|
+
surf.clearcoatInvBasis = inverse( surf.clearcoatBasis );
|
|
3332
|
+
|
|
3333
|
+
return HIT_SURFACE;
|
|
3334
|
+
|
|
3335
|
+
}
|
|
3336
|
+
`,Co=`
|
|
3337
|
+
|
|
3338
|
+
struct Ray {
|
|
3339
|
+
|
|
3340
|
+
vec3 origin;
|
|
3341
|
+
vec3 direction;
|
|
3342
|
+
|
|
3343
|
+
};
|
|
3344
|
+
|
|
3345
|
+
struct SurfaceHit {
|
|
3346
|
+
|
|
3347
|
+
uvec4 faceIndices;
|
|
3348
|
+
vec3 barycoord;
|
|
3349
|
+
vec3 faceNormal;
|
|
3350
|
+
float side;
|
|
3351
|
+
float dist;
|
|
3352
|
+
|
|
3353
|
+
};
|
|
3354
|
+
|
|
3355
|
+
struct RenderState {
|
|
3356
|
+
|
|
3357
|
+
bool firstRay;
|
|
3358
|
+
bool transmissiveRay;
|
|
3359
|
+
bool isShadowRay;
|
|
3360
|
+
float accumulatedRoughness;
|
|
3361
|
+
int transmissiveTraversals;
|
|
3362
|
+
int traversals;
|
|
3363
|
+
uint depth;
|
|
3364
|
+
vec3 throughputColor;
|
|
3365
|
+
Material fogMaterial;
|
|
3366
|
+
|
|
3367
|
+
};
|
|
3368
|
+
|
|
3369
|
+
RenderState initRenderState() {
|
|
3370
|
+
|
|
3371
|
+
RenderState result;
|
|
3372
|
+
result.firstRay = true;
|
|
3373
|
+
result.transmissiveRay = true;
|
|
3374
|
+
result.isShadowRay = false;
|
|
3375
|
+
result.accumulatedRoughness = 0.0;
|
|
3376
|
+
result.transmissiveTraversals = 0;
|
|
3377
|
+
result.traversals = 0;
|
|
3378
|
+
result.throughputColor = vec3( 1.0 );
|
|
3379
|
+
result.depth = 0u;
|
|
3380
|
+
result.fogMaterial.fogVolume = false;
|
|
3381
|
+
return result;
|
|
3382
|
+
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
`,Fo=`
|
|
3386
|
+
|
|
3387
|
+
#define NO_HIT 0
|
|
3388
|
+
#define SURFACE_HIT 1
|
|
3389
|
+
#define LIGHT_HIT 2
|
|
3390
|
+
#define FOG_HIT 3
|
|
3391
|
+
|
|
3392
|
+
// Passing the global variable 'lights' into this function caused shader program errors.
|
|
3393
|
+
// So global variables like 'lights' and 'bvh' were moved out of the function parameters.
|
|
3394
|
+
// For more information, refer to: https://github.com/gkjohnson/three-gpu-pathtracer/pull/457
|
|
3395
|
+
int traceScene(
|
|
3396
|
+
Ray ray, Material fogMaterial, inout SurfaceHit surfaceHit
|
|
3397
|
+
) {
|
|
3398
|
+
|
|
3399
|
+
int result = NO_HIT;
|
|
3400
|
+
bool hit = bvhIntersectFirstHit( bvh, ray.origin, ray.direction, surfaceHit.faceIndices, surfaceHit.faceNormal, surfaceHit.barycoord, surfaceHit.side, surfaceHit.dist );
|
|
3401
|
+
|
|
3402
|
+
#if FEATURE_FOG
|
|
3403
|
+
|
|
3404
|
+
if ( fogMaterial.fogVolume ) {
|
|
3405
|
+
|
|
3406
|
+
// offset the distance so we don't run into issues with particles on the same surface
|
|
3407
|
+
// as other objects
|
|
3408
|
+
float particleDist = intersectFogVolume( fogMaterial, rand( 1 ) );
|
|
3409
|
+
if ( particleDist + RAY_OFFSET < surfaceHit.dist ) {
|
|
3410
|
+
|
|
3411
|
+
surfaceHit.side = 1.0;
|
|
3412
|
+
surfaceHit.faceNormal = normalize( - ray.direction );
|
|
3413
|
+
surfaceHit.dist = particleDist;
|
|
3414
|
+
return FOG_HIT;
|
|
3415
|
+
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
#endif
|
|
3421
|
+
|
|
3422
|
+
if ( hit ) {
|
|
3423
|
+
|
|
3424
|
+
result = SURFACE_HIT;
|
|
3425
|
+
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
return result;
|
|
3429
|
+
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
`;class Do extends Bi{onBeforeRender(){this.setDefine("FEATURE_DOF",this.physicalCamera.bokehSize===0?0:1),this.setDefine("FEATURE_BACKGROUND_MAP",this.backgroundMap?1:0),this.setDefine("FEATURE_FOG",this.materials.features.isUsed("FOG")?1:0)}constructor(e){super({transparent:!0,depthWrite:!1,defines:{FEATURE_MIS:1,FEATURE_RUSSIAN_ROULETTE:1,FEATURE_DOF:1,FEATURE_BACKGROUND_MAP:0,FEATURE_FOG:1,RANDOM_TYPE:2,CAMERA_TYPE:0,DEBUG_MODE:0,ATTR_NORMAL:0,ATTR_TANGENT:1,ATTR_UV:2,ATTR_COLOR:3},uniforms:{resolution:{value:new L},opacity:{value:1},bounces:{value:10},transmissiveBounces:{value:10},filterGlossyFactor:{value:0},physicalCamera:{value:new Ra},cameraWorldMatrix:{value:new Y},invProjectionMatrix:{value:new Y},bvh:{value:new Kn},attributesArray:{value:new La},materialIndexAttribute:{value:new Jr},materials:{value:new ja},textures:{value:new Ir().texture},lights:{value:new Oa},iesProfiles:{value:new Ir(360,180,{type:fe,wrapS:Me,wrapT:Me}).texture},environmentIntensity:{value:1},environmentRotation:{value:new Y},envMapInfo:{value:new Ca},backgroundBlur:{value:0},backgroundMap:{value:null},backgroundAlpha:{value:1},backgroundIntensity:{value:1},backgroundRotation:{value:new Y},seed:{value:0},sobolTexture:{value:null},stratifiedTexture:{value:new Ja},stratifiedOffsetTexture:{value:new no(64,1)}},vertexShader:`
|
|
3433
|
+
|
|
3434
|
+
varying vec2 vUv;
|
|
3435
|
+
void main() {
|
|
3436
|
+
|
|
3437
|
+
vec4 mvPosition = vec4( position, 1.0 );
|
|
3438
|
+
mvPosition = modelViewMatrix * mvPosition;
|
|
3439
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
3440
|
+
|
|
3441
|
+
vUv = uv;
|
|
3442
|
+
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
`,fragmentShader:`
|
|
3446
|
+
#define RAY_OFFSET 1e-4
|
|
3447
|
+
#define INFINITY 1e20
|
|
3448
|
+
|
|
3449
|
+
precision highp isampler2D;
|
|
3450
|
+
precision highp usampler2D;
|
|
3451
|
+
precision highp sampler2DArray;
|
|
3452
|
+
vec4 envMapTexelToLinear( vec4 a ) { return a; }
|
|
3453
|
+
#include <common>
|
|
3454
|
+
|
|
3455
|
+
// bvh intersection
|
|
3456
|
+
${Jn}
|
|
3457
|
+
${ta}
|
|
3458
|
+
${ea}
|
|
3459
|
+
|
|
3460
|
+
// uniform structs
|
|
3461
|
+
${ao}
|
|
3462
|
+
${co}
|
|
3463
|
+
${oo}
|
|
3464
|
+
${lo}
|
|
3465
|
+
${uo}
|
|
3466
|
+
|
|
3467
|
+
// random
|
|
3468
|
+
#if RANDOM_TYPE == 2 // Stratified List
|
|
3469
|
+
|
|
3470
|
+
${yo}
|
|
3471
|
+
|
|
3472
|
+
#elif RANDOM_TYPE == 1 // Sobol
|
|
3473
|
+
|
|
3474
|
+
${Cr}
|
|
3475
|
+
${ss}
|
|
3476
|
+
${Aa}
|
|
3477
|
+
|
|
3478
|
+
#define rand(v) sobol(v)
|
|
3479
|
+
#define rand2(v) sobol2(v)
|
|
3480
|
+
#define rand3(v) sobol3(v)
|
|
3481
|
+
#define rand4(v) sobol4(v)
|
|
3482
|
+
|
|
3483
|
+
#else // PCG
|
|
3484
|
+
|
|
3485
|
+
${Cr}
|
|
3486
|
+
|
|
3487
|
+
// Using the sobol functions seems to break the the compiler on MacOS
|
|
3488
|
+
// - specifically the "sobolReverseBits" function.
|
|
3489
|
+
uint sobolPixelIndex = 0u;
|
|
3490
|
+
uint sobolPathIndex = 0u;
|
|
3491
|
+
uint sobolBounceIndex = 0u;
|
|
3492
|
+
|
|
3493
|
+
#define rand(v) pcgRand()
|
|
3494
|
+
#define rand2(v) pcgRand2()
|
|
3495
|
+
#define rand3(v) pcgRand3()
|
|
3496
|
+
#define rand4(v) pcgRand4()
|
|
3497
|
+
|
|
3498
|
+
#endif
|
|
3499
|
+
|
|
3500
|
+
// common
|
|
3501
|
+
${xo}
|
|
3502
|
+
${po}
|
|
3503
|
+
${as}
|
|
3504
|
+
${go}
|
|
3505
|
+
${vo}
|
|
3506
|
+
|
|
3507
|
+
// environment
|
|
3508
|
+
uniform EquirectHdrInfo envMapInfo;
|
|
3509
|
+
uniform mat4 environmentRotation;
|
|
3510
|
+
uniform float environmentIntensity;
|
|
3511
|
+
|
|
3512
|
+
// lighting
|
|
3513
|
+
uniform sampler2DArray iesProfiles;
|
|
3514
|
+
uniform LightsInfo lights;
|
|
3515
|
+
|
|
3516
|
+
// background
|
|
3517
|
+
uniform float backgroundBlur;
|
|
3518
|
+
uniform float backgroundAlpha;
|
|
3519
|
+
#if FEATURE_BACKGROUND_MAP
|
|
3520
|
+
|
|
3521
|
+
uniform sampler2D backgroundMap;
|
|
3522
|
+
uniform mat4 backgroundRotation;
|
|
3523
|
+
uniform float backgroundIntensity;
|
|
3524
|
+
|
|
3525
|
+
#endif
|
|
3526
|
+
|
|
3527
|
+
// camera
|
|
3528
|
+
uniform mat4 cameraWorldMatrix;
|
|
3529
|
+
uniform mat4 invProjectionMatrix;
|
|
3530
|
+
#if FEATURE_DOF
|
|
3531
|
+
|
|
3532
|
+
uniform PhysicalCamera physicalCamera;
|
|
3533
|
+
|
|
3534
|
+
#endif
|
|
3535
|
+
|
|
3536
|
+
// geometry
|
|
3537
|
+
uniform sampler2DArray attributesArray;
|
|
3538
|
+
uniform usampler2D materialIndexAttribute;
|
|
3539
|
+
uniform sampler2D materials;
|
|
3540
|
+
uniform sampler2DArray textures;
|
|
3541
|
+
uniform BVH bvh;
|
|
3542
|
+
|
|
3543
|
+
// path tracer
|
|
3544
|
+
uniform int bounces;
|
|
3545
|
+
uniform int transmissiveBounces;
|
|
3546
|
+
uniform float filterGlossyFactor;
|
|
3547
|
+
uniform int seed;
|
|
3548
|
+
|
|
3549
|
+
// image
|
|
3550
|
+
uniform vec2 resolution;
|
|
3551
|
+
uniform float opacity;
|
|
3552
|
+
|
|
3553
|
+
varying vec2 vUv;
|
|
3554
|
+
|
|
3555
|
+
// globals
|
|
3556
|
+
mat3 envRotation3x3;
|
|
3557
|
+
mat3 invEnvRotation3x3;
|
|
3558
|
+
float lightsDenom;
|
|
3559
|
+
|
|
3560
|
+
// sampling
|
|
3561
|
+
${mo}
|
|
3562
|
+
${fo}
|
|
3563
|
+
${ho}
|
|
3564
|
+
|
|
3565
|
+
${So}
|
|
3566
|
+
${wo}
|
|
3567
|
+
${_o}
|
|
3568
|
+
${Ao}
|
|
3569
|
+
${To}
|
|
3570
|
+
${bo}
|
|
3571
|
+
|
|
3572
|
+
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
3573
|
+
|
|
3574
|
+
return clamp(
|
|
3575
|
+
max(
|
|
3576
|
+
roughness,
|
|
3577
|
+
accumulatedRoughness * filterGlossyFactor * 5.0 ),
|
|
3578
|
+
0.0,
|
|
3579
|
+
1.0
|
|
3580
|
+
);
|
|
3581
|
+
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
vec3 sampleBackground( vec3 direction, vec2 uv ) {
|
|
3585
|
+
|
|
3586
|
+
vec3 sampleDir = sampleHemisphere( direction, uv ) * 0.5 * backgroundBlur;
|
|
3587
|
+
|
|
3588
|
+
#if FEATURE_BACKGROUND_MAP
|
|
3589
|
+
|
|
3590
|
+
sampleDir = normalize( mat3( backgroundRotation ) * direction + sampleDir );
|
|
3591
|
+
return backgroundIntensity * sampleEquirectColor( backgroundMap, sampleDir );
|
|
3592
|
+
|
|
3593
|
+
#else
|
|
3594
|
+
|
|
3595
|
+
sampleDir = normalize( envRotation3x3 * direction + sampleDir );
|
|
3596
|
+
return environmentIntensity * sampleEquirectColor( envMapInfo.map, sampleDir );
|
|
3597
|
+
|
|
3598
|
+
#endif
|
|
3599
|
+
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
${Co}
|
|
3603
|
+
${Ro}
|
|
3604
|
+
${Fo}
|
|
3605
|
+
${Mo}
|
|
3606
|
+
${Io}
|
|
3607
|
+
${Po}
|
|
3608
|
+
|
|
3609
|
+
void main() {
|
|
3610
|
+
|
|
3611
|
+
// init
|
|
3612
|
+
rng_initialize( gl_FragCoord.xy, seed );
|
|
3613
|
+
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | uint( gl_FragCoord.y );
|
|
3614
|
+
sobolPathIndex = uint( seed );
|
|
3615
|
+
|
|
3616
|
+
// get camera ray
|
|
3617
|
+
Ray ray = getCameraRay();
|
|
3618
|
+
|
|
3619
|
+
// inverse environment rotation
|
|
3620
|
+
envRotation3x3 = mat3( environmentRotation );
|
|
3621
|
+
invEnvRotation3x3 = inverse( envRotation3x3 );
|
|
3622
|
+
lightsDenom =
|
|
3623
|
+
( environmentIntensity == 0.0 || envMapInfo.totalSum == 0.0 ) && lights.count != 0u ?
|
|
3624
|
+
float( lights.count ) :
|
|
3625
|
+
float( lights.count + 1u );
|
|
3626
|
+
|
|
3627
|
+
// final color
|
|
3628
|
+
gl_FragColor = vec4( 0, 0, 0, 1 );
|
|
3629
|
+
|
|
3630
|
+
// surface results
|
|
3631
|
+
SurfaceHit surfaceHit;
|
|
3632
|
+
ScatterRecord scatterRec;
|
|
3633
|
+
|
|
3634
|
+
// path tracing state
|
|
3635
|
+
RenderState state = initRenderState();
|
|
3636
|
+
state.transmissiveTraversals = transmissiveBounces;
|
|
3637
|
+
#if FEATURE_FOG
|
|
3638
|
+
|
|
3639
|
+
state.fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
|
|
3640
|
+
ray.origin, - ray.direction,
|
|
3641
|
+
materialIndexAttribute, materials,
|
|
3642
|
+
state.fogMaterial
|
|
3643
|
+
);
|
|
3644
|
+
|
|
3645
|
+
#endif
|
|
3646
|
+
|
|
3647
|
+
for ( int i = 0; i < bounces; i ++ ) {
|
|
3648
|
+
|
|
3649
|
+
sobolBounceIndex ++;
|
|
3650
|
+
|
|
3651
|
+
state.depth ++;
|
|
3652
|
+
state.traversals = bounces - i;
|
|
3653
|
+
state.firstRay = i == 0 && state.transmissiveTraversals == transmissiveBounces;
|
|
3654
|
+
|
|
3655
|
+
int hitType = traceScene( ray, state.fogMaterial, surfaceHit );
|
|
3656
|
+
|
|
3657
|
+
// check if we intersect any lights and accumulate the light contribution
|
|
3658
|
+
// TODO: we can add support for light surface rendering in the else condition if we
|
|
3659
|
+
// add the ability to toggle visibility of the the light
|
|
3660
|
+
if ( ! state.firstRay && ! state.transmissiveRay ) {
|
|
3661
|
+
|
|
3662
|
+
LightRecord lightRec;
|
|
3663
|
+
float lightDist = hitType == NO_HIT ? INFINITY : surfaceHit.dist;
|
|
3664
|
+
for ( uint i = 0u; i < lights.count; i ++ ) {
|
|
3665
|
+
|
|
3666
|
+
if (
|
|
3667
|
+
intersectLightAtIndex( lights.tex, ray.origin, ray.direction, i, lightRec ) &&
|
|
3668
|
+
lightRec.dist < lightDist
|
|
3669
|
+
) {
|
|
3670
|
+
|
|
3671
|
+
#if FEATURE_MIS
|
|
3672
|
+
|
|
3673
|
+
// weight the contribution
|
|
3674
|
+
// NOTE: Only area lights are supported for forward sampling and can be hit
|
|
3675
|
+
float misWeight = misHeuristic( scatterRec.pdf, lightRec.pdf / lightsDenom );
|
|
3676
|
+
gl_FragColor.rgb += lightRec.emission * state.throughputColor * misWeight;
|
|
3677
|
+
|
|
3678
|
+
#else
|
|
3679
|
+
|
|
3680
|
+
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
3681
|
+
|
|
3682
|
+
#endif
|
|
3683
|
+
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3690
|
+
if ( hitType == NO_HIT ) {
|
|
3691
|
+
|
|
3692
|
+
if ( state.firstRay || state.transmissiveRay ) {
|
|
3693
|
+
|
|
3694
|
+
gl_FragColor.rgb += sampleBackground( ray.direction, rand2( 2 ) ) * state.throughputColor;
|
|
3695
|
+
gl_FragColor.a = backgroundAlpha;
|
|
3696
|
+
|
|
3697
|
+
} else {
|
|
3698
|
+
|
|
3699
|
+
#if FEATURE_MIS
|
|
3700
|
+
|
|
3701
|
+
// get the PDF of the hit envmap point
|
|
3702
|
+
vec3 envColor;
|
|
3703
|
+
float envPdf = sampleEquirect( envRotation3x3 * ray.direction, envColor );
|
|
3704
|
+
envPdf /= lightsDenom;
|
|
3705
|
+
|
|
3706
|
+
// and weight the contribution
|
|
3707
|
+
float misWeight = misHeuristic( scatterRec.pdf, envPdf );
|
|
3708
|
+
gl_FragColor.rgb += environmentIntensity * envColor * state.throughputColor * misWeight;
|
|
3709
|
+
|
|
3710
|
+
#else
|
|
3711
|
+
|
|
3712
|
+
gl_FragColor.rgb +=
|
|
3713
|
+
environmentIntensity *
|
|
3714
|
+
sampleEquirectColor( envMapInfo.map, envRotation3x3 * ray.direction ) *
|
|
3715
|
+
state.throughputColor;
|
|
3716
|
+
|
|
3717
|
+
#endif
|
|
3718
|
+
|
|
3719
|
+
}
|
|
3720
|
+
break;
|
|
3721
|
+
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;
|
|
3725
|
+
Material material = readMaterialInfo( materials, materialIndex );
|
|
3726
|
+
|
|
3727
|
+
#if FEATURE_FOG
|
|
3728
|
+
|
|
3729
|
+
if ( hitType == FOG_HIT ) {
|
|
3730
|
+
|
|
3731
|
+
material = state.fogMaterial;
|
|
3732
|
+
state.accumulatedRoughness += 0.2;
|
|
3733
|
+
|
|
3734
|
+
} else if ( material.fogVolume ) {
|
|
3735
|
+
|
|
3736
|
+
state.fogMaterial = material;
|
|
3737
|
+
state.fogMaterial.fogVolume = surfaceHit.side == 1.0;
|
|
3738
|
+
|
|
3739
|
+
ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
|
|
3740
|
+
|
|
3741
|
+
i -= sign( state.transmissiveTraversals );
|
|
3742
|
+
state.transmissiveTraversals -= sign( state.transmissiveTraversals );
|
|
3743
|
+
continue;
|
|
3744
|
+
|
|
3745
|
+
}
|
|
3746
|
+
|
|
3747
|
+
#endif
|
|
3748
|
+
|
|
3749
|
+
// early out if this is a matte material
|
|
3750
|
+
if ( material.matte && state.firstRay ) {
|
|
3751
|
+
|
|
3752
|
+
gl_FragColor = vec4( 0.0 );
|
|
3753
|
+
break;
|
|
3754
|
+
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3757
|
+
// if we've determined that this is a shadow ray and we've hit an item with no shadow casting
|
|
3758
|
+
// then skip it
|
|
3759
|
+
if ( ! material.castShadow && state.isShadowRay ) {
|
|
3760
|
+
|
|
3761
|
+
ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
|
|
3762
|
+
continue;
|
|
3763
|
+
|
|
3764
|
+
}
|
|
3765
|
+
|
|
3766
|
+
SurfaceRecord surf;
|
|
3767
|
+
if (
|
|
3768
|
+
getSurfaceRecord(
|
|
3769
|
+
material, surfaceHit, attributesArray, state.accumulatedRoughness,
|
|
3770
|
+
surf
|
|
3771
|
+
) == SKIP_SURFACE
|
|
3772
|
+
) {
|
|
3773
|
+
|
|
3774
|
+
// only allow a limited number of transparency discards otherwise we could
|
|
3775
|
+
// crash the context with too long a loop.
|
|
3776
|
+
i -= sign( state.transmissiveTraversals );
|
|
3777
|
+
state.transmissiveTraversals -= sign( state.transmissiveTraversals );
|
|
3778
|
+
|
|
3779
|
+
ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
|
|
3780
|
+
continue;
|
|
3781
|
+
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
scatterRec = bsdfSample( - ray.direction, surf );
|
|
3785
|
+
state.isShadowRay = scatterRec.specularPdf < rand( 4 );
|
|
3786
|
+
|
|
3787
|
+
bool isBelowSurface = ! surf.volumeParticle && dot( scatterRec.direction, surf.faceNormal ) < 0.0;
|
|
3788
|
+
vec3 hitPoint = stepRayOrigin( ray.origin, ray.direction, isBelowSurface ? - surf.faceNormal : surf.faceNormal, surfaceHit.dist );
|
|
3789
|
+
|
|
3790
|
+
// next event estimation
|
|
3791
|
+
#if FEATURE_MIS
|
|
3792
|
+
|
|
3793
|
+
gl_FragColor.rgb += directLightContribution( - ray.direction, surf, state, hitPoint );
|
|
3794
|
+
|
|
3795
|
+
#endif
|
|
3796
|
+
|
|
3797
|
+
// accumulate a roughness value to offset diffuse, specular, diffuse rays that have high contribution
|
|
3798
|
+
// to a single pixel resulting in fireflies
|
|
3799
|
+
// TODO: handle transmissive surfaces
|
|
3800
|
+
if ( ! surf.volumeParticle && ! isBelowSurface ) {
|
|
3801
|
+
|
|
3802
|
+
// determine if this is a rough normal or not by checking how far off straight up it is
|
|
3803
|
+
vec3 halfVector = normalize( - ray.direction + scatterRec.direction );
|
|
3804
|
+
state.accumulatedRoughness += max(
|
|
3805
|
+
sin( acosApprox( dot( halfVector, surf.normal ) ) ),
|
|
3806
|
+
sin( acosApprox( dot( halfVector, surf.clearcoatNormal ) ) )
|
|
3807
|
+
);
|
|
3808
|
+
|
|
3809
|
+
state.transmissiveRay = false;
|
|
3810
|
+
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
// accumulate emissive color
|
|
3814
|
+
gl_FragColor.rgb += ( surf.emission * state.throughputColor );
|
|
3815
|
+
|
|
3816
|
+
// skip the sample if our PDF or ray is impossible
|
|
3817
|
+
if ( scatterRec.pdf <= 0.0 || ! isDirectionValid( scatterRec.direction, surf.normal, surf.faceNormal ) ) {
|
|
3818
|
+
|
|
3819
|
+
break;
|
|
3820
|
+
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3823
|
+
// if we're bouncing around the inside a transmissive material then decrement
|
|
3824
|
+
// perform this separate from a bounce
|
|
3825
|
+
bool isTransmissiveRay = ! surf.volumeParticle && dot( scatterRec.direction, surf.faceNormal * surfaceHit.side ) < 0.0;
|
|
3826
|
+
if ( ( isTransmissiveRay || isBelowSurface ) && state.transmissiveTraversals > 0 ) {
|
|
3827
|
+
|
|
3828
|
+
state.transmissiveTraversals --;
|
|
3829
|
+
i --;
|
|
3830
|
+
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
//
|
|
3834
|
+
|
|
3835
|
+
// handle throughput color transformation
|
|
3836
|
+
// attenuate the throughput color by the medium color
|
|
3837
|
+
if ( ! surf.frontFace ) {
|
|
3838
|
+
|
|
3839
|
+
state.throughputColor *= transmissionAttenuation( surfaceHit.dist, surf.attenuationColor, surf.attenuationDistance );
|
|
3840
|
+
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
#if FEATURE_RUSSIAN_ROULETTE
|
|
3844
|
+
|
|
3845
|
+
// russian roulette path termination
|
|
3846
|
+
// https://www.arnoldrenderer.com/research/physically_based_shader_design_in_arnold.pdf
|
|
3847
|
+
uint minBounces = 3u;
|
|
3848
|
+
float depthProb = float( state.depth < minBounces );
|
|
3849
|
+
|
|
3850
|
+
float rrProb = luminance( state.throughputColor * scatterRec.color / scatterRec.pdf );
|
|
3851
|
+
rrProb /= luminance( state.throughputColor );
|
|
3852
|
+
rrProb = sqrt( rrProb );
|
|
3853
|
+
rrProb = max( rrProb, depthProb );
|
|
3854
|
+
rrProb = min( rrProb, 1.0 );
|
|
3855
|
+
if ( rand( 8 ) > rrProb ) {
|
|
3856
|
+
|
|
3857
|
+
break;
|
|
3858
|
+
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3861
|
+
// perform sample clamping here to avoid bright pixels
|
|
3862
|
+
state.throughputColor *= min( 1.0 / rrProb, 20.0 );
|
|
3863
|
+
|
|
3864
|
+
#endif
|
|
3865
|
+
|
|
3866
|
+
// adjust the throughput and discard and exit if we find discard the sample if there are any NaNs
|
|
3867
|
+
state.throughputColor *= scatterRec.color / scatterRec.pdf;
|
|
3868
|
+
if ( any( isnan( state.throughputColor ) ) || any( isinf( state.throughputColor ) ) ) {
|
|
3869
|
+
|
|
3870
|
+
break;
|
|
3871
|
+
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
//
|
|
3875
|
+
|
|
3876
|
+
// prepare for next ray
|
|
3877
|
+
ray.direction = scatterRec.direction;
|
|
3878
|
+
ray.origin = hitPoint;
|
|
3879
|
+
|
|
3880
|
+
}
|
|
3881
|
+
|
|
3882
|
+
gl_FragColor.a *= opacity;
|
|
3883
|
+
|
|
3884
|
+
#if DEBUG_MODE == 1
|
|
3885
|
+
|
|
3886
|
+
// output the number of rays checked in the path and number of
|
|
3887
|
+
// transmissive rays encountered.
|
|
3888
|
+
gl_FragColor.rgb = vec3(
|
|
3889
|
+
float( state.depth ),
|
|
3890
|
+
transmissiveBounces - state.transmissiveTraversals,
|
|
3891
|
+
0.0
|
|
3892
|
+
);
|
|
3893
|
+
gl_FragColor.a = 1.0;
|
|
3894
|
+
|
|
3895
|
+
#endif
|
|
3896
|
+
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3899
|
+
`}),this.setValues(e)}}function*Eo(){const{_renderer:s,_fsQuad:e,_blendQuad:i,_primaryTarget:t,_blendTargets:n,_sobolTarget:a,_subframe:r,alpha:c,material:l}=this,h=new Je,f=new Je,u=i.material;let[o,m]=n;for(;;){c?(u.opacity=this._opacityFactor/(this.samples+1),l.blending=vt,l.opacity=1):(l.opacity=this._opacityFactor/(this.samples+1),l.blending=Wr);const[v,b,d,p]=r,g=t.width,y=t.height;l.resolution.set(g*d,y*p),l.sobolTexture=a.texture,l.stratifiedTexture.init(20,l.bounces+l.transmissiveBounces+5),l.stratifiedTexture.next(),l.seed++;const w=this.tiles.x||1,T=this.tiles.y||1,_=w*T,A=Math.ceil(g*d),S=Math.ceil(y*p),R=Math.floor(v*g),I=Math.floor(b*y),P=Math.ceil(A/w),M=Math.ceil(S/T);for(let F=0;F<T;F++)for(let E=0;E<w;E++){const B=s.getRenderTarget(),z=s.autoClear,X=s.getScissorTest();s.getScissor(h),s.getViewport(f);let ee=E,te=F;if(!this.stableTiles){const Be=this._currentTile%(w*T);ee=Be%w,te=~~(Be/w),this._currentTile=Be+1}const Ee=T-te-1;t.scissor.set(R+ee*P,I+Ee*M,Math.min(P,A-ee*P),Math.min(M,S-Ee*M)),t.viewport.set(R,I,A,S),s.setRenderTarget(t),s.setScissorTest(!0),s.autoClear=!1,e.render(s),s.setViewport(f),s.setScissor(h),s.setScissorTest(X),s.setRenderTarget(B),s.autoClear=z,c&&(u.target1=o.texture,u.target2=t.texture,s.setRenderTarget(m),i.render(s),s.setRenderTarget(B)),this.samples+=1/_,E===w-1&&F===T-1&&(this.samples=Math.round(this.samples)),yield}[o,m]=[m,o]}}const Fr=new xt;class Dr{get material(){return this._fsQuad.material}set material(e){this._fsQuad.material.removeEventListener("recompilation",this._compileFunction),e.addEventListener("recompilation",this._compileFunction),this._fsQuad.material=e}get target(){return this._alpha?this._blendTargets[1]:this._primaryTarget}set alpha(e){this._alpha!==e&&(e||(this._blendTargets[0].dispose(),this._blendTargets[1].dispose()),this._alpha=e,this.reset())}get alpha(){return this._alpha}get isCompiling(){return!!this._compilePromise}constructor(e){this.camera=null,this.tiles=new L(3,3),this.stableNoise=!1,this.stableTiles=!0,this.samples=0,this._subframe=new Je(0,0,1,1),this._opacityFactor=1,this._renderer=e,this._alpha=!1,this._fsQuad=new et(new Do),this._blendQuad=new et(new Ta),this._task=null,this._currentTile=0,this._compilePromise=null,this._sobolTarget=new Sa().generate(e),this._primaryTarget=new pt(1,1,{format:V,type:q,magFilter:U,minFilter:U}),this._blendTargets=[new pt(1,1,{format:V,type:q,magFilter:U,minFilter:U}),new pt(1,1,{format:V,type:q,magFilter:U,minFilter:U})],this._compileFunction=()=>{const i=this.compileMaterial(this._fsQuad._mesh);i.then(()=>{this._compilePromise===i&&(this._compilePromise=null)}),this._compilePromise=i},this.material.addEventListener("recompilation",this._compileFunction)}compileMaterial(){return this._renderer.compileAsync(this._fsQuad._mesh)}setCamera(e){const{material:i}=this;i.cameraWorldMatrix.copy(e.matrixWorld),i.invProjectionMatrix.copy(e.projectionMatrixInverse),i.physicalCamera.updateFrom(e);let t=0;e.projectionMatrix.elements[15]>0&&(t=1),e.isEquirectCamera&&(t=2),i.setDefine("CAMERA_TYPE",t),this.camera=e}setSize(e,i){e=Math.ceil(e),i=Math.ceil(i),!(this._primaryTarget.width===e&&this._primaryTarget.height===i)&&(this._primaryTarget.setSize(e,i),this._blendTargets[0].setSize(e,i),this._blendTargets[1].setSize(e,i),this.reset())}getSize(e){e.x=this._primaryTarget.width,e.y=this._primaryTarget.height}dispose(){this._primaryTarget.dispose(),this._blendTargets[0].dispose(),this._blendTargets[1].dispose(),this._sobolTarget.dispose(),this._fsQuad.dispose(),this._blendQuad.dispose(),this._task=null}reset(){const{_renderer:e,_primaryTarget:i,_blendTargets:t}=this,n=e.getRenderTarget(),a=e.getClearAlpha();e.getClearColor(Fr),e.setRenderTarget(i),e.setClearColor(0,0),e.clearColor(),e.setRenderTarget(t[0]),e.setClearColor(0,0),e.clearColor(),e.setRenderTarget(t[1]),e.setClearColor(0,0),e.clearColor(),e.setClearColor(Fr,a),e.setRenderTarget(n),this.samples=0,this._task=null,this.material.stratifiedTexture.stableNoise=this.stableNoise,this.stableNoise&&(this.material.seed=0,this.material.stratifiedTexture.reset())}update(){this.material.onBeforeRender(),!this.isCompiling&&(this._task||(this._task=Eo.call(this)),this._task.next())}}const Fe=new L,Er=new L,Lt=new di,Ht=new xt;class Bo extends ae{constructor(e=512,i=512){super(new Float32Array(e*i*4),e,i,V,q,Vr,_e,Me,le,le),this.generationCallback=null}update(){this.dispose(),this.needsUpdate=!0;const{data:e,width:i,height:t}=this.image;for(let n=0;n<i;n++)for(let a=0;a<t;a++){Er.set(i,t),Fe.set(n/i,a/t),Fe.x-=.5,Fe.y=1-Fe.y,Lt.theta=Fe.x*2*Math.PI,Lt.phi=Fe.y*Math.PI,Lt.radius=1,this.generationCallback(Lt,Fe,Er,Ht);const c=4*(a*i+n);e[c+0]=Ht.r,e[c+1]=Ht.g,e[c+2]=Ht.b,e[c+3]=1}}copy(e){return super.copy(e),this.generationCallback=e.generationCallback,this}}const Br=new C;class ko extends Bo{constructor(e=512){super(e,e),this.topColor=new xt().set(16777215),this.bottomColor=new xt().set(0),this.exponent=2,this.generationCallback=(i,t,n,a)=>{Br.setFromSpherical(i);const r=Br.y*.5+.5;a.lerpColors(this.bottomColor,this.topColor,r**this.exponent)}}copy(e){return super.copy(e),this.topColor.copy(e.topColor),this.bottomColor.copy(e.bottomColor),this}}class zo extends qt{get map(){return this.uniforms.map.value}set map(e){this.uniforms.map.value=e}get opacity(){return this.uniforms.opacity.value}set opacity(e){this.uniforms&&(this.uniforms.opacity.value=e)}constructor(e){super({uniforms:{map:{value:null},opacity:{value:1}},vertexShader:`
|
|
3900
|
+
varying vec2 vUv;
|
|
3901
|
+
void main() {
|
|
3902
|
+
|
|
3903
|
+
vUv = uv;
|
|
3904
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
3905
|
+
|
|
3906
|
+
}
|
|
3907
|
+
`,fragmentShader:`
|
|
3908
|
+
uniform sampler2D map;
|
|
3909
|
+
uniform float opacity;
|
|
3910
|
+
varying vec2 vUv;
|
|
3911
|
+
|
|
3912
|
+
vec4 clampedTexelFatch( sampler2D map, ivec2 px, int lod ) {
|
|
3913
|
+
|
|
3914
|
+
vec4 res = texelFetch( map, ivec2( px.x, px.y ), 0 );
|
|
3915
|
+
|
|
3916
|
+
#if defined( TONE_MAPPING )
|
|
3917
|
+
|
|
3918
|
+
res.xyz = toneMapping( res.xyz );
|
|
3919
|
+
|
|
3920
|
+
#endif
|
|
3921
|
+
|
|
3922
|
+
return linearToOutputTexel( res );
|
|
3923
|
+
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
void main() {
|
|
3927
|
+
|
|
3928
|
+
vec2 size = vec2( textureSize( map, 0 ) );
|
|
3929
|
+
vec2 pxUv = vUv * size;
|
|
3930
|
+
vec2 pxCurr = floor( pxUv );
|
|
3931
|
+
vec2 pxFrac = fract( pxUv ) - 0.5;
|
|
3932
|
+
vec2 pxOffset;
|
|
3933
|
+
pxOffset.x = pxFrac.x > 0.0 ? 1.0 : - 1.0;
|
|
3934
|
+
pxOffset.y = pxFrac.y > 0.0 ? 1.0 : - 1.0;
|
|
3935
|
+
|
|
3936
|
+
vec2 pxNext = clamp( pxOffset + pxCurr, vec2( 0.0 ), size - 1.0 );
|
|
3937
|
+
vec2 alpha = abs( pxFrac );
|
|
3938
|
+
|
|
3939
|
+
vec4 p1 = mix(
|
|
3940
|
+
clampedTexelFatch( map, ivec2( pxCurr.x, pxCurr.y ), 0 ),
|
|
3941
|
+
clampedTexelFatch( map, ivec2( pxNext.x, pxCurr.y ), 0 ),
|
|
3942
|
+
alpha.x
|
|
3943
|
+
);
|
|
3944
|
+
|
|
3945
|
+
vec4 p2 = mix(
|
|
3946
|
+
clampedTexelFatch( map, ivec2( pxCurr.x, pxNext.y ), 0 ),
|
|
3947
|
+
clampedTexelFatch( map, ivec2( pxNext.x, pxNext.y ), 0 ),
|
|
3948
|
+
alpha.x
|
|
3949
|
+
);
|
|
3950
|
+
|
|
3951
|
+
gl_FragColor = mix( p1, p2, alpha.y );
|
|
3952
|
+
gl_FragColor.a *= opacity;
|
|
3953
|
+
#include <premultiplied_alpha_fragment>
|
|
3954
|
+
|
|
3955
|
+
}
|
|
3956
|
+
`}),this.setValues(e)}}class Oo extends qt{constructor(){super({uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:`
|
|
3957
|
+
varying vec2 vUv;
|
|
3958
|
+
void main() {
|
|
3959
|
+
|
|
3960
|
+
vUv = uv;
|
|
3961
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
3962
|
+
|
|
3963
|
+
}`,fragmentShader:`
|
|
3964
|
+
#define ENVMAP_TYPE_CUBE_UV
|
|
3965
|
+
|
|
3966
|
+
uniform samplerCube envMap;
|
|
3967
|
+
uniform float flipEnvMap;
|
|
3968
|
+
varying vec2 vUv;
|
|
3969
|
+
|
|
3970
|
+
#include <common>
|
|
3971
|
+
#include <cube_uv_reflection_fragment>
|
|
3972
|
+
|
|
3973
|
+
${as}
|
|
3974
|
+
|
|
3975
|
+
void main() {
|
|
3976
|
+
|
|
3977
|
+
vec3 rayDirection = equirectUvToDirection( vUv );
|
|
3978
|
+
rayDirection.x *= flipEnvMap;
|
|
3979
|
+
gl_FragColor = textureCube( envMap, rayDirection );
|
|
3980
|
+
|
|
3981
|
+
}`}),this.depthWrite=!1,this.depthTest=!1}}class kr{constructor(e){this._renderer=e,this._quad=new et(new Oo)}generate(e,i=null,t=null){if(!e.isCubeTexture)throw new Error("CubeToEquirectMaterial: Source can only be cube textures.");const n=e.images[0],a=this._renderer,r=this._quad;i===null&&(i=4*n.height),t===null&&(t=2*n.height);const c=new pt(i,t,{type:q,colorSpace:n.colorSpace}),l=n.height,h=Math.log2(l)-2,f=1/l,u=1/(3*Math.max(Math.pow(2,h),7*16));r.material.defines.CUBEUV_MAX_MIP=`${h}.0`,r.material.defines.CUBEUV_TEXEL_WIDTH=u,r.material.defines.CUBEUV_TEXEL_HEIGHT=f,r.material.uniforms.envMap.value=e,r.material.uniforms.flipEnvMap.value=e.isRenderTargetTexture?1:-1,r.material.needsUpdate=!0;const o=a.getRenderTarget(),m=a.autoClear;a.autoClear=!0,a.setRenderTarget(c),r.render(a),a.setRenderTarget(o),a.autoClear=m;const v=new Uint16Array(i*t*4),b=new Float32Array(i*t*4);a.readRenderTargetPixels(c,0,0,i,t,b),c.dispose();for(let p=0,g=b.length;p<g;p++)v[p]=ve.toHalfFloat(b[p]);const d=new ae(v,i,t,V,fe);return d.minFilter=Hs,d.magFilter=le,d.wrapS=_e,d.wrapT=_e,d.mapping=Vr,d.needsUpdate=!0,d}dispose(){this._quad.dispose()}}function No(s){return s.extensions.get("EXT_float_blend")}const Ke=new L;class Go{get multipleImportanceSampling(){return!!this._pathTracer.material.defines.FEATURE_MIS}set multipleImportanceSampling(e){this._pathTracer.material.setDefine("FEATURE_MIS",e?1:0)}get transmissiveBounces(){return this._pathTracer.material.transmissiveBounces}set transmissiveBounces(e){this._pathTracer.material.transmissiveBounces=e}get bounces(){return this._pathTracer.material.bounces}set bounces(e){this._pathTracer.material.bounces=e}get filterGlossyFactor(){return this._pathTracer.material.filterGlossyFactor}set filterGlossyFactor(e){this._pathTracer.material.filterGlossyFactor=e}get samples(){return this._pathTracer.samples}get target(){return this._pathTracer.target}get tiles(){return this._pathTracer.tiles}get stableNoise(){return this._pathTracer.stableNoise}set stableNoise(e){this._pathTracer.stableNoise=e}get isCompiling(){return!!this._pathTracer.isCompiling}constructor(e){this._renderer=e,this._generator=new ba,this._pathTracer=new Dr(e),this._queueReset=!1,this._clock=new Us,this._compilePromise=null,this._lowResPathTracer=new Dr(e),this._lowResPathTracer.tiles.set(1,1),this._quad=new et(new zo({map:null,transparent:!0,blending:vt,premultipliedAlpha:e.getContextAttributes().premultipliedAlpha})),this._materials=null,this._previousEnvironment=null,this._previousBackground=null,this._internalBackground=null,this.renderDelay=100,this.minSamples=5,this.fadeDuration=500,this.enablePathTracing=!0,this.pausePathTracing=!1,this.dynamicLowRes=!1,this.lowResScale=.25,this.renderScale=1,this.synchronizeRenderSize=!0,this.rasterizeScene=!0,this.renderToCanvas=!0,this.textureSize=new L(1024,1024),this.rasterizeSceneCallback=(i,t)=>{this._renderer.render(i,t)},this.renderToCanvasCallback=(i,t,n)=>{const a=t.autoClear;t.autoClear=!1,n.render(t),t.autoClear=a},this.setScene(new Ws,new Ur)}setBVHWorker(e){this._generator.setBVHWorker(e)}setScene(e,i,t={}){e.updateMatrixWorld(!0),i.updateMatrixWorld();const n=this._generator;if(n.setObjects(e),this._buildAsync)return n.generateAsync(t.onProgress).then(a=>this._updateFromResults(e,i,a));{const a=n.generate();return this._updateFromResults(e,i,a)}}setSceneAsync(...e){this._buildAsync=!0;const i=this.setScene(...e);return this._buildAsync=!1,i}setCamera(e){this.camera=e,this.updateCamera()}updateCamera(){const e=this.camera;e.updateMatrixWorld(),this._pathTracer.setCamera(e),this._lowResPathTracer.setCamera(e),this.reset()}updateMaterials(){const e=this._pathTracer.material,i=this._renderer,t=this._materials,n=this.textureSize,a=Wa(t);e.textures.setTextures(i,a,n.x,n.y),e.materials.updateFrom(t,a),this.reset()}updateLights(){const e=this.scene,i=this._renderer,t=this._pathTracer.material,n=Va(e),a=Ua(n);t.lights.updateFrom(n,a),t.iesProfiles.setTextures(i,a),this.reset()}updateEnvironment(){const e=this.scene,i=this._pathTracer.material;if(this._internalBackground&&(this._internalBackground.dispose(),this._internalBackground=null),i.backgroundBlur=e.backgroundBlurriness,i.backgroundIntensity=e.backgroundIntensity??1,i.backgroundRotation.makeRotationFromEuler(e.backgroundRotation).invert(),e.background===null)i.backgroundMap=null,i.backgroundAlpha=0;else if(e.background.isColor){this._colorBackground=this._colorBackground||new ko(16);const t=this._colorBackground;t.topColor.equals(e.background)||(t.topColor.set(e.background),t.bottomColor.set(e.background),t.update()),i.backgroundMap=t,i.backgroundAlpha=1}else if(e.background.isCubeTexture){if(e.background!==this._previousBackground){const t=new kr(this._renderer).generate(e.background);this._internalBackground=t,i.backgroundMap=t,i.backgroundAlpha=1}}else i.backgroundMap=e.background,i.backgroundAlpha=1;if(i.environmentIntensity=e.environmentIntensity??1,i.environmentRotation.makeRotationFromEuler(e.environmentRotation).invert(),this._previousEnvironment!==e.environment)if(e.environment!==null)if(e.environment.isCubeTexture){const t=new kr(this._renderer).generate(e.environment);i.envMapInfo.updateFrom(t)}else i.envMapInfo.updateFrom(e.environment);else i.environmentIntensity=0;this._previousEnvironment=e.environment,this._previousBackground=e.background,this.reset()}_updateFromResults(e,i,t){const{materials:n,geometry:a,bvh:r,bvhChanged:c}=t;this._materials=n;const h=this._pathTracer.material;return c&&(h.bvh.updateFrom(r),h.attributesArray.updateFrom(a.attributes.normal,a.attributes.tangent,a.attributes.uv,a.attributes.color),h.materialIndexAttribute.updateFrom(a.attributes.materialIndex)),this._previousScene=e,this.scene=e,this.camera=i,this.updateCamera(),this.updateMaterials(),this.updateEnvironment(),this.updateLights(),t}renderSample(){const e=this._lowResPathTracer,i=this._pathTracer,t=this._renderer,n=this._clock,a=this._quad;this._updateScale(),this._queueReset&&(i.reset(),e.reset(),this._queueReset=!1,a.material.opacity=0,n.start());const r=n.getDelta()*1e3,c=n.getElapsedTime()*1e3;if(!this.pausePathTracing&&this.enablePathTracing&&this.renderDelay<=c&&!this.isCompiling&&i.update(),i.alpha=i.material.backgroundAlpha!==1||!No(t),e.alpha=i.alpha,this.renderToCanvas){const l=this._renderer,h=this.minSamples;if(c>=this.renderDelay&&this.samples>=this.minSamples&&(this.fadeDuration!==0?a.material.opacity=Math.min(a.material.opacity+r/this.fadeDuration,1):a.material.opacity=1),!this.enablePathTracing||this.samples<h||a.material.opacity<1){if(this.dynamicLowRes&&!this.isCompiling){e.samples<1&&(e.material=i.material,e.update());const f=a.material.opacity;a.material.opacity=1-a.material.opacity,a.material.map=e.target.texture,a.render(l),a.material.opacity=f}(!this.dynamicLowRes&&this.rasterizeScene||this.dynamicLowRes&&this.isCompiling)&&this.rasterizeSceneCallback(this.scene,this.camera)}this.enablePathTracing&&a.material.opacity>0&&(a.material.opacity<1&&(a.material.blending=this.dynamicLowRes?Vs:Wr),a.material.map=i.target.texture,this.renderToCanvasCallback(i.target,l,a),a.material.blending=vt)}}reset(){this._queueReset=!0,this._pathTracer.samples=0}dispose(){this._renderQuad.dispose(),this._renderQuad.material.dispose(),this._pathTracer.dispose()}_updateScale(){if(this.synchronizeRenderSize){this._renderer.getDrawingBufferSize(Ke);const e=Math.floor(this.renderScale*Ke.x),i=Math.floor(this.renderScale*Ke.y);if(this._pathTracer.getSize(Ke),Ke.x!==e||Ke.y!==i){const t=this.lowResScale;this._pathTracer.setSize(e,i),this._lowResPathTracer.setSize(Math.floor(e*t),Math.floor(i*t))}}}}const Yo=""+new URL("lightroom_14b_512-nMVn659Q.hdr",import.meta.url).href;export{ue as E,et as F,Yo as H,Di as M,jo as O,qo as P,Go as W,Vo as r};
|