@soonspacejs/plugin-heat-cloud 2.13.5 → 2.13.7
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/README.md +17 -17
- package/dist/index.esm.js +3360 -1
- package/dist/index.esm.js.map +1 -0
- package/package.json +3 -3
- package/dist/demo.d.ts +0 -1
- package/dist/index.d.ts +0 -26
- package/dist/types.d.ts +0 -8
package/dist/index.esm.js
CHANGED
|
@@ -1 +1,3360 @@
|
|
|
1
|
-
import{TextureLoader as t,Texture as e,Matrix3 as n,Vector3 as i,Vector4 as a,Vector2 as o,AlphaFormat as r,RedFormat as s,RedIntegerFormat as l,RGFormat as c,RGIntegerFormat as u,RGBAFormat as d,RGBAIntegerFormat as m,LuminanceFormat as p,LuminanceAlphaFormat as f,DepthFormat as h,DepthStencilFormat as v,ShaderMaterial as g,GLSL3 as x,Matrix4 as _,DoubleSide as y,Mesh as w,BoxGeometry as M,Data3DTexture as z,FloatType as D,LinearFilter as S,UnsignedByteType as b,Color as C,FrontSide as N,UniformsUtils as U,ShaderLib as A,Points as P,PlaneGeometry as O,Box3 as I,Line3 as T,Quaternion as F,BackSide as R,RawShaderMaterial as V,BufferGeometry as E,Float32BufferAttribute as G,Uint8ClampedBufferAttribute as j}from"three";import L from"soonspacejs";var B,k=(t=>(t[t.x=0]="x",t[t.y=1]="y",t[t.z=2]="z",t))(k||{});(B=k||(k={})).toKey=function(t){return B[t]},B.toIndex=function(t){return B[t]},B.getCrossAxiss=function(t){return[(t+1)%3,(t+2)%3]};var H=(t=>(t[t.x=0]="x",t[t.y=1]="y",t[t.z=2]="z",t[t.w=3]="w",t))(H||{});(t=>{t.toKey=function(e){return t[e]},t.toIndex=function(e){return t[e]},t.getCrossAxiss=function(t){return[(t+1)%4,(t+2)%4]}})(H||(H={}));var q=Object.defineProperty,K=(t,e,n)=>(((t,e,n)=>{e in t?q(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n})(t,"symbol"!=typeof e?e+"":e,n),n);function W(t,e,n,i="srgb"){const a=new OffscreenCanvas(e,n).getContext("2d"),o=a.createLinearGradient(0,0,256,1);for(const[e,n]of t)o.addColorStop(Number(e),n);return a.fillStyle=o,a.fillRect(0,0,e,n),a.getImageData(0,0,e,n,{colorSpace:i})}function Y(t,e){let{area:n,width:i,height:a,colorSpace:o}=e||{};o=o??"srgb",n=n||{};const r=n.x??0,s=n.y??0,l=X(t),c=n.width??l.width,u=n.height??l.height;i=i??c,a=a??u;const d=new OffscreenCanvas(i,a).getContext("2d");return d.drawImage(t,r,s,c,u,0,0,i,a),d.getImageData(0,0,i,a,{colorSpace:o})}function X(t){let e=0,n=0;return t instanceof HTMLImageElement?(e=t.naturalWidth,n=t.naturalHeight):t instanceof HTMLVideoElement?(e=t.videoWidth,n=t.videoHeight):(e=t.width,n=t.height),{width:e,height:n}}function Z(t){const{data:e,width:n,height:i,colorSpace:a}=t,o=e.length,r=new Uint8ClampedArray(o);for(let t=0;t<i;t++){const i=t*n,a=-(i+n),o=a+n,s=e.slice(4*a,4*o);r.set(s,4*i)}return new ImageData(r,n,i,{colorSpace:a})}function J(t,e){const{data:n,width:i}=t,a=e*i,o=a+i;return n.slice(4*a,4*o)}function Q(t,e,n){const{data:i,width:a}=t,o=4*(e*a+n);return i.slice(o,o+4)}function $(t){const e=document.createElement("canvas"),n=e.getContext("2d");return e.width=t.width,e.height=t.height,n.putImageData(t,0,0),e}function tt(t){return $(t).toDataURL()}function et(t){return t&&null!=t.data&&null!=t.width&&null!=t.height}function nt(t){return et(t)&&null!=t.depth}function it(t,e){for(const[n,i]of Object.entries(t))if(0<=i&&i<=e[n])return!0;return!1}function at(t,e){const{x:n,y:i}=e;return t.z*i*n+t.y*n+t.x}function ot(t,e){const{x:n,y:i}=e,a=Math.trunc(t/n),o=t-a*n,r=Math.trunc(a/i);return{x:o,y:a-r*i,z:r}}function rt(t,e,n=1){let{x:i,y:a,z:o}=e;const r=t.size;return i=Math.max(0,Math.min(r.x-1,i)),a=Math.max(0,Math.min(r.y-1,a)),o=Math.max(0,Math.min(r.z-1,o)),st(t,{x:i,y:a,z:o},n)}function st(t,e,n=1){const{data:i,size:a}=t,o=at(e,a);let r=[];if(n>0){const t=o*n;for(let e=0;e<n;e++)r.push(i[t+e])}return{index:o,value:r}}function lt(t,e){let{x:n,y:i,z:a}=e;const o=t.size;return n=Math.max(0,Math.min(o.x-1,n)),i=Math.max(0,Math.min(o.y-1,i)),a=Math.max(0,Math.min(o.z-1,a)),ct(t,{x:n,y:i,z:a})}function ct(t,e){const{data:n,size:i}=t,a=at(e,i);return{index:a,value:n[a]}}function ut(t,e){const{voidValue:n,valuesAccumulate:i,verifyVoid:a=(()=>!1)}=e;let{x:o,y:r,z:s}=t[0].size;const l=t.length;for(let e=1;e<l;e++){const n=t[e].size;o=Math.max(o,n.x),r=Math.max(r,n.y),s=Math.max(s,n.z)}const c=new Array(o*r*s),u=o*r;for(let e=0;e<s;e++){const s=e*u;for(let l=0;l<r;l++){const r=s+l*o;for(let s=0;s<o;s++){const o=r+s,u={x:s,y:l,z:e},d=[];for(const n of t){const t=n.size;if(s<t.x&&l<t.y&&e<t.z)continue;const{index:i,value:o}=ct(n,u);a(o,n,i)||d.push({value:o,index:i,data3D:n,coord:u})}const m=d.length;let p=n;m>1?p=i(d):1===m&&(p=d[0].value),c[o]=p}}}return{data:c,size:{x:o,y:r,z:s}}}function dt(t,e,n,i=1){const{size:a}=t,o=k.toKey(e),[r,s]=k.getCrossAxiss(e),l=k.toKey(r),c=k.toKey(s),u=a[l],d=a[c],m=[],p=a[o];n=Math.trunc(n),n=Math.max(0,Math.min(p-1,n));let f={x:0,y:0,z:0};f[o]=n;for(let e=0;e<d;e++){f[c]=e;for(let e=0;e<u;e++){f[l]=e;const{value:n}=st(t,f,i);m.push(...n)}}return{data:m,size:{x:u,y:d}}}function mt(t,e,n){e=Math.trunc(e);const{data:i,width:a,height:o,colorSpace:r}=n?Z(t):t,s=i.length,l=new Uint8ClampedArray(s*e);for(let t=0;t<e;t++)l.set(i,t*s);return{data:l,width:a,height:o,depth:e,colorSpace:r}}function pt(t,e,n){const i=n||{},a=i.reverseY,o=i.axis??"z",r=et(t)?t:Y(t,i);return"z"===o?mt(r,e,a):ft(r,o,e,a)}function ft(t,e,n,i){n=Math.trunc(n);const{data:a,width:o,height:r,colorSpace:s}=i?Z(t):t,l=k.toKey(e),c=(e+1)%3,u=(e+2)%3,d=k.toKey(c),m=k.toKey(u),p={[d]:o,[m]:r,[l]:n},f=new Uint8ClampedArray(a.length*n),h={x:0,y:0,z:0};for(let t=0;t<n;t++){h[l]=t;for(let t=0;t<r;t++){h[m]=t;for(let e=0;e<o;e++){h[d]=e;const n=4*(t*o+e),i=n+4,r=a.subarray(n,i),s=4*at(h,p);f.set(r,s)}}}return{data:f,width:p.x,height:p.y,depth:p.z,colorSpace:s}}function ht(t,e){return t.y*e.x+t.x}function vt(t,e){const{x:n}=e,i=Math.trunc(t/n);return{x:t-i*n,y:i}}function gt(t,e,n=1){let{x:i,y:a}=e;const o=t.size;return i=Math.max(0,Math.min(o.x-1,i)),a=Math.max(0,Math.min(o.y-1,a)),xt(t,{x:i,y:a},n)}function xt(t,e,n=1){const{data:i,size:a}=t,o=ht(e,a);let r=[];if(n>0){const t=o*n;for(let e=0;e<n;e++)r.push(i[t+e])}return{index:o,value:r}}function _t(t,e){let{x:n,y:i}=e;const a=t.size;return n=Math.max(0,Math.min(a.x-1,n)),i=Math.max(0,Math.min(a.y-1,i)),yt(t,{x:n,y:i})}function yt(t,e){const{data:n,size:i}=t,a=ht(e,i);return{index:a,value:n[a]}}function wt(t,e,n=1){const{data:i,size:a}=t,o=a.x,r=e*o,s=r+o;return("function"==typeof i.slice?i:Array.from(i)).slice(r*n,s*n)}class Mt{constructor(t){K(this,"isImageData3DSlice",!0),K(this,"_image3D"),K(this,"_canvas"),K(this,"_context"),K(this,"_axis",k.z),K(this,"_depth",0),K(this,"_sliceSize",null),K(this,"_slice"),this.image3D=t}get image3D(){return this._image3D}set image3D(t){this._image3D=t,this.updateSize()}get canvas(){let t=this._canvas;return t||(t=this._canvas=document.createElement("canvas"),t.width=this.sliceSize.x,t.height=this.sliceSize.y),t}get context(){return this._context??(this._context=this.canvas.getContext("2d"))}get axis(){return this._axis}set axis(t){this._axis=t,this.updateSize()}get depth(){return this._depth}set depth(t){this._depth=t,this.updateSlice()}get sliceSize(){let t=this._sliceSize;if(!t){const{axis:e,image3D:n}=this,{width:i,height:a,depth:o}=n,[r,s]=k.getCrossAxiss(e),l=[i,a,o];this._sliceSize=t={x:l[r],y:l[s]}}return t}get slice(){return this._slice??(this._slice=this.getSlice(this.axis,this.depth))}getSlice(t,e){const{data:n,width:i,height:a,depth:o,colorSpace:r}=this.image3D,{data:s,size:l}=dt({data:n,size:{x:i,y:a,z:o}},t,e,4),c=s instanceof Uint8ClampedArray?s:Uint8ClampedArray.from(s);return new ImageData(c,l.x,l.y,{colorSpace:r})}getDataURL(){return this.canvas.toDataURL()}getColor(t){const{x:e,y:n}=t;return Q(this.slice,n,e)}updateSize(){this._sliceSize=null;const t=this.canvas;t.width=this.sliceSize.x,t.height=this.sliceSize.y,this.updateSlice()}updateSlice(){this._slice=null,this.context.putImageData(this.slice,0,0)}}var zt=Object.defineProperty,Dt=(t,e,n)=>(((t,e,n)=>{e in t?zt(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n})(t,"symbol"!=typeof e?e+"":e,n),n);function St(t){const e=t.length,n=[];if(0===e)return n;const[r,s]=function(t){return void 0!==t.w?[a,4]:void 0!==t.z?[i,3]:[o,2]}(t[0]);for(let i=0;i<e;i++){const a=t[i],o=(new r).copy(a),s=a.radius,l=n[i]??(n[i]=[]);for(let a=i+1;a<e;a++){const e=t[a];o.distanceToSquared(e)<=(e.radius+s)**2&&(l.push(a),(n[a]=[]).push(i))}}return n}let bt;function Ct(n){if("string"==typeof n)return(bt||(bt=new t)).load(n);if(n.isTexture)return n;const i=Array.isArray(n)?W(n,256,1):n,a=new e(i);return"srgb"===i.colorSpace&&(a.colorSpace="srgb"),a.needsUpdate=!0,a}function Nt(t,e,n){let i=function(t,e){const n=Math.sqrt(t.lengthSq()*e.lengthSq());if(0===n)return 0;let i=t.dot(e)/n;return i=Math.max(-1,Math.min(1,i)),Math.acos(i)}(t,e);return 0===i?i:t.clone().cross(e).dot(n)<0?-i:i}const Ut=180/Math.PI,At={yaw:[{name:"前",range:[-15,15]},{name:"左",range:[15,165]},{name:"右",range:[-165,-15]},{name:"后",range:[-180.1,-165]},{name:"后",range:[165,180.1]}],pitch:[{name:"前",range:[-15,15]},{name:"上",range:[15,165]},{name:"下",range:[-165,-15]},{name:"后",range:[-180.1,-165]},{name:"后",range:[165,180.1]}],roll:[{name:"上",range:[-15,15]},{name:"左",range:[15,165]},{name:"右",range:[-165,-15]},{name:"下",range:[-180.1,-165]},{name:"下",range:[165,180.1]}]};const Pt={degrees:!0,map:At,front:{x:0,y:0,z:1},up:{x:0,y:1,z:0}};let Ot=class{constructor(t){Dt(this,"_options"),Dt(this,"_listMap"),Dt(this,"_front"),Dt(this,"_up"),t&&(this.options=t)}static get options(){return this._options??(this.options=Pt)}static set options(t){this._options=Object.assign({},structuredClone(At),t)}get defaultOptions(){return this.constructor.options}get options(){return this._options??(this.options=this.defaultOptions)}set options(t){this._options=Object.assign({},structuredClone(this.defaultOptions),t),this._listMap=null,this._front=null,this._up=null}get degrees(){return this.options.degrees??(this.options.degrees=this.defaultOptions.degrees??!0)}set degrees(t){this.options.degrees=t}get map(){return this.options.map||(this.map=this.defaultOptions.map),this.options.map}set map(t){const e=structuredClone(this.defaultOptions.map),n=structuredClone(At);t=t?{yaw:t.yaw??e.yaw??n.yaw,pitch:t.pitch??e.pitch??n.pitch,roll:t.roll??e.roll??n.roll}:e,this.options.map=t,this._listMap=null}get listMap(){return this._listMap??(this._listMap=function(t){const e={};for(const[n,i]of Object.entries(t))e[n]=Array.isArray(i)?i:Object.entries(i).map((([t,e])=>({name:t,range:e})));return e}(this.map??{}))}get front(){return this._front||(this.front=this.options.front??this.defaultOptions.front??Pt.front),this._front}set front(t){this._front=(new i).copy(t)}get up(){return this._up||(this.up=this.options.up??this.defaultOptions.up??Pt.up),this._up}set up(t){this._up=(new i).copy(t)}computeAzimuth(t,e,n){const a=(new i).copy(t),o=(new i).copy(e??this.front),r=(new i).copy(n??this.up);let{yaw:s,pitch:l,roll:c}=function(t,e,n){const i=e.clone().negate(),a=n.clone().projectOnPlane(e),o=Nt(e,t.clone().projectOnPlane(a),a),r=e.clone().cross(a);return{yaw:o,pitch:Nt(e,t.clone().projectOnPlane(r),r),roll:Nt(a,t.clone().projectOnPlane(i),i)}}(a,o,r);return this.degrees&&(s*=Ut,l*=Ut,c*=Ut),{yaw:{angle:s,name:this.findAzimuthNames("yaw",s)},pitch:{angle:l,name:this.findAzimuthNames("pitch",l)},roll:{angle:c,name:this.findAzimuthNames("roll",c)}}}findAzimuthNames(t,e){const n=[],i=this.listMap[t];if(!i)return n;for(const{name:t,range:[a,o]}of i)(e>=a&&e<o||e<=a&&e>o)&&n.push(t);return n}};Dt(Ot,"_options"),new Ot;const It={[r]:1,[s]:1,[l]:1,[c]:3,[u]:2,[d]:4,[m]:4,[p]:1,[f]:2,[h]:1,[v]:2};function Tt(t){return It[t]}new n;var Ft=Object.defineProperty,Rt=(t,e,n)=>(((t,e,n)=>{e in t?Ft(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n})(t,"symbol"!=typeof e?e+"":e,n),n);var Vt=(t=>(t[t.Fill=0]="Fill",t[t.Align=1]="Align",t[t.Raw=2]="Raw",t))(Vt||{});class Et extends g{constructor(t){const{map:e,opacity:n,accFactor:a,steps:r,alphaRange:s,fit:l,atomize:c,side:u,containerMin:d,containerMax:m,uniforms:p,...f}=t??{},h=n??1,v=a??1,g=r??100,_=(new o).copy(s??{x:0,y:.95}),y=l??0,w=c??!0,M=u??N,z=(new i).copy(d??{x:0,y:0,z:0}),D=new i;if(m)D.copy(m);else if(e){const{width:t,height:n,depth:a}=e.image,o=new i(t-1,n-1,a-1);D.addVectors(z,o)}const S={map:{value:e},containerMin:{value:z},containerMax:{value:D},fit:{value:y},opacity:{value:h},alphaRange:{value:_},accFactor:{value:v},steps:{value:g},isDoubleSide:{value:!1},atomize:{value:w},...p};super({glslVersion:x,uniforms:S,transparent:!0,vertexShader:"precision highp sampler3D;\n\nuniform sampler3D map;\nuniform vec3 containerMin;\nuniform vec3 containerMax;\n\n// 0: 充满;1: 对齐;2: 原始\nuniform int fit;\n\n\nout vec3 cameraPos;\nout vec3 lookDir;\nout vec3 displayMin;\nout vec3 displayMax;\n\n\n\nvoid main() {\n cameraPos = vec3( inverse( modelMatrix ) * vec4( cameraPosition, 1.0 ) ).xyz;\n lookDir = position - cameraPos;\n\n vec3 containerSize = containerMax - containerMin;\n vec3 origin = containerMin;\n vec3 textSize = vec3(textureSize(map,0));\n displayMin = containerMin;\n displayMax = containerMax;\n\n switch (fit) {\n case 1:\n displayMax = displayMin + textSize;\n break;\n case 2:\n origin = vec3(0.0);\n break;\n default:\n textSize = containerSize;\n }\n\n vec3 scale = 1.0/textSize;\n cameraPos = (cameraPos - origin)*scale;\n lookDir *= scale;\n\n displayMin = max((displayMin - origin)*scale,vec3(0.0));\n displayMax = min((displayMax - origin)*scale,vec3(1.0));\n \n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",...f}),Rt(this,"isVolumeMaterial",!0),Rt(this,"_side",N),this.opacity=h,this.side=M}get map(){return this.uniforms.map.value}set map(t){this.uniforms.map.value=t,this.uniformsNeedUpdate=!0}get containerMin(){return this.uniforms.containerMin.value}set containerMin(t){this.uniforms.containerMin.value.copy(t),this.uniformsNeedUpdate=!0}get containerMax(){return this.uniforms.containerMax.value}set containerMax(t){this.uniforms.containerMax.value.copy(t),this.uniformsNeedUpdate=!0}get containerSize(){return this.containerMax.clone().sub(this.containerMin)}get fit(){return this.uniforms.fit.value}set fit(t){this.uniforms.fit.value=t,this.uniformsNeedUpdate=!0}getFitTranslate(){return 2===this.fit?new i:this.containerMin.clone()}getFitScale(){var t;const e=new i(1,1,1),n=null==(t=this.map)?void 0:t.image,a=this.fit;if(!n||2===a||1===a)return e;const o=new i(n.width,n.height,n.depth);return e.copy(this.containerSize).divide(o),e}getFitMatrix(){var t;const e=new _,n=null==(t=this.map)?void 0:t.image,a=this.fit;if(!n||2===a)return e;if(0===a){const t=new i(n.width,n.height,n.depth),a=this.containerSize.divide(t);e.makeScale(a.x,a.y,a.z)}return e.setPosition(this.containerMin),e}getFitMatrixInvert(){return this.getFitMatrix().invert()}get side(){return this._side}set side(t){this._side=t,this.uniforms&&(this.uniforms.isDoubleSide.value=t===y,this.uniformsNeedUpdate=!0)}get opacity(){return this.uniforms.opacity.value}set opacity(t){this.uniforms&&(this.uniforms.opacity.value=t),this.uniformsNeedUpdate=!0}get alphaRange(){return this.uniforms.alphaRange.value}set alphaRange(t){this.uniforms.alphaRange.value.copy(t),this.uniformsNeedUpdate=!0}get atomize(){return this.uniforms.atomize.value}set atomize(t){this.uniforms.atomize.value=t,this.uniformsNeedUpdate=!0}get steps(){return this.uniforms.steps.value}set steps(t){this.uniforms.steps.value=t,this.uniformsNeedUpdate=!0}get accFactor(){return this.uniforms.accFactor.value}set accFactor(t){this.uniforms&&(this.uniforms.accFactor.value=t),this.uniformsNeedUpdate=!0}toMapPosition(t){const e=new i(t.x,t.y,t.z).applyMatrix4(this.getFitMatrixInvert());return e.set(Math.trunc(e.x),Math.trunc(e.y),Math.trunc(e.z)),e}toMapDepth(t,e){const a=k.toKey(t),o=new i;o[a]=1;const r=(new n).setFromMatrix4(this.getFitMatrix());return o.applyMatrix3(r),e/=o.length(),Math.trunc(e)}getData3DSlice(t,e){const n=this.map;return null!=n&&n.image?function(t,e,n){const{data:i,width:a,height:o,depth:r}=t.image;return dt({data:i,size:{x:a,y:o,z:r}},e,n,Tt(t.format))}(n,t,e=this.toMapDepth(t,e)):null}getItem(t){const e=this.map;return null!=e&&e.image?function(t,e){const{data:n,width:i,height:a,depth:o}=t.image;return rt({data:n,size:{x:i,y:a,z:o}},e,Tt(t.format))}(e,this.toMapPosition(t)).value:null}}function Gt(t){t.boundingBox||t.computeBoundingBox();const{x:e,y:n,z:i}=t.boundingBox.min;return t.translate(-e,-n,-i),t}class jt extends w{constructor(t){var e;const{width:n,height:i,depth:a}=(null==(e=t.map)?void 0:e.image)||{},o=new M(n,i,a);Gt(o),super(o,t),Rt(this,"isVolumeMesh",!0),Rt(this,"_geometry"),Rt(this,"autoUpdateMaterial",!0),Rt(this,"_material"),Rt(this,"autoUpdateGeometry",!0),Rt(this,"autoNormalize",!1),Object.defineProperties(this,{geometry:{get:()=>this._geometry,set:t=>{this._geometry=t,this.autoNormalize?this.normalize():this.autoUpdateMaterial&&this.updateMaterial()}},material:{get:()=>this._material,set:t=>{this._material=t,this.autoUpdateGeometry&&this.updateGeometry()}}}),this.geometry=o,this.material=t}updateMaterial(){const{geometry:t,material:e}=this;if(!e||!t)return!1;t.boundingBox||t.computeBoundingBox();const{min:n,max:i}=t.boundingBox;e.containerMin=n,e.containerMax=i}updateGeometry(){var t;const{geometry:e,material:n,autoUpdateMaterial:a}=this,o=null==(t=n.map)?void 0:t.image;if(!o)return!1;e.boundingBox||e.computeBoundingBox();const{width:r,height:s,depth:l}=o,c=e.boundingBox.getSize(new i);e.scale(r/c.x,s/c.y,l/c.z),a&&this.updateMaterial()}normalize(){const{geometry:t,autoUpdateMaterial:e}=this;t.boundingBox||t.computeBoundingBox();const{x:n,y:i,z:a}=t.boundingBox.min;t.translate(-n,-i,-a),e&&this.updateMaterial()}toMapPosition(t){const e=this.worldToLocal(new i(t.x,t.y,t.z));return this.material.toMapPosition(e)}toMaterialDepth(t,e){const a=k.toKey(t),o=new i;o[a]=1;const r=(new n).setFromMatrix4(this.matrixWorld);return o.applyMatrix3(r),e/=o.length()}toMapDepth(t,e){return e=this.toMaterialDepth(t,e),this.material.toMapDepth(t,e)}getData3DSlice(t,e){return e=this.toMaterialDepth(t,e),this.material.getData3DSlice(t,e)}getItem(t){const e=this.worldToLocal(new i(t.x,t.y,t.z));return this.material.getItem(e)}}class Lt extends Et{constructor(t){const{gradient:e,range:n,discardOut:i,voidRange:a,...r}=t??{},s=(new o).copy(n??{x:0,y:100}),l=i??!0,c=(new o).copy(a??{x:-100,y:-1});super({...r,fragmentShader:"precision highp float;\nprecision highp sampler3D;\n\nuniform sampler3D map;\nuniform sampler2D gradient;\n\nuniform bool atomize;\nuniform float steps;\n// 颜色累积系数\nuniform float accFactor;\nuniform vec2 range;\n// 是否丢弃超出范围的像素\nuniform bool discardOut;\n// 空值范围\nuniform vec2 voidRange;\nuniform float opacity;\nuniform vec2 alphaRange;\nuniform bool isDoubleSide;\n\nin vec3 cameraPos;\nin vec3 lookDir;\nin vec3 displayMin;\nin vec3 displayMax;\nout vec4 fragColor;\n\nvec4 colorBlend(vec4 near,vec4 far){\n float nA = near.a;\n if (nA >= 1.0){\n return near;\n }\n if (nA <= 0.0){\n return far;\n }\n \n float fA = far.a;\n float a = fA + nA - fA*nA;\n vec3 color = (far.rgb * fA * (1.0 - nA) + near.rgb*nA)/a;\n return vec4(color,a);\n}\n\n\n\n\nvec2 intersectBox( vec3 orig, vec3 dir ) {\n vec3 inv_dir = 1.0 / dir;\n vec3 tmin_tmp = (displayMin - orig ) * inv_dir;\n vec3 tmax_tmp = (displayMax - orig ) * inv_dir;\n vec3 tmin = min( tmin_tmp, tmax_tmp );\n vec3 tmax = max( tmin_tmp, tmax_tmp );\n float t0 = max( tmin.x, max( tmin.y, tmin.z ) );\n float t1 = min( tmax.x, min( tmax.y, tmax.z ) );\n return vec2( t0, t1 );\n}\n\nfloat getValue( vec3 point ) {\n return texture( map, point ).r;\n}\n\n// 获取梯度颜色\nvec4 getGradientColor(float val) {\n val = clamp( val, 0.0,1.0);\n return texture2D(gradient, vec2(val, 0.5));\n}\n\n\n\n\nvoid main(){\n vec3 rayDir = normalize( lookDir );\n\n vec2 times = intersectBox( cameraPos, rayDir );\n float tMin = times.x;\n float tMax = times.y;\n if ( tMin > tMax || tMax < 0.0 ) discard;\n tMin = max( tMin, 0.0 );\n\n vec3 point = cameraPos + tMin * rayDir;\n \n float step = 1.0/steps;\n float opacityFactor = atomize ? step * accFactor : 1.0;\n\n\n float invRangeLen = 1.0/(range.y - range.x);\n vec3 stepDir = rayDir * step;\n\n vec4 finalColor = vec4( 0,0,0,0);\n float alphaMax = alphaRange.y;\n\n for ( float t = tMin; t <= tMax; t += step,point += stepDir ) {\n float val = getValue( point);\n if (voidRange.x <= val && val <= voidRange.y ) continue;\n val = (val - range.x) * invRangeLen;\n if (discardOut && (val < 0.0 || val > 1.0)) continue;\n\n vec4 gradientColor = getGradientColor(val);\n gradientColor.a *= opacityFactor;\n finalColor = colorBlend(finalColor,gradientColor);\n if ( finalColor.a >= alphaMax ) break;\n }\n\n finalColor.a *= opacity;\n if ( finalColor.a <= alphaRange.x ) discard;\n if (isDoubleSide){\n finalColor.a = 1.0 - sqrt(1.0 - finalColor.a);\n }\n fragColor = finalColor;\n\n}",uniforms:{gradient:{value:null==e?e:Ct(e)},range:{value:s},discardOut:{value:l},voidRange:{value:c}}}),Rt(this,"isGradientVolumeMaterial",!0)}get gradient(){return this.uniforms.gradient.value}set gradient(t){this.uniforms.gradient.value=t,this.uniformsNeedUpdate=!0}get range(){return this.uniforms.range.value}set range(t){this.uniforms.range.value.copy(t),this.uniformsNeedUpdate=!0}get discardOut(){return this.uniforms.discardOut.value}set discardOut(t){this.uniforms.discardOut.value=t,this.uniformsNeedUpdate=!0}get voidRange(){return this.uniforms.voidRange.value}set voidRange(t){this.uniforms.voidRange.value.copy(t),this.uniformsNeedUpdate=!0}}class Bt extends z{constructor(t,e,n,i,a){super(t,e,n,i),Rt(this,"isGradientData3DTexture",!0),this.format=s,this.type=a??D,this.minFilter=this.magFilter=S,this.unpackAlignment=1,this.needsUpdate=!0}getData3DSlice(t,e){const{data:n,width:i,height:a,depth:o}=this.image;return dt({data:n,size:{x:i,y:a,z:o}},t,e,1)}getItem(t){const{data:e,width:n,height:i,depth:a}=this.image;return rt({data:e,size:{x:n,y:i,z:a}},t).value}getValue(t){const{data:e,width:n,height:i,depth:a}=this.image;return lt({data:e,size:{x:n,y:i,z:a}},t).value}}function kt(t,e){const{data:n,size:i}=t,{x:a,y:o,z:r}=i,s=a*o*r,{voidValue:l=0,uint8:c}=e??{};let u;if(c){u=new Uint8Array(s);for(let t=0;t<s;t++){const e=n[t]??l;u[t]=Math.trunc(e)}}else{u=new Float32Array(s);for(let t=0;t<s;t++){const e=n[t]??l;u[t]=e}}return new Bt(u,a,o,r,c?b:D)}class Ht extends Et{constructor(t){super({...t,fragmentShader:"precision highp float;\nprecision highp sampler3D;\n\nuniform sampler3D map;\n\n\n\n// 颜色累积系数\nuniform float accFactor;\nuniform bool isDoubleSide;\nuniform bool atomize;\n\n\nuniform float opacity;\nuniform vec2 alphaRange;\nuniform float steps;\n\nin vec3 cameraPos;\nin vec3 lookDir;\nin vec3 displayMin;\nin vec3 displayMax;\nout vec4 fragColor;\n\n// 混合颜色\nvec4 colorBlend(vec4 near,vec4 far){\n float nA = near.a;\n if (nA >= 1.0){\n return near;\n }\n if (nA <= 0.0){\n return far;\n }\n \n float fA = far.a;\n float a = fA + nA - fA*nA;\n vec3 color = (far.rgb * fA * (1.0 - nA) + near.rgb*nA)/a;\n return vec4(color,a);\n}\n\n\n\n\n// 包围盒求交\nvec2 intersectBox( vec3 orig, vec3 dir ) {\n vec3 inv_dir = 1.0 / dir;\n vec3 tmin_tmp = (displayMin - orig ) * inv_dir;\n vec3 tmax_tmp = (displayMax - orig ) * inv_dir;\n vec3 tmin = min( tmin_tmp, tmax_tmp );\n vec3 tmax = max( tmin_tmp, tmax_tmp );\n float t0 = max( tmin.x, max( tmin.y, tmin.z ) );\n float t1 = min( tmax.x, min( tmax.y, tmax.z ) );\n return vec2( t0, t1 );\n}\n\n\n\nvoid main(){\n vec3 rayDir = normalize( lookDir );\n\n vec2 times = intersectBox( cameraPos, rayDir );\n float tMin = times.x;\n float tMax = times.y;\n if ( tMin > tMax || tMax < 0.0 ) discard;\n tMin = max( tMin, 0.0 );\n\n vec3 point = cameraPos + tMin * rayDir;\n \n float step = 1.0/steps;\n float opacityFactor = atomize ? step * accFactor : 1.0;\n\n vec3 stepDir = rayDir * step;\n\n vec4 finalColor = vec4( 0,0,0,0);\n float alphaMax = alphaRange.y;\n\n for ( float t = tMin; t <= tMax; t += step,point += stepDir ) {\n vec4 textureColor = texture( map, point );\n textureColor.a *= opacityFactor;\n finalColor = colorBlend(finalColor,textureColor);\n if ( finalColor.a >= alphaMax ) break;\n }\n\n finalColor.a *= opacity;\n if ( finalColor.a <= alphaRange.x ) discard;\n if (isDoubleSide){\n finalColor.a = 1.0 - sqrt(1.0 - finalColor.a);\n }\n fragColor = finalColor;\n\n}"}),Rt(this,"isImageVolumeMaterial",!0)}}function qt(t,e,n){const i=n??{},{x:a,y:o}=i.range??{x:0,y:100},r=i.discardOut??!0,{x:s,y:l}=i.voidRange??{x:-100,y:-1},c=i.voidColor??[0,0,0,0],{width:u,height:d}=e,m=Math.trunc(d/2),p=u-1;function f(t){const n=Math.trunc(p*t);return Q(e,m,n)}const h=1/(o-a),{data:v,size:g}=t,x=v.length,_=[];for(let t=0;t<x;t++){let e=c,n=v[t];(n<=s||l<=n)&&(n=(n-a)*h,r&&(n<0||n>1)||(n=Math.min(Math.max(n,0),1),e=f(n))),_.push(...e)}return{data:_,size:g}}class Kt extends z{constructor(t,e,n,i){super(t,e,n,i),Rt(this,"isImageData3DTexture",!0),this.format=d,this.type=b,this.minFilter=this.magFilter=S,this.unpackAlignment=1,this.needsUpdate=!0}getData3DSlice(t,e){const{data:n,width:i,height:a,depth:o}=this.image;return dt({data:n,size:{x:i,y:a,z:o}},t,e,4)}getItem(t){return this.getColor(t)}getColor(t){const{data:e,width:n,height:i,depth:a}=this.image;return rt({data:e,size:{x:n,y:i,z:a}},t,4).value}}function Wt(t,e,n){const i=(null==n?void 0:n.reverseY)??!0,{data:a,width:o,height:r,depth:s,colorSpace:l}=pt(t,e,{...n,reverseY:i}),c=new Kt(a,o,r,s);return"srgb"===l&&(c.colorSpace="srgb"),c}function Yt(t,e){const n=e.gradient,i=Array.isArray(n)?W(n,256,1):et(n)?n:Y(n);let a=t;nt(t)&&(a={data:t.data,size:{x:t.width,y:t.height,z:t.depth}});const{data:o,size:r}=qt(a,i,e),s=Uint8ClampedArray.from(o);return new Kt(s,r.x,r.y,r.z)}class Xt extends g{constructor(t){const e=t??{},n=e.color??new C(1,1,1),i=e.solid??0,a=e.exp??1,o=e.opacity??1,r=e.side??N;super({glslVersion:x,uniforms:{color:{value:n},solid:{value:i},exp:{value:a},opacity:{value:o},isDoubleSide:{value:!1}},vertexShader:"out vec3 lookDir;\nout vec3 normalDir;\n\n#if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )\n out vec4 verColor;\n#endif\n\nvoid main() {\n vec3 cameraPos = vec3( inverse( modelMatrix ) * vec4( cameraPosition, 1.0 ) ).xyz;\n lookDir = position - cameraPos;\n normalDir = normal;\n\n #if defined( USE_COLOR_ALPHA )\n verColor = color;\n #elif defined( USE_INSTANCING_COLOR )\n overColor = vec3(instanceColor,1.0);\n #elif defined( USE_COLOR )\n overColor = vec3(color,1.0);\n #endif\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform vec3 color;\nuniform float solid;\nuniform float exp;\n\nuniform float opacity;\nuniform bool isDoubleSide;\n\nin vec3 lookDir;\nin vec3 normalDir;\n\n#if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )\n in vec4 verColor;\n#endif\n\nout vec4 fragColor;\n\n\nvoid main(){\n #if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )\n fragColor = verColor;\n #else\n fragColor = vec4(color,1.0);\n #endif\n\n vec3 dir = normalize(lookDir);\n vec3 nor = normalize(normalDir);\n float depth = abs(dot(nor,dir));\n float dist = sqrt(1.0 - pow(depth,2.0));\n\n float finalAlpha = fragColor.a * depth;\n if (dist > solid) {\n float distAlpha = 1.0 - (dist - solid)/(1.0 - solid);\n finalAlpha *= pow(distAlpha,exp);\n }\n \n finalAlpha *= opacity;\n if ( finalAlpha == 0.0 ) discard;\n if (isDoubleSide){\n finalAlpha = 1.0 - sqrt(1.0 - finalAlpha);\n }\n fragColor.a = finalAlpha;\n}",side:N,transparent:!0}),Rt(this,"isSphereFogMaterial",!0),Rt(this,"_side",N),this.opacity=o,this.side=r}get side(){return this._side}set side(t){this._side=t,this.uniforms&&(this.uniforms.isDoubleSide.value=t===y,this.uniformsNeedUpdate=!0)}get color(){return this.uniforms.color.value}set color(t){this.uniforms.color.value.copy(t),this.uniformsNeedUpdate=!0}get opacity(){return this.uniforms.opacity.value}set opacity(t){this.uniforms&&(this.uniforms.opacity.value=t),this.uniformsNeedUpdate=!0}get solid(){return this.uniforms.solid.value}set solid(t){this.uniforms&&(this.uniforms.solid.value=t),this.uniformsNeedUpdate=!0}get exp(){return this.uniforms.exp.value}set exp(t){this.uniforms&&(this.uniforms.exp.value=t),this.uniformsNeedUpdate=!0}}class Zt extends g{constructor(t,e){const{solid:n=0,exp:i=1,useRadius:a=!0,sizeAttenuation:o=!0,star:r=!1,...s}=t??{},{uniforms:l,...c}=e||{},u={star:{value:r},solid:{value:n},exp:{value:i}};super({uniforms:U.merge([A.points.uniforms,u,l]),transparent:!0,depthTest:!1,defines:{useRadius:a},...c}),Rt(this,"isFogPointsMaterial",!0),Rt(this,"sizeAttenuation",!0),Object.assign(this,{...s,solid:n,exp:i,sizeAttenuation:o})}get map(){return this.uniforms.map.value}set map(t){this.uniforms.map.value=t,this.uniformsNeedUpdate=!0}get star(){return this.uniforms.star.value}set star(t){this.uniforms.star.value=t,this.uniformsNeedUpdate=!0}get size(){return this.uniforms.size.value}set size(t){this.uniforms.size.value=t,this.uniformsNeedUpdate=!0}get opacity(){return this.uniforms.opacity.value}set opacity(t){this.uniforms&&(this.uniforms.opacity.value=t),this.uniformsNeedUpdate=!0}get solid(){return this.uniforms.solid.value}set solid(t){this.uniforms&&(this.uniforms.solid.value=t),this.uniformsNeedUpdate=!0}get exp(){return this.uniforms.exp.value}set exp(t){this.uniforms&&(this.uniforms.exp.value=t),this.uniformsNeedUpdate=!0}get scale(){return this.uniforms.scale.value}set scale(t){this.uniforms&&(this.uniforms.scale.value=t),this.uniformsNeedUpdate=!0}get fogDensity(){return this.uniforms.fogDensity.value}set fogDensity(t){this.uniforms&&(this.uniforms.fogDensity.value=t),this.uniformsNeedUpdate=!0}get fogNear(){return this.uniforms.fogNear.value}set fogNear(t){this.uniforms&&(this.uniforms.fogNear.value=t),this.uniformsNeedUpdate=!0}get fogFar(){return this.uniforms.fogFar.value}set fogFar(t){this.uniforms&&(this.uniforms.fogFar.value=t),this.uniformsNeedUpdate=!0}get fogColor(){return this.uniforms.fogColor.value}set fogColor(t){this.uniforms.fogColor.value.copy(t),this.uniformsNeedUpdate=!0}}class Jt extends Zt{constructor(t){super(t,{vertexShader:"#ifdef useRadius\n\tattribute float radius;\n#endif\n\nuniform float size;\nuniform float scale;\n\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n\n#ifdef USE_POINTS_UV\n\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n\n#endif\n\nvoid main() {\n\n\t#ifdef USE_POINTS_UV\n\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\n\t#endif\n\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\n\t#ifdef useRadius\n\t\tgl_PointSize = radius;\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\n\t#ifdef USE_SIZEATTENUATION\n\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\n\t#endif\n\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n\n}",fragmentShader:"uniform float solid;\nuniform float exp;\nuniform bool star;\n\nuniform vec3 diffuse;\nuniform float opacity;\n\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\n\n\nvec4 getColor(vec4 originColor){\n\tfloat finalAlpha = originColor.a;\n\tfloat dist = 0.0;\n\tif (star){\n\t\tvec2 coord = abs(gl_PointCoord - vec2(0.5));\n\t\tdist = max(coord.x,coord.y);\n\t}else{\n\t\tdist = distance(gl_PointCoord,vec2(0.5));\n\t\tif (dist>0.5) discard;\n\t}\n\tdist /= 0.5;\n\tfloat depth = sqrt(1.0 - pow(dist,2.0));\n\tfinalAlpha *= depth;\n if (dist > solid) {\n float distAlpha = 1.0 - (dist - solid)/(1.0 - solid);\n finalAlpha *= pow(distAlpha,exp);\n }\n\toriginColor.a = finalAlpha;\n\treturn originColor;\n}\n\nvoid main() {\n\n\t#include <clipping_planes_fragment>\n\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\n\tdiffuseColor = getColor(diffuseColor);\n\toutgoingLight = diffuseColor.rgb;\n\n\t#include <output_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\n}"}),Rt(this,"isColorFogPointsMaterial",!0)}get color(){return this.uniforms.diffuse.value}set color(t){this.uniforms.diffuse.value.copy(t),this.uniformsNeedUpdate=!0}get alphaMap(){return this.uniforms.alphaMap.value}set alphaMap(t){this.uniforms&&(this.uniforms.alphaMap.value=t),this.uniformsNeedUpdate=!0}get uvTransform(){return this.uniforms.uvTransform.value}set uvTransform(t){this.uniforms&&this.uniforms.uvTransform.value.copy(t),this.uniformsNeedUpdate=!0}}function Qt(t){const e=new Jt(t),n=function(t){const{points:e,radius:n=10,color:i=[0,0,0,0]}=t,a=[],o=[],r=[];for(const{x:t,y:s,z:l,radius:c,color:u}of e){a.push(t,s,l),o.push(c??n);const e=u??i,d=e[3];e[3]=Math.trunc(255*d),r.push(...e)}const s=new E;return s.setAttribute("position",new G(a,3)),s.setAttribute("radius",new G(o,1)),s.setAttribute("color",new j(r,4,!0)),s}(t);return new P(n,e)}class $t extends Zt{constructor(t){const{range:e,...n}=t||{};super(n,{vertexShader:"attribute float value;\nuniform vec2 range;\nvarying float vValue;\n#ifdef useRadius\n\tattribute float radius;\n#endif\n\n\nuniform float size;\nuniform float scale;\n\n#include <common>\n// #include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n\n#ifdef USE_POINTS_UV\n\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n\n#endif\n\nvoid main() {\n\tvValue = (value - range.x)/(range.y - range.x);\n\n\t#ifdef USE_POINTS_UV\n\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\n\t#endif\n\n\t// #include <color_vertex>\n\t// #include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\n\t#ifdef useRadius\n\t\tgl_PointSize = radius;\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\n\t#ifdef USE_SIZEATTENUATION\n\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\n\t#endif\n\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n\n}",fragmentShader:"varying float vValue;\nuniform sampler2D map;\n\n\nuniform float solid;\nuniform float exp;\nuniform bool star;\n\n// uniform vec3 diffuse;\nuniform float opacity;\n\n#include <common>\n// #include <color_pars_fragment>\n// #include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\n\n\n// 获取梯度颜色\nvec4 getGradientColor(float val) {\n\tval = clamp( val, 0.0,1.0);\n return texture2D(map, vec2(val, 0.5));\n}\n\n\nvec4 getColor(){\n\tfloat val = vValue;\n\tfloat dist = 0.0;\n\tif (star){\n\t\tvec2 coord = abs(gl_PointCoord - vec2(0.5));\n\t\tdist = max(coord.x,coord.y);\n\t}else{\n\t\tdist = distance(gl_PointCoord,vec2(0.5));\n\t\tif (dist>0.5) discard;\n\t}\n\tdist /= 0.5;\n\tfloat depth = sqrt(1.0 - pow(dist,2.0));\n if (dist > solid) {\n float solidDist = 1.0 - (dist - solid)/(1.0 - solid);\n val *= pow(solidDist,exp);\n }\n\tvec4 valColor = getGradientColor(val);\n\tvalColor.a *= depth * opacity;\n\treturn valColor;\n}\n\nvoid main() {\n\n\t#include <clipping_planes_fragment>\n\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = getColor();\n\n\t#include <logdepthbuf_fragment>\n\t// #include <map_particle_fragment>\n\t// #include <color_fragment>\n\t#include <alphatest_fragment>\n\n\toutgoingLight = diffuseColor.rgb;\n\n\t#include <output_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\n}",uniforms:{range:{value:(new o).copy(e??{x:0,y:100})}}}),Rt(this,"isColorFogPointsMaterial",!0)}get range(){return this.uniforms.range.value}set range(t){this.uniforms.range.value.copy(t),this.uniformsNeedUpdate=!0}}function te(t){const e=t.gradient,n=null==e?e:Ct(e),i=new $t({...t,map:n}),a=function(t){const{points:e,radius:n=10,value:i=100}=t,a=[],o=[],r=[];for(const{x:t,y:s,z:l,radius:c,value:u}of e)a.push(t,s,l),o.push(c??n),r.push(u??i);const s=new E;return s.setAttribute("position",new G(a,3)),s.setAttribute("radius",new G(o,1)),s.setAttribute("value",new G(r,1)),s}(t);return new P(a,i)}class ee extends g{constructor(t){const e=t??{};let{map:n,opacity:i,axis:a,depth:o,side:r,...s}=e;i=i??1,a=a??k.z,o=o??0,r=r??y,super({...s,glslVersion:x,uniforms:{map:{value:n},opacity:{value:i},axis:{value:a},depth:{value:o}},transparent:!0,vertexShader:"\tout vec2 vUv;\n \n\tvoid main() {\n\t\tvUv = uv;\n\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t}",fragmentShader:"precision highp float;\nprecision highp sampler3D;\n\nuniform sampler3D map;\n\nuniform float opacity;\nuniform int axis;\nuniform float depth;\n\nin vec2 vUv;\nout vec4 fragColor;\n\nvoid main(){\n vec3 uv3 = vec3(0.0);\n int depthSize = textureSize(map,0)[axis];\n uv3[axis] = depth/float(depthSize);\n int xIndex = (axis + 1)%3;\n int yIndex = (axis + 2)%3;\n uv3[xIndex] = vUv.x;\n uv3[yIndex] = vUv.y;\n\n fragColor = texture(map, uv3);\n fragColor.a *= opacity;\n}",side:r}),Rt(this,"isSliceMaterial",!0),Rt(this,"_sliceSize",null),this.opacity=i}get map(){return this.uniforms.map.value}set map(t){this.uniforms.map.value=t,this._sliceSize=null,this.uniformsNeedUpdate=!0}get opacity(){return this.uniforms.opacity.value}set opacity(t){this.uniforms&&(this.uniforms.opacity.value=t),this.uniformsNeedUpdate=!0}get axis(){return this.uniforms.axis.value}set axis(t){this.uniforms.axis.value=t,this._sliceSize=null,this.uniformsNeedUpdate=!0}get depth(){return this.uniforms.depth.value}set depth(t){this.uniforms.depth.value=t,this.uniformsNeedUpdate=!0}get sliceSize(){let t=this._sliceSize;if(!t){this._sliceSize=t=new o(1,1);const{axis:e,map:n}=this;if(n){const{width:i,height:a,depth:o}=n.image,[r,s]=k.getCrossAxiss(e),l=[i,a,o];t.set(l[r],l[s])}}return t}}class ne extends w{constructor(t){const e=new ee(t),n=new O;super(n,e),Rt(this,"isSliceMesh",!0),Rt(this,"_geometry"),Rt(this,"_material"),Rt(this,"autoUpdateGeometry",!0),Object.defineProperties(this,{geometry:{get:()=>this._geometry,set:t=>{this._geometry=t,this.autoUpdateGeometry&&this.updateGeometry()}},material:{get:()=>this._material,set:t=>{this._material=t,this.autoUpdateGeometry&&this.updateGeometry()}}}),this.geometry=n,this.material=e}updateGeometry(){var t;const{geometry:e,material:n}=this;if(!n||!(null==(t=n.map)?void 0:t.image))return!1;e.boundingBox||e.computeBoundingBox();const a=n.sliceSize,o=e.boundingBox.getSize(new i);e.scale(a.x/o.x,a.y/o.y,1)}get map(){return this.material.map}set map(t){this.material.map=t,this.material=this.material}get axis(){return this.material.axis}set axis(t){this.material.axis=t,this.material=this.material}get depth(){return this.material.depth}set depth(t){this.material.depth=t}get sliceSize(){return this.material.sliceSize}}class ie extends Mt{constructor(t){super(nt(t)?t:t.image),Rt(this,"isImageData3DTextureSlice",!0)}set texture(t){this.image3D=nt(t)?t:t.image}}function ae({ratio:t,value:e}){return e-e*t}function oe(t,e){const{x:n,y:i}=e;let a=0;for(const{value:e,clim:{x:n,y:i}}of t)a+=(e-n)/(i-n);return a*(i-n)+n}function re(t,e,n){const{size:a,data3D:o,tags:r}=e,{clim:s,radius:l,value:c,hollow:u,valueGradient:d,valuesAccumulate:m}=t,p=(new i).copy(t),f=[],h=[],v={particles:f,values:h},g=l*u,x=p.clone().subScalar(l),_=p.clone().addScalar(l);x.max(new i(0,0,0));const y=(new i).copy(a).subScalar(1);_.min(y);let{x:w,y:M,z:z}=x;w=Math.trunc(w),M=Math.trunc(M),z=Math.trunc(z);let{x:D,y:S,z:b}=_;if(D=Math.trunc(D),S=Math.trunc(S),b=Math.trunc(b),w>D||M>S||z>b)return v;const{x:C,y:N}=a,U=C*N;for(let e=z;e<=b;e++){const a=e*U;for(let v=M;v<=S;v++){const x=a+v*C;t:for(let a=w;a<=D;a++){const _=x+a;if(r[_])continue;const y=new i(a,v,e),w=y.distanceTo(p);if(w>l||w<g)continue;r[_]=!0;const M=[],z={...{radius:l,hollow:u,hollowRadius:g,distance:w,clim:s,value:c},ratio:w/l,distance:w,point:y},D=d(z);M.push({...t,...z,value:D});for(const t of n){const e=y.distanceTo(t),{hollow:n,radius:i}=t;if(e<=i){const a=i*n;if(e<a)continue t;const o={...t,ratio:e/i,distance:e,hollowRadius:a,point:y},r=d(o);M.push({...o,value:r})}}const S=m(M,s);o[_]=S,f.push(y),h.push(S)}}}return v}function se(t){const{points:e,clim:n={x:0,y:100},radius:i=10,value:a=100,hollow:o=0,valueGradient:r=ae,valuesAccumulate:s=oe,size:l}=t,c={clim:n,radius:i,value:a,hollow:o,valueGradient:r,valuesAccumulate:s},u=e.map((t=>({...c,...t})));let d=l;l||(d=(new I).setFromPoints(u).max.addScalar(1));const m=St(u);let{x:p,y:f,z:h}=d;p=d.x=Math.trunc(p),f=d.y=Math.trunc(f),h=d.z=Math.trunc(h);const v=new Array(p*f*h),g={size:d,data3D:v,tags:new Array(p*f*h)},x=u.length;for(let t=0;t<x;t++){re(u[t],g,m[t].map((t=>u[t])))}return{data:v,size:d}}function le({startRadius:t,addedRadius:e,ratio:n}){return e*n+t}function ce({startHollow:t,addedHollow:e,ratio:n}){return e*n+t}function ue({startValue:t,addedValue:e,ratio:n}){return e*n+t}function de(t,e){const{x:n,y:i}=e;return t.reduce(((t,e)=>t+e-n),0)}function me(t){const{points:e,size:n,clim:a={x:0,y:100},radius:o=10,value:r=100,hollow:s=0,valueGradient:l=ae,radiusGradient:c=le,hollowGradient:u=ce,lineValueGradient:d=ue,valuesAccumulate:m=de}=t,p={radius:o,value:r,hollow:s},f=e.map((function(t){return Object.assign(new i,p,t)})),h=n?(new i).copy(n).subScalar(1):(new I).setFromPoints(f).max;h.x=Math.trunc(h.x),h.y=Math.trunc(h.y),h.z=Math.trunc(h.z);const v=h.clone().addScalar(1),{x:g,y:x,z:y}=v,w=g*x,M=new Array(w*y),z=[],D=[],S={particles:z,values:D,size:v,data:M},b=new i(0,0,0),C=e.length,N=Math.trunc(C/2);for(let t=0;t<N;t++){const e=2*t,n=f[e],p=f[e+1],v=new T(n,p),x=v.distance(),y=v.delta(new i).normalize(),C=new F;C.setFromUnitVectors(new i(0,1,0),y);const N=(new _).makeRotationFromQuaternion(C);N.setPosition(n);const{radius:U,value:A,hollow:P}=n,{radius:O,value:R,hollow:V}=p,E={length:x,startRadius:U,endRadius:O,addedRadius:O-U,defaultRadius:o,radius:o,startValue:A,endValue:R,addedValue:R-A,defaultValue:r,startHollow:P,endHollow:V,addedHollow:V-P,defaultHollow:s,clim:a},G=Math.max(U,O),j=new i(-G,0,-G),L=new i(G,x,G),B=new I(j,L);B.applyMatrix4(N);const{min:k,max:H}=B;k.max(b),H.min(h);let{x:q,y:K,z:W}=k;q=Math.trunc(q),K=Math.trunc(K),W=Math.trunc(W);let{x:Y,y:X,z:Z}=H;if(Y=Math.trunc(Y),X=Math.trunc(X),Z=Math.trunc(Z),q>Y||K>X||W>Z)return S;N.invert();for(let t=W;t<=Z;t++){const e=t*w;for(let n=K;n<=X;n++){const o=e+n*g;for(let e=q;e<=Y;e++){const r=o+e,s=new i(e,n,t),p=s.clone();p.applyMatrix4(N);const{x:f,y:h,z:v}=p;if(h<0||h>x)continue;const g=Math.hypot(f,v),_={...E,ratio:h/x,point:s},y=c(_);_.radius=y;const w=u(_),S=y*w;if(g>y||g<S)continue;const b=d(_);let C=l({...E,value:b,ratio:g/y,radius:y,hollow:w,hollowRadius:S,distance:g,point:s});const U=D[r];void 0!==U&&(C=m([U,C],a)),M[r]=C,z.push(s),D.push(C)}}}}return S}function pe(t,e){const a=(new i).setFromMatrixScale(e),o=Math.sqrt(a.lengthSq()/3),r=(new n).setFromMatrix4(e);let{points:s,size:l,radius:c,...u}=t;if(l&&(l=(new i).copy(l).applyMatrix3(r)),c&&(c*=o),s){const t=[];for(let{x:n,y:a,z:r,radius:l,...c}of s){l&&(l*=o);const s=new i(n,a,r).applyMatrix4(e);Object.assign(s,c,{radius:l}),t.push(s)}s=t}return{points:s,size:l,radius:c,...u}}function fe(t,e,n=1){let{points:a,size:o,radius:r,...s}=t;if(r&&(r*=n),a){const t=[];for(let{x:o,y:r,z:s,radius:l,...c}of a){l&&(l*=n);const a=new i(o,r,s).add(e).multiplyScalar(n);Object.assign(a,c,{radius:l}),t.push(a)}a=t}return o&&(o=(new i).copy(o).add(e).multiplyScalar(n)),{points:a,size:o,radius:r,...s}}function he(t,e){const{points:n,radius:a}=t;if(!n)return{options:t,position:new i,scale:1};const o=new I;for(const t of n){const e=(new i).copy(t),n=t.radius??a;n?(o.expandByPoint(e.clone().subScalar(n)),o.expandByPoint(e.addScalar(n))):o.expandByPoint(e)}const r=(new i).max(o.min),s=o.max.clone().sub(r).addScalar(1);t.size&&s.min(t.size);let{scale:l,maxSize:c}=e||{};l||(c=c??100,l=c/Math.max(s.x,s.y,s.z)),s.multiplyScalar(l);const u=fe(t,r.clone().negate(),l);return u.size=s,{options:u,position:r,scale:1/l}}const ve={uniforms:{u_size:{value:new i(1,1,1)},u_renderstyle:{value:0},u_renderthreshold:{value:.5},u_clim:{value:new o(1,1)},u_data:{value:null},u_cmdata:{value:null}},vertexShader:'\n\n\t\tvarying vec4 v_nearpos;\n\t\tvarying vec4 v_farpos;\n\t\tvarying vec3 v_position;\n\n\t\tvoid main() {\n\t\t\t\t// Prepare transforms to map to "camera view". See also:\n\t\t\t\t// https://threejs.org/docs/#api/renderers/webgl/WebGLProgram\n\t\t\t\tmat4 viewtransformf = modelViewMatrix;\n\t\t\t\tmat4 viewtransformi = inverse(modelViewMatrix);\n\n\t\t\t\t// Project local vertex coordinate to camera position. Then do a step\n\t\t\t\t// backward (in cam coords) to the near clipping plane, and project back. Do\n\t\t\t\t// the same for the far clipping plane. This gives us all the information we\n\t\t\t\t// need to calculate the ray and truncate it to the viewing cone.\n\t\t\t\tvec4 position4 = vec4(position, 1.0);\n\t\t\t\tvec4 pos_in_cam = viewtransformf * position4;\n\n\t\t\t\t// Intersection of ray and near clipping plane (z = -1 in clip coords)\n\t\t\t\tpos_in_cam.z = -pos_in_cam.w;\n\t\t\t\tv_nearpos = viewtransformi * pos_in_cam;\n\n\t\t\t\t// Intersection of ray and far clipping plane (z = +1 in clip coords)\n\t\t\t\tpos_in_cam.z = pos_in_cam.w;\n\t\t\t\tv_farpos = viewtransformi * pos_in_cam;\n\n\t\t\t\t// Set varyings and output pos\n\t\t\t\tv_position = position;\n\t\t\t\tgl_Position = projectionMatrix * viewMatrix * modelMatrix * position4;\n\t\t}',fragmentShader:"\n\n\t\t\t\tprecision highp float;\n\t\t\t\tprecision mediump sampler3D;\n\n\t\t\t\tuniform vec3 u_size;\n\t\t\t\tuniform int u_renderstyle;\n\t\t\t\tuniform float u_renderthreshold;\n\t\t\t\tuniform vec2 u_clim;\n\n\t\t\t\tuniform sampler3D u_data;\n\t\t\t\tuniform sampler2D u_cmdata;\n\n\t\t\t\tvarying vec3 v_position;\n\t\t\t\tvarying vec4 v_nearpos;\n\t\t\t\tvarying vec4 v_farpos;\n\n\t\t\t\t// The maximum distance through our rendering volume is sqrt(3).\n\t\t\t\tconst int MAX_STEPS = 887;\t// 887 for 512^3, 1774 for 1024^3\n\t\t\t\tconst int REFINEMENT_STEPS = 4;\n\t\t\t\tconst float relative_step_size = 1.0;\n\t\t\t\tconst vec4 ambient_color = vec4(0.2, 0.4, 0.2, 1.0);\n\t\t\t\tconst vec4 diffuse_color = vec4(0.8, 0.2, 0.2, 1.0);\n\t\t\t\tconst vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);\n\t\t\t\tconst float shininess = 40.0;\n\n\t\t\t\tvoid cast_mip(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray);\n\t\t\t\tvoid cast_iso(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray);\n\n\t\t\t\tfloat sample1(vec3 texcoords);\n\t\t\t\tvec4 apply_colormap(float val);\n\t\t\t\tvec4 add_lighting(float val, vec3 loc, vec3 step, vec3 view_ray);\n\n\n\t\t\t\tvoid main() {\n\t\t\t\t\t\t// Normalize clipping plane info\n\t\t\t\t\t\tvec3 farpos = v_farpos.xyz / v_farpos.w;\n\t\t\t\t\t\tvec3 nearpos = v_nearpos.xyz / v_nearpos.w;\n\n\t\t\t\t\t\t// Calculate unit vector pointing in the view direction through this fragment.\n\t\t\t\t\t\tvec3 view_ray = normalize(nearpos.xyz - farpos.xyz);\n\n\t\t\t\t\t\t// Compute the (negative) distance to the front surface or near clipping plane.\n\t\t\t\t\t\t// v_position is the back face of the cuboid, so the initial distance calculated in the dot\n\t\t\t\t\t\t// product below is the distance from near clip plane to the back of the cuboid\n\t\t\t\t\t\tfloat distance = dot(nearpos - v_position, view_ray);\n\t\t\t\t\t\tdistance = max(distance, min((-0.5 - v_position.x) / view_ray.x,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(u_size.x - 0.5 - v_position.x) / view_ray.x));\n\t\t\t\t\t\tdistance = max(distance, min((-0.5 - v_position.y) / view_ray.y,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(u_size.y - 0.5 - v_position.y) / view_ray.y));\n\t\t\t\t\t\tdistance = max(distance, min((-0.5 - v_position.z) / view_ray.z,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(u_size.z - 0.5 - v_position.z) / view_ray.z));\n\n\t\t\t\t\t\t// Now we have the starting position on the front surface\n\t\t\t\t\t\tvec3 front = v_position + view_ray * distance;\n\n\t\t\t\t\t\t// Decide how many steps to take\n\t\t\t\t\t\tint nsteps = int(-distance / relative_step_size + 0.5);\n\t\t\t\t\t\tif ( nsteps < 1 )\n\t\t\t\t\t\t\t\tdiscard;\n\n\t\t\t\t\t\t// Get starting location and step vector in texture coordinates\n\t\t\t\t\t\tvec3 step = ((v_position - front) / u_size) / float(nsteps);\n\t\t\t\t\t\tvec3 start_loc = front / u_size;\n\n\t\t\t\t\t\t// For testing: show the number of steps. This helps to establish\n\t\t\t\t\t\t// whether the rays are correctly oriented\n\t\t\t\t\t\t//'gl_FragColor = vec4(0.0, float(nsteps) / 1.0 / u_size.x, 1.0, 1.0);\n\t\t\t\t\t\t//'return;\n\n\t\t\t\t\t\tif (u_renderstyle == 0)\n\t\t\t\t\t\t\t\tcast_mip(start_loc, step, nsteps, view_ray);\n\t\t\t\t\t\telse if (u_renderstyle == 1)\n\t\t\t\t\t\t\t\tcast_iso(start_loc, step, nsteps, view_ray);\n\n\t\t\t\t\t\tif (gl_FragColor.a < 0.05)\n\t\t\t\t\t\t\t\tdiscard;\n\t\t\t\t}\n\n\n\t\t\t\tfloat sample1(vec3 texcoords) {\n\t\t\t\t\t\t/* Sample float value from a 3D texture. Assumes intensity data. */\n\t\t\t\t\t\treturn texture(u_data, texcoords.xyz).r;\n\t\t\t\t}\n\n\n\t\t\t\tvec4 apply_colormap(float val) {\n\t\t\t\t\t\tval = (val - u_clim[0]) / (u_clim[1] - u_clim[0]);\n\t\t\t\t\t\treturn texture2D(u_cmdata, vec2(val, 0.5));\n\t\t\t\t}\n\n\n\t\t\t\tvoid cast_mip(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray) {\n\n\t\t\t\t\t\tfloat max_val = -1e6;\n\t\t\t\t\t\tint max_i = 100;\n\t\t\t\t\t\tvec3 loc = start_loc;\n\n\t\t\t\t\t\t// Enter the raycasting loop. In WebGL 1 the loop index cannot be compared with\n\t\t\t\t\t\t// non-constant expression. So we use a hard-coded max, and an additional condition\n\t\t\t\t\t\t// inside the loop.\n\t\t\t\t\t\tfor (int iter=0; iter<MAX_STEPS; iter++) {\n\t\t\t\t\t\t\t\tif (iter >= nsteps)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t// Sample from the 3D texture\n\t\t\t\t\t\t\t\tfloat val = sample1(loc);\n\t\t\t\t\t\t\t\t// Apply MIP operation\n\t\t\t\t\t\t\t\tif (val > max_val) {\n\t\t\t\t\t\t\t\t\t\tmax_val = val;\n\t\t\t\t\t\t\t\t\t\tmax_i = iter;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Advance location deeper into the volume\n\t\t\t\t\t\t\t\tloc += step;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Refine location, gives crispier images\n\t\t\t\t\t\tvec3 iloc = start_loc + step * (float(max_i) - 0.5);\n\t\t\t\t\t\tvec3 istep = step / float(REFINEMENT_STEPS);\n\t\t\t\t\t\tfor (int i=0; i<REFINEMENT_STEPS; i++) {\n\t\t\t\t\t\t\t\tmax_val = max(max_val, sample1(iloc));\n\t\t\t\t\t\t\t\tiloc += istep;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Resolve final color\n\t\t\t\t\t\tgl_FragColor = apply_colormap(max_val);\n\t\t\t\t}\n\n\n\t\t\t\tvoid cast_iso(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray) {\n\n\t\t\t\t\t\tgl_FragColor = vec4(0.0);\t// init transparent\n\t\t\t\t\t\tvec4 color3 = vec4(0.0);\t// final color\n\t\t\t\t\t\tvec3 dstep = 1.5 / u_size;\t// step to sample derivative\n\t\t\t\t\t\tvec3 loc = start_loc;\n\n\t\t\t\t\t\tfloat low_threshold = u_renderthreshold - 0.02 * (u_clim[1] - u_clim[0]);\n\n\t\t\t\t\t\t// Enter the raycasting loop. In WebGL 1 the loop index cannot be compared with\n\t\t\t\t\t\t// non-constant expression. So we use a hard-coded max, and an additional condition\n\t\t\t\t\t\t// inside the loop.\n\t\t\t\t\t\tfor (int iter=0; iter<MAX_STEPS; iter++) {\n\t\t\t\t\t\t\t\tif (iter >= nsteps)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t// Sample from the 3D texture\n\t\t\t\t\t\t\t\tfloat val = sample1(loc);\n\n\t\t\t\t\t\t\t\tif (val > low_threshold) {\n\t\t\t\t\t\t\t\t\t\t// Take the last interval in smaller steps\n\t\t\t\t\t\t\t\t\t\tvec3 iloc = loc - 0.5 * step;\n\t\t\t\t\t\t\t\t\t\tvec3 istep = step / float(REFINEMENT_STEPS);\n\t\t\t\t\t\t\t\t\t\tfor (int i=0; i<REFINEMENT_STEPS; i++) {\n\t\t\t\t\t\t\t\t\t\t\t\tval = sample1(iloc);\n\t\t\t\t\t\t\t\t\t\t\t\tif (val > u_renderthreshold) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tgl_FragColor = add_lighting(val, iloc, dstep, view_ray);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\tiloc += istep;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Advance location deeper into the volume\n\t\t\t\t\t\t\t\tloc += step;\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\t\tvec4 add_lighting(float val, vec3 loc, vec3 step, vec3 view_ray)\n\t\t\t\t{\n\t\t\t\t\t// Calculate color by incorporating lighting\n\n\t\t\t\t\t\t// View direction\n\t\t\t\t\t\tvec3 V = normalize(view_ray);\n\n\t\t\t\t\t\t// calculate normal vector from gradient\n\t\t\t\t\t\tvec3 N;\n\t\t\t\t\t\tfloat val1, val2;\n\t\t\t\t\t\tval1 = sample1(loc + vec3(-step[0], 0.0, 0.0));\n\t\t\t\t\t\tval2 = sample1(loc + vec3(+step[0], 0.0, 0.0));\n\t\t\t\t\t\tN[0] = val1 - val2;\n\t\t\t\t\t\tval = max(max(val1, val2), val);\n\t\t\t\t\t\tval1 = sample1(loc + vec3(0.0, -step[1], 0.0));\n\t\t\t\t\t\tval2 = sample1(loc + vec3(0.0, +step[1], 0.0));\n\t\t\t\t\t\tN[1] = val1 - val2;\n\t\t\t\t\t\tval = max(max(val1, val2), val);\n\t\t\t\t\t\tval1 = sample1(loc + vec3(0.0, 0.0, -step[2]));\n\t\t\t\t\t\tval2 = sample1(loc + vec3(0.0, 0.0, +step[2]));\n\t\t\t\t\t\tN[2] = val1 - val2;\n\t\t\t\t\t\tval = max(max(val1, val2), val);\n\n\t\t\t\t\t\tfloat gm = length(N); // gradient magnitude\n\t\t\t\t\t\tN = normalize(N);\n\n\t\t\t\t\t\t// Flip normal so it points towards viewer\n\t\t\t\t\t\tfloat Nselect = float(dot(N, V) > 0.0);\n\t\t\t\t\t\tN = (2.0 * Nselect - 1.0) * N;\t// ==\tNselect * N - (1.0-Nselect)*N;\n\n\t\t\t\t\t\t// Init colors\n\t\t\t\t\t\tvec4 ambient_color = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\tvec4 diffuse_color = vec4(0.0, 0.0, 0.0, 0.0);\n\t\t\t\t\t\tvec4 specular_color = vec4(0.0, 0.0, 0.0, 0.0);\n\n\t\t\t\t\t\t// note: could allow multiple lights\n\t\t\t\t\t\tfor (int i=0; i<1; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t // Get light direction (make sure to prevent zero devision)\n\t\t\t\t\t\t\t\tvec3 L = normalize(view_ray);\t//lightDirs[i];\n\t\t\t\t\t\t\t\tfloat lightEnabled = float( length(L) > 0.0 );\n\t\t\t\t\t\t\t\tL = normalize(L + (1.0 - lightEnabled));\n\n\t\t\t\t\t\t\t\t// Calculate lighting properties\n\t\t\t\t\t\t\t\tfloat lambertTerm = clamp(dot(N, L), 0.0, 1.0);\n\t\t\t\t\t\t\t\tvec3 H = normalize(L+V); // Halfway vector\n\t\t\t\t\t\t\t\tfloat specularTerm = pow(max(dot(H, N), 0.0), shininess);\n\n\t\t\t\t\t\t\t\t// Calculate mask\n\t\t\t\t\t\t\t\tfloat mask1 = lightEnabled;\n\n\t\t\t\t\t\t\t\t// Calculate colors\n\t\t\t\t\t\t\t\tambient_color +=\tmask1 * ambient_color;\t// * gl_LightSource[i].ambient;\n\t\t\t\t\t\t\t\tdiffuse_color +=\tmask1 * lambertTerm;\n\t\t\t\t\t\t\t\tspecular_color += mask1 * specularTerm * specular_color;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Calculate final color by componing different components\n\t\t\t\t\t\tvec4 final_color;\n\t\t\t\t\t\tvec4 color = apply_colormap(val);\n\t\t\t\t\t\tfinal_color = color * (ambient_color + diffuse_color) + specular_color;\n\t\t\t\t\t\tfinal_color.a = color.a;\n\t\t\t\t\t\treturn final_color;\n\t\t\t\t}"};var ge=(t=>(t[t.MIP=0]="MIP",t[t.ISO=1]="ISO",t))(ge||{});class xe extends g{constructor(t){const{style:e,threshold:n,clim:a,map:r,gradient:s}=t??{},l=new i(1,1,1);if(r){const{width:t,height:e,depth:n}=r.image;l.set(t,e,n)}const c=null==s?s:Ct(s),u=U.clone(ve.uniforms);u.u_size.value.copy(l),u.u_clim.value.copy(a??new o(1,1)),u.u_renderstyle.value=e??1,u.u_renderthreshold.value=n??.5,u.u_data.value=r??null,u.u_cmdata.value=c??null,super({...ve,uniforms:u,side:R}),Rt(this,"isExampleVolumeMaterial_1",!0),Rt(this,"_gradient")}get map(){return this.uniforms.u_data.value}set map(t){this.uniforms.u_data.value=t,this.uniformsNeedUpdate=!0}get gradientMap(){return this.uniforms.u_cmdata.value}get gradient(){return this._gradient}set gradient(t){this._gradient=t;const e=null==t?t:Ct(t);this.uniforms.u_cmdata.value=e??null,this.uniformsNeedUpdate=!0}get size(){return this.uniforms.u_size.value}set size(t){this.uniforms.u_size.value.copy(t),this.uniformsNeedUpdate=!0}get style(){return this.uniforms.u_renderstyle.value}set style(t){this.uniforms.u_renderstyle.value=t,this.uniformsNeedUpdate=!0}get clim(){return this.uniforms.u_clim.value}set clim(t){this.uniforms.u_clim.value=t,this.uniformsNeedUpdate=!0}get threshold(){return this.uniforms.u_renderthreshold.value}set threshold(t){this.uniforms.u_renderthreshold.value=t,this.uniformsNeedUpdate=!0}}const _e="in vec3 position;\n\nuniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform vec3 cameraPos;\n\nout vec3 vOrigin;\nout vec3 vDirection;\n\nvoid main() {\n vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;\n vDirection = position - vOrigin;\n gl_Position = projectionMatrix * mvPosition;\n}";class ye extends V{constructor(t){let{color:e,threshold:n,map:a,opacity:o,range:r,steps:s,frame:l,cameraPos:c}=t??{};e=e??new C(1,1,1),n=n??.25,o=o??.25,r=r??.1,s=s??100,l=l??100,c=c??new i,super({glslVersion:x,uniforms:{base:{value:e},map:{value:a},cameraPos:{value:c},threshold:{value:n},opacity:{value:o},range:{value:r},steps:{value:s},frame:{value:l}},vertexShader:_e,fragmentShader:"precision highp float;\nprecision highp sampler3D;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nin vec3 vOrigin;\nin vec3 vDirection;\n\nout vec4 color;\n\nuniform vec3 base;\nuniform sampler3D map;\n\nuniform float threshold;\nuniform float range;\nuniform float opacity;\nuniform float steps;\nuniform float frame;\n\nuint wang_hash(uint seed)\n{\n seed = (seed ^ 61u) ^ (seed >> 16u);\n seed *= 9u;\n seed = seed ^ (seed >> 4u);\n seed *= 0x27d4eb2du;\n seed = seed ^ (seed >> 15u);\n return seed;\n}\n\nfloat randomFloat(inout uint seed)\n{\n return float(wang_hash(seed)) / 4294967296.;\n}\n\nvec2 hitBox( vec3 orig, vec3 dir ) {\n const vec3 box_min = vec3( - 0.5 );\n const vec3 box_max = vec3( 0.5 );\n vec3 inv_dir = 1.0 / dir;\n vec3 tmin_tmp = ( box_min - orig ) * inv_dir;\n vec3 tmax_tmp = ( box_max - orig ) * inv_dir;\n vec3 tmin = min( tmin_tmp, tmax_tmp );\n vec3 tmax = max( tmin_tmp, tmax_tmp );\n float t0 = max( tmin.x, max( tmin.y, tmin.z ) );\n float t1 = min( tmax.x, min( tmax.y, tmax.z ) );\n return vec2( t0, t1 );\n}\n\nfloat sample1( vec3 p ) {\n return texture( map, p ).r;\n}\n\nfloat shading( vec3 coord ) {\n float step = 0.01;\n return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) );\n}\n\nvoid main(){\n vec3 rayDir = normalize( vDirection );\n vec2 bounds = hitBox( vOrigin, rayDir );\n\n if ( bounds.x > bounds.y ) discard;\n\n bounds.x = max( bounds.x, 0.0 );\n\n vec3 p = vOrigin + bounds.x * rayDir;\n vec3 inc = 1.0 / abs( rayDir );\n float delta = min( inc.x, min( inc.y, inc.z ) );\n delta /= steps;\n\n // Jitter\n\n // Nice little seed from\n // https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/\n uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 );\n vec3 size = vec3( textureSize( map, 0 ) );\n float randNum = randomFloat( seed ) * 2.0 - 1.0;\n p += rayDir * randNum * ( 1.0 / size );\n\n //\n\n vec4 ac = vec4( base, 0.0 );\n\n for ( float t = bounds.x; t < bounds.y; t += delta ) {\n\n float d = sample1( p + 0.5 );\n\n d = smoothstep( threshold - range, threshold + range, d ) * opacity;\n\n float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2;\n\n ac.rgb += ( 1.0 - ac.a ) * d * col;\n\n ac.a += ( 1.0 - ac.a ) * d;\n\n if ( ac.a >= 0.95 ) break;\n\n p += rayDir * delta;\n\n }\n\n color = ac;\n\n if ( color.a == 0.0 ) discard;\n\n}",side:R,transparent:!0}),Rt(this,"isExampleVolumeMaterial_Cloud",!0),this.opacity=o}get map(){return this.uniforms.map.value}set map(t){this.uniforms.map.value=t,this.uniformsNeedUpdate=!0}get color(){return this.uniforms.base.value}set color(t){this.uniforms.base.value=t,this.uniformsNeedUpdate=!0}get opacity(){return this.uniforms.opacity.value}set opacity(t){this.uniforms&&(this.uniforms.opacity.value=t),this.uniformsNeedUpdate=!0}get threshold(){return this.uniforms.threshold.value}set threshold(t){this.uniforms.threshold.value=t,this.uniformsNeedUpdate=!0}get range(){return this.uniforms.range.value}set range(t){this.uniforms.range.value=t,this.uniformsNeedUpdate=!0}get steps(){return this.uniforms.steps.value}set steps(t){this.uniforms.steps.value=t,this.uniformsNeedUpdate=!0}get frame(){return this.uniforms.frame.value}set frame(t){this.uniforms.frame.value=t,this.uniformsNeedUpdate=!0}get cameraPos(){return this.uniforms.cameraPos.value}set cameraPos(t){this.uniforms.cameraPos.value.copy(t),this.uniformsNeedUpdate=!0}}class we extends V{constructor(t){let{threshold:e,map:n,steps:a,cameraPos:o}=t??{};e=e??.25,a=a??100,o=o??new i,super({glslVersion:x,uniforms:{map:{value:n},cameraPos:{value:o},threshold:{value:e},steps:{value:a}},vertexShader:_e,fragmentShader:"precision highp float;\nprecision highp sampler3D;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nin vec3 vOrigin;\nin vec3 vDirection;\n\nout vec4 color;\n\nuniform sampler3D map;\n\nuniform float threshold;\nuniform float steps;\n\nvec2 hitBox( vec3 orig, vec3 dir ) {\n const vec3 box_min = vec3( - 0.5 );\n const vec3 box_max = vec3( 0.5 );\n vec3 inv_dir = 1.0 / dir;\n vec3 tmin_tmp = ( box_min - orig ) * inv_dir;\n vec3 tmax_tmp = ( box_max - orig ) * inv_dir;\n vec3 tmin = min( tmin_tmp, tmax_tmp );\n vec3 tmax = max( tmin_tmp, tmax_tmp );\n float t0 = max( tmin.x, max( tmin.y, tmin.z ) );\n float t1 = min( tmax.x, min( tmax.y, tmax.z ) );\n return vec2( t0, t1 );\n}\n\nfloat sample1( vec3 p ) {\n return texture( map, p ).r;\n}\n\n#define epsilon .0001\n\nvec3 normal( vec3 coord ) {\n if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 );\n if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 );\n if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 );\n if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 );\n if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 );\n if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 );\n\n float step = 0.01;\n float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) );\n float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) );\n float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) );\n\n return normalize( vec3( x, y, z ) );\n}\n\nvoid main(){\n\n vec3 rayDir = normalize( vDirection );\n vec2 bounds = hitBox( vOrigin, rayDir );\n\n if ( bounds.x > bounds.y ) discard;\n\n bounds.x = max( bounds.x, 0.0 );\n\n vec3 p = vOrigin + bounds.x * rayDir;\n vec3 inc = 1.0 / abs( rayDir );\n float delta = min( inc.x, min( inc.y, inc.z ) );\n delta /= steps;\n\n for ( float t = bounds.x; t < bounds.y; t += delta ) {\n\n float d = sample1( p + 0.5 );\n\n if ( d > threshold ) {\n\n color.rgb = normal( p + 0.5 ) * 0.5 + ( p * 1.5 + 0.25 );\n color.a = 1.;\n break;\n\n }\n\n p += rayDir * delta;\n\n }\n\n if ( color.a == 0.0 ) discard;\n\n}",side:R,transparent:!0}),Rt(this,"isExampleVolumeMaterial_Perlin",!0)}get map(){return this.uniforms.map.value}set map(t){this.uniforms.map.value=t,this.uniformsNeedUpdate=!0}get threshold(){return this.uniforms.threshold.value}set threshold(t){this.uniforms.threshold.value=t,this.uniformsNeedUpdate=!0}get steps(){return this.uniforms.steps.value}set steps(t){this.uniforms.steps.value=t,this.uniformsNeedUpdate=!0}get cameraPos(){return this.uniforms.cameraPos.value}set cameraPos(t){this.uniforms.cameraPos.value.copy(t),this.uniformsNeedUpdate=!0}}class Me{constructor(t){this.ssp=t,this.defaultColorGradient=[[0,"rgba(0,255,0,0)"],[.5,"rgba(64,255,255,0.5)"],[1,"rgba(255,64,255,1)"]],this.defaultGradientVolumeMaterialOptions={fit:Vt.Raw,accFactor:2,depthTest:!1,side:R,discardOut:!1,gradient:Ct(this.defaultColorGradient)}}_createTexture(t,e,n=!1){const i=he(Object.assign({points:t},e),Object.assign({maxSize:60},e)),{options:a,position:o,scale:r}=i,s=kt(n?me(a):se(a),Object.assign({},e)),l=new Lt(Object.assign(Object.assign(Object.assign({},this.defaultGradientVolumeMaterialOptions),{map:s}),e)),c=new jt(l);return c.position.copy(o),c.scale.set(r,r,r),this.ssp.addObject(c),c}createHeatCloud(t,e){return this._createTexture(t,e)}createLineHeat(t,e){return this._createTexture(t,e,!0)}async createImageExtrusion(t,e){var n;const i=new Ht(Object.assign({side:R,depthTest:!1},e)),a=Wt(await L.utils.imageLoader.loadAsync(t),null!==(n=null==e?void 0:e.depth)&&void 0!==n?n:200,e);i.map=a;const o=new jt(i);return this.ssp.addObject(o),o}createSliceMesh(t,e){let n=t.map;if(!n)return;if(t instanceof Lt){const{gradient:i,range:a,discardOut:o,voidRange:r}=t;n=Yt(n.image,Object.assign({gradient:null==i?void 0:i.image,range:a,discardOut:o,voidRange:r},e))}const i=new ne(Object.assign({map:n},e));return this.ssp.addObject(i),i}createImageSlice(t,e){const n=t.map;if(!n)return;let i=null;if(t instanceof Lt){const{gradient:a,range:o,discardOut:r,voidRange:s}=t;i=Yt(n.image,Object.assign({gradient:null==a?void 0:a.image,range:o,discardOut:r,voidRange:s},e))}if(t instanceof Ht&&(i=n),!i)return;return new ie(i)}}export{Jt as ColorFogPointsMaterial,xe as ExampleVolumeMaterial_1,ye as ExampleVolumeMaterial_Cloud,we as ExampleVolumeMaterial_Perlin,Zt as FogPointsMaterial,Bt as GradientData3DTexture,$t as GradientFogPointsMaterial,Lt as GradientVolumeMaterial,Me as HeatMapPlugin,Mt as ImageData3DSlice,Kt as ImageData3DTexture,ie as ImageData3DTextureSlice,Ht as ImageVolumeMaterial,ee as SliceMaterial,ne as SliceMesh,Xt as SphereFogMaterial,Vt as VolumeFit,Et as VolumeMaterial,jt as VolumeMesh,ge as VolumeRenderStyle,re as computeHeatData3DForPoint,Qt as createColorFogPoints,kt as createGradientData3DTexture,te as createGradientFogPoints,se as createHeatData3D,Wt as createImageData3DTextureByExtrudeImage,Yt as createImageData3DTextureFromGradient,me as createLineData3D,W as createLinearGradientImageData,Ct as createLinearGradientTexture,ht as data2DCoordToIndex,vt as data2DIndexToCoord,at as data3DCoordToIndex,ot as data3DIndexToCoord,Me as default,pt as extrudeImage,mt as extrudeImageData,ft as extrudeImageDataOnAxis,xt as getData2DItem,gt as getData2DItemSafe,wt as getData2DRow,yt as getData2DValue,_t as getData2DValueSafe,st as getData3DItem,rt as getData3DItemSafe,dt as getData3DSlice,ct as getData3DValue,lt as getData3DValueSafe,Q as getImageDateColor,Y as getImageDateOfImage,J as getImageDateRow,X as getNaturalSizeOfImageSource,qt as gradientData3DToImageData3D,ce as hollowGradient_Default,$ as imageDataToCanvas,tt as imageDataToUrl,et as isIImageData2,nt as isIImageData3,it as isOutOfSize,ue as lineValueGradient_Default,Gt as makeOriginOnBoundingBoxMinOfGeometry,ut as mergeData3Ds,de as numberValuesAccumulate_Default,he as optimizeGradientOptions,le as radiusGradient_Default,Z as reverseImageDateY,pe as transformGradientOptions,fe as translateScaleGradientOptions,ae as valueGradient_Default,oe as valuesAccumulate_Default};
|
|
1
|
+
import { TextureLoader, Texture, Matrix3, Vector3, Vector4, Vector2, AlphaFormat, RedFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAFormat, RGBAIntegerFormat, LuminanceFormat, LuminanceAlphaFormat, DepthFormat, DepthStencilFormat, ShaderMaterial, GLSL3, Matrix4, DoubleSide, Mesh, BoxGeometry, Data3DTexture, FloatType, LinearFilter, UnsignedByteType, Color, FrontSide, UniformsUtils, ShaderLib, Points, PlaneGeometry, Box3, Line3, Quaternion, BackSide, RawShaderMaterial, BufferGeometry, Float32BufferAttribute, Uint8ClampedBufferAttribute } from 'three';
|
|
2
|
+
import SoonSpace from 'soonspacejs';
|
|
3
|
+
|
|
4
|
+
var f$1 = /* @__PURE__ */ ((n) => (n[n.x = 0] = "x", n[n.y = 1] = "y", n[n.z = 2] = "z", n))(f$1 || {});
|
|
5
|
+
((n) => {
|
|
6
|
+
function t(r) {
|
|
7
|
+
return n[r];
|
|
8
|
+
}
|
|
9
|
+
n.toKey = t;
|
|
10
|
+
function e(r) {
|
|
11
|
+
return n[r];
|
|
12
|
+
}
|
|
13
|
+
n.toIndex = e;
|
|
14
|
+
function o(r) {
|
|
15
|
+
const c = (r + 1) % 3, i = (r + 2) % 3;
|
|
16
|
+
return [c, i];
|
|
17
|
+
}
|
|
18
|
+
n.getCrossAxiss = o;
|
|
19
|
+
})(f$1 || (f$1 = {}));
|
|
20
|
+
var s$1 = /* @__PURE__ */ ((n) => (n[n.x = 0] = "x", n[n.y = 1] = "y", n[n.z = 2] = "z", n[n.w = 3] = "w", n))(s$1 || {});
|
|
21
|
+
((n) => {
|
|
22
|
+
function t(r) {
|
|
23
|
+
return n[r];
|
|
24
|
+
}
|
|
25
|
+
n.toKey = t;
|
|
26
|
+
function e(r) {
|
|
27
|
+
return n[r];
|
|
28
|
+
}
|
|
29
|
+
n.toIndex = e;
|
|
30
|
+
function o(r) {
|
|
31
|
+
const c = (r + 1) % 4, i = (r + 2) % 4;
|
|
32
|
+
return [c, i];
|
|
33
|
+
}
|
|
34
|
+
n.getCrossAxiss = o;
|
|
35
|
+
})(s$1 || (s$1 = {}));
|
|
36
|
+
|
|
37
|
+
var f = /* @__PURE__ */ ((n) => (n[n.x = 0] = "x", n[n.y = 1] = "y", n[n.z = 2] = "z", n))(f || {});
|
|
38
|
+
((n) => {
|
|
39
|
+
function t(r) {
|
|
40
|
+
return n[r];
|
|
41
|
+
}
|
|
42
|
+
n.toKey = t;
|
|
43
|
+
function e(r) {
|
|
44
|
+
return n[r];
|
|
45
|
+
}
|
|
46
|
+
n.toIndex = e;
|
|
47
|
+
function o(r) {
|
|
48
|
+
const c = (r + 1) % 3, i = (r + 2) % 3;
|
|
49
|
+
return [c, i];
|
|
50
|
+
}
|
|
51
|
+
n.getCrossAxiss = o;
|
|
52
|
+
})(f || (f = {}));
|
|
53
|
+
var s = /* @__PURE__ */ ((n) => (n[n.x = 0] = "x", n[n.y = 1] = "y", n[n.z = 2] = "z", n[n.w = 3] = "w", n))(s || {});
|
|
54
|
+
((n) => {
|
|
55
|
+
function t(r) {
|
|
56
|
+
return n[r];
|
|
57
|
+
}
|
|
58
|
+
n.toKey = t;
|
|
59
|
+
function e(r) {
|
|
60
|
+
return n[r];
|
|
61
|
+
}
|
|
62
|
+
n.toIndex = e;
|
|
63
|
+
function o(r) {
|
|
64
|
+
const c = (r + 1) % 4, i = (r + 2) % 4;
|
|
65
|
+
return [c, i];
|
|
66
|
+
}
|
|
67
|
+
n.getCrossAxiss = o;
|
|
68
|
+
})(s || (s = {}));
|
|
69
|
+
|
|
70
|
+
function B$1(e, t, n, a = "srgb") {
|
|
71
|
+
const i = new OffscreenCanvas(t, n).getContext("2d"), o = i.createLinearGradient(0, 0, 256, 1);
|
|
72
|
+
for (const [c, r] of e)
|
|
73
|
+
o.addColorStop(Number(c), r);
|
|
74
|
+
return i.fillStyle = o, i.fillRect(0, 0, t, n), i.getImageData(0, 0, t, n, { colorSpace: a });
|
|
75
|
+
}
|
|
76
|
+
function _$1(e, t) {
|
|
77
|
+
const { x: n, y: a } = t;
|
|
78
|
+
return e.z * a * n + e.y * n + e.x;
|
|
79
|
+
}
|
|
80
|
+
function $$1(e, t, n = 1) {
|
|
81
|
+
let { x: a, y: s, z: i } = t;
|
|
82
|
+
const o = e.size;
|
|
83
|
+
return a = Math.max(0, Math.min(o.x - 1, a)), s = Math.max(0, Math.min(o.y - 1, s)), i = Math.max(0, Math.min(o.z - 1, i)), U$1(e, { x: a, y: s, z: i }, n);
|
|
84
|
+
}
|
|
85
|
+
function U$1(e, t, n = 1) {
|
|
86
|
+
const { data: a, size: s } = e, i = _$1(t, s);
|
|
87
|
+
let o = [];
|
|
88
|
+
if (n > 0) {
|
|
89
|
+
const c = i * n;
|
|
90
|
+
for (let r = 0; r < n; r++)
|
|
91
|
+
o.push(a[c + r]);
|
|
92
|
+
}
|
|
93
|
+
return { index: i, value: o };
|
|
94
|
+
}
|
|
95
|
+
function E$1(e, t, n, a = 1) {
|
|
96
|
+
const { size: s } = e, i = f.toKey(t), [o, c] = f.getCrossAxiss(t), r = f.toKey(o), u = f.toKey(c), h = s[r], g = s[u], l = [], f$1 = s[i];
|
|
97
|
+
n = Math.trunc(n), n = Math.max(0, Math.min(f$1 - 1, n));
|
|
98
|
+
let x = { x: 0, y: 0, z: 0 };
|
|
99
|
+
x[i] = n;
|
|
100
|
+
for (let m = 0; m < g; m++) {
|
|
101
|
+
x[u] = m;
|
|
102
|
+
for (let d = 0; d < h; d++) {
|
|
103
|
+
x[r] = d;
|
|
104
|
+
const { value: y } = U$1(e, x, a);
|
|
105
|
+
l.push(...y);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { data: l, size: { x: h, y: g } };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var zt = Object.defineProperty;
|
|
112
|
+
var Ut$1 = (t, n, e) => n in t ? zt(t, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[n] = e;
|
|
113
|
+
var j$1 = (t, n, e) => (Ut$1(t, typeof n != "symbol" ? n + "" : n, e), e);
|
|
114
|
+
function Pt$1(t) {
|
|
115
|
+
return t.w !== void 0 ? [Vector4, 4] : t.z !== void 0 ? [Vector3, 3] : [Vector2, 2];
|
|
116
|
+
}
|
|
117
|
+
function En(t) {
|
|
118
|
+
const n = t.length, e = [];
|
|
119
|
+
if (n === 0)
|
|
120
|
+
return e;
|
|
121
|
+
const [o, s] = Pt$1(t[0]);
|
|
122
|
+
for (let c = 0; c < n; c++) {
|
|
123
|
+
const r = t[c], i = new o().copy(r), l = r.radius, u = e[c] ?? (e[c] = []);
|
|
124
|
+
for (let a = c + 1; a < n; a++) {
|
|
125
|
+
const f = t[a];
|
|
126
|
+
i.distanceToSquared(f) <= (f.radius + l) ** 2 && (u.push(a), (e[a] = []).push(c));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return e;
|
|
130
|
+
}
|
|
131
|
+
let Tt$1;
|
|
132
|
+
function Gn(t) {
|
|
133
|
+
if (typeof t == "string")
|
|
134
|
+
return (Tt$1 || (Tt$1 = new TextureLoader())).load(t);
|
|
135
|
+
if (t.isTexture)
|
|
136
|
+
return t;
|
|
137
|
+
const n = Array.isArray(t) ? B$1(t, 256, 1) : t, e = new Texture(n);
|
|
138
|
+
return n.colorSpace === "srgb" && (e.colorSpace = "srgb"), e.needsUpdate = !0, e;
|
|
139
|
+
}
|
|
140
|
+
function an(t, n) {
|
|
141
|
+
const e = Math.sqrt(t.lengthSq() * n.lengthSq());
|
|
142
|
+
if (e === 0)
|
|
143
|
+
return 0;
|
|
144
|
+
let o = t.dot(n) / e;
|
|
145
|
+
return o = Math.max(-1, Math.min(1, o)), Math.acos(o);
|
|
146
|
+
}
|
|
147
|
+
function J$1(t, n, e) {
|
|
148
|
+
let o = an(t, n);
|
|
149
|
+
return o === 0 ? o : t.clone().cross(n).dot(e) < 0 ? -o : o;
|
|
150
|
+
}
|
|
151
|
+
function fn$1(t, n, e) {
|
|
152
|
+
const o = n.clone().negate(), s = e.clone().projectOnPlane(n), c = t.clone().projectOnPlane(s), r = J$1(n, c, s), i = n.clone().cross(s), l = t.clone().projectOnPlane(i), u = J$1(n, l, i), a = t.clone().projectOnPlane(o), f = J$1(s, a, o);
|
|
153
|
+
return { yaw: r, pitch: u, roll: f };
|
|
154
|
+
}
|
|
155
|
+
const it$1 = 180 / Math.PI, ut = {
|
|
156
|
+
yaw: [
|
|
157
|
+
{ name: "前", range: [-15, 15] },
|
|
158
|
+
{ name: "左", range: [15, 165] },
|
|
159
|
+
{ name: "右", range: [-165, -15] },
|
|
160
|
+
{ name: "后", range: [-180.1, -165] },
|
|
161
|
+
{ name: "后", range: [165, 180.1] }
|
|
162
|
+
],
|
|
163
|
+
pitch: [
|
|
164
|
+
{ name: "前", range: [-15, 15] },
|
|
165
|
+
{ name: "上", range: [15, 165] },
|
|
166
|
+
{ name: "下", range: [-165, -15] },
|
|
167
|
+
{ name: "后", range: [-180.1, -165] },
|
|
168
|
+
{ name: "后", range: [165, 180.1] }
|
|
169
|
+
],
|
|
170
|
+
roll: [
|
|
171
|
+
{ name: "上", range: [-15, 15] },
|
|
172
|
+
{ name: "左", range: [15, 165] },
|
|
173
|
+
{ name: "右", range: [-165, -15] },
|
|
174
|
+
{ name: "下", range: [-180.1, -165] },
|
|
175
|
+
{ name: "下", range: [165, 180.1] }
|
|
176
|
+
]
|
|
177
|
+
};
|
|
178
|
+
function pn$1(t) {
|
|
179
|
+
const n = {};
|
|
180
|
+
for (const [e, o] of Object.entries(t))
|
|
181
|
+
n[e] = Array.isArray(o) ? o : Object.entries(o).map(([s, c]) => ({ name: s, range: c }));
|
|
182
|
+
return n;
|
|
183
|
+
}
|
|
184
|
+
const lt = {
|
|
185
|
+
degrees: !0,
|
|
186
|
+
map: ut,
|
|
187
|
+
front: { x: 0, y: 0, z: 1 },
|
|
188
|
+
up: { x: 0, y: 1, z: 0 }
|
|
189
|
+
};
|
|
190
|
+
let It$1 = class It {
|
|
191
|
+
constructor(n) {
|
|
192
|
+
j$1(this, "_options");
|
|
193
|
+
j$1(this, "_listMap");
|
|
194
|
+
j$1(this, "_front");
|
|
195
|
+
j$1(this, "_up");
|
|
196
|
+
n && (this.options = n);
|
|
197
|
+
}
|
|
198
|
+
static get options() {
|
|
199
|
+
return this._options ?? (this.options = lt);
|
|
200
|
+
}
|
|
201
|
+
static set options(n) {
|
|
202
|
+
this._options = Object.assign({}, structuredClone(ut), n);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 默认选项
|
|
206
|
+
*/
|
|
207
|
+
get defaultOptions() {
|
|
208
|
+
return this.constructor.options;
|
|
209
|
+
}
|
|
210
|
+
get options() {
|
|
211
|
+
return this._options ?? (this.options = this.defaultOptions);
|
|
212
|
+
}
|
|
213
|
+
set options(n) {
|
|
214
|
+
this._options = Object.assign({}, structuredClone(this.defaultOptions), n), this._listMap = null, this._front = null, this._up = null;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* 是否使用角度,而非弧度
|
|
218
|
+
*/
|
|
219
|
+
get degrees() {
|
|
220
|
+
return this.options.degrees ?? (this.options.degrees = this.defaultOptions.degrees ?? !0);
|
|
221
|
+
}
|
|
222
|
+
set degrees(n) {
|
|
223
|
+
this.options.degrees = n;
|
|
224
|
+
}
|
|
225
|
+
get map() {
|
|
226
|
+
return this.options.map || (this.map = this.defaultOptions.map), this.options.map;
|
|
227
|
+
}
|
|
228
|
+
set map(n) {
|
|
229
|
+
const e = structuredClone(this.defaultOptions.map), o = structuredClone(ut);
|
|
230
|
+
n = n ? {
|
|
231
|
+
yaw: n.yaw ?? e.yaw ?? o.yaw,
|
|
232
|
+
pitch: n.pitch ?? e.pitch ?? o.pitch,
|
|
233
|
+
roll: n.roll ?? e.roll ?? o.roll
|
|
234
|
+
} : e, this.options.map = n, this._listMap = null;
|
|
235
|
+
}
|
|
236
|
+
get listMap() {
|
|
237
|
+
return this._listMap ?? (this._listMap = pn$1(this.map ?? {}));
|
|
238
|
+
}
|
|
239
|
+
get front() {
|
|
240
|
+
return this._front || (this.front = this.options.front ?? this.defaultOptions.front ?? lt.front), this._front;
|
|
241
|
+
}
|
|
242
|
+
set front(n) {
|
|
243
|
+
this._front = new Vector3().copy(n);
|
|
244
|
+
}
|
|
245
|
+
get up() {
|
|
246
|
+
return this._up || (this.up = this.options.up ?? this.defaultOptions.up ?? lt.up), this._up;
|
|
247
|
+
}
|
|
248
|
+
set up(n) {
|
|
249
|
+
this._up = new Vector3().copy(n);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 计算方位
|
|
253
|
+
* @param target
|
|
254
|
+
* @param front
|
|
255
|
+
* @param up
|
|
256
|
+
*/
|
|
257
|
+
computeAzimuth(n, e, o) {
|
|
258
|
+
const s = new Vector3().copy(n), c = new Vector3().copy(e ?? this.front), r = new Vector3().copy(o ?? this.up);
|
|
259
|
+
let { yaw: i, pitch: l, roll: u } = fn$1(s, c, r);
|
|
260
|
+
return this.degrees && (i *= it$1, l *= it$1, u *= it$1), {
|
|
261
|
+
yaw: {
|
|
262
|
+
angle: i,
|
|
263
|
+
name: this.findAzimuthNames("yaw", i)
|
|
264
|
+
},
|
|
265
|
+
pitch: {
|
|
266
|
+
angle: l,
|
|
267
|
+
name: this.findAzimuthNames("pitch", l)
|
|
268
|
+
},
|
|
269
|
+
roll: {
|
|
270
|
+
angle: u,
|
|
271
|
+
name: this.findAzimuthNames("roll", u)
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 查找匹配的方位名字
|
|
277
|
+
* @param type - 类型
|
|
278
|
+
* @param angle - 角度
|
|
279
|
+
* @returns 匹配的名字列表
|
|
280
|
+
*/
|
|
281
|
+
findAzimuthNames(n, e) {
|
|
282
|
+
const o = [], s = this.listMap[n];
|
|
283
|
+
if (!s)
|
|
284
|
+
return o;
|
|
285
|
+
for (const { name: c, range: [r, i] } of s)
|
|
286
|
+
(e >= r && e < i || e <= r && e > i) && o.push(c);
|
|
287
|
+
return o;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
j$1(It$1, "_options");
|
|
291
|
+
new It$1(); const mn$1 = {
|
|
292
|
+
[AlphaFormat]: 1,
|
|
293
|
+
[RedFormat]: 1,
|
|
294
|
+
[RedIntegerFormat]: 1,
|
|
295
|
+
[RGFormat]: 3,
|
|
296
|
+
[RGIntegerFormat]: 2,
|
|
297
|
+
[RGBAFormat]: 4,
|
|
298
|
+
[RGBAIntegerFormat]: 4,
|
|
299
|
+
[LuminanceFormat]: 1,
|
|
300
|
+
[LuminanceAlphaFormat]: 2,
|
|
301
|
+
[DepthFormat]: 1,
|
|
302
|
+
[DepthStencilFormat]: 2
|
|
303
|
+
};
|
|
304
|
+
function Mt(t) {
|
|
305
|
+
return mn$1[t];
|
|
306
|
+
}
|
|
307
|
+
function Yn(t, n, e) {
|
|
308
|
+
const { data: o, width: s, height: c, depth: r } = t.image, i = Mt(t.format);
|
|
309
|
+
return E$1({ data: o, size: { x: s, y: c, z: r } }, n, e, i);
|
|
310
|
+
}
|
|
311
|
+
function Zn(t, n) {
|
|
312
|
+
const { data: e, width: o, height: s, depth: c } = t.image, r = Mt(t.format);
|
|
313
|
+
return $$1({ data: e, size: { x: o, y: s, z: c } }, n, r);
|
|
314
|
+
}
|
|
315
|
+
new Matrix3();
|
|
316
|
+
|
|
317
|
+
var T = Object.defineProperty;
|
|
318
|
+
var R = (e, t, n) => t in e ? T(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
319
|
+
var D = (e, t, n) => (R(e, typeof t != "symbol" ? t + "" : t, n), n);
|
|
320
|
+
function B(e, t, n, a = "srgb") {
|
|
321
|
+
const i = new OffscreenCanvas(t, n).getContext("2d"), o = i.createLinearGradient(0, 0, 256, 1);
|
|
322
|
+
for (const [c, r] of e)
|
|
323
|
+
o.addColorStop(Number(c), r);
|
|
324
|
+
return i.fillStyle = o, i.fillRect(0, 0, t, n), i.getImageData(0, 0, t, n, { colorSpace: a });
|
|
325
|
+
}
|
|
326
|
+
function K(e, t) {
|
|
327
|
+
let { area: n, width: a, height: s, colorSpace: i } = t || {};
|
|
328
|
+
i = i ?? "srgb", n = n || {};
|
|
329
|
+
const o = n.x ?? 0, c = n.y ?? 0, r = b(e), u = n.width ?? r.width, h = n.height ?? r.height;
|
|
330
|
+
a = a ?? u, s = s ?? h;
|
|
331
|
+
const l = new OffscreenCanvas(a, s).getContext("2d");
|
|
332
|
+
return l.drawImage(e, o, c, u, h, 0, 0, a, s), l.getImageData(0, 0, a, s, { colorSpace: i });
|
|
333
|
+
}
|
|
334
|
+
function b(e) {
|
|
335
|
+
let t = 0, n = 0;
|
|
336
|
+
return e instanceof HTMLImageElement ? (t = e.naturalWidth, n = e.naturalHeight) : e instanceof HTMLVideoElement ? (t = e.videoWidth, n = e.videoHeight) : (t = e.width, n = e.height), { width: t, height: n };
|
|
337
|
+
}
|
|
338
|
+
function V(e) {
|
|
339
|
+
const { data: t, width: n, height: a, colorSpace: s } = e, i = t.length, o = new Uint8ClampedArray(i);
|
|
340
|
+
for (let c = 0; c < a; c++) {
|
|
341
|
+
const r = c * n, u = -(r + n), h = u + n, g = t.slice(u * 4, h * 4);
|
|
342
|
+
o.set(g, r * 4);
|
|
343
|
+
}
|
|
344
|
+
return new ImageData(o, n, a, { colorSpace: s });
|
|
345
|
+
}
|
|
346
|
+
function F(e, t) {
|
|
347
|
+
const { data: n, width: a } = e, s = t * a, i = s + a;
|
|
348
|
+
return n.slice(s * 4, i * 4);
|
|
349
|
+
}
|
|
350
|
+
function H(e, t, n) {
|
|
351
|
+
const { data: a, width: s } = e, o = (t * s + n) * 4;
|
|
352
|
+
return a.slice(o, o + 4);
|
|
353
|
+
}
|
|
354
|
+
function Y(e) {
|
|
355
|
+
const t = document.createElement("canvas"), n = t.getContext("2d");
|
|
356
|
+
return t.width = e.width, t.height = e.height, n.putImageData(e, 0, 0), t;
|
|
357
|
+
}
|
|
358
|
+
function J(e) {
|
|
359
|
+
return Y(e).toDataURL();
|
|
360
|
+
}
|
|
361
|
+
function L(e) {
|
|
362
|
+
return e && e.data != null && e.width != null && e.height != null;
|
|
363
|
+
}
|
|
364
|
+
function P(e) {
|
|
365
|
+
return L(e) && e.depth != null;
|
|
366
|
+
}
|
|
367
|
+
function Q(e, t) {
|
|
368
|
+
for (const [n, a] of Object.entries(e))
|
|
369
|
+
if (0 <= a && a <= t[n])
|
|
370
|
+
return !0;
|
|
371
|
+
return !1;
|
|
372
|
+
}
|
|
373
|
+
function _(e, t) {
|
|
374
|
+
const { x: n, y: a } = t;
|
|
375
|
+
return e.z * a * n + e.y * n + e.x;
|
|
376
|
+
}
|
|
377
|
+
function Z(e, t) {
|
|
378
|
+
const { x: n, y: a } = t, s = Math.trunc(e / n), i = e - s * n, o = Math.trunc(s / a), c = s - o * a;
|
|
379
|
+
return { x: i, y: c, z: o };
|
|
380
|
+
}
|
|
381
|
+
function $(e, t, n = 1) {
|
|
382
|
+
let { x: a, y: s, z: i } = t;
|
|
383
|
+
const o = e.size;
|
|
384
|
+
return a = Math.max(0, Math.min(o.x - 1, a)), s = Math.max(0, Math.min(o.y - 1, s)), i = Math.max(0, Math.min(o.z - 1, i)), U(e, { x: a, y: s, z: i }, n);
|
|
385
|
+
}
|
|
386
|
+
function U(e, t, n = 1) {
|
|
387
|
+
const { data: a, size: s } = e, i = _(t, s);
|
|
388
|
+
let o = [];
|
|
389
|
+
if (n > 0) {
|
|
390
|
+
const c = i * n;
|
|
391
|
+
for (let r = 0; r < n; r++)
|
|
392
|
+
o.push(a[c + r]);
|
|
393
|
+
}
|
|
394
|
+
return { index: i, value: o };
|
|
395
|
+
}
|
|
396
|
+
function tt(e, t) {
|
|
397
|
+
let { x: n, y: a, z: s } = t;
|
|
398
|
+
const i = e.size;
|
|
399
|
+
return n = Math.max(0, Math.min(i.x - 1, n)), a = Math.max(0, Math.min(i.y - 1, a)), s = Math.max(0, Math.min(i.z - 1, s)), N(e, { x: n, y: a, z: s });
|
|
400
|
+
}
|
|
401
|
+
function N(e, t) {
|
|
402
|
+
const { data: n, size: a } = e, s = _(t, a);
|
|
403
|
+
return { index: s, value: n[s] };
|
|
404
|
+
}
|
|
405
|
+
function et(e, t) {
|
|
406
|
+
const { voidValue: n, valuesAccumulate: a, verifyVoid: s = () => !1 } = t;
|
|
407
|
+
let { x: i, y: o, z: c } = e[0].size;
|
|
408
|
+
const r = e.length;
|
|
409
|
+
for (let l = 1; l < r; l++) {
|
|
410
|
+
const f = e[l].size;
|
|
411
|
+
i = Math.max(i, f.x), o = Math.max(o, f.y), c = Math.max(c, f.z);
|
|
412
|
+
}
|
|
413
|
+
const u = i * o * c, h = new Array(u), g = i * o;
|
|
414
|
+
for (let l = 0; l < c; l++) {
|
|
415
|
+
const f = l * g;
|
|
416
|
+
for (let x = 0; x < o; x++) {
|
|
417
|
+
const m = f + x * i;
|
|
418
|
+
for (let d = 0; d < i; d++) {
|
|
419
|
+
const y = m + d, v = { x: d, y: x, z: l }, M = [];
|
|
420
|
+
for (const I of e) {
|
|
421
|
+
const p = I.size;
|
|
422
|
+
if (d < p.x && x < p.y && l < p.z)
|
|
423
|
+
continue;
|
|
424
|
+
const { index: C, value: A } = N(I, v);
|
|
425
|
+
s(A, I, C) || M.push({ value: A, index: C, data3D: I, coord: v });
|
|
426
|
+
}
|
|
427
|
+
const S = M.length;
|
|
428
|
+
let w = n;
|
|
429
|
+
S > 1 ? w = a(M) : S === 1 && (w = M[0].value), h[y] = w;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
data: h,
|
|
435
|
+
size: { x: i, y: o, z: c }
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function E(e, t, n, a = 1) {
|
|
439
|
+
const { size: s } = e, i = f$1.toKey(t), [o, c] = f$1.getCrossAxiss(t), r = f$1.toKey(o), u = f$1.toKey(c), h = s[r], g = s[u], l = [], f = s[i];
|
|
440
|
+
n = Math.trunc(n), n = Math.max(0, Math.min(f - 1, n));
|
|
441
|
+
let x = { x: 0, y: 0, z: 0 };
|
|
442
|
+
x[i] = n;
|
|
443
|
+
for (let m = 0; m < g; m++) {
|
|
444
|
+
x[u] = m;
|
|
445
|
+
for (let d = 0; d < h; d++) {
|
|
446
|
+
x[r] = d;
|
|
447
|
+
const { value: y } = U(e, x, a);
|
|
448
|
+
l.push(...y);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return { data: l, size: { x: h, y: g } };
|
|
452
|
+
}
|
|
453
|
+
function W(e, t, n) {
|
|
454
|
+
t = Math.trunc(t);
|
|
455
|
+
const { data: a, width: s, height: i, colorSpace: o } = n ? V(e) : e, c = a.length, r = c * t, u = new Uint8ClampedArray(r);
|
|
456
|
+
for (let h = 0; h < t; h++)
|
|
457
|
+
u.set(a, h * c);
|
|
458
|
+
return { data: u, width: s, height: i, depth: t, colorSpace: o };
|
|
459
|
+
}
|
|
460
|
+
function nt(e, t, n) {
|
|
461
|
+
const a = n || {}, s = a.reverseY, i = a.axis ?? "z", o = L(e) ? e : K(e, a);
|
|
462
|
+
return i === "z" ? W(o, t, s) : X(o, i, t, s);
|
|
463
|
+
}
|
|
464
|
+
function X(e, t, n, a) {
|
|
465
|
+
n = Math.trunc(n);
|
|
466
|
+
const { data: s, width: i, height: o, colorSpace: c } = a ? V(e) : e, r = f$1.toKey(t), u = (t + 1) % 3, h = (t + 2) % 3, g = f$1.toKey(u), l = f$1.toKey(h), f = {
|
|
467
|
+
[g]: i,
|
|
468
|
+
[l]: o,
|
|
469
|
+
[r]: n
|
|
470
|
+
}, x = new Uint8ClampedArray(s.length * n), m = { x: 0, y: 0, z: 0 };
|
|
471
|
+
for (let d = 0; d < n; d++) {
|
|
472
|
+
m[r] = d;
|
|
473
|
+
for (let y = 0; y < o; y++) {
|
|
474
|
+
m[l] = y;
|
|
475
|
+
for (let v = 0; v < i; v++) {
|
|
476
|
+
m[g] = v;
|
|
477
|
+
const S = (y * i + v) * 4, w = S + 4, I = s.subarray(S, w), C = _(m, f) * 4;
|
|
478
|
+
x.set(I, C);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return { data: x, width: f.x, height: f.y, depth: f.z, colorSpace: c };
|
|
483
|
+
}
|
|
484
|
+
function O(e, t) {
|
|
485
|
+
return e.y * t.x + e.x;
|
|
486
|
+
}
|
|
487
|
+
function at$1(e, t) {
|
|
488
|
+
const { x: n } = t, a = Math.trunc(e / n);
|
|
489
|
+
return { x: e - a * n, y: a };
|
|
490
|
+
}
|
|
491
|
+
function st(e, t, n = 1) {
|
|
492
|
+
let { x: a, y: s } = t;
|
|
493
|
+
const i = e.size;
|
|
494
|
+
return a = Math.max(0, Math.min(i.x - 1, a)), s = Math.max(0, Math.min(i.y - 1, s)), G(e, { x: a, y: s }, n);
|
|
495
|
+
}
|
|
496
|
+
function G(e, t, n = 1) {
|
|
497
|
+
const { data: a, size: s } = e, i = O(t, s);
|
|
498
|
+
let o = [];
|
|
499
|
+
if (n > 0) {
|
|
500
|
+
const c = i * n;
|
|
501
|
+
for (let r = 0; r < n; r++)
|
|
502
|
+
o.push(a[c + r]);
|
|
503
|
+
}
|
|
504
|
+
return { index: i, value: o };
|
|
505
|
+
}
|
|
506
|
+
function it(e, t) {
|
|
507
|
+
let { x: n, y: a } = t;
|
|
508
|
+
const s = e.size;
|
|
509
|
+
return n = Math.max(0, Math.min(s.x - 1, n)), a = Math.max(0, Math.min(s.y - 1, a)), j(e, { x: n, y: a });
|
|
510
|
+
}
|
|
511
|
+
function j(e, t) {
|
|
512
|
+
const { data: n, size: a } = e, s = O(t, a);
|
|
513
|
+
return { index: s, value: n[s] };
|
|
514
|
+
}
|
|
515
|
+
function ot$1(e, t, n = 1) {
|
|
516
|
+
const { data: a, size: s } = e, i = s.x, o = t * i, c = o + i;
|
|
517
|
+
return (typeof a.slice == "function" ? a : Array.from(a)).slice(o * n, c * n);
|
|
518
|
+
}
|
|
519
|
+
class ct {
|
|
520
|
+
constructor(t) {
|
|
521
|
+
D(this, "isImageData3DSlice", !0);
|
|
522
|
+
D(this, "_image3D");
|
|
523
|
+
D(this, "_canvas");
|
|
524
|
+
D(this, "_context");
|
|
525
|
+
D(this, "_axis", f$1.z);
|
|
526
|
+
D(this, "_depth", 0);
|
|
527
|
+
D(this, "_sliceSize", null);
|
|
528
|
+
D(this, "_slice");
|
|
529
|
+
this.image3D = t;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* 3D图像数据
|
|
533
|
+
*/
|
|
534
|
+
get image3D() {
|
|
535
|
+
return this._image3D;
|
|
536
|
+
}
|
|
537
|
+
set image3D(t) {
|
|
538
|
+
this._image3D = t, this.updateSize();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* 呈现切片的 canvas 元素
|
|
542
|
+
* @remarks
|
|
543
|
+
* 当 {@link ImageData3DSlice.axis} 或 {@link ImageData3DSlice.depth} 变更时,它会自动更新切片
|
|
544
|
+
*/
|
|
545
|
+
get canvas() {
|
|
546
|
+
let t = this._canvas;
|
|
547
|
+
return t || (t = this._canvas = document.createElement("canvas"), t.width = this.sliceSize.x, t.height = this.sliceSize.y), t;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* canvas 的 2d 上下文对象
|
|
551
|
+
*/
|
|
552
|
+
get context() {
|
|
553
|
+
return this._context ?? (this._context = this.canvas.getContext("2d"));
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* 轴
|
|
557
|
+
* @remarks
|
|
558
|
+
* 会沿该轴的垂直截面生成切片
|
|
559
|
+
*
|
|
560
|
+
* @defaultValue Axis.z
|
|
561
|
+
*/
|
|
562
|
+
get axis() {
|
|
563
|
+
return this._axis;
|
|
564
|
+
}
|
|
565
|
+
set axis(t) {
|
|
566
|
+
this._axis = t, this.updateSize();
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* 轴上的坐标值
|
|
570
|
+
* @remarks
|
|
571
|
+
* 会在轴的该位置处获取切片
|
|
572
|
+
* @defaultValue 0
|
|
573
|
+
*/
|
|
574
|
+
get depth() {
|
|
575
|
+
return this._depth;
|
|
576
|
+
}
|
|
577
|
+
set depth(t) {
|
|
578
|
+
this._depth = t, this.updateSlice();
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* 切片的尺寸
|
|
582
|
+
* @remarks
|
|
583
|
+
* 不同轴上的切片的尺寸一般不一样
|
|
584
|
+
*/
|
|
585
|
+
get sliceSize() {
|
|
586
|
+
let t = this._sliceSize;
|
|
587
|
+
if (!t) {
|
|
588
|
+
const { axis: n, image3D: a } = this, { width: s, height: i, depth: o } = a, [c, r] = f$1.getCrossAxiss(n), u = [s, i, o];
|
|
589
|
+
this._sliceSize = t = {
|
|
590
|
+
x: u[c],
|
|
591
|
+
y: u[r]
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
return t;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* 获取切片数据
|
|
598
|
+
* @remarks
|
|
599
|
+
* 总是获取当前轴和深度处的切片
|
|
600
|
+
*/
|
|
601
|
+
get slice() {
|
|
602
|
+
return this._slice ?? (this._slice = this.getSlice(this.axis, this.depth));
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* 获取切片数据
|
|
606
|
+
* @remarks
|
|
607
|
+
* 可以指定轴和深度;该方法不会更新 {@link ImageData3DSlice.axis} 和 {@link ImageData3DSlice.depth} 属性
|
|
608
|
+
* @param axis - 轴
|
|
609
|
+
* @param depth - 深度
|
|
610
|
+
* @returns
|
|
611
|
+
*/
|
|
612
|
+
getSlice(t, n) {
|
|
613
|
+
const { data: a, width: s, height: i, depth: o, colorSpace: c } = this.image3D, { data: r, size: u } = E({ data: a, size: { x: s, y: i, z: o } }, t, n, 4), h = r instanceof Uint8ClampedArray ? r : Uint8ClampedArray.from(r);
|
|
614
|
+
return new ImageData(h, u.x, u.y, { colorSpace: c });
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* 获取切片图像的 url
|
|
618
|
+
* @returns
|
|
619
|
+
*/
|
|
620
|
+
getDataURL() {
|
|
621
|
+
return this.canvas.toDataURL();
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* 获取切片上指定坐标处的颜色
|
|
625
|
+
* @param coord - 坐标
|
|
626
|
+
* @returns
|
|
627
|
+
*/
|
|
628
|
+
getColor(t) {
|
|
629
|
+
const { x: n, y: a } = t;
|
|
630
|
+
return H(this.slice, a, n);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 更新切片尺寸相关的信息
|
|
634
|
+
*/
|
|
635
|
+
updateSize() {
|
|
636
|
+
this._sliceSize = null;
|
|
637
|
+
const t = this.canvas;
|
|
638
|
+
t.width = this.sliceSize.x, t.height = this.sliceSize.y, this.updateSlice();
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 更新切片相关的信息
|
|
642
|
+
*/
|
|
643
|
+
updateSlice() {
|
|
644
|
+
this._slice = null, this.context.putImageData(this.slice, 0, 0);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
var at = Object.defineProperty;
|
|
649
|
+
var ot = (o, s, e) => s in o ? at(o, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[s] = e;
|
|
650
|
+
var v = (o, s, e) => (ot(o, typeof s != "symbol" ? s + "" : s, e), e);
|
|
651
|
+
const St = `precision highp sampler3D;
|
|
652
|
+
|
|
653
|
+
uniform sampler3D map;
|
|
654
|
+
uniform vec3 containerMin;
|
|
655
|
+
uniform vec3 containerMax;
|
|
656
|
+
|
|
657
|
+
// 0: 充满;1: 对齐;2: 原始
|
|
658
|
+
uniform int fit;
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
out vec3 cameraPos;
|
|
662
|
+
out vec3 lookDir;
|
|
663
|
+
out vec3 displayMin;
|
|
664
|
+
out vec3 displayMax;
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
void main() {
|
|
669
|
+
cameraPos = vec3( inverse( modelMatrix ) * vec4( cameraPosition, 1.0 ) ).xyz;
|
|
670
|
+
lookDir = position - cameraPos;
|
|
671
|
+
|
|
672
|
+
vec3 containerSize = containerMax - containerMin;
|
|
673
|
+
vec3 origin = containerMin;
|
|
674
|
+
vec3 textSize = vec3(textureSize(map,0));
|
|
675
|
+
displayMin = containerMin;
|
|
676
|
+
displayMax = containerMax;
|
|
677
|
+
|
|
678
|
+
switch (fit) {
|
|
679
|
+
case 1:
|
|
680
|
+
displayMax = displayMin + textSize;
|
|
681
|
+
break;
|
|
682
|
+
case 2:
|
|
683
|
+
origin = vec3(0.0);
|
|
684
|
+
break;
|
|
685
|
+
default:
|
|
686
|
+
textSize = containerSize;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
vec3 scale = 1.0/textSize;
|
|
690
|
+
cameraPos = (cameraPos - origin)*scale;
|
|
691
|
+
lookDir *= scale;
|
|
692
|
+
|
|
693
|
+
displayMin = max((displayMin - origin)*scale,vec3(0.0));
|
|
694
|
+
displayMax = min((displayMax - origin)*scale,vec3(1.0));
|
|
695
|
+
|
|
696
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
697
|
+
}`;
|
|
698
|
+
var Dt = /* @__PURE__ */ ((o) => (o[o.Fill = 0] = "Fill", o[o.Align = 1] = "Align", o[o.Raw = 2] = "Raw", o))(Dt || {});
|
|
699
|
+
class Xe extends ShaderMaterial {
|
|
700
|
+
constructor(e) {
|
|
701
|
+
const { map: t, opacity: n, accFactor: i, steps: a, alphaRange: r, fit: l, atomize: u, side: c, containerMin: p, containerMax: m, uniforms: f, ...h } = e ?? {}, _ = n ?? 1, M = i ?? 1, S = a ?? 100, D = new Vector2().copy(r ?? { x: 0, y: 0.95 }), w = l ?? 0, x = u ?? !0, y = c ?? FrontSide, g = new Vector3().copy(p ?? { x: 0, y: 0, z: 0 }), z = new Vector3();
|
|
702
|
+
if (m)
|
|
703
|
+
z.copy(m);
|
|
704
|
+
else if (t) {
|
|
705
|
+
const { width: U, height: T, depth: C } = t.image, V = new Vector3(U - 1, T - 1, C - 1);
|
|
706
|
+
z.addVectors(g, V);
|
|
707
|
+
}
|
|
708
|
+
const N = {
|
|
709
|
+
map: { value: t },
|
|
710
|
+
containerMin: { value: g },
|
|
711
|
+
containerMax: { value: z },
|
|
712
|
+
fit: { value: w },
|
|
713
|
+
opacity: { value: _ },
|
|
714
|
+
alphaRange: { value: D },
|
|
715
|
+
accFactor: { value: M },
|
|
716
|
+
steps: { value: S },
|
|
717
|
+
isDoubleSide: { value: !1 },
|
|
718
|
+
atomize: { value: x },
|
|
719
|
+
...f
|
|
720
|
+
};
|
|
721
|
+
super({
|
|
722
|
+
glslVersion: GLSL3,
|
|
723
|
+
// @ts-ignore
|
|
724
|
+
uniforms: N,
|
|
725
|
+
transparent: !0,
|
|
726
|
+
vertexShader: St,
|
|
727
|
+
...h
|
|
728
|
+
});
|
|
729
|
+
v(this, "isVolumeMaterial", !0);
|
|
730
|
+
v(this, "_side", FrontSide);
|
|
731
|
+
this.opacity = _, this.side = y;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* 三维的纹理
|
|
735
|
+
*/
|
|
736
|
+
get map() {
|
|
737
|
+
return this.uniforms.map.value;
|
|
738
|
+
}
|
|
739
|
+
set map(e) {
|
|
740
|
+
this.uniforms.map.value = e, this.uniformsNeedUpdate = !0;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* 渲染体积材质的容器的最小点
|
|
744
|
+
* @remarks
|
|
745
|
+
* 容器的最小点和最大点一般是被设置成 geometry 的AABB包围盒;但也可以不是
|
|
746
|
+
* 总之,体积材质的渲染依托于 geometry 的形状,它不会超出 geometry 的尺寸;
|
|
747
|
+
* 但可以控制容器的最小点和最大点来控制体积材质的渲染尺寸;
|
|
748
|
+
*/
|
|
749
|
+
get containerMin() {
|
|
750
|
+
return this.uniforms.containerMin.value;
|
|
751
|
+
}
|
|
752
|
+
set containerMin(e) {
|
|
753
|
+
this.uniforms.containerMin.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* 渲染体积材质的容器的最大点
|
|
757
|
+
* @remarks
|
|
758
|
+
* 容器的最小点和最大点一般是被设置成 geometry 的AABB包围盒;但也可以不是
|
|
759
|
+
* 总之,体积材质的渲染依托于 geometry 的形状,它不会超出 geometry 的尺寸;
|
|
760
|
+
* 但可以控制容器的最小点和最大点来控制体积材质的渲染尺寸;
|
|
761
|
+
*/
|
|
762
|
+
get containerMax() {
|
|
763
|
+
return this.uniforms.containerMax.value;
|
|
764
|
+
}
|
|
765
|
+
set containerMax(e) {
|
|
766
|
+
this.uniforms.containerMax.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* 渲染体积材质容器的尺寸
|
|
770
|
+
* @remarks
|
|
771
|
+
* 每次调用都会重新计算
|
|
772
|
+
*/
|
|
773
|
+
get containerSize() {
|
|
774
|
+
return this.containerMax.clone().sub(this.containerMin);
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* 体积材质在容器内的填充模式
|
|
778
|
+
* @defaultValue VolumeFit.Fill
|
|
779
|
+
*/
|
|
780
|
+
get fit() {
|
|
781
|
+
return this.uniforms.fit.value;
|
|
782
|
+
}
|
|
783
|
+
set fit(e) {
|
|
784
|
+
this.uniforms.fit.value = e, this.uniformsNeedUpdate = !0;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* 获取当前填模式下对 map 的应用的平移
|
|
788
|
+
* @returns
|
|
789
|
+
*/
|
|
790
|
+
getFitTranslate() {
|
|
791
|
+
return this.fit === 2 ? new Vector3() : this.containerMin.clone();
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* 获取当前填模式下对 map 的应用的缩放
|
|
795
|
+
* @returns
|
|
796
|
+
*/
|
|
797
|
+
getFitScale() {
|
|
798
|
+
var a;
|
|
799
|
+
const e = new Vector3(1, 1, 1), t = (a = this.map) == null ? void 0 : a.image, n = this.fit;
|
|
800
|
+
if (!t || n === 2 || n === 1)
|
|
801
|
+
return e;
|
|
802
|
+
const i = new Vector3(t.width, t.height, t.depth);
|
|
803
|
+
return e.copy(this.containerSize).divide(i), e;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* 获取当前填模式下对 map 的应用的变换矩阵
|
|
807
|
+
* @returns
|
|
808
|
+
*/
|
|
809
|
+
getFitMatrix() {
|
|
810
|
+
var i;
|
|
811
|
+
const e = new Matrix4(), t = (i = this.map) == null ? void 0 : i.image, n = this.fit;
|
|
812
|
+
if (!t || n === 2)
|
|
813
|
+
return e;
|
|
814
|
+
if (n === 0) {
|
|
815
|
+
const a = new Vector3(t.width, t.height, t.depth), l = this.containerSize.divide(a);
|
|
816
|
+
e.makeScale(l.x, l.y, l.z);
|
|
817
|
+
}
|
|
818
|
+
return e.setPosition(this.containerMin), e;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* 获取当前填模式下对 map 的应用的变换矩阵的逆矩阵
|
|
822
|
+
* @returns
|
|
823
|
+
*/
|
|
824
|
+
getFitMatrixInvert() {
|
|
825
|
+
return this.getFitMatrix().invert();
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Mesh三角形的渲染面
|
|
829
|
+
* @remarks
|
|
830
|
+
* 可设置为前面、后面、或者两面都渲染
|
|
831
|
+
* 如果只渲染前面,进入体积材质内部,体积材质就会消失
|
|
832
|
+
* 如果只渲染后面,体积初遮挡,就会消失
|
|
833
|
+
* 如果两面都渲染,则会隐藏看到容器的面
|
|
834
|
+
*/
|
|
835
|
+
// @ts-ignore
|
|
836
|
+
get side() {
|
|
837
|
+
return this._side;
|
|
838
|
+
}
|
|
839
|
+
set side(e) {
|
|
840
|
+
this._side = e, this.uniforms && (this.uniforms.isDoubleSide.value = e === DoubleSide, this.uniformsNeedUpdate = !0);
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* 透明度
|
|
844
|
+
* @remarks
|
|
845
|
+
* 决定整体的透明度
|
|
846
|
+
*/
|
|
847
|
+
// @ts-ignore
|
|
848
|
+
get opacity() {
|
|
849
|
+
return this.uniforms.opacity.value;
|
|
850
|
+
}
|
|
851
|
+
set opacity(e) {
|
|
852
|
+
this.uniforms && (this.uniforms.opacity.value = e), this.uniformsNeedUpdate = !0;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* 有效透明度的取值范围
|
|
856
|
+
* @remarks
|
|
857
|
+
* 如果最终颜色的透明度小于或等于 alphaRange.x ,则被认为是完全透明
|
|
858
|
+
* 如果最终颜色的透明度在于或等于 alphaRange.y ,则被认为是完全不透明
|
|
859
|
+
* 取值范围应当在 0 - 1
|
|
860
|
+
* @defaultValue {x:0,y:0.95}
|
|
861
|
+
*/
|
|
862
|
+
get alphaRange() {
|
|
863
|
+
return this.uniforms.alphaRange.value;
|
|
864
|
+
}
|
|
865
|
+
set alphaRange(e) {
|
|
866
|
+
this.uniforms.alphaRange.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* 是否开启雾化的效果
|
|
870
|
+
* @remarks
|
|
871
|
+
* 开启后的渲染效果会更像雾
|
|
872
|
+
* @defaultValue true
|
|
873
|
+
*/
|
|
874
|
+
get atomize() {
|
|
875
|
+
return this.uniforms.atomize.value;
|
|
876
|
+
}
|
|
877
|
+
set atomize(e) {
|
|
878
|
+
this.uniforms.atomize.value = e, this.uniformsNeedUpdate = !0;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* 体积材质渲染的采样数
|
|
882
|
+
* @remarks
|
|
883
|
+
* 采样数越高,占用的GPU资源就越大;所以该数据设置的适宜最好;
|
|
884
|
+
* @defaultValue 100
|
|
885
|
+
*/
|
|
886
|
+
get steps() {
|
|
887
|
+
return this.uniforms.steps.value;
|
|
888
|
+
}
|
|
889
|
+
set steps(e) {
|
|
890
|
+
this.uniforms.steps.value = e, this.uniformsNeedUpdate = !0;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* 颜色累积系数
|
|
894
|
+
* @remarks
|
|
895
|
+
* 它是对体积材质进行积分时使用的系数;只在开启雾化效果{@link VolumeMaterial.atomize}时才有效;
|
|
896
|
+
* 值越小,最终呈现出的效果就越雾化;
|
|
897
|
+
* @defaultValue 1
|
|
898
|
+
*/
|
|
899
|
+
get accFactor() {
|
|
900
|
+
return this.uniforms.accFactor.value;
|
|
901
|
+
}
|
|
902
|
+
set accFactor(e) {
|
|
903
|
+
this.uniforms && (this.uniforms.accFactor.value = e), this.uniformsNeedUpdate = !0;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* 将材质空间下的坐标转为 map 空间下的坐标
|
|
907
|
+
* @param coord - 材质空间下的坐标
|
|
908
|
+
* @returns
|
|
909
|
+
*/
|
|
910
|
+
toMapPosition(e) {
|
|
911
|
+
const t = new Vector3(e.x, e.y, e.z).applyMatrix4(this.getFitMatrixInvert());
|
|
912
|
+
return t.set(Math.trunc(t.x), Math.trunc(t.y), Math.trunc(t.z)), t;
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* 将材质空间下的深度转为 map 空间下的深度
|
|
916
|
+
* @param axis - map坐标系下的坐标轴
|
|
917
|
+
* @param depth - 材质空间下的深度
|
|
918
|
+
* @returns
|
|
919
|
+
*/
|
|
920
|
+
toMapDepth(e, t) {
|
|
921
|
+
const n = f$1.toKey(e), i = new Vector3();
|
|
922
|
+
i[n] = 1;
|
|
923
|
+
const a = new Matrix3().setFromMatrix4(this.getFitMatrix());
|
|
924
|
+
return i.applyMatrix3(a), t /= i.length(), Math.trunc(t);
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* 获取3D数据的切片
|
|
928
|
+
* @remarks
|
|
929
|
+
* 切片就是指定轴的指定位置的垂直截面
|
|
930
|
+
* @param axis - map坐标系下的坐标轴
|
|
931
|
+
* @param depth - 材质空间下,在轴方向的坐标值
|
|
932
|
+
* @returns
|
|
933
|
+
*/
|
|
934
|
+
getData3DSlice(e, t) {
|
|
935
|
+
const n = this.map;
|
|
936
|
+
return n != null && n.image ? (t = this.toMapDepth(e, t), Yn(n, e, t)) : null;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* 获取3D数据中指定坐标处的数据项目
|
|
940
|
+
* @param coord
|
|
941
|
+
* @returns
|
|
942
|
+
*/
|
|
943
|
+
getItem(e) {
|
|
944
|
+
const t = this.map;
|
|
945
|
+
return t != null && t.image ? Zn(t, this.toMapPosition(e)).value : null;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function bt(o) {
|
|
949
|
+
o.boundingBox || o.computeBoundingBox();
|
|
950
|
+
const { x: s, y: e, z: t } = o.boundingBox.min;
|
|
951
|
+
return o.translate(-s, -e, -t), o;
|
|
952
|
+
}
|
|
953
|
+
class rn extends Mesh {
|
|
954
|
+
constructor(e) {
|
|
955
|
+
var r;
|
|
956
|
+
const { width: t, height: n, depth: i } = ((r = e.map) == null ? void 0 : r.image) || {}, a = new BoxGeometry(t, n, i);
|
|
957
|
+
bt(a);
|
|
958
|
+
super(a, e);
|
|
959
|
+
v(this, "isVolumeMesh", !0);
|
|
960
|
+
// @ts-ignore
|
|
961
|
+
// override get geometry(){
|
|
962
|
+
// return this._geometry;
|
|
963
|
+
// }
|
|
964
|
+
// override set geometry(value){
|
|
965
|
+
// this._geometry = value;
|
|
966
|
+
// this.configMaterial();
|
|
967
|
+
// }
|
|
968
|
+
v(this, "_geometry");
|
|
969
|
+
/**
|
|
970
|
+
* 是否自动更新材质
|
|
971
|
+
* @remarks
|
|
972
|
+
* 当启动该选项后,在 VolumeMesh 监测到 geometry 变更时,会自动更新体积材质的相关选项,以适应新的 geometry
|
|
973
|
+
* @defaultValue true
|
|
974
|
+
*/
|
|
975
|
+
v(this, "autoUpdateMaterial", !0);
|
|
976
|
+
// @ts-ignore
|
|
977
|
+
// override get material(){
|
|
978
|
+
// return this._material;
|
|
979
|
+
// }
|
|
980
|
+
// override set material(value){
|
|
981
|
+
// this._material = value;
|
|
982
|
+
// this.configGeometry();
|
|
983
|
+
// }
|
|
984
|
+
v(this, "_material");
|
|
985
|
+
/**
|
|
986
|
+
* 是否自动更新几何体
|
|
987
|
+
* @remarks
|
|
988
|
+
* 当启动该选项后,在 VolumeMesh 监测到 material 变更时,会自动更新 geometry 的相关选项,以适应新的 体积材质
|
|
989
|
+
* @defaultValue true
|
|
990
|
+
*/
|
|
991
|
+
v(this, "autoUpdateGeometry", !0);
|
|
992
|
+
/**
|
|
993
|
+
* 自动规范化
|
|
994
|
+
* @remarks
|
|
995
|
+
* 开启该选项,设置新的 geometry 时,对 geometry 自动执行规范化操作
|
|
996
|
+
*/
|
|
997
|
+
v(this, "autoNormalize", !1);
|
|
998
|
+
Object.defineProperties(this, {
|
|
999
|
+
geometry: {
|
|
1000
|
+
get: () => this._geometry,
|
|
1001
|
+
set: (l) => {
|
|
1002
|
+
this._geometry = l, this.autoNormalize ? this.normalize() : this.autoUpdateMaterial && this.updateMaterial();
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
material: {
|
|
1006
|
+
get: () => this._material,
|
|
1007
|
+
set: (l) => {
|
|
1008
|
+
this._material = l, this.autoUpdateGeometry && this.updateGeometry();
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}), this.geometry = a, this.material = e;
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* 更新材质
|
|
1015
|
+
* @remarks
|
|
1016
|
+
* 更新体积材质的相关选项以使其匹配 geometry
|
|
1017
|
+
*/
|
|
1018
|
+
updateMaterial() {
|
|
1019
|
+
const { geometry: e, material: t } = this;
|
|
1020
|
+
if (!(t && e))
|
|
1021
|
+
return !1;
|
|
1022
|
+
e.boundingBox || e.computeBoundingBox();
|
|
1023
|
+
const { min: n, max: i } = e.boundingBox;
|
|
1024
|
+
t.containerMin = n, t.containerMax = i;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* 更新几何体
|
|
1028
|
+
* @remarks
|
|
1029
|
+
* 更新 geometry 的相关选项以使其匹配体积材质
|
|
1030
|
+
*/
|
|
1031
|
+
updateGeometry() {
|
|
1032
|
+
var c;
|
|
1033
|
+
const { geometry: e, material: t, autoUpdateMaterial: n } = this, i = (c = t.map) == null ? void 0 : c.image;
|
|
1034
|
+
if (!i)
|
|
1035
|
+
return !1;
|
|
1036
|
+
e.boundingBox || e.computeBoundingBox();
|
|
1037
|
+
const { width: a, height: r, depth: l } = i, u = e.boundingBox.getSize(new Vector3());
|
|
1038
|
+
e.scale(a / u.x, r / u.y, l / u.z), n && this.updateMaterial();
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* 规范化
|
|
1042
|
+
* @remarks
|
|
1043
|
+
* 将 geometry 的原点移动到包围盒的最小点处
|
|
1044
|
+
*/
|
|
1045
|
+
normalize() {
|
|
1046
|
+
const { geometry: e, autoUpdateMaterial: t } = this;
|
|
1047
|
+
e.boundingBox || e.computeBoundingBox();
|
|
1048
|
+
const { x: n, y: i, z: a } = e.boundingBox.min;
|
|
1049
|
+
e.translate(-n, -i, -a), t && this.updateMaterial();
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* 将材质空间下的坐标转为 map 空间下的坐标
|
|
1053
|
+
* @param coord - 材质空间下的坐标
|
|
1054
|
+
* @returns
|
|
1055
|
+
*/
|
|
1056
|
+
toMapPosition(e) {
|
|
1057
|
+
const t = this.worldToLocal(new Vector3(e.x, e.y, e.z));
|
|
1058
|
+
return this.material.toMapPosition(t);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* 将世界坐标系下的深度转为 material 空间下的深度
|
|
1062
|
+
* @param axis - 材质空间下的坐标轴
|
|
1063
|
+
* @param depth - 深度
|
|
1064
|
+
* @returns
|
|
1065
|
+
*/
|
|
1066
|
+
toMaterialDepth(e, t) {
|
|
1067
|
+
const n = f$1.toKey(e), i = new Vector3();
|
|
1068
|
+
i[n] = 1;
|
|
1069
|
+
const a = new Matrix3().setFromMatrix4(this.matrixWorld);
|
|
1070
|
+
return i.applyMatrix3(a), t /= i.length(), t;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* 将世界坐标系下的深度转为 map 空间下的深度
|
|
1074
|
+
* @param axis - map空间下的坐标轴
|
|
1075
|
+
* @param depth - 深度
|
|
1076
|
+
* @returns
|
|
1077
|
+
*/
|
|
1078
|
+
toMapDepth(e, t) {
|
|
1079
|
+
return t = this.toMaterialDepth(e, t), this.material.toMapDepth(e, t);
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* 获取3D数据的切片
|
|
1083
|
+
* @remarks
|
|
1084
|
+
* 切片就是指定轴的指定位置的垂直截面;
|
|
1085
|
+
* 轴和深度都是局部坐标系下的
|
|
1086
|
+
* @param axis - map空间下的坐标轴
|
|
1087
|
+
* @param depth - 世界空间下在轴方向上的坐标值
|
|
1088
|
+
* @returns
|
|
1089
|
+
*/
|
|
1090
|
+
getData3DSlice(e, t) {
|
|
1091
|
+
return t = this.toMaterialDepth(e, t), this.material.getData3DSlice(e, t);
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* 获取3D数据中指定坐标处的数据项目
|
|
1095
|
+
* @param coord - 世界坐标系下的坐标
|
|
1096
|
+
* @returns
|
|
1097
|
+
*/
|
|
1098
|
+
getItem(e) {
|
|
1099
|
+
const t = this.worldToLocal(new Vector3(e.x, e.y, e.z));
|
|
1100
|
+
return this.material.getItem(t);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
const Ct = `precision highp float;
|
|
1104
|
+
precision highp sampler3D;
|
|
1105
|
+
|
|
1106
|
+
uniform sampler3D map;
|
|
1107
|
+
uniform sampler2D gradient;
|
|
1108
|
+
|
|
1109
|
+
uniform bool atomize;
|
|
1110
|
+
uniform float steps;
|
|
1111
|
+
// 颜色累积系数
|
|
1112
|
+
uniform float accFactor;
|
|
1113
|
+
uniform vec2 range;
|
|
1114
|
+
// 是否丢弃超出范围的像素
|
|
1115
|
+
uniform bool discardOut;
|
|
1116
|
+
// 空值范围
|
|
1117
|
+
uniform vec2 voidRange;
|
|
1118
|
+
uniform float opacity;
|
|
1119
|
+
uniform vec2 alphaRange;
|
|
1120
|
+
uniform bool isDoubleSide;
|
|
1121
|
+
|
|
1122
|
+
in vec3 cameraPos;
|
|
1123
|
+
in vec3 lookDir;
|
|
1124
|
+
in vec3 displayMin;
|
|
1125
|
+
in vec3 displayMax;
|
|
1126
|
+
out vec4 fragColor;
|
|
1127
|
+
|
|
1128
|
+
vec4 colorBlend(vec4 near,vec4 far){
|
|
1129
|
+
float nA = near.a;
|
|
1130
|
+
if (nA >= 1.0){
|
|
1131
|
+
return near;
|
|
1132
|
+
}
|
|
1133
|
+
if (nA <= 0.0){
|
|
1134
|
+
return far;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
float fA = far.a;
|
|
1138
|
+
float a = fA + nA - fA*nA;
|
|
1139
|
+
vec3 color = (far.rgb * fA * (1.0 - nA) + near.rgb*nA)/a;
|
|
1140
|
+
return vec4(color,a);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
vec2 intersectBox( vec3 orig, vec3 dir ) {
|
|
1147
|
+
vec3 inv_dir = 1.0 / dir;
|
|
1148
|
+
vec3 tmin_tmp = (displayMin - orig ) * inv_dir;
|
|
1149
|
+
vec3 tmax_tmp = (displayMax - orig ) * inv_dir;
|
|
1150
|
+
vec3 tmin = min( tmin_tmp, tmax_tmp );
|
|
1151
|
+
vec3 tmax = max( tmin_tmp, tmax_tmp );
|
|
1152
|
+
float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
|
|
1153
|
+
float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
|
|
1154
|
+
return vec2( t0, t1 );
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
float getValue( vec3 point ) {
|
|
1158
|
+
return texture( map, point ).r;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// 获取梯度颜色
|
|
1162
|
+
vec4 getGradientColor(float val) {
|
|
1163
|
+
val = clamp( val, 0.0,1.0);
|
|
1164
|
+
return texture2D(gradient, vec2(val, 0.5));
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
void main(){
|
|
1171
|
+
vec3 rayDir = normalize( lookDir );
|
|
1172
|
+
|
|
1173
|
+
vec2 times = intersectBox( cameraPos, rayDir );
|
|
1174
|
+
float tMin = times.x;
|
|
1175
|
+
float tMax = times.y;
|
|
1176
|
+
if ( tMin > tMax || tMax < 0.0 ) discard;
|
|
1177
|
+
tMin = max( tMin, 0.0 );
|
|
1178
|
+
|
|
1179
|
+
vec3 point = cameraPos + tMin * rayDir;
|
|
1180
|
+
|
|
1181
|
+
float step = 1.0/steps;
|
|
1182
|
+
float opacityFactor = atomize ? step * accFactor : 1.0;
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
float invRangeLen = 1.0/(range.y - range.x);
|
|
1186
|
+
vec3 stepDir = rayDir * step;
|
|
1187
|
+
|
|
1188
|
+
vec4 finalColor = vec4( 0,0,0,0);
|
|
1189
|
+
float alphaMax = alphaRange.y;
|
|
1190
|
+
|
|
1191
|
+
for ( float t = tMin; t <= tMax; t += step,point += stepDir ) {
|
|
1192
|
+
float val = getValue( point);
|
|
1193
|
+
if (voidRange.x <= val && val <= voidRange.y ) continue;
|
|
1194
|
+
val = (val - range.x) * invRangeLen;
|
|
1195
|
+
if (discardOut && (val < 0.0 || val > 1.0)) continue;
|
|
1196
|
+
|
|
1197
|
+
vec4 gradientColor = getGradientColor(val);
|
|
1198
|
+
gradientColor.a *= opacityFactor;
|
|
1199
|
+
finalColor = colorBlend(finalColor,gradientColor);
|
|
1200
|
+
if ( finalColor.a >= alphaMax ) break;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
finalColor.a *= opacity;
|
|
1204
|
+
if ( finalColor.a <= alphaRange.x ) discard;
|
|
1205
|
+
if (isDoubleSide){
|
|
1206
|
+
finalColor.a = 1.0 - sqrt(1.0 - finalColor.a);
|
|
1207
|
+
}
|
|
1208
|
+
fragColor = finalColor;
|
|
1209
|
+
|
|
1210
|
+
}`;
|
|
1211
|
+
class sn extends Xe {
|
|
1212
|
+
constructor(e) {
|
|
1213
|
+
const { gradient: t, range: n, discardOut: i, voidRange: a, ...r } = e ?? {}, l = new Vector2().copy(n ?? { x: 0, y: 100 }), u = i ?? !0, c = new Vector2().copy(a ?? { x: -100, y: -1 }), m = {
|
|
1214
|
+
gradient: { value: t == null ? t : Gn(t) },
|
|
1215
|
+
range: { value: l },
|
|
1216
|
+
discardOut: { value: u },
|
|
1217
|
+
voidRange: { value: c }
|
|
1218
|
+
};
|
|
1219
|
+
super({ ...r, fragmentShader: Ct, uniforms: m });
|
|
1220
|
+
v(this, "isGradientVolumeMaterial", !0);
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* 数值的梯度映射纹理
|
|
1224
|
+
*/
|
|
1225
|
+
get gradient() {
|
|
1226
|
+
return this.uniforms.gradient.value;
|
|
1227
|
+
}
|
|
1228
|
+
set gradient(e) {
|
|
1229
|
+
this.uniforms.gradient.value = e, this.uniformsNeedUpdate = !0;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* 数值的映射区间
|
|
1233
|
+
* @remarks
|
|
1234
|
+
* x 为最小值,y 为最大值
|
|
1235
|
+
*
|
|
1236
|
+
* @defaultValue {x:0,y:100}
|
|
1237
|
+
*/
|
|
1238
|
+
get range() {
|
|
1239
|
+
return this.uniforms.range.value;
|
|
1240
|
+
}
|
|
1241
|
+
set range(e) {
|
|
1242
|
+
this.uniforms.range.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* 是否丢弃超出映射范围的数值
|
|
1246
|
+
* @remarks
|
|
1247
|
+
* 当数值超出映射区间 {@link GradientVolumeMaterial.range} 时,是否丢弃;
|
|
1248
|
+
*
|
|
1249
|
+
* 包含左右边界值
|
|
1250
|
+
* @defaultValue true
|
|
1251
|
+
*/
|
|
1252
|
+
get discardOut() {
|
|
1253
|
+
return this.uniforms.discardOut.value;
|
|
1254
|
+
}
|
|
1255
|
+
set discardOut(e) {
|
|
1256
|
+
this.uniforms.discardOut.value = e, this.uniformsNeedUpdate = !0;
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* 空值的范围
|
|
1260
|
+
* @remarks
|
|
1261
|
+
* 当数值在此范围中时,会被认为是空的值,渲染时会被丢弃
|
|
1262
|
+
*
|
|
1263
|
+
* 包含左右边界值
|
|
1264
|
+
*
|
|
1265
|
+
* @defaultValue {x:-100,y:-1}
|
|
1266
|
+
*/
|
|
1267
|
+
get voidRange() {
|
|
1268
|
+
return this.uniforms.voidRange.value;
|
|
1269
|
+
}
|
|
1270
|
+
set voidRange(e) {
|
|
1271
|
+
this.uniforms.voidRange.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
class Pt extends Data3DTexture {
|
|
1275
|
+
constructor(e, t, n, i, a) {
|
|
1276
|
+
super(e, t, n, i);
|
|
1277
|
+
v(this, "isGradientData3DTexture", !0);
|
|
1278
|
+
this.format = RedFormat, this.type = a ?? FloatType, this.minFilter = this.magFilter = LinearFilter, this.unpackAlignment = 1, this.needsUpdate = !0;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* 获取3D数据的切片
|
|
1282
|
+
* @remarks
|
|
1283
|
+
* 切片就是指定轴的指定位置的垂直截面
|
|
1284
|
+
* @param axis - 轴
|
|
1285
|
+
* @param depth - 在轴上的坐标值
|
|
1286
|
+
* @returns
|
|
1287
|
+
*/
|
|
1288
|
+
getData3DSlice(e, t) {
|
|
1289
|
+
const { data: n, width: i, height: a, depth: r } = this.image;
|
|
1290
|
+
return E({ data: n, size: { x: i, y: a, z: r } }, e, t, 1);
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* 获取3D数据中指定坐标处的数据项目
|
|
1294
|
+
* @remarks
|
|
1295
|
+
* 在 ImageData3DTexture 中,与 {@link ImageData3DTexture.getColor} 返回的值一样;
|
|
1296
|
+
* @param coord
|
|
1297
|
+
* @returns
|
|
1298
|
+
*/
|
|
1299
|
+
getItem(e) {
|
|
1300
|
+
const { data: t, width: n, height: i, depth: a } = this.image;
|
|
1301
|
+
return $({ data: t, size: { x: n, y: i, z: a } }, e).value;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* 获取3D数据中指定坐标处的值
|
|
1305
|
+
* @param coord - 坐标
|
|
1306
|
+
* @returns
|
|
1307
|
+
*/
|
|
1308
|
+
getValue(e) {
|
|
1309
|
+
const { data: t, width: n, height: i, depth: a } = this.image;
|
|
1310
|
+
return tt({ data: t, size: { x: n, y: i, z: a } }, e).value;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
function ln(o, s) {
|
|
1314
|
+
const { data: e, size: t } = o, { x: n, y: i, z: a } = t, r = n * i * a, { voidValue: l = 0, uint8: u } = s ?? {};
|
|
1315
|
+
let c;
|
|
1316
|
+
if (u) {
|
|
1317
|
+
c = new Uint8Array(r);
|
|
1318
|
+
for (let m = 0; m < r; m++) {
|
|
1319
|
+
const f = e[m] ?? l;
|
|
1320
|
+
c[m] = Math.trunc(f);
|
|
1321
|
+
}
|
|
1322
|
+
} else {
|
|
1323
|
+
c = new Float32Array(r);
|
|
1324
|
+
for (let m = 0; m < r; m++) {
|
|
1325
|
+
const f = e[m] ?? l;
|
|
1326
|
+
c[m] = f;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
const p = u ? UnsignedByteType : FloatType;
|
|
1330
|
+
return new Pt(c, n, i, a, p);
|
|
1331
|
+
}
|
|
1332
|
+
const Nt = `precision highp float;
|
|
1333
|
+
precision highp sampler3D;
|
|
1334
|
+
|
|
1335
|
+
uniform sampler3D map;
|
|
1336
|
+
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
// 颜色累积系数
|
|
1340
|
+
uniform float accFactor;
|
|
1341
|
+
uniform bool isDoubleSide;
|
|
1342
|
+
uniform bool atomize;
|
|
1343
|
+
|
|
1344
|
+
|
|
1345
|
+
uniform float opacity;
|
|
1346
|
+
uniform vec2 alphaRange;
|
|
1347
|
+
uniform float steps;
|
|
1348
|
+
|
|
1349
|
+
in vec3 cameraPos;
|
|
1350
|
+
in vec3 lookDir;
|
|
1351
|
+
in vec3 displayMin;
|
|
1352
|
+
in vec3 displayMax;
|
|
1353
|
+
out vec4 fragColor;
|
|
1354
|
+
|
|
1355
|
+
// 混合颜色
|
|
1356
|
+
vec4 colorBlend(vec4 near,vec4 far){
|
|
1357
|
+
float nA = near.a;
|
|
1358
|
+
if (nA >= 1.0){
|
|
1359
|
+
return near;
|
|
1360
|
+
}
|
|
1361
|
+
if (nA <= 0.0){
|
|
1362
|
+
return far;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
float fA = far.a;
|
|
1366
|
+
float a = fA + nA - fA*nA;
|
|
1367
|
+
vec3 color = (far.rgb * fA * (1.0 - nA) + near.rgb*nA)/a;
|
|
1368
|
+
return vec4(color,a);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
|
|
1373
|
+
|
|
1374
|
+
// 包围盒求交
|
|
1375
|
+
vec2 intersectBox( vec3 orig, vec3 dir ) {
|
|
1376
|
+
vec3 inv_dir = 1.0 / dir;
|
|
1377
|
+
vec3 tmin_tmp = (displayMin - orig ) * inv_dir;
|
|
1378
|
+
vec3 tmax_tmp = (displayMax - orig ) * inv_dir;
|
|
1379
|
+
vec3 tmin = min( tmin_tmp, tmax_tmp );
|
|
1380
|
+
vec3 tmax = max( tmin_tmp, tmax_tmp );
|
|
1381
|
+
float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
|
|
1382
|
+
float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
|
|
1383
|
+
return vec2( t0, t1 );
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
void main(){
|
|
1389
|
+
vec3 rayDir = normalize( lookDir );
|
|
1390
|
+
|
|
1391
|
+
vec2 times = intersectBox( cameraPos, rayDir );
|
|
1392
|
+
float tMin = times.x;
|
|
1393
|
+
float tMax = times.y;
|
|
1394
|
+
if ( tMin > tMax || tMax < 0.0 ) discard;
|
|
1395
|
+
tMin = max( tMin, 0.0 );
|
|
1396
|
+
|
|
1397
|
+
vec3 point = cameraPos + tMin * rayDir;
|
|
1398
|
+
|
|
1399
|
+
float step = 1.0/steps;
|
|
1400
|
+
float opacityFactor = atomize ? step * accFactor : 1.0;
|
|
1401
|
+
|
|
1402
|
+
vec3 stepDir = rayDir * step;
|
|
1403
|
+
|
|
1404
|
+
vec4 finalColor = vec4( 0,0,0,0);
|
|
1405
|
+
float alphaMax = alphaRange.y;
|
|
1406
|
+
|
|
1407
|
+
for ( float t = tMin; t <= tMax; t += step,point += stepDir ) {
|
|
1408
|
+
vec4 textureColor = texture( map, point );
|
|
1409
|
+
textureColor.a *= opacityFactor;
|
|
1410
|
+
finalColor = colorBlend(finalColor,textureColor);
|
|
1411
|
+
if ( finalColor.a >= alphaMax ) break;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
finalColor.a *= opacity;
|
|
1415
|
+
if ( finalColor.a <= alphaRange.x ) discard;
|
|
1416
|
+
if (isDoubleSide){
|
|
1417
|
+
finalColor.a = 1.0 - sqrt(1.0 - finalColor.a);
|
|
1418
|
+
}
|
|
1419
|
+
fragColor = finalColor;
|
|
1420
|
+
|
|
1421
|
+
}`;
|
|
1422
|
+
class cn extends Xe {
|
|
1423
|
+
constructor(e) {
|
|
1424
|
+
super({ ...e, fragmentShader: Nt });
|
|
1425
|
+
v(this, "isImageVolumeMaterial", !0);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
function Ut(o, s, e) {
|
|
1429
|
+
const t = e ?? {}, { x: n, y: i } = t.range ?? { x: 0, y: 100 }, a = t.discardOut ?? !0, { x: r, y: l } = t.voidRange ?? { x: -100, y: -1 }, u = t.voidColor ?? [0, 0, 0, 0], { width: c, height: p } = s, m = Math.trunc(p / 2), f = c - 1;
|
|
1430
|
+
function h(x) {
|
|
1431
|
+
const y = Math.trunc(f * x);
|
|
1432
|
+
return H(s, m, y);
|
|
1433
|
+
}
|
|
1434
|
+
const _ = 1 / (i - n), { data: M, size: S } = o, D = M.length, w = [];
|
|
1435
|
+
for (let x = 0; x < D; x++) {
|
|
1436
|
+
let y = u, g = M[x];
|
|
1437
|
+
(g <= r || l <= g) && (g = (g - n) * _, a && (g < 0 || g > 1) || (g = Math.min(Math.max(g, 0), 1), y = h(g))), w.push(...y);
|
|
1438
|
+
}
|
|
1439
|
+
return { data: w, size: S };
|
|
1440
|
+
}
|
|
1441
|
+
class $e extends Data3DTexture {
|
|
1442
|
+
constructor(e, t, n, i) {
|
|
1443
|
+
super(e, t, n, i);
|
|
1444
|
+
v(this, "isImageData3DTexture", !0);
|
|
1445
|
+
this.format = RGBAFormat, this.type = UnsignedByteType, this.minFilter = this.magFilter = LinearFilter, this.unpackAlignment = 1, this.needsUpdate = !0;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* 获取3D数据的切片
|
|
1449
|
+
* @remarks
|
|
1450
|
+
* 切片就是指定轴的指定位置的垂直截面
|
|
1451
|
+
* @param axis - 轴
|
|
1452
|
+
* @param depth - 在轴上的坐标值
|
|
1453
|
+
* @returns
|
|
1454
|
+
*/
|
|
1455
|
+
getData3DSlice(e, t) {
|
|
1456
|
+
const { data: n, width: i, height: a, depth: r } = this.image;
|
|
1457
|
+
return E({ data: n, size: { x: i, y: a, z: r } }, e, t, 4);
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* 获取3D数据中指定坐标处的数据项目
|
|
1461
|
+
* @remarks
|
|
1462
|
+
* 在 ImageData3DTexture 中,与 {@link ImageData3DTexture.getColor} 返回的值一样;
|
|
1463
|
+
* @param coord
|
|
1464
|
+
* @returns
|
|
1465
|
+
*/
|
|
1466
|
+
getItem(e) {
|
|
1467
|
+
return this.getColor(e);
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* 获取3D图像中指定坐标处的颜色
|
|
1471
|
+
* @param coord - 坐标
|
|
1472
|
+
* @returns
|
|
1473
|
+
*/
|
|
1474
|
+
getColor(e) {
|
|
1475
|
+
const { data: t, width: n, height: i, depth: a } = this.image;
|
|
1476
|
+
return $({ data: t, size: { x: n, y: i, z: a } }, e, 4).value;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function un(o, s, e) {
|
|
1480
|
+
const t = (e == null ? void 0 : e.reverseY) ?? !0, { data: n, width: i, height: a, depth: r, colorSpace: l } = nt(o, s, { ...e, reverseY: t }), u = new $e(n, i, a, r);
|
|
1481
|
+
return l === "srgb" && (u.colorSpace = "srgb"), u;
|
|
1482
|
+
}
|
|
1483
|
+
function mn(o, s) {
|
|
1484
|
+
const e = s.gradient, t = Array.isArray(e) ? B(e, 256, 1) : L(e) ? e : K(e);
|
|
1485
|
+
let n = o;
|
|
1486
|
+
P(o) && (n = {
|
|
1487
|
+
// @ts-ignore
|
|
1488
|
+
data: o.data,
|
|
1489
|
+
size: { x: o.width, y: o.height, z: o.depth }
|
|
1490
|
+
});
|
|
1491
|
+
const { data: i, size: a } = Ut(n, t, s), r = Uint8ClampedArray.from(i);
|
|
1492
|
+
return new $e(r, a.x, a.y, a.z);
|
|
1493
|
+
}
|
|
1494
|
+
const At = `out vec3 lookDir;
|
|
1495
|
+
out vec3 normalDir;
|
|
1496
|
+
|
|
1497
|
+
#if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )
|
|
1498
|
+
out vec4 verColor;
|
|
1499
|
+
#endif
|
|
1500
|
+
|
|
1501
|
+
void main() {
|
|
1502
|
+
vec3 cameraPos = vec3( inverse( modelMatrix ) * vec4( cameraPosition, 1.0 ) ).xyz;
|
|
1503
|
+
lookDir = position - cameraPos;
|
|
1504
|
+
normalDir = normal;
|
|
1505
|
+
|
|
1506
|
+
#if defined( USE_COLOR_ALPHA )
|
|
1507
|
+
verColor = color;
|
|
1508
|
+
#elif defined( USE_INSTANCING_COLOR )
|
|
1509
|
+
overColor = vec3(instanceColor,1.0);
|
|
1510
|
+
#elif defined( USE_COLOR )
|
|
1511
|
+
overColor = vec3(color,1.0);
|
|
1512
|
+
#endif
|
|
1513
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
1514
|
+
}`, Ft = `uniform vec3 color;
|
|
1515
|
+
uniform float solid;
|
|
1516
|
+
uniform float exp;
|
|
1517
|
+
|
|
1518
|
+
uniform float opacity;
|
|
1519
|
+
uniform bool isDoubleSide;
|
|
1520
|
+
|
|
1521
|
+
in vec3 lookDir;
|
|
1522
|
+
in vec3 normalDir;
|
|
1523
|
+
|
|
1524
|
+
#if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )
|
|
1525
|
+
in vec4 verColor;
|
|
1526
|
+
#endif
|
|
1527
|
+
|
|
1528
|
+
out vec4 fragColor;
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
void main(){
|
|
1532
|
+
#if defined( USE_COLOR_ALPHA ) || defined( USE_COLOR )
|
|
1533
|
+
fragColor = verColor;
|
|
1534
|
+
#else
|
|
1535
|
+
fragColor = vec4(color,1.0);
|
|
1536
|
+
#endif
|
|
1537
|
+
|
|
1538
|
+
vec3 dir = normalize(lookDir);
|
|
1539
|
+
vec3 nor = normalize(normalDir);
|
|
1540
|
+
float depth = abs(dot(nor,dir));
|
|
1541
|
+
float dist = sqrt(1.0 - pow(depth,2.0));
|
|
1542
|
+
|
|
1543
|
+
float finalAlpha = fragColor.a * depth;
|
|
1544
|
+
if (dist > solid) {
|
|
1545
|
+
float distAlpha = 1.0 - (dist - solid)/(1.0 - solid);
|
|
1546
|
+
finalAlpha *= pow(distAlpha,exp);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
finalAlpha *= opacity;
|
|
1550
|
+
if ( finalAlpha == 0.0 ) discard;
|
|
1551
|
+
if (isDoubleSide){
|
|
1552
|
+
finalAlpha = 1.0 - sqrt(1.0 - finalAlpha);
|
|
1553
|
+
}
|
|
1554
|
+
fragColor.a = finalAlpha;
|
|
1555
|
+
}`;
|
|
1556
|
+
class dn extends ShaderMaterial {
|
|
1557
|
+
constructor(e) {
|
|
1558
|
+
const t = e ?? {}, n = t.color ?? new Color(1, 1, 1), i = t.solid ?? 0, a = t.exp ?? 1, r = t.opacity ?? 1, l = t.side ?? FrontSide;
|
|
1559
|
+
super({
|
|
1560
|
+
glslVersion: GLSL3,
|
|
1561
|
+
// @ts-ignore
|
|
1562
|
+
uniforms: {
|
|
1563
|
+
color: { value: n },
|
|
1564
|
+
solid: { value: i },
|
|
1565
|
+
exp: { value: a },
|
|
1566
|
+
opacity: { value: r },
|
|
1567
|
+
isDoubleSide: { value: !1 }
|
|
1568
|
+
},
|
|
1569
|
+
vertexShader: At,
|
|
1570
|
+
fragmentShader: Ft,
|
|
1571
|
+
side: FrontSide,
|
|
1572
|
+
transparent: !0
|
|
1573
|
+
});
|
|
1574
|
+
v(this, "isSphereFogMaterial", !0);
|
|
1575
|
+
v(this, "_side", FrontSide);
|
|
1576
|
+
this.opacity = r, this.side = l;
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Mesh三角形的渲染面
|
|
1580
|
+
* @remarks
|
|
1581
|
+
* 可设置为前面、后面、或者两面都渲染
|
|
1582
|
+
* 如果只渲染前面,进入体积材质内部,体积材质就会消失
|
|
1583
|
+
* 如果只渲染后面,体积初遮挡,就会消失
|
|
1584
|
+
* 如果两面都渲染,则会隐藏看到容器的面
|
|
1585
|
+
*/
|
|
1586
|
+
// @ts-ignore
|
|
1587
|
+
get side() {
|
|
1588
|
+
return this._side;
|
|
1589
|
+
}
|
|
1590
|
+
set side(e) {
|
|
1591
|
+
this._side = e, this.uniforms && (this.uniforms.isDoubleSide.value = e === DoubleSide, this.uniformsNeedUpdate = !0);
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* 球形雾的颜色
|
|
1595
|
+
* @remarks
|
|
1596
|
+
* 当开启顶点颜色 {@link SphereFogMaterial.vertexColors} 时,此设置将无论;
|
|
1597
|
+
*/
|
|
1598
|
+
get color() {
|
|
1599
|
+
return this.uniforms.color.value;
|
|
1600
|
+
}
|
|
1601
|
+
set color(e) {
|
|
1602
|
+
this.uniforms.color.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* 透明度
|
|
1606
|
+
* @remarks
|
|
1607
|
+
* 决定整体的透明度
|
|
1608
|
+
* @defaultValue 1
|
|
1609
|
+
*/
|
|
1610
|
+
// @ts-ignore
|
|
1611
|
+
get opacity() {
|
|
1612
|
+
return this.uniforms.opacity.value;
|
|
1613
|
+
}
|
|
1614
|
+
set opacity(e) {
|
|
1615
|
+
this.uniforms && (this.uniforms.opacity.value = e), this.uniformsNeedUpdate = !0;
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* 实心因子
|
|
1619
|
+
* @remarks
|
|
1620
|
+
* 在实心范围内,球形雾不会衰减
|
|
1621
|
+
* @defaultValue 0
|
|
1622
|
+
*/
|
|
1623
|
+
get solid() {
|
|
1624
|
+
return this.uniforms.solid.value;
|
|
1625
|
+
}
|
|
1626
|
+
set solid(e) {
|
|
1627
|
+
this.uniforms && (this.uniforms.solid.value = e), this.uniformsNeedUpdate = !0;
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* 雾的衰减指数
|
|
1631
|
+
* @defaultValue 1
|
|
1632
|
+
*/
|
|
1633
|
+
get exp() {
|
|
1634
|
+
return this.uniforms.exp.value;
|
|
1635
|
+
}
|
|
1636
|
+
set exp(e) {
|
|
1637
|
+
this.uniforms && (this.uniforms.exp.value = e), this.uniformsNeedUpdate = !0;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
class Ye extends ShaderMaterial {
|
|
1641
|
+
constructor(e, t) {
|
|
1642
|
+
const { solid: n = 0, exp: i = 1, useRadius: a = !0, sizeAttenuation: r = !0, star: l = !1, ...u } = e ?? {}, { uniforms: c, ...p } = t || {}, m = {
|
|
1643
|
+
star: { value: l },
|
|
1644
|
+
solid: { value: n },
|
|
1645
|
+
exp: { value: i }
|
|
1646
|
+
};
|
|
1647
|
+
super({
|
|
1648
|
+
// glslVersion: GLSL3,
|
|
1649
|
+
// @ts-ignore
|
|
1650
|
+
uniforms: UniformsUtils.merge([ShaderLib.points.uniforms, m, c]),
|
|
1651
|
+
transparent: !0,
|
|
1652
|
+
depthTest: !1,
|
|
1653
|
+
// depthWrite:false,
|
|
1654
|
+
defines: {
|
|
1655
|
+
useRadius: a
|
|
1656
|
+
},
|
|
1657
|
+
...p
|
|
1658
|
+
});
|
|
1659
|
+
v(this, "isFogPointsMaterial", !0);
|
|
1660
|
+
/**
|
|
1661
|
+
* 点的大小是否因相机深度而衰减
|
|
1662
|
+
* @remarks
|
|
1663
|
+
* 仅限透视摄像头
|
|
1664
|
+
*
|
|
1665
|
+
* @defaultValue true
|
|
1666
|
+
*/
|
|
1667
|
+
v(this, "sizeAttenuation", !0);
|
|
1668
|
+
Object.assign(this, { ...u, solid: n, exp: i, sizeAttenuation: r });
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* 使用来自Texture的数据设置点的颜色
|
|
1672
|
+
* @remarks
|
|
1673
|
+
* 可以选择包括一个alpha通道,通常与 .transparent或.alphaTest。
|
|
1674
|
+
*/
|
|
1675
|
+
get map() {
|
|
1676
|
+
return this.uniforms.map.value;
|
|
1677
|
+
}
|
|
1678
|
+
set map(e) {
|
|
1679
|
+
this.uniforms.map.value = e, this.uniformsNeedUpdate = !0;
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* 是否渲染成星星的样式
|
|
1683
|
+
* @remarks
|
|
1684
|
+
* 否则,将被渲染成球形
|
|
1685
|
+
*/
|
|
1686
|
+
get star() {
|
|
1687
|
+
return this.uniforms.star.value;
|
|
1688
|
+
}
|
|
1689
|
+
set star(e) {
|
|
1690
|
+
this.uniforms.star.value = e, this.uniformsNeedUpdate = !0;
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* 点的大小
|
|
1694
|
+
* @defaultValue 1.0
|
|
1695
|
+
*/
|
|
1696
|
+
get size() {
|
|
1697
|
+
return this.uniforms.size.value;
|
|
1698
|
+
}
|
|
1699
|
+
set size(e) {
|
|
1700
|
+
this.uniforms.size.value = e, this.uniformsNeedUpdate = !0;
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* 透明度
|
|
1704
|
+
* @remarks
|
|
1705
|
+
* 决定整体的透明度
|
|
1706
|
+
* @defaultValue 1
|
|
1707
|
+
*/
|
|
1708
|
+
// @ts-ignore
|
|
1709
|
+
get opacity() {
|
|
1710
|
+
return this.uniforms.opacity.value;
|
|
1711
|
+
}
|
|
1712
|
+
set opacity(e) {
|
|
1713
|
+
this.uniforms && (this.uniforms.opacity.value = e), this.uniformsNeedUpdate = !0;
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* 实心因子
|
|
1717
|
+
* @remarks
|
|
1718
|
+
* 在实心范围内,雾点不会衰减
|
|
1719
|
+
* @defaultValue 0
|
|
1720
|
+
*/
|
|
1721
|
+
get solid() {
|
|
1722
|
+
return this.uniforms.solid.value;
|
|
1723
|
+
}
|
|
1724
|
+
set solid(e) {
|
|
1725
|
+
this.uniforms && (this.uniforms.solid.value = e), this.uniformsNeedUpdate = !0;
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* 雾的衰减指数
|
|
1729
|
+
* @defaultValue 1
|
|
1730
|
+
*/
|
|
1731
|
+
get exp() {
|
|
1732
|
+
return this.uniforms.exp.value;
|
|
1733
|
+
}
|
|
1734
|
+
set exp(e) {
|
|
1735
|
+
this.uniforms && (this.uniforms.exp.value = e), this.uniformsNeedUpdate = !0;
|
|
1736
|
+
}
|
|
1737
|
+
get scale() {
|
|
1738
|
+
return this.uniforms.scale.value;
|
|
1739
|
+
}
|
|
1740
|
+
set scale(e) {
|
|
1741
|
+
this.uniforms && (this.uniforms.scale.value = e), this.uniformsNeedUpdate = !0;
|
|
1742
|
+
}
|
|
1743
|
+
get fogDensity() {
|
|
1744
|
+
return this.uniforms.fogDensity.value;
|
|
1745
|
+
}
|
|
1746
|
+
set fogDensity(e) {
|
|
1747
|
+
this.uniforms && (this.uniforms.fogDensity.value = e), this.uniformsNeedUpdate = !0;
|
|
1748
|
+
}
|
|
1749
|
+
get fogNear() {
|
|
1750
|
+
return this.uniforms.fogNear.value;
|
|
1751
|
+
}
|
|
1752
|
+
set fogNear(e) {
|
|
1753
|
+
this.uniforms && (this.uniforms.fogNear.value = e), this.uniformsNeedUpdate = !0;
|
|
1754
|
+
}
|
|
1755
|
+
get fogFar() {
|
|
1756
|
+
return this.uniforms.fogFar.value;
|
|
1757
|
+
}
|
|
1758
|
+
set fogFar(e) {
|
|
1759
|
+
this.uniforms && (this.uniforms.fogFar.value = e), this.uniformsNeedUpdate = !0;
|
|
1760
|
+
}
|
|
1761
|
+
get fogColor() {
|
|
1762
|
+
return this.uniforms.fogColor.value;
|
|
1763
|
+
}
|
|
1764
|
+
set fogColor(e) {
|
|
1765
|
+
this.uniforms.fogColor.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
const Rt = `#ifdef useRadius
|
|
1769
|
+
attribute float radius;
|
|
1770
|
+
#endif
|
|
1771
|
+
|
|
1772
|
+
uniform float size;
|
|
1773
|
+
uniform float scale;
|
|
1774
|
+
|
|
1775
|
+
#include <common>
|
|
1776
|
+
#include <color_pars_vertex>
|
|
1777
|
+
#include <fog_pars_vertex>
|
|
1778
|
+
#include <morphtarget_pars_vertex>
|
|
1779
|
+
#include <logdepthbuf_pars_vertex>
|
|
1780
|
+
#include <clipping_planes_pars_vertex>
|
|
1781
|
+
|
|
1782
|
+
#ifdef USE_POINTS_UV
|
|
1783
|
+
|
|
1784
|
+
varying vec2 vUv;
|
|
1785
|
+
uniform mat3 uvTransform;
|
|
1786
|
+
|
|
1787
|
+
#endif
|
|
1788
|
+
|
|
1789
|
+
void main() {
|
|
1790
|
+
|
|
1791
|
+
#ifdef USE_POINTS_UV
|
|
1792
|
+
|
|
1793
|
+
vUv = ( uvTransform * vec3( uv, 1 ) ).xy;
|
|
1794
|
+
|
|
1795
|
+
#endif
|
|
1796
|
+
|
|
1797
|
+
#include <color_vertex>
|
|
1798
|
+
#include <morphcolor_vertex>
|
|
1799
|
+
#include <begin_vertex>
|
|
1800
|
+
#include <morphtarget_vertex>
|
|
1801
|
+
#include <project_vertex>
|
|
1802
|
+
|
|
1803
|
+
#ifdef useRadius
|
|
1804
|
+
gl_PointSize = radius;
|
|
1805
|
+
#else
|
|
1806
|
+
gl_PointSize = size;
|
|
1807
|
+
#endif
|
|
1808
|
+
|
|
1809
|
+
#ifdef USE_SIZEATTENUATION
|
|
1810
|
+
|
|
1811
|
+
bool isPerspective = isPerspectiveMatrix( projectionMatrix );
|
|
1812
|
+
|
|
1813
|
+
if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );
|
|
1814
|
+
|
|
1815
|
+
#endif
|
|
1816
|
+
|
|
1817
|
+
#include <logdepthbuf_vertex>
|
|
1818
|
+
#include <clipping_planes_vertex>
|
|
1819
|
+
#include <worldpos_vertex>
|
|
1820
|
+
#include <fog_vertex>
|
|
1821
|
+
|
|
1822
|
+
}`, It = `uniform float solid;
|
|
1823
|
+
uniform float exp;
|
|
1824
|
+
uniform bool star;
|
|
1825
|
+
|
|
1826
|
+
uniform vec3 diffuse;
|
|
1827
|
+
uniform float opacity;
|
|
1828
|
+
|
|
1829
|
+
#include <common>
|
|
1830
|
+
#include <color_pars_fragment>
|
|
1831
|
+
#include <map_particle_pars_fragment>
|
|
1832
|
+
#include <alphatest_pars_fragment>
|
|
1833
|
+
#include <fog_pars_fragment>
|
|
1834
|
+
#include <logdepthbuf_pars_fragment>
|
|
1835
|
+
#include <clipping_planes_pars_fragment>
|
|
1836
|
+
|
|
1837
|
+
|
|
1838
|
+
vec4 getColor(vec4 originColor){
|
|
1839
|
+
float finalAlpha = originColor.a;
|
|
1840
|
+
float dist = 0.0;
|
|
1841
|
+
if (star){
|
|
1842
|
+
vec2 coord = abs(gl_PointCoord - vec2(0.5));
|
|
1843
|
+
dist = max(coord.x,coord.y);
|
|
1844
|
+
}else{
|
|
1845
|
+
dist = distance(gl_PointCoord,vec2(0.5));
|
|
1846
|
+
if (dist>0.5) discard;
|
|
1847
|
+
}
|
|
1848
|
+
dist /= 0.5;
|
|
1849
|
+
float depth = sqrt(1.0 - pow(dist,2.0));
|
|
1850
|
+
finalAlpha *= depth;
|
|
1851
|
+
if (dist > solid) {
|
|
1852
|
+
float distAlpha = 1.0 - (dist - solid)/(1.0 - solid);
|
|
1853
|
+
finalAlpha *= pow(distAlpha,exp);
|
|
1854
|
+
}
|
|
1855
|
+
originColor.a = finalAlpha;
|
|
1856
|
+
return originColor;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
void main() {
|
|
1860
|
+
|
|
1861
|
+
#include <clipping_planes_fragment>
|
|
1862
|
+
|
|
1863
|
+
vec3 outgoingLight = vec3( 0.0 );
|
|
1864
|
+
vec4 diffuseColor = vec4( diffuse, opacity );
|
|
1865
|
+
|
|
1866
|
+
#include <logdepthbuf_fragment>
|
|
1867
|
+
#include <map_particle_fragment>
|
|
1868
|
+
#include <color_fragment>
|
|
1869
|
+
#include <alphatest_fragment>
|
|
1870
|
+
|
|
1871
|
+
diffuseColor = getColor(diffuseColor);
|
|
1872
|
+
outgoingLight = diffuseColor.rgb;
|
|
1873
|
+
|
|
1874
|
+
#include <output_fragment>
|
|
1875
|
+
#include <tonemapping_fragment>
|
|
1876
|
+
#include <encodings_fragment>
|
|
1877
|
+
#include <fog_fragment>
|
|
1878
|
+
#include <premultiplied_alpha_fragment>
|
|
1879
|
+
|
|
1880
|
+
}`;
|
|
1881
|
+
class Ot extends Ye {
|
|
1882
|
+
constructor(e) {
|
|
1883
|
+
super(e, { vertexShader: Rt, fragmentShader: It });
|
|
1884
|
+
v(this, "isColorFogPointsMaterial", !0);
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* 雾点的颜色
|
|
1888
|
+
* @remarks
|
|
1889
|
+
* 当开启顶点颜色 {@link SphereFogMaterial.vertexColors} 时,此设置将无论;
|
|
1890
|
+
*/
|
|
1891
|
+
get color() {
|
|
1892
|
+
return this.uniforms.diffuse.value;
|
|
1893
|
+
}
|
|
1894
|
+
set color(e) {
|
|
1895
|
+
this.uniforms.diffuse.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1896
|
+
}
|
|
1897
|
+
get alphaMap() {
|
|
1898
|
+
return this.uniforms.alphaMap.value;
|
|
1899
|
+
}
|
|
1900
|
+
set alphaMap(e) {
|
|
1901
|
+
this.uniforms && (this.uniforms.alphaMap.value = e), this.uniformsNeedUpdate = !0;
|
|
1902
|
+
}
|
|
1903
|
+
get uvTransform() {
|
|
1904
|
+
return this.uniforms.uvTransform.value;
|
|
1905
|
+
}
|
|
1906
|
+
set uvTransform(e) {
|
|
1907
|
+
this.uniforms && this.uniforms.uvTransform.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
function Tt(o) {
|
|
1911
|
+
const { points: s, radius: e = 10, color: t = [0, 0, 0, 0] } = o, n = [], i = [], a = [];
|
|
1912
|
+
for (const { x: l, y: u, z: c, radius: p, color: m } of s) {
|
|
1913
|
+
n.push(l, u, c), i.push(p ?? e);
|
|
1914
|
+
const f = m ?? t, h = f[3];
|
|
1915
|
+
f[3] = Math.trunc(h * 255), a.push(...f);
|
|
1916
|
+
}
|
|
1917
|
+
const r = new BufferGeometry();
|
|
1918
|
+
return r.setAttribute("position", new Float32BufferAttribute(n, 3)), r.setAttribute("radius", new Float32BufferAttribute(i, 1)), r.setAttribute("color", new Uint8ClampedBufferAttribute(a, 4, !0)), r;
|
|
1919
|
+
}
|
|
1920
|
+
function pn(o) {
|
|
1921
|
+
const s = new Ot(o), e = Tt(o);
|
|
1922
|
+
return new Points(e, s);
|
|
1923
|
+
}
|
|
1924
|
+
const Vt = `attribute float value;
|
|
1925
|
+
uniform vec2 range;
|
|
1926
|
+
varying float vValue;
|
|
1927
|
+
#ifdef useRadius
|
|
1928
|
+
attribute float radius;
|
|
1929
|
+
#endif
|
|
1930
|
+
|
|
1931
|
+
|
|
1932
|
+
uniform float size;
|
|
1933
|
+
uniform float scale;
|
|
1934
|
+
|
|
1935
|
+
#include <common>
|
|
1936
|
+
// #include <color_pars_vertex>
|
|
1937
|
+
#include <fog_pars_vertex>
|
|
1938
|
+
#include <morphtarget_pars_vertex>
|
|
1939
|
+
#include <logdepthbuf_pars_vertex>
|
|
1940
|
+
#include <clipping_planes_pars_vertex>
|
|
1941
|
+
|
|
1942
|
+
#ifdef USE_POINTS_UV
|
|
1943
|
+
|
|
1944
|
+
varying vec2 vUv;
|
|
1945
|
+
uniform mat3 uvTransform;
|
|
1946
|
+
|
|
1947
|
+
#endif
|
|
1948
|
+
|
|
1949
|
+
void main() {
|
|
1950
|
+
vValue = (value - range.x)/(range.y - range.x);
|
|
1951
|
+
|
|
1952
|
+
#ifdef USE_POINTS_UV
|
|
1953
|
+
|
|
1954
|
+
vUv = ( uvTransform * vec3( uv, 1 ) ).xy;
|
|
1955
|
+
|
|
1956
|
+
#endif
|
|
1957
|
+
|
|
1958
|
+
// #include <color_vertex>
|
|
1959
|
+
// #include <morphcolor_vertex>
|
|
1960
|
+
#include <begin_vertex>
|
|
1961
|
+
#include <morphtarget_vertex>
|
|
1962
|
+
#include <project_vertex>
|
|
1963
|
+
|
|
1964
|
+
#ifdef useRadius
|
|
1965
|
+
gl_PointSize = radius;
|
|
1966
|
+
#else
|
|
1967
|
+
gl_PointSize = size;
|
|
1968
|
+
#endif
|
|
1969
|
+
|
|
1970
|
+
#ifdef USE_SIZEATTENUATION
|
|
1971
|
+
|
|
1972
|
+
bool isPerspective = isPerspectiveMatrix( projectionMatrix );
|
|
1973
|
+
|
|
1974
|
+
if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );
|
|
1975
|
+
|
|
1976
|
+
#endif
|
|
1977
|
+
|
|
1978
|
+
#include <logdepthbuf_vertex>
|
|
1979
|
+
#include <clipping_planes_vertex>
|
|
1980
|
+
#include <worldpos_vertex>
|
|
1981
|
+
#include <fog_vertex>
|
|
1982
|
+
|
|
1983
|
+
}`, Et = `varying float vValue;
|
|
1984
|
+
uniform sampler2D map;
|
|
1985
|
+
|
|
1986
|
+
|
|
1987
|
+
uniform float solid;
|
|
1988
|
+
uniform float exp;
|
|
1989
|
+
uniform bool star;
|
|
1990
|
+
|
|
1991
|
+
// uniform vec3 diffuse;
|
|
1992
|
+
uniform float opacity;
|
|
1993
|
+
|
|
1994
|
+
#include <common>
|
|
1995
|
+
// #include <color_pars_fragment>
|
|
1996
|
+
// #include <map_particle_pars_fragment>
|
|
1997
|
+
#include <alphatest_pars_fragment>
|
|
1998
|
+
#include <fog_pars_fragment>
|
|
1999
|
+
#include <logdepthbuf_pars_fragment>
|
|
2000
|
+
#include <clipping_planes_pars_fragment>
|
|
2001
|
+
|
|
2002
|
+
|
|
2003
|
+
// 获取梯度颜色
|
|
2004
|
+
vec4 getGradientColor(float val) {
|
|
2005
|
+
val = clamp( val, 0.0,1.0);
|
|
2006
|
+
return texture2D(map, vec2(val, 0.5));
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
|
|
2010
|
+
vec4 getColor(){
|
|
2011
|
+
float val = vValue;
|
|
2012
|
+
float dist = 0.0;
|
|
2013
|
+
if (star){
|
|
2014
|
+
vec2 coord = abs(gl_PointCoord - vec2(0.5));
|
|
2015
|
+
dist = max(coord.x,coord.y);
|
|
2016
|
+
}else{
|
|
2017
|
+
dist = distance(gl_PointCoord,vec2(0.5));
|
|
2018
|
+
if (dist>0.5) discard;
|
|
2019
|
+
}
|
|
2020
|
+
dist /= 0.5;
|
|
2021
|
+
float depth = sqrt(1.0 - pow(dist,2.0));
|
|
2022
|
+
if (dist > solid) {
|
|
2023
|
+
float solidDist = 1.0 - (dist - solid)/(1.0 - solid);
|
|
2024
|
+
val *= pow(solidDist,exp);
|
|
2025
|
+
}
|
|
2026
|
+
vec4 valColor = getGradientColor(val);
|
|
2027
|
+
valColor.a *= depth * opacity;
|
|
2028
|
+
return valColor;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
void main() {
|
|
2032
|
+
|
|
2033
|
+
#include <clipping_planes_fragment>
|
|
2034
|
+
|
|
2035
|
+
vec3 outgoingLight = vec3( 0.0 );
|
|
2036
|
+
vec4 diffuseColor = getColor();
|
|
2037
|
+
|
|
2038
|
+
#include <logdepthbuf_fragment>
|
|
2039
|
+
// #include <map_particle_fragment>
|
|
2040
|
+
// #include <color_fragment>
|
|
2041
|
+
#include <alphatest_fragment>
|
|
2042
|
+
|
|
2043
|
+
outgoingLight = diffuseColor.rgb;
|
|
2044
|
+
|
|
2045
|
+
#include <output_fragment>
|
|
2046
|
+
#include <tonemapping_fragment>
|
|
2047
|
+
#include <encodings_fragment>
|
|
2048
|
+
#include <fog_fragment>
|
|
2049
|
+
#include <premultiplied_alpha_fragment>
|
|
2050
|
+
|
|
2051
|
+
}`;
|
|
2052
|
+
class Gt extends Ye {
|
|
2053
|
+
constructor(e) {
|
|
2054
|
+
const { range: t, ...n } = e || {}, a = {
|
|
2055
|
+
range: { value: new Vector2().copy(t ?? { x: 0, y: 100 }) }
|
|
2056
|
+
};
|
|
2057
|
+
super(n, { vertexShader: Vt, fragmentShader: Et, uniforms: a });
|
|
2058
|
+
v(this, "isColorFogPointsMaterial", !0);
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* 数值的映射区间
|
|
2062
|
+
* @remarks
|
|
2063
|
+
* x 为最小值,y 为最大值
|
|
2064
|
+
*
|
|
2065
|
+
* @defaultValue {x:0,y:100}
|
|
2066
|
+
*/
|
|
2067
|
+
get range() {
|
|
2068
|
+
return this.uniforms.range.value;
|
|
2069
|
+
}
|
|
2070
|
+
set range(e) {
|
|
2071
|
+
this.uniforms.range.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
function Bt(o) {
|
|
2075
|
+
const { points: s, radius: e = 10, value: t = 100 } = o, n = [], i = [], a = [];
|
|
2076
|
+
for (const { x: l, y: u, z: c, radius: p, value: m } of s)
|
|
2077
|
+
n.push(l, u, c), i.push(p ?? e), a.push(m ?? t);
|
|
2078
|
+
const r = new BufferGeometry();
|
|
2079
|
+
return r.setAttribute("position", new Float32BufferAttribute(n, 3)), r.setAttribute("radius", new Float32BufferAttribute(i, 1)), r.setAttribute("value", new Float32BufferAttribute(a, 1)), r;
|
|
2080
|
+
}
|
|
2081
|
+
function fn(o) {
|
|
2082
|
+
const s = o.gradient, e = s == null ? s : Gn(s), t = new Gt({ ...o, map: e }), n = Bt(o);
|
|
2083
|
+
return new Points(n, t);
|
|
2084
|
+
}
|
|
2085
|
+
const Lt = ` out vec2 vUv;
|
|
2086
|
+
|
|
2087
|
+
void main() {
|
|
2088
|
+
vUv = uv;
|
|
2089
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
|
|
2090
|
+
}`, kt = `precision highp float;
|
|
2091
|
+
precision highp sampler3D;
|
|
2092
|
+
|
|
2093
|
+
uniform sampler3D map;
|
|
2094
|
+
|
|
2095
|
+
uniform float opacity;
|
|
2096
|
+
uniform int axis;
|
|
2097
|
+
uniform float depth;
|
|
2098
|
+
|
|
2099
|
+
in vec2 vUv;
|
|
2100
|
+
out vec4 fragColor;
|
|
2101
|
+
|
|
2102
|
+
void main(){
|
|
2103
|
+
vec3 uv3 = vec3(0.0);
|
|
2104
|
+
int depthSize = textureSize(map,0)[axis];
|
|
2105
|
+
uv3[axis] = depth/float(depthSize);
|
|
2106
|
+
int xIndex = (axis + 1)%3;
|
|
2107
|
+
int yIndex = (axis + 2)%3;
|
|
2108
|
+
uv3[xIndex] = vUv.x;
|
|
2109
|
+
uv3[yIndex] = vUv.y;
|
|
2110
|
+
|
|
2111
|
+
fragColor = texture(map, uv3);
|
|
2112
|
+
fragColor.a *= opacity;
|
|
2113
|
+
}`;
|
|
2114
|
+
class jt extends ShaderMaterial {
|
|
2115
|
+
constructor(e) {
|
|
2116
|
+
const t = e ?? {};
|
|
2117
|
+
let { map: n, opacity: i, axis: a, depth: r, side: l, ...u } = t;
|
|
2118
|
+
i = i ?? 1, a = a ?? f$1.z, r = r ?? 0, l = l ?? DoubleSide;
|
|
2119
|
+
super({
|
|
2120
|
+
...u,
|
|
2121
|
+
glslVersion: GLSL3,
|
|
2122
|
+
// @ts-ignore
|
|
2123
|
+
uniforms: {
|
|
2124
|
+
map: { value: n },
|
|
2125
|
+
opacity: { value: i },
|
|
2126
|
+
axis: { value: a },
|
|
2127
|
+
depth: { value: r }
|
|
2128
|
+
},
|
|
2129
|
+
transparent: !0,
|
|
2130
|
+
vertexShader: Lt,
|
|
2131
|
+
fragmentShader: kt,
|
|
2132
|
+
side: l
|
|
2133
|
+
});
|
|
2134
|
+
v(this, "isSliceMaterial", !0);
|
|
2135
|
+
v(this, "_sliceSize", null);
|
|
2136
|
+
this.opacity = i;
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* 三维的纹理
|
|
2140
|
+
*/
|
|
2141
|
+
get map() {
|
|
2142
|
+
return this.uniforms.map.value;
|
|
2143
|
+
}
|
|
2144
|
+
set map(e) {
|
|
2145
|
+
this.uniforms.map.value = e, this._sliceSize = null, this.uniformsNeedUpdate = !0;
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* 透明度
|
|
2149
|
+
* @remarks
|
|
2150
|
+
* 决定整体的透明度
|
|
2151
|
+
* @defaultValue 1
|
|
2152
|
+
*/
|
|
2153
|
+
// @ts-ignore
|
|
2154
|
+
get opacity() {
|
|
2155
|
+
return this.uniforms.opacity.value;
|
|
2156
|
+
}
|
|
2157
|
+
set opacity(e) {
|
|
2158
|
+
this.uniforms && (this.uniforms.opacity.value = e), this.uniformsNeedUpdate = !0;
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* 轴
|
|
2162
|
+
* @remarks
|
|
2163
|
+
* 切片就是垂直于该轴的截面
|
|
2164
|
+
*
|
|
2165
|
+
* @defaultValue Axis.z
|
|
2166
|
+
*/
|
|
2167
|
+
get axis() {
|
|
2168
|
+
return this.uniforms.axis.value;
|
|
2169
|
+
}
|
|
2170
|
+
set axis(e) {
|
|
2171
|
+
this.uniforms.axis.value = e, this._sliceSize = null, this.uniformsNeedUpdate = !0;
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* 轴上的坐标值
|
|
2175
|
+
* @remarks
|
|
2176
|
+
* 会在轴的该位置处获取切片
|
|
2177
|
+
* @defaultValue 0
|
|
2178
|
+
*/
|
|
2179
|
+
get depth() {
|
|
2180
|
+
return this.uniforms.depth.value;
|
|
2181
|
+
}
|
|
2182
|
+
set depth(e) {
|
|
2183
|
+
this.uniforms.depth.value = e, this.uniformsNeedUpdate = !0;
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* 切片的尺寸
|
|
2187
|
+
* @remarks
|
|
2188
|
+
* 不同轴上的切片的尺寸一般不一样
|
|
2189
|
+
*/
|
|
2190
|
+
get sliceSize() {
|
|
2191
|
+
let e = this._sliceSize;
|
|
2192
|
+
if (!e) {
|
|
2193
|
+
this._sliceSize = e = new Vector2(1, 1);
|
|
2194
|
+
const { axis: t, map: n } = this;
|
|
2195
|
+
if (n) {
|
|
2196
|
+
const { width: i, height: a, depth: r } = n.image, [l, u] = f$1.getCrossAxiss(t), c = [i, a, r];
|
|
2197
|
+
e.set(c[l], c[u]);
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
return e;
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
class vn extends Mesh {
|
|
2204
|
+
constructor(e) {
|
|
2205
|
+
const t = new jt(e), n = new PlaneGeometry();
|
|
2206
|
+
super(n, t);
|
|
2207
|
+
v(this, "isSliceMesh", !0);
|
|
2208
|
+
// @ts-ignore
|
|
2209
|
+
// override get geometry(){
|
|
2210
|
+
// return this._geometry;
|
|
2211
|
+
// }
|
|
2212
|
+
// override set geometry(value){
|
|
2213
|
+
// this._geometry = value;
|
|
2214
|
+
// this.configMaterial();
|
|
2215
|
+
// }
|
|
2216
|
+
v(this, "_geometry");
|
|
2217
|
+
// @ts-ignore
|
|
2218
|
+
// override get material(){
|
|
2219
|
+
// return this._material;
|
|
2220
|
+
// }
|
|
2221
|
+
// override set material(value){
|
|
2222
|
+
// this._material = value;
|
|
2223
|
+
// this.configGeometry();
|
|
2224
|
+
// }
|
|
2225
|
+
v(this, "_material");
|
|
2226
|
+
/**
|
|
2227
|
+
* 是否自动更新几何体
|
|
2228
|
+
* @remarks
|
|
2229
|
+
* 当启动该选项后,在 SliceMesh 监测到切片尺寸相关的变更时,会自动更新 geometry 的尺寸,以适应切片的尺寸
|
|
2230
|
+
* @defaultValue true
|
|
2231
|
+
*/
|
|
2232
|
+
v(this, "autoUpdateGeometry", !0);
|
|
2233
|
+
Object.defineProperties(this, {
|
|
2234
|
+
geometry: {
|
|
2235
|
+
get: () => this._geometry,
|
|
2236
|
+
set: (i) => {
|
|
2237
|
+
this._geometry = i, this.autoUpdateGeometry && this.updateGeometry();
|
|
2238
|
+
}
|
|
2239
|
+
},
|
|
2240
|
+
material: {
|
|
2241
|
+
get: () => this._material,
|
|
2242
|
+
set: (i) => {
|
|
2243
|
+
this._material = i, this.autoUpdateGeometry && this.updateGeometry();
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}), this.geometry = n, this.material = t;
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* 更新几何体
|
|
2250
|
+
*/
|
|
2251
|
+
updateGeometry() {
|
|
2252
|
+
var r;
|
|
2253
|
+
const { geometry: e, material: t } = this;
|
|
2254
|
+
if (!t || !((r = t.map) == null ? void 0 : r.image))
|
|
2255
|
+
return !1;
|
|
2256
|
+
e.boundingBox || e.computeBoundingBox();
|
|
2257
|
+
const i = t.sliceSize, a = e.boundingBox.getSize(new Vector3());
|
|
2258
|
+
e.scale(i.x / a.x, i.y / a.y, 1);
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* 三维的纹理
|
|
2262
|
+
*/
|
|
2263
|
+
get map() {
|
|
2264
|
+
return this.material.map;
|
|
2265
|
+
}
|
|
2266
|
+
set map(e) {
|
|
2267
|
+
this.material.map = e, this.material = this.material;
|
|
2268
|
+
}
|
|
2269
|
+
/**
|
|
2270
|
+
* 轴
|
|
2271
|
+
* @remarks
|
|
2272
|
+
* 切片就是垂直于该轴的截面
|
|
2273
|
+
*
|
|
2274
|
+
* @defaultValue Axis.z
|
|
2275
|
+
*/
|
|
2276
|
+
get axis() {
|
|
2277
|
+
return this.material.axis;
|
|
2278
|
+
}
|
|
2279
|
+
set axis(e) {
|
|
2280
|
+
this.material.axis = e, this.material = this.material;
|
|
2281
|
+
}
|
|
2282
|
+
/**
|
|
2283
|
+
* 轴上的坐标值
|
|
2284
|
+
* @remarks
|
|
2285
|
+
* 会在轴的该位置处获取切片
|
|
2286
|
+
* @defaultValue 0
|
|
2287
|
+
*/
|
|
2288
|
+
get depth() {
|
|
2289
|
+
return this.material.depth;
|
|
2290
|
+
}
|
|
2291
|
+
set depth(e) {
|
|
2292
|
+
this.material.depth = e;
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* 切片的尺寸
|
|
2296
|
+
* @remarks
|
|
2297
|
+
* 不同轴上的切片的尺寸一般不一样
|
|
2298
|
+
*/
|
|
2299
|
+
get sliceSize() {
|
|
2300
|
+
return this.material.sliceSize;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
class hn extends ct {
|
|
2304
|
+
constructor(e) {
|
|
2305
|
+
const t = P(e) ? e : e.image;
|
|
2306
|
+
super(t);
|
|
2307
|
+
v(this, "isImageData3DTextureSlice", !0);
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* 设置材质或 IImageData3 类数据
|
|
2311
|
+
*/
|
|
2312
|
+
set texture(e) {
|
|
2313
|
+
this.image3D = P(e) ? e : e.image;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
function Ze({ ratio: o, value: s }) {
|
|
2317
|
+
return s - s * o;
|
|
2318
|
+
}
|
|
2319
|
+
function Ht(o, s) {
|
|
2320
|
+
const { x: e, y: t } = s;
|
|
2321
|
+
let n = 0;
|
|
2322
|
+
for (const { value: i, clim: { x: a, y: r } } of o)
|
|
2323
|
+
n += (i - a) / (r - a);
|
|
2324
|
+
return n * (t - e) + e;
|
|
2325
|
+
}
|
|
2326
|
+
function qt(o, s, e) {
|
|
2327
|
+
const { size: t, data3D: n, tags: i } = s, { clim: a, radius: r, value: l, hollow: u, valueGradient: c, valuesAccumulate: p } = o, m = new Vector3().copy(o), f = [], h = [], _ = {
|
|
2328
|
+
particles: f,
|
|
2329
|
+
values: h
|
|
2330
|
+
}, M = r * u, S = m.clone().subScalar(r), D = m.clone().addScalar(r);
|
|
2331
|
+
S.max(new Vector3(0, 0, 0));
|
|
2332
|
+
const w = new Vector3().copy(t).subScalar(1);
|
|
2333
|
+
D.min(w);
|
|
2334
|
+
let { x, y, z: g } = S;
|
|
2335
|
+
x = Math.trunc(x), y = Math.trunc(y), g = Math.trunc(g);
|
|
2336
|
+
let { x: z, y: N, z: U } = D;
|
|
2337
|
+
if (z = Math.trunc(z), N = Math.trunc(N), U = Math.trunc(U), x > z || y > N || g > U)
|
|
2338
|
+
return _;
|
|
2339
|
+
const { x: T, y: C } = t, V = T * C;
|
|
2340
|
+
for (let A = g; A <= U; A++) {
|
|
2341
|
+
const he = A * V;
|
|
2342
|
+
for (let R = y; R <= N; R++) {
|
|
2343
|
+
const J = he + R * T;
|
|
2344
|
+
e:
|
|
2345
|
+
for (let P = x; P <= z; P++) {
|
|
2346
|
+
const L = J + P;
|
|
2347
|
+
if (i[L])
|
|
2348
|
+
continue;
|
|
2349
|
+
const F = new Vector3(P, R, A), b = F.distanceTo(m);
|
|
2350
|
+
if (b > r || b < M)
|
|
2351
|
+
continue;
|
|
2352
|
+
i[L] = !0;
|
|
2353
|
+
const k = {
|
|
2354
|
+
radius: r,
|
|
2355
|
+
hollow: u,
|
|
2356
|
+
hollowRadius: M,
|
|
2357
|
+
distance: b,
|
|
2358
|
+
clim: a,
|
|
2359
|
+
value: l
|
|
2360
|
+
}, E = [], j = {
|
|
2361
|
+
...k,
|
|
2362
|
+
ratio: b / r,
|
|
2363
|
+
distance: b,
|
|
2364
|
+
point: F
|
|
2365
|
+
}, H = c(j);
|
|
2366
|
+
E.push({
|
|
2367
|
+
...o,
|
|
2368
|
+
...j,
|
|
2369
|
+
value: H
|
|
2370
|
+
});
|
|
2371
|
+
for (const G of e) {
|
|
2372
|
+
const B = F.distanceTo(G), { hollow: ge, radius: X } = G;
|
|
2373
|
+
if (B <= X) {
|
|
2374
|
+
const $ = X * ge;
|
|
2375
|
+
if (B < $)
|
|
2376
|
+
continue e;
|
|
2377
|
+
const I = {
|
|
2378
|
+
...G,
|
|
2379
|
+
ratio: B / X,
|
|
2380
|
+
distance: B,
|
|
2381
|
+
hollowRadius: $,
|
|
2382
|
+
point: F
|
|
2383
|
+
}, xe = c(I);
|
|
2384
|
+
E.push({ ...I, value: xe });
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
const q = p(E, a);
|
|
2388
|
+
n[L] = q, f.push(F), h.push(q);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
return _;
|
|
2393
|
+
}
|
|
2394
|
+
function gn(o) {
|
|
2395
|
+
const { points: s, clim: e = { x: 0, y: 100 }, radius: t = 10, value: n = 100, hollow: i = 0, valueGradient: a = Ze, valuesAccumulate: r = Ht, size: l } = o, u = { clim: e, radius: t, value: n, hollow: i, valueGradient: a, valuesAccumulate: r }, c = s.map((x) => ({ ...u, ...x }));
|
|
2396
|
+
let p = l;
|
|
2397
|
+
l || (p = new Box3().setFromPoints(c).max.addScalar(1));
|
|
2398
|
+
const m = En(c);
|
|
2399
|
+
let { x: f, y: h, z: _ } = p;
|
|
2400
|
+
f = p.x = Math.trunc(f), h = p.y = Math.trunc(h), _ = p.z = Math.trunc(_);
|
|
2401
|
+
const M = new Array(f * h * _), S = new Array(f * h * _), D = { size: p, data3D: M, tags: S }, w = c.length;
|
|
2402
|
+
for (let x = 0; x < w; x++) {
|
|
2403
|
+
const y = c[x], g = m[x].map((z) => c[z]);
|
|
2404
|
+
qt(y, D, g);
|
|
2405
|
+
}
|
|
2406
|
+
return {
|
|
2407
|
+
data: M,
|
|
2408
|
+
size: p
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
function Xt({ startRadius: o, addedRadius: s, ratio: e }) {
|
|
2412
|
+
return s * e + o;
|
|
2413
|
+
}
|
|
2414
|
+
function $t({ startHollow: o, addedHollow: s, ratio: e }) {
|
|
2415
|
+
return s * e + o;
|
|
2416
|
+
}
|
|
2417
|
+
function Yt({ startValue: o, addedValue: s, ratio: e }) {
|
|
2418
|
+
return s * e + o;
|
|
2419
|
+
}
|
|
2420
|
+
function Zt(o, s) {
|
|
2421
|
+
const { x: e, y: t } = s;
|
|
2422
|
+
return o.reduce((n, i) => n + i - e, 0);
|
|
2423
|
+
}
|
|
2424
|
+
function xn(o) {
|
|
2425
|
+
const { points: s, size: e, clim: t = { x: 0, y: 100 }, radius: n = 10, value: i = 100, hollow: a = 0, valueGradient: r = Ze, radiusGradient: l = Xt, hollowGradient: u = $t, lineValueGradient: c = Yt, valuesAccumulate: p = Zt } = o, m = { radius: n, value: i, hollow: a }, f = s.map(function(C) {
|
|
2426
|
+
return Object.assign(new Vector3(), m, C);
|
|
2427
|
+
}), h = e ? new Vector3().copy(e).subScalar(1) : new Box3().setFromPoints(f).max;
|
|
2428
|
+
h.x = Math.trunc(h.x), h.y = Math.trunc(h.y), h.z = Math.trunc(h.z);
|
|
2429
|
+
const _ = h.clone().addScalar(1), { x: M, y: S, z: D } = _, w = M * S, x = new Array(w * D), y = [], g = [], z = {
|
|
2430
|
+
particles: y,
|
|
2431
|
+
values: g,
|
|
2432
|
+
size: _,
|
|
2433
|
+
data: x
|
|
2434
|
+
}, N = new Vector3(0, 0, 0), U = s.length, T = Math.trunc(U / 2);
|
|
2435
|
+
for (let C = 0; C < T; C++) {
|
|
2436
|
+
const V = C * 2, A = f[V], he = V + 1, R = f[he], J = new Line3(A, R), P = J.distance(), L = J.delta(new Vector3()).normalize(), F = new Quaternion();
|
|
2437
|
+
F.setFromUnitVectors(new Vector3(0, 1, 0), L);
|
|
2438
|
+
const b = new Matrix4().makeRotationFromQuaternion(F);
|
|
2439
|
+
b.setPosition(A);
|
|
2440
|
+
const { radius: k, value: E, hollow: j } = A, { radius: H, value: q, hollow: G } = R, B = H - k, ge = q - E, X = G - j, $ = { length: P, startRadius: k, endRadius: H, addedRadius: B, defaultRadius: n, radius: n, startValue: E, endValue: q, addedValue: ge, defaultValue: i, startHollow: j, endHollow: G, addedHollow: X, defaultHollow: a, clim: t }, I = Math.max(k, H), xe = new Vector3(-I, 0, -I), Ke = new Vector3(I, P, I), Se = new Box3(xe, Ke);
|
|
2441
|
+
Se.applyMatrix4(b);
|
|
2442
|
+
const { min: De, max: be } = Se;
|
|
2443
|
+
De.max(N), be.min(h);
|
|
2444
|
+
let { x: ee, y: te, z: ne } = De;
|
|
2445
|
+
ee = Math.trunc(ee), te = Math.trunc(te), ne = Math.trunc(ne);
|
|
2446
|
+
let { x: ie, y: ae, z: oe } = be;
|
|
2447
|
+
if (ie = Math.trunc(ie), ae = Math.trunc(ae), oe = Math.trunc(oe), ee > ie || te > ae || ne > oe)
|
|
2448
|
+
return z;
|
|
2449
|
+
b.invert();
|
|
2450
|
+
for (let re = ne; re <= oe; re++) {
|
|
2451
|
+
const Qe = re * w;
|
|
2452
|
+
for (let se = te; se <= ae; se++) {
|
|
2453
|
+
const Je = Qe + se * M;
|
|
2454
|
+
for (let le = ee; le <= ie; le++) {
|
|
2455
|
+
const Ce = Je + le, ce = new Vector3(le, se, re), Pe = ce.clone();
|
|
2456
|
+
Pe.applyMatrix4(b);
|
|
2457
|
+
const { x: et, y: _e, z: tt } = Pe;
|
|
2458
|
+
if (_e < 0 || _e > P)
|
|
2459
|
+
continue;
|
|
2460
|
+
const ue = Math.hypot(et, tt), me = {
|
|
2461
|
+
...$,
|
|
2462
|
+
ratio: _e / P,
|
|
2463
|
+
point: ce
|
|
2464
|
+
}, Y = l(me);
|
|
2465
|
+
me.radius = Y;
|
|
2466
|
+
const Ne = u(me), Ue = Y * Ne;
|
|
2467
|
+
if (ue > Y || ue < Ue)
|
|
2468
|
+
continue;
|
|
2469
|
+
const nt = c(me), it = {
|
|
2470
|
+
...$,
|
|
2471
|
+
value: nt,
|
|
2472
|
+
ratio: ue / Y,
|
|
2473
|
+
radius: Y,
|
|
2474
|
+
hollow: Ne,
|
|
2475
|
+
hollowRadius: Ue,
|
|
2476
|
+
distance: ue,
|
|
2477
|
+
point: ce
|
|
2478
|
+
};
|
|
2479
|
+
let de = r(it);
|
|
2480
|
+
const Ae = g[Ce];
|
|
2481
|
+
Ae !== void 0 && (de = p([Ae, de], t)), x[Ce] = de, y.push(ce), g.push(de);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
return z;
|
|
2487
|
+
}
|
|
2488
|
+
function _n(o, s) {
|
|
2489
|
+
const e = new Vector3().setFromMatrixScale(s), t = Math.sqrt(e.lengthSq() / 3), n = new Matrix3().setFromMatrix4(s);
|
|
2490
|
+
let { points: i, size: a, radius: r, ...l } = o;
|
|
2491
|
+
if (a && (a = new Vector3().copy(a).applyMatrix3(n)), r && (r *= t), i) {
|
|
2492
|
+
const u = [];
|
|
2493
|
+
for (let { x: c, y: p, z: m, radius: f, ...h } of i) {
|
|
2494
|
+
f && (f *= t);
|
|
2495
|
+
const _ = new Vector3(c, p, m).applyMatrix4(s);
|
|
2496
|
+
Object.assign(_, h, { radius: f }), u.push(_);
|
|
2497
|
+
}
|
|
2498
|
+
i = u;
|
|
2499
|
+
}
|
|
2500
|
+
return { points: i, size: a, radius: r, ...l };
|
|
2501
|
+
}
|
|
2502
|
+
function Wt(o, s, e = 1) {
|
|
2503
|
+
let { points: t, size: n, radius: i, ...a } = o;
|
|
2504
|
+
if (i && (i *= e), t) {
|
|
2505
|
+
const r = [];
|
|
2506
|
+
for (let { x: l, y: u, z: c, radius: p, ...m } of t) {
|
|
2507
|
+
p && (p *= e);
|
|
2508
|
+
const f = new Vector3(l, u, c).add(s).multiplyScalar(e);
|
|
2509
|
+
Object.assign(f, m, { radius: p }), r.push(f);
|
|
2510
|
+
}
|
|
2511
|
+
t = r;
|
|
2512
|
+
}
|
|
2513
|
+
return n && (n = new Vector3().copy(n).add(s).multiplyScalar(e)), { points: t, size: n, radius: i, ...a };
|
|
2514
|
+
}
|
|
2515
|
+
function yn(o, s) {
|
|
2516
|
+
const { points: e, radius: t } = o;
|
|
2517
|
+
if (!e)
|
|
2518
|
+
return { options: o, position: new Vector3(), scale: 1 };
|
|
2519
|
+
const n = new Box3();
|
|
2520
|
+
for (const p of e) {
|
|
2521
|
+
const m = new Vector3().copy(p), f = p.radius ?? t;
|
|
2522
|
+
f ? (n.expandByPoint(m.clone().subScalar(f)), n.expandByPoint(m.addScalar(f))) : n.expandByPoint(m);
|
|
2523
|
+
}
|
|
2524
|
+
const i = new Vector3().max(n.min), a = n.max.clone().sub(i).addScalar(1);
|
|
2525
|
+
o.size && a.min(o.size);
|
|
2526
|
+
let { scale: r, maxSize: l } = s || {};
|
|
2527
|
+
r || (l = l ?? 100, r = l / Math.max(a.x, a.y, a.z)), a.multiplyScalar(r);
|
|
2528
|
+
const u = i.clone().negate(), c = Wt(o, u, r);
|
|
2529
|
+
return c.size = a, { options: c, position: i, scale: 1 / r };
|
|
2530
|
+
}
|
|
2531
|
+
const Fe = {
|
|
2532
|
+
uniforms: {
|
|
2533
|
+
u_size: { value: new Vector3(1, 1, 1) },
|
|
2534
|
+
u_renderstyle: { value: 0 },
|
|
2535
|
+
u_renderthreshold: { value: 0.5 },
|
|
2536
|
+
u_clim: { value: new Vector2(1, 1) },
|
|
2537
|
+
u_data: { value: null },
|
|
2538
|
+
u_cmdata: { value: null }
|
|
2539
|
+
},
|
|
2540
|
+
vertexShader: (
|
|
2541
|
+
/* glsl */
|
|
2542
|
+
`
|
|
2543
|
+
|
|
2544
|
+
varying vec4 v_nearpos;
|
|
2545
|
+
varying vec4 v_farpos;
|
|
2546
|
+
varying vec3 v_position;
|
|
2547
|
+
|
|
2548
|
+
void main() {
|
|
2549
|
+
// Prepare transforms to map to "camera view". See also:
|
|
2550
|
+
// https://threejs.org/docs/#api/renderers/webgl/WebGLProgram
|
|
2551
|
+
mat4 viewtransformf = modelViewMatrix;
|
|
2552
|
+
mat4 viewtransformi = inverse(modelViewMatrix);
|
|
2553
|
+
|
|
2554
|
+
// Project local vertex coordinate to camera position. Then do a step
|
|
2555
|
+
// backward (in cam coords) to the near clipping plane, and project back. Do
|
|
2556
|
+
// the same for the far clipping plane. This gives us all the information we
|
|
2557
|
+
// need to calculate the ray and truncate it to the viewing cone.
|
|
2558
|
+
vec4 position4 = vec4(position, 1.0);
|
|
2559
|
+
vec4 pos_in_cam = viewtransformf * position4;
|
|
2560
|
+
|
|
2561
|
+
// Intersection of ray and near clipping plane (z = -1 in clip coords)
|
|
2562
|
+
pos_in_cam.z = -pos_in_cam.w;
|
|
2563
|
+
v_nearpos = viewtransformi * pos_in_cam;
|
|
2564
|
+
|
|
2565
|
+
// Intersection of ray and far clipping plane (z = +1 in clip coords)
|
|
2566
|
+
pos_in_cam.z = pos_in_cam.w;
|
|
2567
|
+
v_farpos = viewtransformi * pos_in_cam;
|
|
2568
|
+
|
|
2569
|
+
// Set varyings and output pos
|
|
2570
|
+
v_position = position;
|
|
2571
|
+
gl_Position = projectionMatrix * viewMatrix * modelMatrix * position4;
|
|
2572
|
+
}`
|
|
2573
|
+
),
|
|
2574
|
+
fragmentShader: (
|
|
2575
|
+
/* glsl */
|
|
2576
|
+
`
|
|
2577
|
+
|
|
2578
|
+
precision highp float;
|
|
2579
|
+
precision mediump sampler3D;
|
|
2580
|
+
|
|
2581
|
+
uniform vec3 u_size;
|
|
2582
|
+
uniform int u_renderstyle;
|
|
2583
|
+
uniform float u_renderthreshold;
|
|
2584
|
+
uniform vec2 u_clim;
|
|
2585
|
+
|
|
2586
|
+
uniform sampler3D u_data;
|
|
2587
|
+
uniform sampler2D u_cmdata;
|
|
2588
|
+
|
|
2589
|
+
varying vec3 v_position;
|
|
2590
|
+
varying vec4 v_nearpos;
|
|
2591
|
+
varying vec4 v_farpos;
|
|
2592
|
+
|
|
2593
|
+
// The maximum distance through our rendering volume is sqrt(3).
|
|
2594
|
+
const int MAX_STEPS = 887; // 887 for 512^3, 1774 for 1024^3
|
|
2595
|
+
const int REFINEMENT_STEPS = 4;
|
|
2596
|
+
const float relative_step_size = 1.0;
|
|
2597
|
+
const vec4 ambient_color = vec4(0.2, 0.4, 0.2, 1.0);
|
|
2598
|
+
const vec4 diffuse_color = vec4(0.8, 0.2, 0.2, 1.0);
|
|
2599
|
+
const vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
|
|
2600
|
+
const float shininess = 40.0;
|
|
2601
|
+
|
|
2602
|
+
void cast_mip(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray);
|
|
2603
|
+
void cast_iso(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray);
|
|
2604
|
+
|
|
2605
|
+
float sample1(vec3 texcoords);
|
|
2606
|
+
vec4 apply_colormap(float val);
|
|
2607
|
+
vec4 add_lighting(float val, vec3 loc, vec3 step, vec3 view_ray);
|
|
2608
|
+
|
|
2609
|
+
|
|
2610
|
+
void main() {
|
|
2611
|
+
// Normalize clipping plane info
|
|
2612
|
+
vec3 farpos = v_farpos.xyz / v_farpos.w;
|
|
2613
|
+
vec3 nearpos = v_nearpos.xyz / v_nearpos.w;
|
|
2614
|
+
|
|
2615
|
+
// Calculate unit vector pointing in the view direction through this fragment.
|
|
2616
|
+
vec3 view_ray = normalize(nearpos.xyz - farpos.xyz);
|
|
2617
|
+
|
|
2618
|
+
// Compute the (negative) distance to the front surface or near clipping plane.
|
|
2619
|
+
// v_position is the back face of the cuboid, so the initial distance calculated in the dot
|
|
2620
|
+
// product below is the distance from near clip plane to the back of the cuboid
|
|
2621
|
+
float distance = dot(nearpos - v_position, view_ray);
|
|
2622
|
+
distance = max(distance, min((-0.5 - v_position.x) / view_ray.x,
|
|
2623
|
+
(u_size.x - 0.5 - v_position.x) / view_ray.x));
|
|
2624
|
+
distance = max(distance, min((-0.5 - v_position.y) / view_ray.y,
|
|
2625
|
+
(u_size.y - 0.5 - v_position.y) / view_ray.y));
|
|
2626
|
+
distance = max(distance, min((-0.5 - v_position.z) / view_ray.z,
|
|
2627
|
+
(u_size.z - 0.5 - v_position.z) / view_ray.z));
|
|
2628
|
+
|
|
2629
|
+
// Now we have the starting position on the front surface
|
|
2630
|
+
vec3 front = v_position + view_ray * distance;
|
|
2631
|
+
|
|
2632
|
+
// Decide how many steps to take
|
|
2633
|
+
int nsteps = int(-distance / relative_step_size + 0.5);
|
|
2634
|
+
if ( nsteps < 1 )
|
|
2635
|
+
discard;
|
|
2636
|
+
|
|
2637
|
+
// Get starting location and step vector in texture coordinates
|
|
2638
|
+
vec3 step = ((v_position - front) / u_size) / float(nsteps);
|
|
2639
|
+
vec3 start_loc = front / u_size;
|
|
2640
|
+
|
|
2641
|
+
// For testing: show the number of steps. This helps to establish
|
|
2642
|
+
// whether the rays are correctly oriented
|
|
2643
|
+
//'gl_FragColor = vec4(0.0, float(nsteps) / 1.0 / u_size.x, 1.0, 1.0);
|
|
2644
|
+
//'return;
|
|
2645
|
+
|
|
2646
|
+
if (u_renderstyle == 0)
|
|
2647
|
+
cast_mip(start_loc, step, nsteps, view_ray);
|
|
2648
|
+
else if (u_renderstyle == 1)
|
|
2649
|
+
cast_iso(start_loc, step, nsteps, view_ray);
|
|
2650
|
+
|
|
2651
|
+
if (gl_FragColor.a < 0.05)
|
|
2652
|
+
discard;
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
float sample1(vec3 texcoords) {
|
|
2657
|
+
/* Sample float value from a 3D texture. Assumes intensity data. */
|
|
2658
|
+
return texture(u_data, texcoords.xyz).r;
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
|
|
2662
|
+
vec4 apply_colormap(float val) {
|
|
2663
|
+
val = (val - u_clim[0]) / (u_clim[1] - u_clim[0]);
|
|
2664
|
+
return texture2D(u_cmdata, vec2(val, 0.5));
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
|
|
2668
|
+
void cast_mip(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray) {
|
|
2669
|
+
|
|
2670
|
+
float max_val = -1e6;
|
|
2671
|
+
int max_i = 100;
|
|
2672
|
+
vec3 loc = start_loc;
|
|
2673
|
+
|
|
2674
|
+
// Enter the raycasting loop. In WebGL 1 the loop index cannot be compared with
|
|
2675
|
+
// non-constant expression. So we use a hard-coded max, and an additional condition
|
|
2676
|
+
// inside the loop.
|
|
2677
|
+
for (int iter=0; iter<MAX_STEPS; iter++) {
|
|
2678
|
+
if (iter >= nsteps)
|
|
2679
|
+
break;
|
|
2680
|
+
// Sample from the 3D texture
|
|
2681
|
+
float val = sample1(loc);
|
|
2682
|
+
// Apply MIP operation
|
|
2683
|
+
if (val > max_val) {
|
|
2684
|
+
max_val = val;
|
|
2685
|
+
max_i = iter;
|
|
2686
|
+
}
|
|
2687
|
+
// Advance location deeper into the volume
|
|
2688
|
+
loc += step;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
// Refine location, gives crispier images
|
|
2692
|
+
vec3 iloc = start_loc + step * (float(max_i) - 0.5);
|
|
2693
|
+
vec3 istep = step / float(REFINEMENT_STEPS);
|
|
2694
|
+
for (int i=0; i<REFINEMENT_STEPS; i++) {
|
|
2695
|
+
max_val = max(max_val, sample1(iloc));
|
|
2696
|
+
iloc += istep;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
// Resolve final color
|
|
2700
|
+
gl_FragColor = apply_colormap(max_val);
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
|
|
2704
|
+
void cast_iso(vec3 start_loc, vec3 step, int nsteps, vec3 view_ray) {
|
|
2705
|
+
|
|
2706
|
+
gl_FragColor = vec4(0.0); // init transparent
|
|
2707
|
+
vec4 color3 = vec4(0.0); // final color
|
|
2708
|
+
vec3 dstep = 1.5 / u_size; // step to sample derivative
|
|
2709
|
+
vec3 loc = start_loc;
|
|
2710
|
+
|
|
2711
|
+
float low_threshold = u_renderthreshold - 0.02 * (u_clim[1] - u_clim[0]);
|
|
2712
|
+
|
|
2713
|
+
// Enter the raycasting loop. In WebGL 1 the loop index cannot be compared with
|
|
2714
|
+
// non-constant expression. So we use a hard-coded max, and an additional condition
|
|
2715
|
+
// inside the loop.
|
|
2716
|
+
for (int iter=0; iter<MAX_STEPS; iter++) {
|
|
2717
|
+
if (iter >= nsteps)
|
|
2718
|
+
break;
|
|
2719
|
+
|
|
2720
|
+
// Sample from the 3D texture
|
|
2721
|
+
float val = sample1(loc);
|
|
2722
|
+
|
|
2723
|
+
if (val > low_threshold) {
|
|
2724
|
+
// Take the last interval in smaller steps
|
|
2725
|
+
vec3 iloc = loc - 0.5 * step;
|
|
2726
|
+
vec3 istep = step / float(REFINEMENT_STEPS);
|
|
2727
|
+
for (int i=0; i<REFINEMENT_STEPS; i++) {
|
|
2728
|
+
val = sample1(iloc);
|
|
2729
|
+
if (val > u_renderthreshold) {
|
|
2730
|
+
gl_FragColor = add_lighting(val, iloc, dstep, view_ray);
|
|
2731
|
+
return;
|
|
2732
|
+
}
|
|
2733
|
+
iloc += istep;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
// Advance location deeper into the volume
|
|
2738
|
+
loc += step;
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
|
|
2743
|
+
vec4 add_lighting(float val, vec3 loc, vec3 step, vec3 view_ray)
|
|
2744
|
+
{
|
|
2745
|
+
// Calculate color by incorporating lighting
|
|
2746
|
+
|
|
2747
|
+
// View direction
|
|
2748
|
+
vec3 V = normalize(view_ray);
|
|
2749
|
+
|
|
2750
|
+
// calculate normal vector from gradient
|
|
2751
|
+
vec3 N;
|
|
2752
|
+
float val1, val2;
|
|
2753
|
+
val1 = sample1(loc + vec3(-step[0], 0.0, 0.0));
|
|
2754
|
+
val2 = sample1(loc + vec3(+step[0], 0.0, 0.0));
|
|
2755
|
+
N[0] = val1 - val2;
|
|
2756
|
+
val = max(max(val1, val2), val);
|
|
2757
|
+
val1 = sample1(loc + vec3(0.0, -step[1], 0.0));
|
|
2758
|
+
val2 = sample1(loc + vec3(0.0, +step[1], 0.0));
|
|
2759
|
+
N[1] = val1 - val2;
|
|
2760
|
+
val = max(max(val1, val2), val);
|
|
2761
|
+
val1 = sample1(loc + vec3(0.0, 0.0, -step[2]));
|
|
2762
|
+
val2 = sample1(loc + vec3(0.0, 0.0, +step[2]));
|
|
2763
|
+
N[2] = val1 - val2;
|
|
2764
|
+
val = max(max(val1, val2), val);
|
|
2765
|
+
|
|
2766
|
+
float gm = length(N); // gradient magnitude
|
|
2767
|
+
N = normalize(N);
|
|
2768
|
+
|
|
2769
|
+
// Flip normal so it points towards viewer
|
|
2770
|
+
float Nselect = float(dot(N, V) > 0.0);
|
|
2771
|
+
N = (2.0 * Nselect - 1.0) * N; // == Nselect * N - (1.0-Nselect)*N;
|
|
2772
|
+
|
|
2773
|
+
// Init colors
|
|
2774
|
+
vec4 ambient_color = vec4(0.0, 0.0, 0.0, 0.0);
|
|
2775
|
+
vec4 diffuse_color = vec4(0.0, 0.0, 0.0, 0.0);
|
|
2776
|
+
vec4 specular_color = vec4(0.0, 0.0, 0.0, 0.0);
|
|
2777
|
+
|
|
2778
|
+
// note: could allow multiple lights
|
|
2779
|
+
for (int i=0; i<1; i++)
|
|
2780
|
+
{
|
|
2781
|
+
// Get light direction (make sure to prevent zero devision)
|
|
2782
|
+
vec3 L = normalize(view_ray); //lightDirs[i];
|
|
2783
|
+
float lightEnabled = float( length(L) > 0.0 );
|
|
2784
|
+
L = normalize(L + (1.0 - lightEnabled));
|
|
2785
|
+
|
|
2786
|
+
// Calculate lighting properties
|
|
2787
|
+
float lambertTerm = clamp(dot(N, L), 0.0, 1.0);
|
|
2788
|
+
vec3 H = normalize(L+V); // Halfway vector
|
|
2789
|
+
float specularTerm = pow(max(dot(H, N), 0.0), shininess);
|
|
2790
|
+
|
|
2791
|
+
// Calculate mask
|
|
2792
|
+
float mask1 = lightEnabled;
|
|
2793
|
+
|
|
2794
|
+
// Calculate colors
|
|
2795
|
+
ambient_color += mask1 * ambient_color; // * gl_LightSource[i].ambient;
|
|
2796
|
+
diffuse_color += mask1 * lambertTerm;
|
|
2797
|
+
specular_color += mask1 * specularTerm * specular_color;
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
// Calculate final color by componing different components
|
|
2801
|
+
vec4 final_color;
|
|
2802
|
+
vec4 color = apply_colormap(val);
|
|
2803
|
+
final_color = color * (ambient_color + diffuse_color) + specular_color;
|
|
2804
|
+
final_color.a = color.a;
|
|
2805
|
+
return final_color;
|
|
2806
|
+
}`
|
|
2807
|
+
)
|
|
2808
|
+
};
|
|
2809
|
+
var Kt = /* @__PURE__ */ ((o) => (o[o.MIP = 0] = "MIP", o[o.ISO = 1] = "ISO", o))(Kt || {});
|
|
2810
|
+
class Mn extends ShaderMaterial {
|
|
2811
|
+
constructor(e) {
|
|
2812
|
+
const { style: t, threshold: n, clim: i, map: a, gradient: r } = e ?? {}, l = new Vector3(1, 1, 1);
|
|
2813
|
+
if (a) {
|
|
2814
|
+
const { width: p, height: m, depth: f } = a.image;
|
|
2815
|
+
l.set(p, m, f);
|
|
2816
|
+
}
|
|
2817
|
+
const u = r == null ? r : Gn(r), c = UniformsUtils.clone(Fe.uniforms);
|
|
2818
|
+
c.u_size.value.copy(l), c.u_clim.value.copy(i ?? new Vector2(1, 1)), c.u_renderstyle.value = t ?? 1, c.u_renderthreshold.value = n ?? 0.5, c.u_data.value = a ?? null, c.u_cmdata.value = u ?? null;
|
|
2819
|
+
super({
|
|
2820
|
+
...Fe,
|
|
2821
|
+
// @ts-ignore
|
|
2822
|
+
uniforms: c,
|
|
2823
|
+
side: BackSide
|
|
2824
|
+
});
|
|
2825
|
+
v(this, "isExampleVolumeMaterial_1", !0);
|
|
2826
|
+
v(this, "_gradient");
|
|
2827
|
+
}
|
|
2828
|
+
/**
|
|
2829
|
+
* 三维纹理
|
|
2830
|
+
*/
|
|
2831
|
+
get map() {
|
|
2832
|
+
return this.uniforms.u_data.value;
|
|
2833
|
+
}
|
|
2834
|
+
set map(e) {
|
|
2835
|
+
this.uniforms.u_data.value = e, this.uniformsNeedUpdate = !0;
|
|
2836
|
+
}
|
|
2837
|
+
/**
|
|
2838
|
+
* 颜色映射纹理
|
|
2839
|
+
* @remarks
|
|
2840
|
+
* 会将垂直居中的那条水平像素从左到右映射到 clim 表示的限制区间,
|
|
2841
|
+
* 即 clim.x 对应最左边的像素,clim.y 对应最右边的像素
|
|
2842
|
+
*/
|
|
2843
|
+
get gradientMap() {
|
|
2844
|
+
return this.uniforms.u_cmdata.value;
|
|
2845
|
+
}
|
|
2846
|
+
/**
|
|
2847
|
+
* 颜色映射选项
|
|
2848
|
+
*/
|
|
2849
|
+
get gradient() {
|
|
2850
|
+
return this._gradient;
|
|
2851
|
+
}
|
|
2852
|
+
set gradient(e) {
|
|
2853
|
+
this._gradient = e;
|
|
2854
|
+
const t = e == null ? e : Gn(e);
|
|
2855
|
+
this.uniforms.u_cmdata.value = t ?? null, this.uniformsNeedUpdate = !0;
|
|
2856
|
+
}
|
|
2857
|
+
/**
|
|
2858
|
+
* 三维纹理的尺寸
|
|
2859
|
+
* @remarks
|
|
2860
|
+
* 三维纹理的尺寸 要 和 Geometry 的尺寸是一样的,不但比列一样,大小也是一样的
|
|
2861
|
+
* 但 mesh 本身可以进行几何变换;
|
|
2862
|
+
* Geometry 左下角的坐标要从 (0,0,0) 开始;
|
|
2863
|
+
*/
|
|
2864
|
+
get size() {
|
|
2865
|
+
return this.uniforms.u_size.value;
|
|
2866
|
+
}
|
|
2867
|
+
set size(e) {
|
|
2868
|
+
this.uniforms.u_size.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* 渲染样式
|
|
2872
|
+
*/
|
|
2873
|
+
get style() {
|
|
2874
|
+
return this.uniforms.u_renderstyle.value;
|
|
2875
|
+
}
|
|
2876
|
+
set style(e) {
|
|
2877
|
+
this.uniforms.u_renderstyle.value = e, this.uniformsNeedUpdate = !0;
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* 映射区间
|
|
2881
|
+
* @remarks
|
|
2882
|
+
* x 为最小值,y 为最大值
|
|
2883
|
+
*/
|
|
2884
|
+
get clim() {
|
|
2885
|
+
return this.uniforms.u_clim.value;
|
|
2886
|
+
}
|
|
2887
|
+
set clim(e) {
|
|
2888
|
+
this.uniforms.u_clim.value = e, this.uniformsNeedUpdate = !0;
|
|
2889
|
+
}
|
|
2890
|
+
/**
|
|
2891
|
+
* 渲染最低阈值
|
|
2892
|
+
* @remarks
|
|
2893
|
+
* 只对 ISO 样式有效;
|
|
2894
|
+
*
|
|
2895
|
+
* 当三维纹理中的值低于该值时,不会被渲染,即视为空
|
|
2896
|
+
*/
|
|
2897
|
+
get threshold() {
|
|
2898
|
+
return this.uniforms.u_renderthreshold.value;
|
|
2899
|
+
}
|
|
2900
|
+
set threshold(e) {
|
|
2901
|
+
this.uniforms.u_renderthreshold.value = e, this.uniformsNeedUpdate = !0;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
const We = `in vec3 position;
|
|
2905
|
+
|
|
2906
|
+
uniform mat4 modelMatrix;
|
|
2907
|
+
uniform mat4 modelViewMatrix;
|
|
2908
|
+
uniform mat4 projectionMatrix;
|
|
2909
|
+
uniform vec3 cameraPos;
|
|
2910
|
+
|
|
2911
|
+
out vec3 vOrigin;
|
|
2912
|
+
out vec3 vDirection;
|
|
2913
|
+
|
|
2914
|
+
void main() {
|
|
2915
|
+
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
|
|
2916
|
+
vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
|
|
2917
|
+
vDirection = position - vOrigin;
|
|
2918
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
2919
|
+
}`, Qt = `precision highp float;
|
|
2920
|
+
precision highp sampler3D;
|
|
2921
|
+
|
|
2922
|
+
uniform mat4 modelViewMatrix;
|
|
2923
|
+
uniform mat4 projectionMatrix;
|
|
2924
|
+
|
|
2925
|
+
in vec3 vOrigin;
|
|
2926
|
+
in vec3 vDirection;
|
|
2927
|
+
|
|
2928
|
+
out vec4 color;
|
|
2929
|
+
|
|
2930
|
+
uniform vec3 base;
|
|
2931
|
+
uniform sampler3D map;
|
|
2932
|
+
|
|
2933
|
+
uniform float threshold;
|
|
2934
|
+
uniform float range;
|
|
2935
|
+
uniform float opacity;
|
|
2936
|
+
uniform float steps;
|
|
2937
|
+
uniform float frame;
|
|
2938
|
+
|
|
2939
|
+
uint wang_hash(uint seed)
|
|
2940
|
+
{
|
|
2941
|
+
seed = (seed ^ 61u) ^ (seed >> 16u);
|
|
2942
|
+
seed *= 9u;
|
|
2943
|
+
seed = seed ^ (seed >> 4u);
|
|
2944
|
+
seed *= 0x27d4eb2du;
|
|
2945
|
+
seed = seed ^ (seed >> 15u);
|
|
2946
|
+
return seed;
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
float randomFloat(inout uint seed)
|
|
2950
|
+
{
|
|
2951
|
+
return float(wang_hash(seed)) / 4294967296.;
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
vec2 hitBox( vec3 orig, vec3 dir ) {
|
|
2955
|
+
const vec3 box_min = vec3( - 0.5 );
|
|
2956
|
+
const vec3 box_max = vec3( 0.5 );
|
|
2957
|
+
vec3 inv_dir = 1.0 / dir;
|
|
2958
|
+
vec3 tmin_tmp = ( box_min - orig ) * inv_dir;
|
|
2959
|
+
vec3 tmax_tmp = ( box_max - orig ) * inv_dir;
|
|
2960
|
+
vec3 tmin = min( tmin_tmp, tmax_tmp );
|
|
2961
|
+
vec3 tmax = max( tmin_tmp, tmax_tmp );
|
|
2962
|
+
float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
|
|
2963
|
+
float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
|
|
2964
|
+
return vec2( t0, t1 );
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
float sample1( vec3 p ) {
|
|
2968
|
+
return texture( map, p ).r;
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
float shading( vec3 coord ) {
|
|
2972
|
+
float step = 0.01;
|
|
2973
|
+
return sample1( coord + vec3( - step ) ) - sample1( coord + vec3( step ) );
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
void main(){
|
|
2977
|
+
vec3 rayDir = normalize( vDirection );
|
|
2978
|
+
vec2 bounds = hitBox( vOrigin, rayDir );
|
|
2979
|
+
|
|
2980
|
+
if ( bounds.x > bounds.y ) discard;
|
|
2981
|
+
|
|
2982
|
+
bounds.x = max( bounds.x, 0.0 );
|
|
2983
|
+
|
|
2984
|
+
vec3 p = vOrigin + bounds.x * rayDir;
|
|
2985
|
+
vec3 inc = 1.0 / abs( rayDir );
|
|
2986
|
+
float delta = min( inc.x, min( inc.y, inc.z ) );
|
|
2987
|
+
delta /= steps;
|
|
2988
|
+
|
|
2989
|
+
// Jitter
|
|
2990
|
+
|
|
2991
|
+
// Nice little seed from
|
|
2992
|
+
// https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/
|
|
2993
|
+
uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 );
|
|
2994
|
+
vec3 size = vec3( textureSize( map, 0 ) );
|
|
2995
|
+
float randNum = randomFloat( seed ) * 2.0 - 1.0;
|
|
2996
|
+
p += rayDir * randNum * ( 1.0 / size );
|
|
2997
|
+
|
|
2998
|
+
//
|
|
2999
|
+
|
|
3000
|
+
vec4 ac = vec4( base, 0.0 );
|
|
3001
|
+
|
|
3002
|
+
for ( float t = bounds.x; t < bounds.y; t += delta ) {
|
|
3003
|
+
|
|
3004
|
+
float d = sample1( p + 0.5 );
|
|
3005
|
+
|
|
3006
|
+
d = smoothstep( threshold - range, threshold + range, d ) * opacity;
|
|
3007
|
+
|
|
3008
|
+
float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2;
|
|
3009
|
+
|
|
3010
|
+
ac.rgb += ( 1.0 - ac.a ) * d * col;
|
|
3011
|
+
|
|
3012
|
+
ac.a += ( 1.0 - ac.a ) * d;
|
|
3013
|
+
|
|
3014
|
+
if ( ac.a >= 0.95 ) break;
|
|
3015
|
+
|
|
3016
|
+
p += rayDir * delta;
|
|
3017
|
+
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
color = ac;
|
|
3021
|
+
|
|
3022
|
+
if ( color.a == 0.0 ) discard;
|
|
3023
|
+
|
|
3024
|
+
}`;
|
|
3025
|
+
class zn extends RawShaderMaterial {
|
|
3026
|
+
constructor(e) {
|
|
3027
|
+
let { color: t, threshold: n, map: i, opacity: a, range: r, steps: l, frame: u, cameraPos: c } = e ?? {};
|
|
3028
|
+
t = t ?? new Color(1, 1, 1), n = n ?? 0.25, a = a ?? 0.25, r = r ?? 0.1, l = l ?? 100, u = u ?? 100, c = c ?? new Vector3();
|
|
3029
|
+
super({
|
|
3030
|
+
glslVersion: GLSL3,
|
|
3031
|
+
// @ts-ignore
|
|
3032
|
+
uniforms: {
|
|
3033
|
+
base: { value: t },
|
|
3034
|
+
map: { value: i },
|
|
3035
|
+
cameraPos: { value: c },
|
|
3036
|
+
threshold: { value: n },
|
|
3037
|
+
opacity: { value: a },
|
|
3038
|
+
range: { value: r },
|
|
3039
|
+
steps: { value: l },
|
|
3040
|
+
frame: { value: u }
|
|
3041
|
+
},
|
|
3042
|
+
vertexShader: We,
|
|
3043
|
+
fragmentShader: Qt,
|
|
3044
|
+
side: BackSide,
|
|
3045
|
+
transparent: !0
|
|
3046
|
+
});
|
|
3047
|
+
v(this, "isExampleVolumeMaterial_Cloud", !0);
|
|
3048
|
+
this.opacity = a;
|
|
3049
|
+
}
|
|
3050
|
+
/**
|
|
3051
|
+
* 三维纹理
|
|
3052
|
+
*/
|
|
3053
|
+
get map() {
|
|
3054
|
+
return this.uniforms.map.value;
|
|
3055
|
+
}
|
|
3056
|
+
set map(e) {
|
|
3057
|
+
this.uniforms.map.value = e, this.uniformsNeedUpdate = !0;
|
|
3058
|
+
}
|
|
3059
|
+
/**
|
|
3060
|
+
* 颜色
|
|
3061
|
+
*/
|
|
3062
|
+
get color() {
|
|
3063
|
+
return this.uniforms.base.value;
|
|
3064
|
+
}
|
|
3065
|
+
set color(e) {
|
|
3066
|
+
this.uniforms.base.value = e, this.uniformsNeedUpdate = !0;
|
|
3067
|
+
}
|
|
3068
|
+
/**
|
|
3069
|
+
* 透明度
|
|
3070
|
+
*/
|
|
3071
|
+
// @ts-ignore
|
|
3072
|
+
get opacity() {
|
|
3073
|
+
return this.uniforms.opacity.value;
|
|
3074
|
+
}
|
|
3075
|
+
set opacity(e) {
|
|
3076
|
+
this.uniforms && (this.uniforms.opacity.value = e), this.uniformsNeedUpdate = !0;
|
|
3077
|
+
}
|
|
3078
|
+
/**
|
|
3079
|
+
* 渲染最低阈值
|
|
3080
|
+
*/
|
|
3081
|
+
get threshold() {
|
|
3082
|
+
return this.uniforms.threshold.value;
|
|
3083
|
+
}
|
|
3084
|
+
set threshold(e) {
|
|
3085
|
+
this.uniforms.threshold.value = e, this.uniformsNeedUpdate = !0;
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* 范围
|
|
3089
|
+
*/
|
|
3090
|
+
get range() {
|
|
3091
|
+
return this.uniforms.range.value;
|
|
3092
|
+
}
|
|
3093
|
+
set range(e) {
|
|
3094
|
+
this.uniforms.range.value = e, this.uniformsNeedUpdate = !0;
|
|
3095
|
+
}
|
|
3096
|
+
/**
|
|
3097
|
+
* 体积材质渲染的采样数
|
|
3098
|
+
*/
|
|
3099
|
+
get steps() {
|
|
3100
|
+
return this.uniforms.steps.value;
|
|
3101
|
+
}
|
|
3102
|
+
set steps(e) {
|
|
3103
|
+
this.uniforms.steps.value = e, this.uniformsNeedUpdate = !0;
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
* 渲染帧次
|
|
3107
|
+
*/
|
|
3108
|
+
get frame() {
|
|
3109
|
+
return this.uniforms.frame.value;
|
|
3110
|
+
}
|
|
3111
|
+
set frame(e) {
|
|
3112
|
+
this.uniforms.frame.value = e, this.uniformsNeedUpdate = !0;
|
|
3113
|
+
}
|
|
3114
|
+
/**
|
|
3115
|
+
* 相机的位置
|
|
3116
|
+
*/
|
|
3117
|
+
get cameraPos() {
|
|
3118
|
+
return this.uniforms.cameraPos.value;
|
|
3119
|
+
}
|
|
3120
|
+
set cameraPos(e) {
|
|
3121
|
+
this.uniforms.cameraPos.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
const Jt = `precision highp float;
|
|
3125
|
+
precision highp sampler3D;
|
|
3126
|
+
|
|
3127
|
+
uniform mat4 modelViewMatrix;
|
|
3128
|
+
uniform mat4 projectionMatrix;
|
|
3129
|
+
|
|
3130
|
+
in vec3 vOrigin;
|
|
3131
|
+
in vec3 vDirection;
|
|
3132
|
+
|
|
3133
|
+
out vec4 color;
|
|
3134
|
+
|
|
3135
|
+
uniform sampler3D map;
|
|
3136
|
+
|
|
3137
|
+
uniform float threshold;
|
|
3138
|
+
uniform float steps;
|
|
3139
|
+
|
|
3140
|
+
vec2 hitBox( vec3 orig, vec3 dir ) {
|
|
3141
|
+
const vec3 box_min = vec3( - 0.5 );
|
|
3142
|
+
const vec3 box_max = vec3( 0.5 );
|
|
3143
|
+
vec3 inv_dir = 1.0 / dir;
|
|
3144
|
+
vec3 tmin_tmp = ( box_min - orig ) * inv_dir;
|
|
3145
|
+
vec3 tmax_tmp = ( box_max - orig ) * inv_dir;
|
|
3146
|
+
vec3 tmin = min( tmin_tmp, tmax_tmp );
|
|
3147
|
+
vec3 tmax = max( tmin_tmp, tmax_tmp );
|
|
3148
|
+
float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
|
|
3149
|
+
float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
|
|
3150
|
+
return vec2( t0, t1 );
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
float sample1( vec3 p ) {
|
|
3154
|
+
return texture( map, p ).r;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
3157
|
+
#define epsilon .0001
|
|
3158
|
+
|
|
3159
|
+
vec3 normal( vec3 coord ) {
|
|
3160
|
+
if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 );
|
|
3161
|
+
if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 );
|
|
3162
|
+
if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 );
|
|
3163
|
+
if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 );
|
|
3164
|
+
if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 );
|
|
3165
|
+
if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 );
|
|
3166
|
+
|
|
3167
|
+
float step = 0.01;
|
|
3168
|
+
float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) );
|
|
3169
|
+
float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) );
|
|
3170
|
+
float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) );
|
|
3171
|
+
|
|
3172
|
+
return normalize( vec3( x, y, z ) );
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
void main(){
|
|
3176
|
+
|
|
3177
|
+
vec3 rayDir = normalize( vDirection );
|
|
3178
|
+
vec2 bounds = hitBox( vOrigin, rayDir );
|
|
3179
|
+
|
|
3180
|
+
if ( bounds.x > bounds.y ) discard;
|
|
3181
|
+
|
|
3182
|
+
bounds.x = max( bounds.x, 0.0 );
|
|
3183
|
+
|
|
3184
|
+
vec3 p = vOrigin + bounds.x * rayDir;
|
|
3185
|
+
vec3 inc = 1.0 / abs( rayDir );
|
|
3186
|
+
float delta = min( inc.x, min( inc.y, inc.z ) );
|
|
3187
|
+
delta /= steps;
|
|
3188
|
+
|
|
3189
|
+
for ( float t = bounds.x; t < bounds.y; t += delta ) {
|
|
3190
|
+
|
|
3191
|
+
float d = sample1( p + 0.5 );
|
|
3192
|
+
|
|
3193
|
+
if ( d > threshold ) {
|
|
3194
|
+
|
|
3195
|
+
color.rgb = normal( p + 0.5 ) * 0.5 + ( p * 1.5 + 0.25 );
|
|
3196
|
+
color.a = 1.;
|
|
3197
|
+
break;
|
|
3198
|
+
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
p += rayDir * delta;
|
|
3202
|
+
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
if ( color.a == 0.0 ) discard;
|
|
3206
|
+
|
|
3207
|
+
}`;
|
|
3208
|
+
class wn extends RawShaderMaterial {
|
|
3209
|
+
constructor(e) {
|
|
3210
|
+
let { threshold: t, map: n, steps: i, cameraPos: a } = e ?? {};
|
|
3211
|
+
t = t ?? 0.25, i = i ?? 100, a = a ?? new Vector3();
|
|
3212
|
+
super({
|
|
3213
|
+
glslVersion: GLSL3,
|
|
3214
|
+
// @ts-ignore
|
|
3215
|
+
uniforms: {
|
|
3216
|
+
map: { value: n },
|
|
3217
|
+
cameraPos: { value: a },
|
|
3218
|
+
threshold: { value: t },
|
|
3219
|
+
steps: { value: i }
|
|
3220
|
+
},
|
|
3221
|
+
vertexShader: We,
|
|
3222
|
+
fragmentShader: Jt,
|
|
3223
|
+
side: BackSide,
|
|
3224
|
+
transparent: !0
|
|
3225
|
+
});
|
|
3226
|
+
v(this, "isExampleVolumeMaterial_Perlin", !0);
|
|
3227
|
+
}
|
|
3228
|
+
/**
|
|
3229
|
+
* 三维纹理
|
|
3230
|
+
*/
|
|
3231
|
+
get map() {
|
|
3232
|
+
return this.uniforms.map.value;
|
|
3233
|
+
}
|
|
3234
|
+
set map(e) {
|
|
3235
|
+
this.uniforms.map.value = e, this.uniformsNeedUpdate = !0;
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* 渲染最低阈值
|
|
3239
|
+
*/
|
|
3240
|
+
get threshold() {
|
|
3241
|
+
return this.uniforms.threshold.value;
|
|
3242
|
+
}
|
|
3243
|
+
set threshold(e) {
|
|
3244
|
+
this.uniforms.threshold.value = e, this.uniformsNeedUpdate = !0;
|
|
3245
|
+
}
|
|
3246
|
+
/**
|
|
3247
|
+
* 体积材质渲染的采样数
|
|
3248
|
+
*/
|
|
3249
|
+
get steps() {
|
|
3250
|
+
return this.uniforms.steps.value;
|
|
3251
|
+
}
|
|
3252
|
+
set steps(e) {
|
|
3253
|
+
this.uniforms.steps.value = e, this.uniformsNeedUpdate = !0;
|
|
3254
|
+
}
|
|
3255
|
+
/**
|
|
3256
|
+
* 相机的位置
|
|
3257
|
+
*/
|
|
3258
|
+
get cameraPos() {
|
|
3259
|
+
return this.uniforms.cameraPos.value;
|
|
3260
|
+
}
|
|
3261
|
+
set cameraPos(e) {
|
|
3262
|
+
this.uniforms.cameraPos.value.copy(e), this.uniformsNeedUpdate = !0;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
|
|
3266
|
+
class HeatMapPlugin {
|
|
3267
|
+
constructor(ssp) {
|
|
3268
|
+
this.ssp = ssp;
|
|
3269
|
+
this.defaultColorGradient = [
|
|
3270
|
+
[0, 'rgba(0,255,0,0)'],
|
|
3271
|
+
[0.5, 'rgba(64,255,255,0.5)'],
|
|
3272
|
+
[1, 'rgba(255,64,255,1)']
|
|
3273
|
+
];
|
|
3274
|
+
this.defaultGradientVolumeMaterialOptions = {
|
|
3275
|
+
fit: Dt.Raw,
|
|
3276
|
+
accFactor: 2,
|
|
3277
|
+
depthTest: false,
|
|
3278
|
+
side: BackSide,
|
|
3279
|
+
discardOut: false,
|
|
3280
|
+
// 数值的梯度映射纹理
|
|
3281
|
+
gradient: Gn(this.defaultColorGradient),
|
|
3282
|
+
};
|
|
3283
|
+
}
|
|
3284
|
+
_createTexture(points, options, isLine = false) {
|
|
3285
|
+
//优化
|
|
3286
|
+
const optimized = yn(Object.assign({ points }, options), Object.assign({ maxSize: 60 }, options));
|
|
3287
|
+
const { options: optimizedOptions, position, scale, } = optimized;
|
|
3288
|
+
//创建热力3D数据
|
|
3289
|
+
const heatData3D = isLine ? xn(optimizedOptions) : gn(optimizedOptions);
|
|
3290
|
+
//创建热力3D纹理
|
|
3291
|
+
const heatTexture = ln(heatData3D, Object.assign({}, options));
|
|
3292
|
+
//创建热力材质
|
|
3293
|
+
const heatMaterial = new sn(Object.assign(Object.assign(Object.assign({}, this.defaultGradientVolumeMaterialOptions), { map: heatTexture }), options));
|
|
3294
|
+
const volumMesh = new rn(heatMaterial);
|
|
3295
|
+
volumMesh.position.copy(position);
|
|
3296
|
+
volumMesh.scale.set(scale, scale, scale);
|
|
3297
|
+
this.ssp.addObject(volumMesh);
|
|
3298
|
+
return volumMesh;
|
|
3299
|
+
}
|
|
3300
|
+
/**
|
|
3301
|
+
* 创建热力云
|
|
3302
|
+
* return material
|
|
3303
|
+
*/
|
|
3304
|
+
createHeatCloud(points, options) {
|
|
3305
|
+
return this._createTexture(points, options);
|
|
3306
|
+
}
|
|
3307
|
+
//创建线状热力
|
|
3308
|
+
createLineHeat(points, options) {
|
|
3309
|
+
return this._createTexture(points, options, true);
|
|
3310
|
+
}
|
|
3311
|
+
//创建图片挤压
|
|
3312
|
+
async createImageExtrusion(imageUrl, options) {
|
|
3313
|
+
var _a;
|
|
3314
|
+
const material = new cn(Object.assign({ side: BackSide, depthTest: false }, options));
|
|
3315
|
+
const image = await SoonSpace.utils.imageLoader.loadAsync(imageUrl);
|
|
3316
|
+
const texture = un(image, (_a = options === null || options === void 0 ? void 0 : options.depth) !== null && _a !== void 0 ? _a : 200, options);
|
|
3317
|
+
material.map = texture;
|
|
3318
|
+
const volumMesh = new rn(material);
|
|
3319
|
+
this.ssp.addObject(volumMesh);
|
|
3320
|
+
return volumMesh;
|
|
3321
|
+
}
|
|
3322
|
+
//创建切片
|
|
3323
|
+
createSliceMesh(material, options) {
|
|
3324
|
+
let texture = material.map;
|
|
3325
|
+
if (!texture)
|
|
3326
|
+
return;
|
|
3327
|
+
if (material instanceof sn) {
|
|
3328
|
+
const { gradient, range, discardOut, voidRange, } = material;
|
|
3329
|
+
texture = mn(texture.image, Object.assign({ gradient: gradient === null || gradient === void 0 ? void 0 : gradient.image, range,
|
|
3330
|
+
discardOut,
|
|
3331
|
+
voidRange }, options));
|
|
3332
|
+
}
|
|
3333
|
+
const sliceMesh = new vn(Object.assign({ map: texture }, options));
|
|
3334
|
+
this.ssp.addObject(sliceMesh);
|
|
3335
|
+
return sliceMesh;
|
|
3336
|
+
}
|
|
3337
|
+
//创建切片dom
|
|
3338
|
+
createImageSlice(material, options) {
|
|
3339
|
+
const texture = material.map;
|
|
3340
|
+
if (!texture)
|
|
3341
|
+
return;
|
|
3342
|
+
let imageTexture = null;
|
|
3343
|
+
if (material instanceof sn) {
|
|
3344
|
+
const { gradient, range, discardOut, voidRange, } = material;
|
|
3345
|
+
imageTexture = mn(texture.image, Object.assign({ gradient: gradient === null || gradient === void 0 ? void 0 : gradient.image, range,
|
|
3346
|
+
discardOut,
|
|
3347
|
+
voidRange }, options));
|
|
3348
|
+
}
|
|
3349
|
+
if (material instanceof cn) {
|
|
3350
|
+
imageTexture = texture;
|
|
3351
|
+
}
|
|
3352
|
+
if (!imageTexture)
|
|
3353
|
+
return;
|
|
3354
|
+
const imageSlice = new hn(imageTexture);
|
|
3355
|
+
return imageSlice;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
export { Ot as ColorFogPointsMaterial, Mn as ExampleVolumeMaterial_1, zn as ExampleVolumeMaterial_Cloud, wn as ExampleVolumeMaterial_Perlin, Ye as FogPointsMaterial, Pt as GradientData3DTexture, Gt as GradientFogPointsMaterial, sn as GradientVolumeMaterial, HeatMapPlugin, ct as ImageData3DSlice, $e as ImageData3DTexture, hn as ImageData3DTextureSlice, cn as ImageVolumeMaterial, jt as SliceMaterial, vn as SliceMesh, dn as SphereFogMaterial, Dt as VolumeFit, Xe as VolumeMaterial, rn as VolumeMesh, Kt as VolumeRenderStyle, qt as computeHeatData3DForPoint, pn as createColorFogPoints, ln as createGradientData3DTexture, fn as createGradientFogPoints, gn as createHeatData3D, un as createImageData3DTextureByExtrudeImage, mn as createImageData3DTextureFromGradient, xn as createLineData3D, B as createLinearGradientImageData, Gn as createLinearGradientTexture, O as data2DCoordToIndex, at$1 as data2DIndexToCoord, _ as data3DCoordToIndex, Z as data3DIndexToCoord, HeatMapPlugin as default, nt as extrudeImage, W as extrudeImageData, X as extrudeImageDataOnAxis, G as getData2DItem, st as getData2DItemSafe, ot$1 as getData2DRow, j as getData2DValue, it as getData2DValueSafe, U as getData3DItem, $ as getData3DItemSafe, E as getData3DSlice, N as getData3DValue, tt as getData3DValueSafe, H as getImageDateColor, K as getImageDateOfImage, F as getImageDateRow, b as getNaturalSizeOfImageSource, Ut as gradientData3DToImageData3D, $t as hollowGradient_Default, Y as imageDataToCanvas, J as imageDataToUrl, L as isIImageData2, P as isIImageData3, Q as isOutOfSize, Yt as lineValueGradient_Default, bt as makeOriginOnBoundingBoxMinOfGeometry, et as mergeData3Ds, Zt as numberValuesAccumulate_Default, yn as optimizeGradientOptions, Xt as radiusGradient_Default, V as reverseImageDateY, _n as transformGradientOptions, Wt as translateScaleGradientOptions, Ze as valueGradient_Default, Ht as valuesAccumulate_Default };
|
|
3360
|
+
//# sourceMappingURL=index.esm.js.map
|