2026-02-02 16:36:17 +08:00
( function ( ) { "use strict" ; try { if ( typeof document < "u" ) { var e = document . createElement ( "style" ) ; e . appendChild ( document . createTextNode ( ' . bim - engine - wrapper { position : relative ; width : 100 % ; height : 100 % ; font - family : sans - serif ; box - sizing : border - box ; overflow : hidden ; background : linear - gradient ( to bottom , # d6e0eb , # f6faff ) } . bim - engine - opt - btn - container { z - index : 100 } . bim - construct - tree - btn { position : absolute ; top : 20 px ; left : 20 px ! important ; z - index : 100 } . bim - btn - group - root { display : flex ; gap : 8 px ; z - index : 1000 ; position : absolute ; pointer - events : auto } . bim - btn - group - root . static { position : relative ; inset : auto ; transform : none } . bim - btn - group - root . dir - row { flex - direction : row ; align - items : center } . bim - btn - group - root . dir - column { flex - direction : column ; align - items : stretch } . bim - btn - group - section { display : flex ; gap : 4 px ; background - color : var ( -- bim - btn - group - section - bg , rgba ( 17 , 17 , 17 , . 88 ) ) ; border - radius : 6 px ; padding : 4 px ; box - shadow : 0 2 px 8 px # 0000004 d , 0 1 px 3 px # 0003 } . bim - btn - group - root . dir - row . bim - btn - group - section { flex - direction : row ; align - items : center } . bim - btn - group - root . dir - column . bim - btn - group - section { flex - direction : column } . opt - btn - wrapper { position : relative } . opt - btn { display : flex ; cursor : pointer ; border - radius : 4 px ; transition : background - color . 2 s , color . 2 s , border - color . 2 s ; color : var ( -- bim - btn - text - color , # ccc ) ; background - color : var ( -- bim - btn - bg , transparent ) ; padding : 6 px ; align - items : center ; position : relative ; justify - content : center ; border : 1 px solid transparent ; outline : none } . opt - btn : hover { background - color : var ( -- bim - btn - hover - bg , # 444 ) } . opt - btn . active { background - color : var ( -- bim - btn - active - bg , rgba ( 255 , 255 , 255 , . 15 ) ) ; color : var ( -- bim - btn - text - active - color , # fff ) } . opt - btn . disabled { opacity : . 5 ; cursor : not - allowed } . opt - btn - icon { width : var ( -- bim - icon - size , 24 px ) ; height : var ( -- bim - icon - size , 24 px ) ; display : flex ; align - items : center ; justify - content : center ; color : var ( -- bim - icon - color , # ccc ) ; flex - shrink : 0 } . opt - btn - icon svg { width : 100 % ; height : 100 % ; fill : currentColor } . opt - btn - arrow { font - size : 10 px ; opacity : . 6 ; transition : transform . 2 s ; display : inline - block ; margin - left : 4 px } . opt - btn - arrow . rotated { transform : rotate ( 180 deg ) } . opt - btn - text - wrapper { display : flex ; align - items : center ; justify - content : center ; pointer - events : none } . opt - btn - label { display : inline } . opt - btn . no - label . opt - btn - label { display : none } . opt - btn . align - vertical : not ( . no - label ) { flex - direction : column ; text - align : center } . opt - btn . align - vertical : not ( . no - label ) . opt - btn - text - wrapper { margin - top : 4 px } . opt - btn . align - vertical : not ( . no - label ) . opt - btn - label { font - size : 12 px ; line - height : 1.2 } . opt - btn . align - horizontal : not ( . no - label ) { flex - direction : row } . opt - btn . align - horizontal : not ( . no - label ) . opt - btn - text - wrapper { margin - left : 8 px } . opt - btn . align - horizontal : not ( . no - label ) . opt - btn - label { font - size : 14 px } . opt - btn . no - label . opt - btn - text - wrapper { width : 0 ; height : 0 ; margin : 0 ; padding : 0 ; overflow : visible ; position : absolute ; top : 0 ; right : 0 } . opt - btn . no - label . opt - btn - arrow { position : absolute ; top : 2 px ; right : 2 px ; margin : 0 ; font - size : 8 px } . opt - btn - dropdown { position : absolute ; background - color : var ( -- bim - toolbar - bg , rgba ( 17 , 17 , 17 , . 95 ) ) ; border - radius : 4 px ; padding : 4 px ; box - shadow : 0 4 px 12 px # 0003 ; z - index : 1001 ; display : flex ; flex - direction : column ; border : 1 px solid rgba ( 255 , 255 , 255 , . 1 ) ; opacity : 0 ; visibility : hidden ; transform : translateY ( - 10 px ) ; transition : opacity . 2 s ease , transform . 2 s cubic - bezier ( . 2 , 0 , . 2 , 1 ) , visibility . 2 s } @ keyframes dropdown - fade - in { 0 % { opacity : 0 ; transform : translateY ( - 8 px ) scale ( . 98 ) } to { opacity : 1 ; transform : translateY ( 0 ) scale ( 1 ) } } . opt - btn - dropdown { animation : dropdown - fade - in . 2 s cubic - bezier ( . 2 , 0 , . 2 , 1 ) forwards ; opacity : 1 ; visibility : visible ; transform : none } . opt - btn - dropdown - item { display : flex ; align - items : center ; padding : 8 px 12 px ; cursor : pointer ; border - radius : 4 px ; color : var ( -- bim - btn - text - color , # ccc ) ; transition : background . 2 s , border - color . 2 s , color . 2 s ; box - sizing : border - box ; border : 1 px solid transparent ; outline : none } . opt - btn - dropdown - item . opt - btn - icon { color : var ( -- bim - icon - color , # ccc ) } . opt - btn - dropdown - item : hover { background - color : var ( -- bim - btn - hover - bg , # 444 ) } . opt - btn - dropdown - item . active { background - color : var ( -- bim - btn - active - bg , rgba ( 255 , 255 , 255 , . 15 ) ) ; color : var ( -- bim - btn - text - active - color , # fff ) } .
2026-02-02 18:18:36 +08:00
( function ( Bs , Vr ) { typeof exports == "object" && typeof module < "u" ? Vr ( exports ) : typeof define == "function" && define . amd ? define ( [ "exports" ] , Vr ) : ( Bs = typeof globalThis < "u" ? globalThis : Bs || self , Vr ( Bs . IflowEngine = { } ) ) } ) ( this , ( function ( Bs ) { "use strict" ; const Vr = { common : { title : "BimEngine" , description : "这是一个使用 BIM-ENGINE。" , openTestDialog : "打开测试弹窗" , openInfoDialog : "打开信息弹窗 (封装版)" } , toolbar : { home : "首页" , measure : "测量" , zoomBox : "选框放大" , info : "信息" , location : "定位" , setting : "设置" , walk : "漫游" , map : "地图" , property : "构件详情" , fullscreen : "全屏" , walkMenu : "漫游菜单" , walkPerson : "第一人称" , walkBird : "第三人称" , tree : "模型树" , section : "剖切" , sectionPlane : "拾取面剖切" , sectionAxis : "轴向剖切" , sectionBox : "剖切盒" } , dialog : { testTitle : "测试弹窗" , testContent : '<div style="padding: 10px;">这是一个 <b>可拖拽</b> 且 <b>可缩放</b> 的弹窗。<br><br>你可以尝试拖动标题栏,或者拖动右下角改变大小。</div>' } , menu : { info : "信息" , home : "首页" , componentDetail : "构件详情" , hideSelected : "隐藏选中构件" , transparentSelected : "半透明选中构件" , isolateSelected : "隔离选中构件" , hideOthers : "其他构件隐藏" , transparentOthers : "其他构件半透明" , fitSectionBox : "剖切盒适应" , showAll : "显示全部" } , tree : { searchPlaceholder : "请输入要搜索的内容" } , constructTree : { title : "目录树" } , tab : { component : "构件" , system : "系统" , space : "空间" , type : "类型" , major : "专业" } , panel : { property : { title : "构件详情" , base : "基本属性" , material : "材质信息" , advanced : "高级设置" , tab : { props : "属性" , material : "材质" } } , componentDetail : { title : "构件详情" , noSelection : "请先选中构件" } } , measure : { btnName : "测量" , dialogTitle : "测量" , modes : { clearHeight : "净高" , clearDistance : "净距" , distance : "距离" , elevation : "标高" , point : "坐标" , angle : "角度" , area : "面积" , slope : "坡度" } , actions : { expand : "展开" , collapse : "收起" , clearAll : "删除全部" , settings : "设置" } , labels : { currentMode : "当前测量方式:" , x : "X: " , y : "Y: " , z : "Z: " , value : { clearHeight : "净高:" , clearDistance : "净距:" , distance : "距离:" , elevation : "标高:" , point : "坐标:" , angle : "角度:" , area : "面积:" , slope : "坡度:" } } , units : { mm : "mm" , cm : "cm" , m : "m" , km : "km" , deg : "°" , m2 : "m²" , percent : "%" } , settings : { title : "设置" , unit : "单位:" , precision : "精度:" , hint : "距离、净距、净高和标高默认使用该单位;角度和面积有各自默认单位。" , save : "保存设置" , cancel : "取消" } } , sectionPlane : { dialogTitle : "拾取面剖切" , actions : { hide : "隐藏" , reverse : "反向" , reset : "重置" } } , sectionAxis : { dialogTitle : "轴向剖切" , actions : { hide : "隐藏" , reverse : "反向" , axisX : "X" , axisY : "Y" , axisZ : "Z" } } , sectionBox : { dialogTitle : "剖切盒" , actions : { hide : "隐藏" , reverse : "反向" , fitToModel : "适应" , reset : "重置" } , axes : { x : "X" , y : "Y" , z : "Z" } } , walkControl : { speed : "移动速度:" , gravity : "重力" , collision : "碰撞" , characterModel : { label : "建筑工人" , constructionWorker : "建筑工人" , officeMale : "办公室男性" } , walkMode : { label : "行走模式" , walk : "行走模式" , run : "奔跑模式" } , exit : "退出" , path : { dialogTitle : "路径漫游" } } , map : { dialogTitle : "地图" } , aiChat : { title : "AI 助手" , placeholder : "输入你的问题..." , quickPrompt : { summarize : "总结这个模型" , explain : "解释选中的构件" , generate : "生成报告" } , action : { new : "新建对话" , history : "历史记录" , settings : "设置" , close : "关闭" } , helper : { newline : "Shift + Enter 换行" , send : "Enter 发送" } , thinking : "正在思考..." , other : "其他" , otherPlaceholder : "请输入自定义答案" , submit : "提交" } } , K0 = { common : { title : "BimEngine" , description : "This is a BIM-ENGINE demo." , openTestDialog : "Open Test Dialog" , openInfoDialog : "Open Info Dialog (Wrapped)" } , toolbar : { home : "Home" , measure : "Measure" , zoomBox : "Zoom Box" , info : "Info" , location : "Location" , setting : "Settings" , walk : "Walk" , map : "Map" , property : "Property" , fullscreen : "Fullscreen" , walkPerson : "Person" , walkBird : "Bird Eye" , walkMenu : "Menu" , tree : "Tree" , section : "Section" , sectionPlane : "Plane Section" , sectionAxis : "Axis Section" , sectionBox : "Section Box" } , dialog : { testTitl
2026-01-22 11:29:51 +08:00
< li > < strong > Name : < / s t r o n g > S a m p l e P r o j e c t < / l i >
< li > < strong > Version : < / s t r o n g > 1 . 0 . 0 < / l i >
< li > < strong > Date : < / s t r o n g > $ { n e w D a t e ( ) . t o L o c a l e D a t e S t r i n g ( ) } < / l i >
< li > < strong > Status : < / s t r o n g > < s p a n s t y l e = " c o l o r : g r e e n ; " > A c t i v e < / s p a n > < / l i >
2026-02-02 18:18:36 +08:00
` ;const r=document.createElement("button");r.textContent="Update Status",r.style.marginTop="10px",r.onclick=()=>{alert("Status updated!")},t.appendChild(n),t.appendChild(i),t.appendChild(r),super({container:e,title:"dialog.testTitle",content:t,width:320,height:"auto",position:"center",resizable:!0,draggable:!0,onClose:()=>{console.log("Info dialog closed")},onOpen:()=>{console.log("Info dialog opened")}})}}class ag extends mi{container;activeDialogs=[];constructor(e){super(),this.container=e,this.subscribe("ui:open-dialog",t=>{console.log("[DialogManager] Received open-dialog event:",t),t.id==="info"&&this.showInfoDialog()})}create(e){const t=new ad({container:this.container,...e,onClose:()=>{this.activeDialogs=this.activeDialogs.filter(n=>n!==t),e.onClose&&e.onClose()}});return t.setTheme(rt.getTheme()),this.activeDialogs.push(t),t}showInfoDialog(){new rg(this.container)}updateTheme(e){this.activeDialogs.forEach(t=>{t.setTheme&&t.setTheme(e)})}destroy(){this.activeDialogs.forEach(e=>e.destroy()),this.activeDialogs=[],super.destroy()}}const Gr="181",Ns={ROTATE:0,DOLLY:1,PAN:2},ks={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},og=0,od=1,lg=2,ld=1,cd=2,gi=3,Pn=0,on=1,Nt=2,Xt=0,Us=1,Gl=2,hd=3,ud=4,dd=5,Wn=100,cg=101,hg=102,ug=103,dg=104,Wr=200,fg=201,pg=202,mg=203,Wl=204,Xl=205,jl=206,gg=207,ql=208,xg=209,vg=210,bg=211,yg=212,_g=213,Mg=214,Zl=0,Yl=1, $ l=2,Os=3,Kl=4,Jl=5,Ql=6,ec=7,Xa=0,wg=1,Sg=2,Ni=0,fd=1,pd=2,md=3,tc=4,gd=5,xd=6,vd=7,bd="attached",Eg="detached",yd=300,Fs=301,zs=302,nc=303,ic=304,ja=306,ii=1e3,si=1001,qa=1002,Yt=1003,_d=1004,Xr=1005, $ t=1006,Za=1007,xi=1008,Xn=1009,Md=1010,wd=1011,jr=1012,sc=1013,ts=1014,jn=1015,Rn=1016,rc=1017,ac=1018,Hs=1020,Sd=35902,Ed=35899,Td=1021,Cd=1022,pn=1023,qr=1026,Vs=1027,oc=1028,lc=1029,cc=1030,hc=1031,uc=1033,Ya=33776, $ a=33777,Ka=33778,Ja=33779,dc=35840,fc=35841,pc=35842,mc=35843,gc=36196,xc=37492,vc=37496,bc=37808,yc=37809,_c=37810,Mc=37811,wc=37812,Sc=37813,Ec=37814,Tc=37815,Cc=37816,Ac=37817,Pc=37818,Rc=37819,Lc=37820,Ic=37821,Dc=36492,Bc=36494,Nc=36495,kc=36283,Uc=36284,Oc=36285,Fc=36286,Zr=2300,Yr=2301,zc=2302,Ad=2400,Pd=2401,Rd=2402,Tg=2500,Cg=0,Ld=1,Hc=2,Ag=3200,Pg=3201, $ r=0,Rg=1,ki="",mt="srgb",At="srgb-linear",Qa="linear",lt="srgb",Gs=7680,Id=519,Lg=512,Ig=513,Dg=514,Dd=515,Bg=516,Ng=517,kg=518,Ug=519,Vc=35044,Bd="300 es",ri=2e3,eo=2001;function Nd(s){for(let e=s.length-1;e>=0;--e)if(s[e]>=65535)return!0;return!1}function Kr(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function Og(){const s=Kr("canvas");return s.style.display="block",s}const kd={};function to(...s){const e="THREE."+s.shift();console.log(e,...s)}function He(...s){const e="THREE."+s.shift();console.warn(e,...s)}function Qe(...s){const e="THREE."+s.shift();console.error(e,...s)}function Jr(...s){const e=s.join(" ");e in kd||(kd[e]=!0,He(...s))}function Fg(s,e,t){return new Promise(function(n,i){function r(){switch(s.clientWaitSync(e,s.SYNC_FLUSH_COMMANDS_BIT,0)){case s.WAIT_FAILED:i();break;case s.TIMEOUT_EXPIRED:setTimeout(r,t);break;default:n()}}setTimeout(r,t)})}class ns{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){const n=this._listeners;return n===void 0?!1:n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){const n=this._listeners;if(n===void 0)return;const i=n[e];if(i!==void 0){const r=i.indexOf(t);r!==-1&&i.splice(r,1)}}dispatchEvent(e){const t=this._listeners;if(t===void 0)return;const n=t[e.type];if(n!==void 0){e.target=this;const i=n.slice(0);for(let r=0,a=i.length;r<a;r++)i[r].call(this,e);e.target=null}}}const Qt=["00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f","20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f","50","51","52","53","5
2026-01-22 11:29:51 +08:00
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
2026-02-02 18:18:36 +08:00
} ` ,_x= ` void main ( ) {
2026-01-22 11:29:51 +08:00
gl _FragColor = vec4 ( 1.0 , 0.0 , 0.0 , 1.0 ) ;
2026-02-02 18:18:36 +08:00
} ` ;class kt extends xn{constructor(e){super(),this.isShaderMaterial=!0,this.type="ShaderMaterial",this.defines={},this.uniforms={},this.uniformsGroups=[],this.vertexShader=yx,this.fragmentShader=_x,this.linewidth=1,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.lights=!1,this.clipping=!1,this.forceSinglePass=!0,this.extensions={clipCullDistance:!1,multiDraw:!1},this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv1:[0,0]},this.index0AttributeName=void 0,this.uniformsNeedUpdate=!1,this.glslVersion=null,e!==void 0&&this.setValues(e)}copy(e){return super.copy(e),this.fragmentShader=e.fragmentShader,this.vertexShader=e.vertexShader,this.uniforms=nr(e.uniforms),this.uniformsGroups=bx(e.uniformsGroups),this.defines=Object.assign({},e.defines),this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.fog=e.fog,this.lights=e.lights,this.clipping=e.clipping,this.extensions=Object.assign({},e.extensions),this.glslVersion=e.glslVersion,this}toJSON(e){const t=super.toJSON(e);t.glslVersion=this.glslVersion,t.uniforms={};for(const i in this.uniforms){const a=this.uniforms[i].value;a&&a.isTexture?t.uniforms[i]={type:"t",value:a.toJSON(e).uuid}:a&&a.isColor?t.uniforms[i]={type:"c",value:a.getHex()}:a&&a.isVector2?t.uniforms[i]={type:"v2",value:a.toArray()}:a&&a.isVector3?t.uniforms[i]={type:"v3",value:a.toArray()}:a&&a.isVector4?t.uniforms[i]={type:"v4",value:a.toArray()}:a&&a.isMatrix3?t.uniforms[i]={type:"m3",value:a.toArray()}:a&&a.isMatrix4?t.uniforms[i]={type:"m4",value:a.toArray()}:t.uniforms[i]={value:a}}Object.keys(this.defines).length>0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class sf extends St{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new Oe,this.projectionMatrix=new Oe,this.projectionMatrixInverse=new Oe,this.coordinateSystem=ri,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const Wi=new R,rf=new ce,af=new ce;class sn extends sf{constructor(e=50,t=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Ws*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(Qr*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Ws*2*Math.atan(Math.tan(Qr*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){Wi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(Wi.x,Wi.y).multiplyScalar(-e/Wi.z),Wi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(Wi.x,Wi.y).multiplyScalar(-e/Wi.z)}getViewSize(e,t){return this.getViewBounds(e,rf,af),t.subVectors(af,rf)}setViewOffset(e,t,n,i,r,a){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.vie
2026-01-22 11:29:51 +08:00
varying vec3 vWorldDirection ;
vec3 transformDirection ( in vec3 dir , in mat4 matrix ) {
return normalize ( ( matrix * vec4 ( dir , 0.0 ) ) . xyz ) ;
}
void main ( ) {
vWorldDirection = transformDirection ( position , modelMatrix ) ;
# include < begin _vertex >
# include < project _vertex >
}
` ,fragmentShader: `
uniform sampler2D tEquirect ;
varying vec3 vWorldDirection ;
# include < common >
void main ( ) {
vec3 direction = normalize ( vWorldDirection ) ;
vec2 sampleUV = equirectUv ( direction ) ;
gl _FragColor = texture2D ( tEquirect , sampleUV ) ;
}
2026-02-02 18:18:36 +08:00
` },i=new Gi(5,5,5),r=new kt({name:"CubemapFromEquirect",uniforms:nr(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:on,blending:Xt});r.uniforms.tEquirect.value=t;const a=new gt(i,r),o=t.minFilter;return t.minFilter===xi&&(t.minFilter= $ t),new Mx(1,10,this).update(e,a),t.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(e,t=!0,n=!0,i=!0){const r=e.getRenderTarget();for(let a=0;a<6;a++)e.setRenderTarget(this,a),e.clear(t,n,i);e.setRenderTarget(r)}}class Bn extends St{constructor(){super(),this.isGroup=!0,this.type="Group"}}const Sx={type:"move"};class dh{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new Bn,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new Bn,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new R,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new R),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new Bn,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new R,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new R),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){const t=this._hand;if(t)for(const n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let i=null,r=null,a=null;const o=this._targetRay,l=this._grip,c=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(c&&e.hand){a=!0;for(const p of e.hand.values()){const x=t.getJointPose(p,n),g=this._getHandJoint(c,p);x!==null&&(g.matrix.fromArray(x.transform.matrix),g.matrix.decompose(g.position,g.rotation,g.scale),g.matrixWorldNeedsUpdate=!0,g.jointRadius=x.radius),g.visible=x!==null}const h=c.joints["index-finger-tip"],u=c.joints["thumb-tip"],f=h.position.distanceTo(u.position),d=.02,m=.005;c.inputState.pinching&&f>d+m?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&f<=d-m&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),r!==null&&(l.matrix.fromArray(r.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,r.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(r.linearVelocity)):l.hasLinearVelocity=!1,r.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(r.angularVelocity)):l.hasAngularVelocity=!1));o!==null&&(i=t.getPose(e.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(o.matrix.fromArray(i.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,i.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(i.linearVelocity)):o.hasLinearVelocity=!1,i.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(i.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(Sx)))}return o!==null&&(o.visible=i!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new Bn;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class lf extends St{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new gn,thi
2026-01-22 11:29:51 +08:00
if ( diffuseColor . a < getAlphaHashThreshold ( vPosition ) ) discard ;
2026-02-02 18:18:36 +08:00
# endif ` ,t1= ` # ifdef USE _ALPHAHASH
2026-01-22 11:29:51 +08:00
const float ALPHA _HASH _SCALE = 0.05 ;
float hash2D ( vec2 value ) {
return fract ( 1.0 e4 * sin ( 17.0 * value . x + 0.1 * value . y ) * ( 0.1 + abs ( sin ( 13.0 * value . y + value . x ) ) ) ) ;
}
float hash3D ( vec3 value ) {
return hash2D ( vec2 ( hash2D ( value . xy ) , value . z ) ) ;
}
float getAlphaHashThreshold ( vec3 position ) {
float maxDeriv = max (
length ( dFdx ( position . xyz ) ) ,
length ( dFdy ( position . xyz ) )
) ;
float pixScale = 1.0 / ( ALPHA _HASH _SCALE * maxDeriv ) ;
vec2 pixScales = vec2 (
exp2 ( floor ( log2 ( pixScale ) ) ) ,
exp2 ( ceil ( log2 ( pixScale ) ) )
) ;
vec2 alpha = vec2 (
hash3D ( floor ( pixScales . x * position . xyz ) ) ,
hash3D ( floor ( pixScales . y * position . xyz ) )
) ;
float lerpFactor = fract ( log2 ( pixScale ) ) ;
float x = ( 1.0 - lerpFactor ) * alpha . x + lerpFactor * alpha . y ;
float a = min ( lerpFactor , 1.0 - lerpFactor ) ;
vec3 cases = vec3 (
x * x / ( 2.0 * a * ( 1.0 - a ) ) ,
( x - 0.5 * a ) / ( 1.0 - a ) ,
1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )
) ;
float threshold = ( x < ( 1.0 - a ) )
? ( ( x < a ) ? cases . x : cases . y )
: cases . z ;
return clamp ( threshold , 1.0 e - 6 , 1.0 ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,n1= ` # ifdef USE _ALPHAMAP
2026-01-22 11:29:51 +08:00
diffuseColor . a *= texture2D ( alphaMap , vAlphaMapUv ) . g ;
2026-02-02 18:18:36 +08:00
# endif ` ,i1= ` # ifdef USE _ALPHAMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D alphaMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,s1= ` # ifdef USE _ALPHATEST
2026-01-22 11:29:51 +08:00
# ifdef ALPHA _TO _COVERAGE
diffuseColor . a = smoothstep ( alphaTest , alphaTest + fwidth ( diffuseColor . a ) , diffuseColor . a ) ;
if ( diffuseColor . a == 0.0 ) discard ;
# else
if ( diffuseColor . a < alphaTest ) discard ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,r1= ` # ifdef USE _ALPHATEST
2026-01-22 11:29:51 +08:00
uniform float alphaTest ;
2026-02-02 18:18:36 +08:00
# endif ` ,a1= ` # ifdef USE _AOMAP
2026-01-22 11:29:51 +08:00
float ambientOcclusion = ( texture2D ( aoMap , vAoMapUv ) . r - 1.0 ) * aoMapIntensity + 1.0 ;
reflectedLight . indirectDiffuse *= ambientOcclusion ;
# if defined ( USE _CLEARCOAT )
clearcoatSpecularIndirect *= ambientOcclusion ;
# endif
# if defined ( USE _SHEEN )
sheenSpecularIndirect *= ambientOcclusion ;
# endif
# if defined ( USE _ENVMAP ) && defined ( STANDARD )
float dotNV = saturate ( dot ( geometryNormal , geometryViewDir ) ) ;
reflectedLight . indirectSpecular *= computeSpecularOcclusion ( dotNV , ambientOcclusion , material . roughness ) ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,o1= ` # ifdef USE _AOMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D aoMap ;
uniform float aoMapIntensity ;
2026-02-02 18:18:36 +08:00
# endif ` ,l1= ` # ifdef USE _BATCHING
2026-01-22 11:29:51 +08:00
# if ! defined ( GL _ANGLE _multi _draw )
# define gl _DrawID _gl _DrawID
uniform int _gl _DrawID ;
# endif
uniform highp sampler2D batchingTexture ;
uniform highp usampler2D batchingIdTexture ;
mat4 getBatchingMatrix ( const in float i ) {
int size = textureSize ( batchingTexture , 0 ) . x ;
int j = int ( i ) * 4 ;
int x = j % size ;
int y = j / size ;
vec4 v1 = texelFetch ( batchingTexture , ivec2 ( x , y ) , 0 ) ;
vec4 v2 = texelFetch ( batchingTexture , ivec2 ( x + 1 , y ) , 0 ) ;
vec4 v3 = texelFetch ( batchingTexture , ivec2 ( x + 2 , y ) , 0 ) ;
vec4 v4 = texelFetch ( batchingTexture , ivec2 ( x + 3 , y ) , 0 ) ;
return mat4 ( v1 , v2 , v3 , v4 ) ;
}
float getIndirectIndex ( const in int i ) {
int size = textureSize ( batchingIdTexture , 0 ) . x ;
int x = i % size ;
int y = i / size ;
return float ( texelFetch ( batchingIdTexture , ivec2 ( x , y ) , 0 ) . r ) ;
}
# endif
# ifdef USE _BATCHING _COLOR
uniform sampler2D batchingColorTexture ;
vec3 getBatchingColor ( const in float i ) {
int size = textureSize ( batchingColorTexture , 0 ) . x ;
int j = int ( i ) ;
int x = j % size ;
int y = j / size ;
return texelFetch ( batchingColorTexture , ivec2 ( x , y ) , 0 ) . rgb ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,c1= ` # ifdef USE _BATCHING
2026-01-22 11:29:51 +08:00
mat4 batchingMatrix = getBatchingMatrix ( getIndirectIndex ( gl _DrawID ) ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,h1= ` vec3 transformed = vec3 ( position ) ;
2026-01-22 11:29:51 +08:00
# ifdef USE _ALPHAHASH
vPosition = vec3 ( position ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,u1= ` vec3 objectNormal = vec3 ( normal ) ;
2026-01-22 11:29:51 +08:00
# ifdef USE _TANGENT
vec3 objectTangent = vec3 ( tangent . xyz ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,d1= ` float G _BlinnPhong _Implicit ( ) {
2026-01-22 11:29:51 +08:00
return 0.25 ;
}
float D _BlinnPhong ( const in float shininess , const in float dotNH ) {
return RECIPROCAL _PI * ( shininess * 0.5 + 1.0 ) * pow ( dotNH , shininess ) ;
}
vec3 BRDF _BlinnPhong ( const in vec3 lightDir , const in vec3 viewDir , const in vec3 normal , const in vec3 specularColor , const in float shininess ) {
vec3 halfDir = normalize ( lightDir + viewDir ) ;
float dotNH = saturate ( dot ( normal , halfDir ) ) ;
float dotVH = saturate ( dot ( viewDir , halfDir ) ) ;
vec3 F = F _Schlick ( specularColor , 1.0 , dotVH ) ;
float G = G _BlinnPhong _Implicit ( ) ;
float D = D _BlinnPhong ( shininess , dotNH ) ;
return F * ( G * D ) ;
2026-02-02 18:18:36 +08:00
} // validated`,f1=`#ifdef USE_IRIDESCENCE
2026-01-22 11:29:51 +08:00
const mat3 XYZ _TO _REC709 = mat3 (
3.2404542 , - 0.9692660 , 0.0556434 ,
- 1.5371385 , 1.8760108 , - 0.2040259 ,
- 0.4985314 , 0.0415560 , 1.0572252
) ;
vec3 Fresnel0ToIor ( vec3 fresnel0 ) {
vec3 sqrtF0 = sqrt ( fresnel0 ) ;
return ( vec3 ( 1.0 ) + sqrtF0 ) / ( vec3 ( 1.0 ) - sqrtF0 ) ;
}
vec3 IorToFresnel0 ( vec3 transmittedIor , float incidentIor ) {
return pow2 ( ( transmittedIor - vec3 ( incidentIor ) ) / ( transmittedIor + vec3 ( incidentIor ) ) ) ;
}
float IorToFresnel0 ( float transmittedIor , float incidentIor ) {
return pow2 ( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ) ) ;
}
vec3 evalSensitivity ( float OPD , vec3 shift ) {
float phase = 2.0 * PI * OPD * 1.0 e - 9 ;
vec3 val = vec3 ( 5.4856 e - 13 , 4.4201 e - 13 , 5.2481 e - 13 ) ;
vec3 pos = vec3 ( 1.6810 e + 06 , 1.7953 e + 06 , 2.2084 e + 06 ) ;
vec3 var = vec3 ( 4.3278 e + 09 , 9.3046 e + 09 , 6.6121 e + 09 ) ;
vec3 xyz = val * sqrt ( 2.0 * PI * var ) * cos ( pos * phase + shift ) * exp ( - pow2 ( phase ) * var ) ;
xyz . x += 9.7470 e - 14 * sqrt ( 2.0 * PI * 4.5282 e + 09 ) * cos ( 2.2399 e + 06 * phase + shift [ 0 ] ) * exp ( - 4.5282 e + 09 * pow2 ( phase ) ) ;
xyz /= 1.0685 e - 7 ;
vec3 rgb = XYZ _TO _REC709 * xyz ;
return rgb ;
}
vec3 evalIridescence ( float outsideIOR , float eta2 , float cosTheta1 , float thinFilmThickness , vec3 baseF0 ) {
vec3 I ;
float iridescenceIOR = mix ( outsideIOR , eta2 , smoothstep ( 0.0 , 0.03 , thinFilmThickness ) ) ;
float sinTheta2Sq = pow2 ( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2 ( cosTheta1 ) ) ;
float cosTheta2Sq = 1.0 - sinTheta2Sq ;
if ( cosTheta2Sq < 0.0 ) {
return vec3 ( 1.0 ) ;
}
float cosTheta2 = sqrt ( cosTheta2Sq ) ;
float R0 = IorToFresnel0 ( iridescenceIOR , outsideIOR ) ;
float R12 = F _Schlick ( R0 , 1.0 , cosTheta1 ) ;
float T121 = 1.0 - R12 ;
float phi12 = 0.0 ;
if ( iridescenceIOR < outsideIOR ) phi12 = PI ;
float phi21 = PI - phi12 ;
vec3 baseIOR = Fresnel0ToIor ( clamp ( baseF0 , 0.0 , 0.9999 ) ) ; vec3 R1 = IorToFresnel0 ( baseIOR , iridescenceIOR ) ;
vec3 R23 = F _Schlick ( R1 , 1.0 , cosTheta2 ) ;
vec3 phi23 = vec3 ( 0.0 ) ;
if ( baseIOR [ 0 ] < iridescenceIOR ) phi23 [ 0 ] = PI ;
if ( baseIOR [ 1 ] < iridescenceIOR ) phi23 [ 1 ] = PI ;
if ( baseIOR [ 2 ] < iridescenceIOR ) phi23 [ 2 ] = PI ;
float OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2 ;
vec3 phi = vec3 ( phi21 ) + phi23 ;
vec3 R123 = clamp ( R12 * R23 , 1e-5 , 0.9999 ) ;
vec3 r123 = sqrt ( R123 ) ;
vec3 Rs = pow2 ( T121 ) * R23 / ( vec3 ( 1.0 ) - R123 ) ;
vec3 C0 = R12 + Rs ;
I = C0 ;
vec3 Cm = Rs - T121 ;
for ( int m = 1 ; m <= 2 ; ++ m ) {
Cm *= r123 ;
vec3 Sm = 2.0 * evalSensitivity ( float ( m ) * OPD , float ( m ) * phi ) ;
I += Cm * Sm ;
}
return max ( I , vec3 ( 0.0 ) ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,p1= ` # ifdef USE _BUMPMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D bumpMap ;
uniform float bumpScale ;
vec2 dHdxy _fwd ( ) {
vec2 dSTdx = dFdx ( vBumpMapUv ) ;
vec2 dSTdy = dFdy ( vBumpMapUv ) ;
float Hll = bumpScale * texture2D ( bumpMap , vBumpMapUv ) . x ;
float dBx = bumpScale * texture2D ( bumpMap , vBumpMapUv + dSTdx ) . x - Hll ;
float dBy = bumpScale * texture2D ( bumpMap , vBumpMapUv + dSTdy ) . x - Hll ;
return vec2 ( dBx , dBy ) ;
}
vec3 perturbNormalArb ( vec3 surf _pos , vec3 surf _norm , vec2 dHdxy , float faceDirection ) {
vec3 vSigmaX = normalize ( dFdx ( surf _pos . xyz ) ) ;
vec3 vSigmaY = normalize ( dFdy ( surf _pos . xyz ) ) ;
vec3 vN = surf _norm ;
vec3 R1 = cross ( vSigmaY , vN ) ;
vec3 R2 = cross ( vN , vSigmaX ) ;
float fDet = dot ( vSigmaX , R1 ) * faceDirection ;
vec3 vGrad = sign ( fDet ) * ( dHdxy . x * R1 + dHdxy . y * R2 ) ;
return normalize ( abs ( fDet ) * surf _norm - vGrad ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,m1= ` # if NUM _CLIPPING _PLANES > 0
2026-01-22 11:29:51 +08:00
vec4 plane ;
# ifdef ALPHA _TO _COVERAGE
float distanceToPlane , distanceGradient ;
float clipOpacity = 1.0 ;
# pragma unroll _loop _start
for ( int i = 0 ; i < UNION _CLIPPING _PLANES ; i ++ ) {
plane = clippingPlanes [ i ] ;
distanceToPlane = - dot ( vClipPosition , plane . xyz ) + plane . w ;
distanceGradient = fwidth ( distanceToPlane ) / 2.0 ;
clipOpacity *= smoothstep ( - distanceGradient , distanceGradient , distanceToPlane ) ;
if ( clipOpacity == 0.0 ) discard ;
}
# pragma unroll _loop _end
# if UNION _CLIPPING _PLANES < NUM _CLIPPING _PLANES
float unionClipOpacity = 1.0 ;
# pragma unroll _loop _start
for ( int i = UNION _CLIPPING _PLANES ; i < NUM _CLIPPING _PLANES ; i ++ ) {
plane = clippingPlanes [ i ] ;
distanceToPlane = - dot ( vClipPosition , plane . xyz ) + plane . w ;
distanceGradient = fwidth ( distanceToPlane ) / 2.0 ;
unionClipOpacity *= 1.0 - smoothstep ( - distanceGradient , distanceGradient , distanceToPlane ) ;
}
# pragma unroll _loop _end
clipOpacity *= 1.0 - unionClipOpacity ;
# endif
diffuseColor . a *= clipOpacity ;
if ( diffuseColor . a == 0.0 ) discard ;
# else
# pragma unroll _loop _start
for ( int i = 0 ; i < UNION _CLIPPING _PLANES ; i ++ ) {
plane = clippingPlanes [ i ] ;
if ( dot ( vClipPosition , plane . xyz ) > plane . w ) discard ;
}
# pragma unroll _loop _end
# if UNION _CLIPPING _PLANES < NUM _CLIPPING _PLANES
bool clipped = true ;
# pragma unroll _loop _start
for ( int i = UNION _CLIPPING _PLANES ; i < NUM _CLIPPING _PLANES ; i ++ ) {
plane = clippingPlanes [ i ] ;
clipped = ( dot ( vClipPosition , plane . xyz ) > plane . w ) && clipped ;
}
# pragma unroll _loop _end
if ( clipped ) discard ;
# endif
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,g1= ` # if NUM _CLIPPING _PLANES > 0
2026-01-22 11:29:51 +08:00
varying vec3 vClipPosition ;
uniform vec4 clippingPlanes [ NUM _CLIPPING _PLANES ] ;
2026-02-02 18:18:36 +08:00
# endif ` ,x1= ` # if NUM _CLIPPING _PLANES > 0
2026-01-22 11:29:51 +08:00
varying vec3 vClipPosition ;
2026-02-02 18:18:36 +08:00
# endif ` ,v1= ` # if NUM _CLIPPING _PLANES > 0
2026-01-22 11:29:51 +08:00
vClipPosition = - mvPosition . xyz ;
2026-02-02 18:18:36 +08:00
# endif ` ,b1= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
diffuseColor *= vColor ;
# elif defined ( USE _COLOR )
diffuseColor . rgb *= vColor ;
2026-02-02 18:18:36 +08:00
# endif ` ,y1= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
varying vec4 vColor ;
# elif defined ( USE _COLOR )
varying vec3 vColor ;
2026-02-02 18:18:36 +08:00
# endif ` ,_1= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
varying vec4 vColor ;
# elif defined ( USE _COLOR ) || defined ( USE _INSTANCING _COLOR ) || defined ( USE _BATCHING _COLOR )
varying vec3 vColor ;
2026-02-02 18:18:36 +08:00
# endif ` ,M1= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
vColor = vec4 ( 1.0 ) ;
# elif defined ( USE _COLOR ) || defined ( USE _INSTANCING _COLOR ) || defined ( USE _BATCHING _COLOR )
vColor = vec3 ( 1.0 ) ;
# endif
# ifdef USE _COLOR
vColor *= color ;
# endif
# ifdef USE _INSTANCING _COLOR
vColor . xyz *= instanceColor . xyz ;
# endif
# ifdef USE _BATCHING _COLOR
vec3 batchingColor = getBatchingColor ( getIndirectIndex ( gl _DrawID ) ) ;
vColor . xyz *= batchingColor . xyz ;
2026-02-02 18:18:36 +08:00
# endif ` ,w1= ` # define PI 3.141592653589793
2026-01-22 11:29:51 +08:00
# define PI2 6.283185307179586
# define PI _HALF 1.5707963267948966
# define RECIPROCAL _PI 0.3183098861837907
# define RECIPROCAL _PI2 0.15915494309189535
# define EPSILON 1e-6
# ifndef saturate
# define saturate ( a ) clamp ( a , 0.0 , 1.0 )
# endif
# define whiteComplement ( a ) ( 1.0 - saturate ( a ) )
float pow2 ( const in float x ) { return x * x ; }
vec3 pow2 ( const in vec3 x ) { return x * x ; }
float pow3 ( const in float x ) { return x * x * x ; }
float pow4 ( const in float x ) { float x2 = x * x ; return x2 * x2 ; }
float max3 ( const in vec3 v ) { return max ( max ( v . x , v . y ) , v . z ) ; }
float average ( const in vec3 v ) { return dot ( v , vec3 ( 0.3333333 ) ) ; }
highp float rand ( const in vec2 uv ) {
const highp float a = 12.9898 , b = 78.233 , c = 43758.5453 ;
highp float dt = dot ( uv . xy , vec2 ( a , b ) ) , sn = mod ( dt , PI ) ;
return fract ( sin ( sn ) * c ) ;
}
# ifdef HIGH _PRECISION
float precisionSafeLength ( vec3 v ) { return length ( v ) ; }
# else
float precisionSafeLength ( vec3 v ) {
float maxComponent = max3 ( abs ( v ) ) ;
return length ( v / maxComponent ) * maxComponent ;
}
# endif
struct IncidentLight {
vec3 color ;
vec3 direction ;
bool visible ;
} ;
struct ReflectedLight {
vec3 directDiffuse ;
vec3 directSpecular ;
vec3 indirectDiffuse ;
vec3 indirectSpecular ;
} ;
# ifdef USE _ALPHAHASH
varying vec3 vPosition ;
# endif
vec3 transformDirection ( in vec3 dir , in mat4 matrix ) {
return normalize ( ( matrix * vec4 ( dir , 0.0 ) ) . xyz ) ;
}
vec3 inverseTransformDirection ( in vec3 dir , in mat4 matrix ) {
return normalize ( ( vec4 ( dir , 0.0 ) * matrix ) . xyz ) ;
}
bool isPerspectiveMatrix ( mat4 m ) {
return m [ 2 ] [ 3 ] == - 1.0 ;
}
vec2 equirectUv ( in vec3 dir ) {
float u = atan ( dir . z , dir . x ) * RECIPROCAL _PI2 + 0.5 ;
float v = asin ( clamp ( dir . y , - 1.0 , 1.0 ) ) * RECIPROCAL _PI + 0.5 ;
return vec2 ( u , v ) ;
}
vec3 BRDF _Lambert ( const in vec3 diffuseColor ) {
return RECIPROCAL _PI * diffuseColor ;
}
vec3 F _Schlick ( const in vec3 f0 , const in float f90 , const in float dotVH ) {
float fresnel = exp2 ( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ) ;
return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ) ;
}
float F _Schlick ( const in float f0 , const in float f90 , const in float dotVH ) {
float fresnel = exp2 ( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ) ;
return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ) ;
2026-02-02 18:18:36 +08:00
} // validated`,S1=`#ifdef ENVMAP_TYPE_CUBE_UV
2026-01-22 11:29:51 +08:00
# define cubeUV _minMipLevel 4.0
# define cubeUV _minTileSize 16.0
float getFace ( vec3 direction ) {
vec3 absDirection = abs ( direction ) ;
float face = - 1.0 ;
if ( absDirection . x > absDirection . z ) {
if ( absDirection . x > absDirection . y )
face = direction . x > 0.0 ? 0.0 : 3.0 ;
else
face = direction . y > 0.0 ? 1.0 : 4.0 ;
} else {
if ( absDirection . z > absDirection . y )
face = direction . z > 0.0 ? 2.0 : 5.0 ;
else
face = direction . y > 0.0 ? 1.0 : 4.0 ;
}
return face ;
}
vec2 getUV ( vec3 direction , float face ) {
vec2 uv ;
if ( face == 0.0 ) {
uv = vec2 ( direction . z , direction . y ) / abs ( direction . x ) ;
} else if ( face == 1.0 ) {
uv = vec2 ( - direction . x , - direction . z ) / abs ( direction . y ) ;
} else if ( face == 2.0 ) {
uv = vec2 ( - direction . x , direction . y ) / abs ( direction . z ) ;
} else if ( face == 3.0 ) {
uv = vec2 ( - direction . z , direction . y ) / abs ( direction . x ) ;
} else if ( face == 4.0 ) {
uv = vec2 ( - direction . x , direction . z ) / abs ( direction . y ) ;
} else {
uv = vec2 ( direction . x , direction . y ) / abs ( direction . z ) ;
}
return 0.5 * ( uv + 1.0 ) ;
}
vec3 bilinearCubeUV ( sampler2D envMap , vec3 direction , float mipInt ) {
float face = getFace ( direction ) ;
float filterInt = max ( cubeUV _minMipLevel - mipInt , 0.0 ) ;
mipInt = max ( mipInt , cubeUV _minMipLevel ) ;
float faceSize = exp2 ( mipInt ) ;
highp vec2 uv = getUV ( direction , face ) * ( faceSize - 2.0 ) + 1.0 ;
if ( face > 2.0 ) {
uv . y += faceSize ;
face -= 3.0 ;
}
uv . x += face * faceSize ;
uv . x += filterInt * 3.0 * cubeUV _minTileSize ;
uv . y += 4.0 * ( exp2 ( CUBEUV _MAX _MIP ) - faceSize ) ;
uv . x *= CUBEUV _TEXEL _WIDTH ;
uv . y *= CUBEUV _TEXEL _HEIGHT ;
# ifdef texture2DGradEXT
return texture2DGradEXT ( envMap , uv , vec2 ( 0.0 ) , vec2 ( 0.0 ) ) . rgb ;
# else
return texture2D ( envMap , uv ) . rgb ;
# endif
}
# define cubeUV _r0 1.0
# define cubeUV _m0 - 2.0
# define cubeUV _r1 0.8
# define cubeUV _m1 - 1.0
# define cubeUV _r4 0.4
# define cubeUV _m4 2.0
# define cubeUV _r5 0.305
# define cubeUV _m5 3.0
# define cubeUV _r6 0.21
# define cubeUV _m6 4.0
float roughnessToMip ( float roughness ) {
float mip = 0.0 ;
if ( roughness >= cubeUV _r1 ) {
mip = ( cubeUV _r0 - roughness ) * ( cubeUV _m1 - cubeUV _m0 ) / ( cubeUV _r0 - cubeUV _r1 ) + cubeUV _m0 ;
} else if ( roughness >= cubeUV _r4 ) {
mip = ( cubeUV _r1 - roughness ) * ( cubeUV _m4 - cubeUV _m1 ) / ( cubeUV _r1 - cubeUV _r4 ) + cubeUV _m1 ;
} else if ( roughness >= cubeUV _r5 ) {
mip = ( cubeUV _r4 - roughness ) * ( cubeUV _m5 - cubeUV _m4 ) / ( cubeUV _r4 - cubeUV _r5 ) + cubeUV _m4 ;
} else if ( roughness >= cubeUV _r6 ) {
mip = ( cubeUV _r5 - roughness ) * ( cubeUV _m6 - cubeUV _m5 ) / ( cubeUV _r5 - cubeUV _r6 ) + cubeUV _m5 ;
} else {
mip = - 2.0 * log2 ( 1.16 * roughness ) ; }
return mip ;
}
vec4 textureCubeUV ( sampler2D envMap , vec3 sampleDir , float roughness ) {
float mip = clamp ( roughnessToMip ( roughness ) , cubeUV _m0 , CUBEUV _MAX _MIP ) ;
float mipF = fract ( mip ) ;
float mipInt = floor ( mip ) ;
vec3 color0 = bilinearCubeUV ( envMap , sampleDir , mipInt ) ;
if ( mipF == 0.0 ) {
return vec4 ( color0 , 1.0 ) ;
} else {
vec3 color1 = bilinearCubeUV ( envMap , sampleDir , mipInt + 1.0 ) ;
return vec4 ( mix ( color0 , color1 , mipF ) , 1.0 ) ;
}
}
2026-02-02 18:18:36 +08:00
# endif ` ,E1= ` vec3 transformedNormal = objectNormal ;
2026-01-22 11:29:51 +08:00
# ifdef USE _TANGENT
vec3 transformedTangent = objectTangent ;
# endif
# ifdef USE _BATCHING
mat3 bm = mat3 ( batchingMatrix ) ;
transformedNormal /= vec3 ( dot ( bm [ 0 ] , bm [ 0 ] ) , dot ( bm [ 1 ] , bm [ 1 ] ) , dot ( bm [ 2 ] , bm [ 2 ] ) ) ;
transformedNormal = bm * transformedNormal ;
# ifdef USE _TANGENT
transformedTangent = bm * transformedTangent ;
# endif
# endif
# ifdef USE _INSTANCING
mat3 im = mat3 ( instanceMatrix ) ;
transformedNormal /= vec3 ( dot ( im [ 0 ] , im [ 0 ] ) , dot ( im [ 1 ] , im [ 1 ] ) , dot ( im [ 2 ] , im [ 2 ] ) ) ;
transformedNormal = im * transformedNormal ;
# ifdef USE _TANGENT
transformedTangent = im * transformedTangent ;
# endif
# endif
transformedNormal = normalMatrix * transformedNormal ;
# ifdef FLIP _SIDED
transformedNormal = - transformedNormal ;
# endif
# ifdef USE _TANGENT
transformedTangent = ( modelViewMatrix * vec4 ( transformedTangent , 0.0 ) ) . xyz ;
# ifdef FLIP _SIDED
transformedTangent = - transformedTangent ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,T1= ` # ifdef USE _DISPLACEMENTMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D displacementMap ;
uniform float displacementScale ;
uniform float displacementBias ;
2026-02-02 18:18:36 +08:00
# endif ` ,C1= ` # ifdef USE _DISPLACEMENTMAP
2026-01-22 11:29:51 +08:00
transformed += normalize ( objectNormal ) * ( texture2D ( displacementMap , vDisplacementMapUv ) . x * displacementScale + displacementBias ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,A1= ` # ifdef USE _EMISSIVEMAP
2026-01-22 11:29:51 +08:00
vec4 emissiveColor = texture2D ( emissiveMap , vEmissiveMapUv ) ;
# ifdef DECODE _VIDEO _TEXTURE _EMISSIVE
emissiveColor = sRGBTransferEOTF ( emissiveColor ) ;
# endif
totalEmissiveRadiance *= emissiveColor . rgb ;
2026-02-02 18:18:36 +08:00
# endif ` ,P1= ` # ifdef USE _EMISSIVEMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D emissiveMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,R1="gl_FragColor = linearToOutputTexel( gl_FragColor );",L1= ` vec4 LinearTransferOETF ( in vec4 value ) {
2026-01-22 11:29:51 +08:00
return value ;
}
vec4 sRGBTransferEOTF ( in vec4 value ) {
return vec4 ( mix ( pow ( value . rgb * 0.9478672986 + vec3 ( 0.0521327014 ) , vec3 ( 2.4 ) ) , value . rgb * 0.0773993808 , vec3 ( lessThanEqual ( value . rgb , vec3 ( 0.04045 ) ) ) ) , value . a ) ;
}
vec4 sRGBTransferOETF ( in vec4 value ) {
return vec4 ( mix ( pow ( value . rgb , vec3 ( 0.41666 ) ) * 1.055 - vec3 ( 0.055 ) , value . rgb * 12.92 , vec3 ( lessThanEqual ( value . rgb , vec3 ( 0.0031308 ) ) ) ) , value . a ) ;
2026-02-02 18:18:36 +08:00
} ` ,I1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
# ifdef ENV _WORLDPOS
vec3 cameraToFrag ;
if ( isOrthographic ) {
cameraToFrag = normalize ( vec3 ( - viewMatrix [ 0 ] [ 2 ] , - viewMatrix [ 1 ] [ 2 ] , - viewMatrix [ 2 ] [ 2 ] ) ) ;
} else {
cameraToFrag = normalize ( vWorldPosition - cameraPosition ) ;
}
vec3 worldNormal = inverseTransformDirection ( normal , viewMatrix ) ;
# ifdef ENVMAP _MODE _REFLECTION
vec3 reflectVec = reflect ( cameraToFrag , worldNormal ) ;
# else
vec3 reflectVec = refract ( cameraToFrag , worldNormal , refractionRatio ) ;
# endif
# else
vec3 reflectVec = vReflect ;
# endif
# ifdef ENVMAP _TYPE _CUBE
vec4 envColor = textureCube ( envMap , envMapRotation * vec3 ( flipEnvMap * reflectVec . x , reflectVec . yz ) ) ;
# else
vec4 envColor = vec4 ( 0.0 ) ;
# endif
# ifdef ENVMAP _BLENDING _MULTIPLY
outgoingLight = mix ( outgoingLight , outgoingLight * envColor . xyz , specularStrength * reflectivity ) ;
# elif defined ( ENVMAP _BLENDING _MIX )
outgoingLight = mix ( outgoingLight , envColor . xyz , specularStrength * reflectivity ) ;
# elif defined ( ENVMAP _BLENDING _ADD )
outgoingLight += envColor . xyz * specularStrength * reflectivity ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,D1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
uniform float envMapIntensity ;
uniform float flipEnvMap ;
uniform mat3 envMapRotation ;
# ifdef ENVMAP _TYPE _CUBE
uniform samplerCube envMap ;
# else
uniform sampler2D envMap ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,B1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
uniform float reflectivity ;
# if defined ( USE _BUMPMAP ) || defined ( USE _NORMALMAP ) || defined ( PHONG ) || defined ( LAMBERT )
# define ENV _WORLDPOS
# endif
# ifdef ENV _WORLDPOS
varying vec3 vWorldPosition ;
uniform float refractionRatio ;
# else
varying vec3 vReflect ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,N1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
# if defined ( USE _BUMPMAP ) || defined ( USE _NORMALMAP ) || defined ( PHONG ) || defined ( LAMBERT )
# define ENV _WORLDPOS
# endif
# ifdef ENV _WORLDPOS
varying vec3 vWorldPosition ;
# else
varying vec3 vReflect ;
uniform float refractionRatio ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,k1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
# ifdef ENV _WORLDPOS
vWorldPosition = worldPosition . xyz ;
# else
vec3 cameraToVertex ;
if ( isOrthographic ) {
cameraToVertex = normalize ( vec3 ( - viewMatrix [ 0 ] [ 2 ] , - viewMatrix [ 1 ] [ 2 ] , - viewMatrix [ 2 ] [ 2 ] ) ) ;
} else {
cameraToVertex = normalize ( worldPosition . xyz - cameraPosition ) ;
}
vec3 worldNormal = inverseTransformDirection ( transformedNormal , viewMatrix ) ;
# ifdef ENVMAP _MODE _REFLECTION
vReflect = reflect ( cameraToVertex , worldNormal ) ;
# else
vReflect = refract ( cameraToVertex , worldNormal , refractionRatio ) ;
# endif
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,U1= ` # ifdef USE _FOG
2026-01-22 11:29:51 +08:00
vFogDepth = - mvPosition . z ;
2026-02-02 18:18:36 +08:00
# endif ` ,O1= ` # ifdef USE _FOG
2026-01-28 18:40:46 +08:00
varying float vFogDepth ;
2026-02-02 18:18:36 +08:00
# endif ` ,F1= ` # ifdef USE _FOG
2026-01-22 11:29:51 +08:00
# ifdef FOG _EXP2
float fogFactor = 1.0 - exp ( - fogDensity * fogDensity * vFogDepth * vFogDepth ) ;
# else
float fogFactor = smoothstep ( fogNear , fogFar , vFogDepth ) ;
# endif
gl _FragColor . rgb = mix ( gl _FragColor . rgb , fogColor , fogFactor ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,z1= ` # ifdef USE _FOG
2026-01-22 11:29:51 +08:00
uniform vec3 fogColor ;
varying float vFogDepth ;
# ifdef FOG _EXP2
uniform float fogDensity ;
# else
uniform float fogNear ;
uniform float fogFar ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,H1= ` # ifdef USE _GRADIENTMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D gradientMap ;
# endif
vec3 getGradientIrradiance ( vec3 normal , vec3 lightDirection ) {
float dotNL = dot ( normal , lightDirection ) ;
vec2 coord = vec2 ( dotNL * 0.5 + 0.5 , 0.0 ) ;
# ifdef USE _GRADIENTMAP
return vec3 ( texture2D ( gradientMap , coord ) . r ) ;
# else
vec2 fw = fwidth ( coord ) * 0.5 ;
return mix ( vec3 ( 0.7 ) , vec3 ( 1.0 ) , smoothstep ( 0.7 - fw . x , 0.7 + fw . x , coord . x ) ) ;
# endif
2026-02-02 18:18:36 +08:00
} ` ,V1= ` # ifdef USE _LIGHTMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D lightMap ;
uniform float lightMapIntensity ;
2026-02-02 18:18:36 +08:00
# endif ` ,G1= ` LambertMaterial material ;
2026-01-22 11:29:51 +08:00
material . diffuseColor = diffuseColor . rgb ;
2026-02-02 18:18:36 +08:00
material . specularStrength = specularStrength ; ` ,W1= ` varying vec3 vViewPosition ;
2026-01-22 11:29:51 +08:00
struct LambertMaterial {
vec3 diffuseColor ;
float specularStrength ;
} ;
void RE _Direct _Lambert ( const in IncidentLight directLight , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in LambertMaterial material , inout ReflectedLight reflectedLight ) {
float dotNL = saturate ( dot ( geometryNormal , directLight . direction ) ) ;
vec3 irradiance = dotNL * directLight . color ;
reflectedLight . directDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
void RE _IndirectDiffuse _Lambert ( const in vec3 irradiance , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in LambertMaterial material , inout ReflectedLight reflectedLight ) {
reflectedLight . indirectDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
# define RE _Direct RE _Direct _Lambert
2026-02-02 18:18:36 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _Lambert ` ,X1= ` uniform bool receiveShadow ;
2026-01-22 11:29:51 +08:00
uniform vec3 ambientLightColor ;
# if defined ( USE _LIGHT _PROBES )
uniform vec3 lightProbe [ 9 ] ;
# endif
vec3 shGetIrradianceAt ( in vec3 normal , in vec3 shCoefficients [ 9 ] ) {
float x = normal . x , y = normal . y , z = normal . z ;
vec3 result = shCoefficients [ 0 ] * 0.886227 ;
result += shCoefficients [ 1 ] * 2.0 * 0.511664 * y ;
result += shCoefficients [ 2 ] * 2.0 * 0.511664 * z ;
result += shCoefficients [ 3 ] * 2.0 * 0.511664 * x ;
result += shCoefficients [ 4 ] * 2.0 * 0.429043 * x * y ;
result += shCoefficients [ 5 ] * 2.0 * 0.429043 * y * z ;
result += shCoefficients [ 6 ] * ( 0.743125 * z * z - 0.247708 ) ;
result += shCoefficients [ 7 ] * 2.0 * 0.429043 * x * z ;
result += shCoefficients [ 8 ] * 0.429043 * ( x * x - y * y ) ;
return result ;
}
vec3 getLightProbeIrradiance ( const in vec3 lightProbe [ 9 ] , const in vec3 normal ) {
vec3 worldNormal = inverseTransformDirection ( normal , viewMatrix ) ;
vec3 irradiance = shGetIrradianceAt ( worldNormal , lightProbe ) ;
return irradiance ;
}
vec3 getAmbientLightIrradiance ( const in vec3 ambientLightColor ) {
vec3 irradiance = ambientLightColor ;
return irradiance ;
}
float getDistanceAttenuation ( const in float lightDistance , const in float cutoffDistance , const in float decayExponent ) {
float distanceFalloff = 1.0 / max ( pow ( lightDistance , decayExponent ) , 0.01 ) ;
if ( cutoffDistance > 0.0 ) {
distanceFalloff *= pow2 ( saturate ( 1.0 - pow4 ( lightDistance / cutoffDistance ) ) ) ;
}
return distanceFalloff ;
}
float getSpotAttenuation ( const in float coneCosine , const in float penumbraCosine , const in float angleCosine ) {
return smoothstep ( coneCosine , penumbraCosine , angleCosine ) ;
}
# if NUM _DIR _LIGHTS > 0
struct DirectionalLight {
vec3 direction ;
vec3 color ;
} ;
uniform DirectionalLight directionalLights [ NUM _DIR _LIGHTS ] ;
void getDirectionalLightInfo ( const in DirectionalLight directionalLight , out IncidentLight light ) {
light . color = directionalLight . color ;
light . direction = directionalLight . direction ;
light . visible = true ;
}
# endif
# if NUM _POINT _LIGHTS > 0
struct PointLight {
vec3 position ;
vec3 color ;
float distance ;
float decay ;
} ;
uniform PointLight pointLights [ NUM _POINT _LIGHTS ] ;
void getPointLightInfo ( const in PointLight pointLight , const in vec3 geometryPosition , out IncidentLight light ) {
vec3 lVector = pointLight . position - geometryPosition ;
light . direction = normalize ( lVector ) ;
float lightDistance = length ( lVector ) ;
light . color = pointLight . color ;
light . color *= getDistanceAttenuation ( lightDistance , pointLight . distance , pointLight . decay ) ;
light . visible = ( light . color != vec3 ( 0.0 ) ) ;
}
# endif
# if NUM _SPOT _LIGHTS > 0
struct SpotLight {
vec3 position ;
vec3 direction ;
vec3 color ;
float distance ;
float decay ;
float coneCos ;
float penumbraCos ;
} ;
uniform SpotLight spotLights [ NUM _SPOT _LIGHTS ] ;
void getSpotLightInfo ( const in SpotLight spotLight , const in vec3 geometryPosition , out IncidentLight light ) {
vec3 lVector = spotLight . position - geometryPosition ;
light . direction = normalize ( lVector ) ;
float angleCos = dot ( light . direction , spotLight . direction ) ;
float spotAttenuation = getSpotAttenuation ( spotLight . coneCos , spotLight . penumbraCos , angleCos ) ;
if ( spotAttenuation > 0.0 ) {
float lightDistance = length ( lVector ) ;
light . color = spotLight . color * spotAttenuation ;
light . color *= getDistanceAttenuation ( lightDistance , spotLight . distance , spotLight . decay ) ;
light . visible = ( light . color != vec3 ( 0.0 ) ) ;
} else {
light . color = vec3 ( 0.0 ) ;
light . visible = false ;
}
}
# endif
# if NUM _RECT _AREA _LIGHTS > 0
struct RectAreaLight {
vec3 color ;
vec3 position ;
vec3 halfWidth ;
vec3 halfHeight ;
} ;
uniform sampler2D ltc _1 ; uniform sampler2D ltc _2 ;
uniform RectAreaLight rectAreaLights [ NUM _RECT _AREA _LIGHTS ] ;
# endif
# if NUM _HEMI _LIGHTS > 0
struct HemisphereLight {
vec3 direction ;
vec3 skyColor ;
vec3 groundColor ;
} ;
uniform HemisphereLight hemisphereLights [ NUM _HEMI _LIGHTS ] ;
vec3 getHemisphereLightIrradiance ( const in HemisphereLight hemiLight , const in vec3 normal ) {
float dotNL = dot ( normal , hemiLight . direction ) ;
float hemiDiffuseWeight = 0.5 * dotNL + 0.5 ;
vec3 irradiance = mix ( hemiLight . groundColor , hemiLight . skyColor , hemiDiffuseWeight ) ;
return irradiance ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,j1= ` # ifdef USE _ENVMAP
2026-01-22 11:29:51 +08:00
vec3 getIBLIrradiance ( const in vec3 normal ) {
# ifdef ENVMAP _TYPE _CUBE _UV
vec3 worldNormal = inverseTransformDirection ( normal , viewMatrix ) ;
vec4 envMapColor = textureCubeUV ( envMap , envMapRotation * worldNormal , 1.0 ) ;
return PI * envMapColor . rgb * envMapIntensity ;
# else
return vec3 ( 0.0 ) ;
# endif
}
vec3 getIBLRadiance ( const in vec3 viewDir , const in vec3 normal , const in float roughness ) {
# ifdef ENVMAP _TYPE _CUBE _UV
vec3 reflectVec = reflect ( - viewDir , normal ) ;
reflectVec = normalize ( mix ( reflectVec , normal , pow4 ( roughness ) ) ) ;
reflectVec = inverseTransformDirection ( reflectVec , viewMatrix ) ;
vec4 envMapColor = textureCubeUV ( envMap , envMapRotation * reflectVec , roughness ) ;
return envMapColor . rgb * envMapIntensity ;
# else
return vec3 ( 0.0 ) ;
# endif
}
# ifdef USE _ANISOTROPY
vec3 getIBLAnisotropyRadiance ( const in vec3 viewDir , const in vec3 normal , const in float roughness , const in vec3 bitangent , const in float anisotropy ) {
# ifdef ENVMAP _TYPE _CUBE _UV
vec3 bentNormal = cross ( bitangent , viewDir ) ;
bentNormal = normalize ( cross ( bentNormal , bitangent ) ) ;
bentNormal = normalize ( mix ( bentNormal , normal , pow2 ( pow2 ( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ) ;
return getIBLRadiance ( viewDir , bentNormal , roughness ) ;
# else
return vec3 ( 0.0 ) ;
# endif
}
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,q1= ` ToonMaterial material ;
material . diffuseColor = diffuseColor . rgb ; ` ,Z1= ` varying vec3 vViewPosition ;
2026-01-22 11:29:51 +08:00
struct ToonMaterial {
vec3 diffuseColor ;
} ;
void RE _Direct _Toon ( const in IncidentLight directLight , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in ToonMaterial material , inout ReflectedLight reflectedLight ) {
vec3 irradiance = getGradientIrradiance ( geometryNormal , directLight . direction ) * directLight . color ;
reflectedLight . directDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
void RE _IndirectDiffuse _Toon ( const in vec3 irradiance , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in ToonMaterial material , inout ReflectedLight reflectedLight ) {
reflectedLight . indirectDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
# define RE _Direct RE _Direct _Toon
2026-02-02 18:18:36 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _Toon ` ,Y1= ` BlinnPhongMaterial material ;
2026-01-22 11:29:51 +08:00
material . diffuseColor = diffuseColor . rgb ;
material . specularColor = specular ;
material . specularShininess = shininess ;
2026-02-02 18:18:36 +08:00
material . specularStrength = specularStrength ; ` , $ 1= ` varying vec3 vViewPosition ;
2026-01-22 11:29:51 +08:00
struct BlinnPhongMaterial {
vec3 diffuseColor ;
vec3 specularColor ;
float specularShininess ;
float specularStrength ;
} ;
void RE _Direct _BlinnPhong ( const in IncidentLight directLight , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in BlinnPhongMaterial material , inout ReflectedLight reflectedLight ) {
float dotNL = saturate ( dot ( geometryNormal , directLight . direction ) ) ;
vec3 irradiance = dotNL * directLight . color ;
reflectedLight . directDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
reflectedLight . directSpecular += irradiance * BRDF _BlinnPhong ( directLight . direction , geometryViewDir , geometryNormal , material . specularColor , material . specularShininess ) * material . specularStrength ;
}
void RE _IndirectDiffuse _BlinnPhong ( const in vec3 irradiance , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in BlinnPhongMaterial material , inout ReflectedLight reflectedLight ) {
reflectedLight . indirectDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
# define RE _Direct RE _Direct _BlinnPhong
2026-02-02 18:18:36 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _BlinnPhong ` ,K1= ` PhysicalMaterial material ;
2026-01-22 11:29:51 +08:00
material . diffuseColor = diffuseColor . rgb * ( 1.0 - metalnessFactor ) ;
vec3 dxy = max ( abs ( dFdx ( nonPerturbedNormal ) ) , abs ( dFdy ( nonPerturbedNormal ) ) ) ;
float geometryRoughness = max ( max ( dxy . x , dxy . y ) , dxy . z ) ;
material . roughness = max ( roughnessFactor , 0.0525 ) ; material . roughness += geometryRoughness ;
material . roughness = min ( material . roughness , 1.0 ) ;
# ifdef IOR
material . ior = ior ;
# ifdef USE _SPECULAR
float specularIntensityFactor = specularIntensity ;
vec3 specularColorFactor = specularColor ;
# ifdef USE _SPECULAR _COLORMAP
specularColorFactor *= texture2D ( specularColorMap , vSpecularColorMapUv ) . rgb ;
# endif
# ifdef USE _SPECULAR _INTENSITYMAP
specularIntensityFactor *= texture2D ( specularIntensityMap , vSpecularIntensityMapUv ) . a ;
# endif
material . specularF90 = mix ( specularIntensityFactor , 1.0 , metalnessFactor ) ;
# else
float specularIntensityFactor = 1.0 ;
vec3 specularColorFactor = vec3 ( 1.0 ) ;
material . specularF90 = 1.0 ;
# endif
material . specularColor = mix ( min ( pow2 ( ( material . ior - 1.0 ) / ( material . ior + 1.0 ) ) * specularColorFactor , vec3 ( 1.0 ) ) * specularIntensityFactor , diffuseColor . rgb , metalnessFactor ) ;
# else
material . specularColor = mix ( vec3 ( 0.04 ) , diffuseColor . rgb , metalnessFactor ) ;
material . specularF90 = 1.0 ;
# endif
# ifdef USE _CLEARCOAT
material . clearcoat = clearcoat ;
material . clearcoatRoughness = clearcoatRoughness ;
material . clearcoatF0 = vec3 ( 0.04 ) ;
material . clearcoatF90 = 1.0 ;
# ifdef USE _CLEARCOATMAP
material . clearcoat *= texture2D ( clearcoatMap , vClearcoatMapUv ) . x ;
# endif
# ifdef USE _CLEARCOAT _ROUGHNESSMAP
material . clearcoatRoughness *= texture2D ( clearcoatRoughnessMap , vClearcoatRoughnessMapUv ) . y ;
# endif
material . clearcoat = saturate ( material . clearcoat ) ; material . clearcoatRoughness = max ( material . clearcoatRoughness , 0.0525 ) ;
material . clearcoatRoughness += geometryRoughness ;
material . clearcoatRoughness = min ( material . clearcoatRoughness , 1.0 ) ;
# endif
# ifdef USE _DISPERSION
material . dispersion = dispersion ;
# endif
# ifdef USE _IRIDESCENCE
material . iridescence = iridescence ;
material . iridescenceIOR = iridescenceIOR ;
# ifdef USE _IRIDESCENCEMAP
material . iridescence *= texture2D ( iridescenceMap , vIridescenceMapUv ) . r ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
material . iridescenceThickness = ( iridescenceThicknessMaximum - iridescenceThicknessMinimum ) * texture2D ( iridescenceThicknessMap , vIridescenceThicknessMapUv ) . g + iridescenceThicknessMinimum ;
# else
material . iridescenceThickness = iridescenceThicknessMaximum ;
# endif
# endif
# ifdef USE _SHEEN
material . sheenColor = sheenColor ;
# ifdef USE _SHEEN _COLORMAP
material . sheenColor *= texture2D ( sheenColorMap , vSheenColorMapUv ) . rgb ;
# endif
material . sheenRoughness = clamp ( sheenRoughness , 0.07 , 1.0 ) ;
# ifdef USE _SHEEN _ROUGHNESSMAP
material . sheenRoughness *= texture2D ( sheenRoughnessMap , vSheenRoughnessMapUv ) . a ;
# endif
# endif
# ifdef USE _ANISOTROPY
# ifdef USE _ANISOTROPYMAP
mat2 anisotropyMat = mat2 ( anisotropyVector . x , anisotropyVector . y , - anisotropyVector . y , anisotropyVector . x ) ;
vec3 anisotropyPolar = texture2D ( anisotropyMap , vAnisotropyMapUv ) . rgb ;
vec2 anisotropyV = anisotropyMat * normalize ( 2.0 * anisotropyPolar . rg - vec2 ( 1.0 ) ) * anisotropyPolar . b ;
# else
vec2 anisotropyV = anisotropyVector ;
# endif
material . anisotropy = length ( anisotropyV ) ;
if ( material . anisotropy == 0.0 ) {
anisotropyV = vec2 ( 1.0 , 0.0 ) ;
} else {
anisotropyV /= material . anisotropy ;
material . anisotropy = saturate ( material . anisotropy ) ;
}
material . alphaT = mix ( pow2 ( material . roughness ) , 1.0 , pow2 ( material . anisotropy ) ) ;
material . anisotropyT = tbn [ 0 ] * anisotropyV . x + tbn [ 1 ] * anisotropyV . y ;
material . anisotropyB = tbn [ 1 ] * anisotropyV . x - tbn [ 0 ] * anisotropyV . y ;
2026-02-02 18:18:36 +08:00
# endif ` ,J1= ` uniform sampler2D dfgLUT ;
2026-01-22 11:29:51 +08:00
struct PhysicalMaterial {
vec3 diffuseColor ;
float roughness ;
vec3 specularColor ;
float specularF90 ;
float dispersion ;
# ifdef USE _CLEARCOAT
float clearcoat ;
float clearcoatRoughness ;
vec3 clearcoatF0 ;
float clearcoatF90 ;
# endif
# ifdef USE _IRIDESCENCE
float iridescence ;
float iridescenceIOR ;
float iridescenceThickness ;
vec3 iridescenceFresnel ;
vec3 iridescenceF0 ;
# endif
# ifdef USE _SHEEN
vec3 sheenColor ;
float sheenRoughness ;
# endif
# ifdef IOR
float ior ;
# endif
# ifdef USE _TRANSMISSION
float transmission ;
float transmissionAlpha ;
float thickness ;
float attenuationDistance ;
vec3 attenuationColor ;
# endif
# ifdef USE _ANISOTROPY
float anisotropy ;
float alphaT ;
vec3 anisotropyT ;
vec3 anisotropyB ;
# endif
} ;
vec3 clearcoatSpecularDirect = vec3 ( 0.0 ) ;
vec3 clearcoatSpecularIndirect = vec3 ( 0.0 ) ;
vec3 sheenSpecularDirect = vec3 ( 0.0 ) ;
vec3 sheenSpecularIndirect = vec3 ( 0.0 ) ;
vec3 Schlick _to _F0 ( const in vec3 f , const in float f90 , const in float dotVH ) {
float x = clamp ( 1.0 - dotVH , 0.0 , 1.0 ) ;
float x2 = x * x ;
float x5 = clamp ( x * x2 * x2 , 0.0 , 0.9999 ) ;
return ( f - vec3 ( f90 ) * x5 ) / ( 1.0 - x5 ) ;
}
float V _GGX _SmithCorrelated ( const in float alpha , const in float dotNL , const in float dotNV ) {
float a2 = pow2 ( alpha ) ;
float gv = dotNL * sqrt ( a2 + ( 1.0 - a2 ) * pow2 ( dotNV ) ) ;
float gl = dotNV * sqrt ( a2 + ( 1.0 - a2 ) * pow2 ( dotNL ) ) ;
return 0.5 / max ( gv + gl , EPSILON ) ;
}
float D _GGX ( const in float alpha , const in float dotNH ) {
float a2 = pow2 ( alpha ) ;
float denom = pow2 ( dotNH ) * ( a2 - 1.0 ) + 1.0 ;
return RECIPROCAL _PI * a2 / pow2 ( denom ) ;
}
# ifdef USE _ANISOTROPY
float V _GGX _SmithCorrelated _Anisotropic ( const in float alphaT , const in float alphaB , const in float dotTV , const in float dotBV , const in float dotTL , const in float dotBL , const in float dotNV , const in float dotNL ) {
float gv = dotNL * length ( vec3 ( alphaT * dotTV , alphaB * dotBV , dotNV ) ) ;
float gl = dotNV * length ( vec3 ( alphaT * dotTL , alphaB * dotBL , dotNL ) ) ;
float v = 0.5 / ( gv + gl ) ;
return saturate ( v ) ;
}
float D _GGX _Anisotropic ( const in float alphaT , const in float alphaB , const in float dotNH , const in float dotTH , const in float dotBH ) {
float a2 = alphaT * alphaB ;
highp vec3 v = vec3 ( alphaB * dotTH , alphaT * dotBH , a2 * dotNH ) ;
highp float v2 = dot ( v , v ) ;
float w2 = a2 / v2 ;
return RECIPROCAL _PI * a2 * pow2 ( w2 ) ;
}
# endif
# ifdef USE _CLEARCOAT
vec3 BRDF _GGX _Clearcoat ( const in vec3 lightDir , const in vec3 viewDir , const in vec3 normal , const in PhysicalMaterial material ) {
vec3 f0 = material . clearcoatF0 ;
float f90 = material . clearcoatF90 ;
float roughness = material . clearcoatRoughness ;
float alpha = pow2 ( roughness ) ;
vec3 halfDir = normalize ( lightDir + viewDir ) ;
float dotNL = saturate ( dot ( normal , lightDir ) ) ;
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
float dotNH = saturate ( dot ( normal , halfDir ) ) ;
float dotVH = saturate ( dot ( viewDir , halfDir ) ) ;
vec3 F = F _Schlick ( f0 , f90 , dotVH ) ;
float V = V _GGX _SmithCorrelated ( alpha , dotNL , dotNV ) ;
float D = D _GGX ( alpha , dotNH ) ;
return F * ( V * D ) ;
}
# endif
vec3 BRDF _GGX ( const in vec3 lightDir , const in vec3 viewDir , const in vec3 normal , const in PhysicalMaterial material ) {
vec3 f0 = material . specularColor ;
float f90 = material . specularF90 ;
float roughness = material . roughness ;
float alpha = pow2 ( roughness ) ;
vec3 halfDir = normalize ( lightDir + viewDir ) ;
float dotNL = saturate ( dot ( normal , lightDir ) ) ;
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
float dotNH = saturate ( dot ( normal , halfDir ) ) ;
float dotVH = saturate ( dot ( viewDir , halfDir ) ) ;
vec3 F = F _Schlick ( f0 , f90 , dotVH ) ;
# ifdef USE _IRIDESCENCE
F = mix ( F , material . iridescenceFresnel , material . iridescence ) ;
# endif
# ifdef USE _ANISOTROPY
float dotTL = dot ( material . anisotropyT , lightDir ) ;
float dotTV = dot ( material . anisotropyT , viewDir ) ;
float dotTH = dot ( material . anisotropyT , halfDir ) ;
float dotBL = dot ( material . anisotropyB , lightDir ) ;
float dotBV = dot ( material . anisotropyB , viewDir ) ;
float dotBH = dot ( material . anisotropyB , halfDir ) ;
float V = V _GGX _SmithCorrelated _Anisotropic ( material . alphaT , alpha , dotTV , dotBV , dotTL , dotBL , dotNV , dotNL ) ;
float D = D _GGX _Anisotropic ( material . alphaT , alpha , dotNH , dotTH , dotBH ) ;
# else
float V = V _GGX _SmithCorrelated ( alpha , dotNL , dotNV ) ;
float D = D _GGX ( alpha , dotNH ) ;
# endif
return F * ( V * D ) ;
}
vec2 LTC _Uv ( const in vec3 N , const in vec3 V , const in float roughness ) {
const float LUT _SIZE = 64.0 ;
const float LUT _SCALE = ( LUT _SIZE - 1.0 ) / LUT _SIZE ;
const float LUT _BIAS = 0.5 / LUT _SIZE ;
float dotNV = saturate ( dot ( N , V ) ) ;
vec2 uv = vec2 ( roughness , sqrt ( 1.0 - dotNV ) ) ;
uv = uv * LUT _SCALE + LUT _BIAS ;
return uv ;
}
float LTC _ClippedSphereFormFactor ( const in vec3 f ) {
float l = length ( f ) ;
return max ( ( l * l + f . z ) / ( l + 1.0 ) , 0.0 ) ;
}
vec3 LTC _EdgeVectorFormFactor ( const in vec3 v1 , const in vec3 v2 ) {
float x = dot ( v1 , v2 ) ;
float y = abs ( x ) ;
float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y ;
float b = 3.4175940 + ( 4.1616724 + y ) * y ;
float v = a / b ;
float theta _sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt ( max ( 1.0 - x * x , 1e-7 ) ) - v ;
return cross ( v1 , v2 ) * theta _sintheta ;
}
vec3 LTC _Evaluate ( const in vec3 N , const in vec3 V , const in vec3 P , const in mat3 mInv , const in vec3 rectCoords [ 4 ] ) {
vec3 v1 = rectCoords [ 1 ] - rectCoords [ 0 ] ;
vec3 v2 = rectCoords [ 3 ] - rectCoords [ 0 ] ;
vec3 lightNormal = cross ( v1 , v2 ) ;
if ( dot ( lightNormal , P - rectCoords [ 0 ] ) < 0.0 ) return vec3 ( 0.0 ) ;
vec3 T1 , T2 ;
T1 = normalize ( V - N * dot ( V , N ) ) ;
T2 = - cross ( N , T1 ) ;
mat3 mat = mInv * transpose ( mat3 ( T1 , T2 , N ) ) ;
vec3 coords [ 4 ] ;
coords [ 0 ] = mat * ( rectCoords [ 0 ] - P ) ;
coords [ 1 ] = mat * ( rectCoords [ 1 ] - P ) ;
coords [ 2 ] = mat * ( rectCoords [ 2 ] - P ) ;
coords [ 3 ] = mat * ( rectCoords [ 3 ] - P ) ;
coords [ 0 ] = normalize ( coords [ 0 ] ) ;
coords [ 1 ] = normalize ( coords [ 1 ] ) ;
coords [ 2 ] = normalize ( coords [ 2 ] ) ;
coords [ 3 ] = normalize ( coords [ 3 ] ) ;
vec3 vectorFormFactor = vec3 ( 0.0 ) ;
vectorFormFactor += LTC _EdgeVectorFormFactor ( coords [ 0 ] , coords [ 1 ] ) ;
vectorFormFactor += LTC _EdgeVectorFormFactor ( coords [ 1 ] , coords [ 2 ] ) ;
vectorFormFactor += LTC _EdgeVectorFormFactor ( coords [ 2 ] , coords [ 3 ] ) ;
vectorFormFactor += LTC _EdgeVectorFormFactor ( coords [ 3 ] , coords [ 0 ] ) ;
float result = LTC _ClippedSphereFormFactor ( vectorFormFactor ) ;
return vec3 ( result ) ;
}
# if defined ( USE _SHEEN )
float D _Charlie ( float roughness , float dotNH ) {
float alpha = pow2 ( roughness ) ;
float invAlpha = 1.0 / alpha ;
float cos2h = dotNH * dotNH ;
float sin2h = max ( 1.0 - cos2h , 0.0078125 ) ;
return ( 2.0 + invAlpha ) * pow ( sin2h , invAlpha * 0.5 ) / ( 2.0 * PI ) ;
}
float V _Neubelt ( float dotNV , float dotNL ) {
return saturate ( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ) ;
}
vec3 BRDF _Sheen ( const in vec3 lightDir , const in vec3 viewDir , const in vec3 normal , vec3 sheenColor , const in float sheenRoughness ) {
vec3 halfDir = normalize ( lightDir + viewDir ) ;
float dotNL = saturate ( dot ( normal , lightDir ) ) ;
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
float dotNH = saturate ( dot ( normal , halfDir ) ) ;
float D = D _Charlie ( sheenRoughness , dotNH ) ;
float V = V _Neubelt ( dotNV , dotNL ) ;
return sheenColor * ( D * V ) ;
}
# endif
float IBLSheenBRDF ( const in vec3 normal , const in vec3 viewDir , const in float roughness ) {
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
float r2 = roughness * roughness ;
float a = roughness < 0.25 ? - 339.2 * r2 + 161.4 * roughness - 25.9 : - 8.48 * r2 + 14.3 * roughness - 9.95 ;
float b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72 ;
float DG = exp ( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) ) ;
return saturate ( DG * RECIPROCAL _PI ) ;
}
vec2 DFGApprox ( const in vec3 normal , const in vec3 viewDir , const in float roughness ) {
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
vec2 uv = vec2 ( roughness , dotNV ) ;
return texture2D ( dfgLUT , uv ) . rg ;
}
vec3 EnvironmentBRDF ( const in vec3 normal , const in vec3 viewDir , const in vec3 specularColor , const in float specularF90 , const in float roughness ) {
vec2 fab = DFGApprox ( normal , viewDir , roughness ) ;
return specularColor * fab . x + specularF90 * fab . y ;
}
# ifdef USE _IRIDESCENCE
void computeMultiscatteringIridescence ( const in vec3 normal , const in vec3 viewDir , const in vec3 specularColor , const in float specularF90 , const in float iridescence , const in vec3 iridescenceF0 , const in float roughness , inout vec3 singleScatter , inout vec3 multiScatter ) {
# else
void computeMultiscattering ( const in vec3 normal , const in vec3 viewDir , const in vec3 specularColor , const in float specularF90 , const in float roughness , inout vec3 singleScatter , inout vec3 multiScatter ) {
# endif
vec2 fab = DFGApprox ( normal , viewDir , roughness ) ;
# ifdef USE _IRIDESCENCE
vec3 Fr = mix ( specularColor , iridescenceF0 , iridescence ) ;
# else
vec3 Fr = specularColor ;
# endif
vec3 FssEss = Fr * fab . x + specularF90 * fab . y ;
float Ess = fab . x + fab . y ;
float Ems = 1.0 - Ess ;
vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619 ; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ) ;
singleScatter += FssEss ;
multiScatter += Fms * Ems ;
}
vec3 BRDF _GGX _Multiscatter ( const in vec3 lightDir , const in vec3 viewDir , const in vec3 normal , const in PhysicalMaterial material ) {
vec3 singleScatter = BRDF _GGX ( lightDir , viewDir , normal , material ) ;
float dotNL = saturate ( dot ( normal , lightDir ) ) ;
float dotNV = saturate ( dot ( normal , viewDir ) ) ;
vec2 dfgV = DFGApprox ( vec3 ( 0.0 , 0.0 , 1.0 ) , vec3 ( sqrt ( 1.0 - dotNV * dotNV ) , 0.0 , dotNV ) , material . roughness ) ;
vec2 dfgL = DFGApprox ( vec3 ( 0.0 , 0.0 , 1.0 ) , vec3 ( sqrt ( 1.0 - dotNL * dotNL ) , 0.0 , dotNL ) , material . roughness ) ;
vec3 FssEss _V = material . specularColor * dfgV . x + material . specularF90 * dfgV . y ;
vec3 FssEss _L = material . specularColor * dfgL . x + material . specularF90 * dfgL . y ;
float Ess _V = dfgV . x + dfgV . y ;
float Ess _L = dfgL . x + dfgL . y ;
float Ems _V = 1.0 - Ess _V ;
float Ems _L = 1.0 - Ess _L ;
vec3 Favg = material . specularColor + ( 1.0 - material . specularColor ) * 0.047619 ;
vec3 Fms = FssEss _V * FssEss _L * Favg / ( 1.0 - Ems _V * Ems _L * Favg * Favg + EPSILON ) ;
float compensationFactor = Ems _V * Ems _L ;
vec3 multiScatter = Fms * compensationFactor ;
return singleScatter + multiScatter ;
}
# if NUM _RECT _AREA _LIGHTS > 0
void RE _Direct _RectArea _Physical ( const in RectAreaLight rectAreaLight , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in PhysicalMaterial material , inout ReflectedLight reflectedLight ) {
vec3 normal = geometryNormal ;
vec3 viewDir = geometryViewDir ;
vec3 position = geometryPosition ;
vec3 lightPos = rectAreaLight . position ;
vec3 halfWidth = rectAreaLight . halfWidth ;
vec3 halfHeight = rectAreaLight . halfHeight ;
vec3 lightColor = rectAreaLight . color ;
float roughness = material . roughness ;
vec3 rectCoords [ 4 ] ;
rectCoords [ 0 ] = lightPos + halfWidth - halfHeight ; rectCoords [ 1 ] = lightPos - halfWidth - halfHeight ;
rectCoords [ 2 ] = lightPos - halfWidth + halfHeight ;
rectCoords [ 3 ] = lightPos + halfWidth + halfHeight ;
vec2 uv = LTC _Uv ( normal , viewDir , roughness ) ;
vec4 t1 = texture2D ( ltc _1 , uv ) ;
vec4 t2 = texture2D ( ltc _2 , uv ) ;
mat3 mInv = mat3 (
vec3 ( t1 . x , 0 , t1 . y ) ,
vec3 ( 0 , 1 , 0 ) ,
vec3 ( t1 . z , 0 , t1 . w )
) ;
vec3 fresnel = ( material . specularColor * t2 . x + ( vec3 ( 1.0 ) - material . specularColor ) * t2 . y ) ;
reflectedLight . directSpecular += lightColor * fresnel * LTC _Evaluate ( normal , viewDir , position , mInv , rectCoords ) ;
reflectedLight . directDiffuse += lightColor * material . diffuseColor * LTC _Evaluate ( normal , viewDir , position , mat3 ( 1.0 ) , rectCoords ) ;
}
# endif
void RE _Direct _Physical ( const in IncidentLight directLight , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in PhysicalMaterial material , inout ReflectedLight reflectedLight ) {
float dotNL = saturate ( dot ( geometryNormal , directLight . direction ) ) ;
vec3 irradiance = dotNL * directLight . color ;
# ifdef USE _CLEARCOAT
float dotNLcc = saturate ( dot ( geometryClearcoatNormal , directLight . direction ) ) ;
vec3 ccIrradiance = dotNLcc * directLight . color ;
clearcoatSpecularDirect += ccIrradiance * BRDF _GGX _Clearcoat ( directLight . direction , geometryViewDir , geometryClearcoatNormal , material ) ;
# endif
# ifdef USE _SHEEN
sheenSpecularDirect += irradiance * BRDF _Sheen ( directLight . direction , geometryViewDir , geometryNormal , material . sheenColor , material . sheenRoughness ) ;
# endif
reflectedLight . directSpecular += irradiance * BRDF _GGX _Multiscatter ( directLight . direction , geometryViewDir , geometryNormal , material ) ;
reflectedLight . directDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
void RE _IndirectDiffuse _Physical ( const in vec3 irradiance , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in PhysicalMaterial material , inout ReflectedLight reflectedLight ) {
reflectedLight . indirectDiffuse += irradiance * BRDF _Lambert ( material . diffuseColor ) ;
}
void RE _IndirectSpecular _Physical ( const in vec3 radiance , const in vec3 irradiance , const in vec3 clearcoatRadiance , const in vec3 geometryPosition , const in vec3 geometryNormal , const in vec3 geometryViewDir , const in vec3 geometryClearcoatNormal , const in PhysicalMaterial material , inout ReflectedLight reflectedLight ) {
# ifdef USE _CLEARCOAT
clearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF ( geometryClearcoatNormal , geometryViewDir , material . clearcoatF0 , material . clearcoatF90 , material . clearcoatRoughness ) ;
# endif
# ifdef USE _SHEEN
sheenSpecularIndirect += irradiance * material . sheenColor * IBLSheenBRDF ( geometryNormal , geometryViewDir , material . sheenRoughness ) ;
# endif
vec3 singleScattering = vec3 ( 0.0 ) ;
vec3 multiScattering = vec3 ( 0.0 ) ;
vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL _PI ;
# ifdef USE _IRIDESCENCE
computeMultiscatteringIridescence ( geometryNormal , geometryViewDir , material . specularColor , material . specularF90 , material . iridescence , material . iridescenceFresnel , material . roughness , singleScattering , multiScattering ) ;
# else
computeMultiscattering ( geometryNormal , geometryViewDir , material . specularColor , material . specularF90 , material . roughness , singleScattering , multiScattering ) ;
# endif
vec3 totalScattering = singleScattering + multiScattering ;
vec3 diffuse = material . diffuseColor * ( 1.0 - max ( max ( totalScattering . r , totalScattering . g ) , totalScattering . b ) ) ;
reflectedLight . indirectSpecular += radiance * singleScattering ;
reflectedLight . indirectSpecular += multiScattering * cosineWeightedIrradiance ;
reflectedLight . indirectDiffuse += diffuse * cosineWeightedIrradiance ;
}
# define RE _Direct RE _Direct _Physical
# define RE _Direct _RectArea RE _Direct _RectArea _Physical
# define RE _IndirectDiffuse RE _IndirectDiffuse _Physical
# define RE _IndirectSpecular RE _IndirectSpecular _Physical
float computeSpecularOcclusion ( const in float dotNV , const in float ambientOcclusion , const in float roughness ) {
return saturate ( pow ( dotNV + ambientOcclusion , exp2 ( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ) ;
2026-02-02 18:18:36 +08:00
} ` ,Q1= `
2026-01-22 11:29:51 +08:00
vec3 geometryPosition = - vViewPosition ;
vec3 geometryNormal = normal ;
vec3 geometryViewDir = ( isOrthographic ) ? vec3 ( 0 , 0 , 1 ) : normalize ( vViewPosition ) ;
vec3 geometryClearcoatNormal = vec3 ( 0.0 ) ;
# ifdef USE _CLEARCOAT
geometryClearcoatNormal = clearcoatNormal ;
# endif
# ifdef USE _IRIDESCENCE
float dotNVi = saturate ( dot ( normal , geometryViewDir ) ) ;
if ( material . iridescenceThickness == 0.0 ) {
material . iridescence = 0.0 ;
} else {
material . iridescence = saturate ( material . iridescence ) ;
}
if ( material . iridescence > 0.0 ) {
material . iridescenceFresnel = evalIridescence ( 1.0 , material . iridescenceIOR , dotNVi , material . iridescenceThickness , material . specularColor ) ;
material . iridescenceF0 = Schlick _to _F0 ( material . iridescenceFresnel , 1.0 , dotNVi ) ;
}
# endif
IncidentLight directLight ;
# if ( NUM _POINT _LIGHTS > 0 ) && defined ( RE _Direct )
PointLight pointLight ;
# if defined ( USE _SHADOWMAP ) && NUM _POINT _LIGHT _SHADOWS > 0
PointLightShadow pointLightShadow ;
# endif
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _POINT _LIGHTS ; i ++ ) {
pointLight = pointLights [ i ] ;
getPointLightInfo ( pointLight , geometryPosition , directLight ) ;
# if defined ( USE _SHADOWMAP ) && ( UNROLLED _LOOP _INDEX < NUM _POINT _LIGHT _SHADOWS )
pointLightShadow = pointLightShadows [ i ] ;
directLight . color *= ( directLight . visible && receiveShadow ) ? getPointShadow ( pointShadowMap [ i ] , pointLightShadow . shadowMapSize , pointLightShadow . shadowIntensity , pointLightShadow . shadowBias , pointLightShadow . shadowRadius , vPointShadowCoord [ i ] , pointLightShadow . shadowCameraNear , pointLightShadow . shadowCameraFar ) : 1.0 ;
# endif
RE _Direct ( directLight , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
}
# pragma unroll _loop _end
# endif
# if ( NUM _SPOT _LIGHTS > 0 ) && defined ( RE _Direct )
SpotLight spotLight ;
vec4 spotColor ;
vec3 spotLightCoord ;
bool inSpotLightMap ;
# if defined ( USE _SHADOWMAP ) && NUM _SPOT _LIGHT _SHADOWS > 0
SpotLightShadow spotLightShadow ;
# endif
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _SPOT _LIGHTS ; i ++ ) {
spotLight = spotLights [ i ] ;
getSpotLightInfo ( spotLight , geometryPosition , directLight ) ;
# if ( UNROLLED _LOOP _INDEX < NUM _SPOT _LIGHT _SHADOWS _WITH _MAPS )
# define SPOT _LIGHT _MAP _INDEX UNROLLED _LOOP _INDEX
# elif ( UNROLLED _LOOP _INDEX < NUM _SPOT _LIGHT _SHADOWS )
# define SPOT _LIGHT _MAP _INDEX NUM _SPOT _LIGHT _MAPS
# else
# define SPOT _LIGHT _MAP _INDEX ( UNROLLED _LOOP _INDEX - NUM _SPOT _LIGHT _SHADOWS + NUM _SPOT _LIGHT _SHADOWS _WITH _MAPS )
# endif
# if ( SPOT _LIGHT _MAP _INDEX < NUM _SPOT _LIGHT _MAPS )
spotLightCoord = vSpotLightCoord [ i ] . xyz / vSpotLightCoord [ i ] . w ;
inSpotLightMap = all ( lessThan ( abs ( spotLightCoord * 2. - 1. ) , vec3 ( 1.0 ) ) ) ;
spotColor = texture2D ( spotLightMap [ SPOT _LIGHT _MAP _INDEX ] , spotLightCoord . xy ) ;
directLight . color = inSpotLightMap ? directLight . color * spotColor . rgb : directLight . color ;
# endif
# undef SPOT _LIGHT _MAP _INDEX
# if defined ( USE _SHADOWMAP ) && ( UNROLLED _LOOP _INDEX < NUM _SPOT _LIGHT _SHADOWS )
spotLightShadow = spotLightShadows [ i ] ;
directLight . color *= ( directLight . visible && receiveShadow ) ? getShadow ( spotShadowMap [ i ] , spotLightShadow . shadowMapSize , spotLightShadow . shadowIntensity , spotLightShadow . shadowBias , spotLightShadow . shadowRadius , vSpotLightCoord [ i ] ) : 1.0 ;
# endif
RE _Direct ( directLight , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
}
# pragma unroll _loop _end
# endif
# if ( NUM _DIR _LIGHTS > 0 ) && defined ( RE _Direct )
DirectionalLight directionalLight ;
# if defined ( USE _SHADOWMAP ) && NUM _DIR _LIGHT _SHADOWS > 0
DirectionalLightShadow directionalLightShadow ;
# endif
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _DIR _LIGHTS ; i ++ ) {
directionalLight = directionalLights [ i ] ;
getDirectionalLightInfo ( directionalLight , directLight ) ;
# if defined ( USE _SHADOWMAP ) && ( UNROLLED _LOOP _INDEX < NUM _DIR _LIGHT _SHADOWS )
directionalLightShadow = directionalLightShadows [ i ] ;
directLight . color *= ( directLight . visible && receiveShadow ) ? getShadow ( directionalShadowMap [ i ] , directionalLightShadow . shadowMapSize , directionalLightShadow . shadowIntensity , directionalLightShadow . shadowBias , directionalLightShadow . shadowRadius , vDirectionalShadowCoord [ i ] ) : 1.0 ;
# endif
RE _Direct ( directLight , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
}
# pragma unroll _loop _end
# endif
# if ( NUM _RECT _AREA _LIGHTS > 0 ) && defined ( RE _Direct _RectArea )
RectAreaLight rectAreaLight ;
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _RECT _AREA _LIGHTS ; i ++ ) {
rectAreaLight = rectAreaLights [ i ] ;
RE _Direct _RectArea ( rectAreaLight , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
}
# pragma unroll _loop _end
# endif
# if defined ( RE _IndirectDiffuse )
vec3 iblIrradiance = vec3 ( 0.0 ) ;
vec3 irradiance = getAmbientLightIrradiance ( ambientLightColor ) ;
# if defined ( USE _LIGHT _PROBES )
irradiance += getLightProbeIrradiance ( lightProbe , geometryNormal ) ;
# endif
# if ( NUM _HEMI _LIGHTS > 0 )
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _HEMI _LIGHTS ; i ++ ) {
irradiance += getHemisphereLightIrradiance ( hemisphereLights [ i ] , geometryNormal ) ;
}
# pragma unroll _loop _end
# endif
# endif
# if defined ( RE _IndirectSpecular )
vec3 radiance = vec3 ( 0.0 ) ;
vec3 clearcoatRadiance = vec3 ( 0.0 ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,eb= ` # if defined ( RE _IndirectDiffuse )
2026-01-22 11:29:51 +08:00
# ifdef USE _LIGHTMAP
vec4 lightMapTexel = texture2D ( lightMap , vLightMapUv ) ;
vec3 lightMapIrradiance = lightMapTexel . rgb * lightMapIntensity ;
irradiance += lightMapIrradiance ;
# endif
# if defined ( USE _ENVMAP ) && defined ( STANDARD ) && defined ( ENVMAP _TYPE _CUBE _UV )
iblIrradiance += getIBLIrradiance ( geometryNormal ) ;
# endif
# endif
# if defined ( USE _ENVMAP ) && defined ( RE _IndirectSpecular )
# ifdef USE _ANISOTROPY
radiance += getIBLAnisotropyRadiance ( geometryViewDir , geometryNormal , material . roughness , material . anisotropyB , material . anisotropy ) ;
# else
radiance += getIBLRadiance ( geometryViewDir , geometryNormal , material . roughness ) ;
# endif
# ifdef USE _CLEARCOAT
clearcoatRadiance += getIBLRadiance ( geometryViewDir , geometryClearcoatNormal , material . clearcoatRoughness ) ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,tb= ` # if defined ( RE _IndirectDiffuse )
2026-01-22 11:29:51 +08:00
RE _IndirectDiffuse ( irradiance , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
# endif
# if defined ( RE _IndirectSpecular )
RE _IndirectSpecular ( radiance , iblIrradiance , clearcoatRadiance , geometryPosition , geometryNormal , geometryViewDir , geometryClearcoatNormal , material , reflectedLight ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,nb= ` # if defined ( USE _LOGARITHMIC _DEPTH _BUFFER )
2026-01-22 11:29:51 +08:00
gl _FragDepth = vIsPerspective == 0.0 ? gl _FragCoord . z : log2 ( vFragDepth ) * logDepthBufFC * 0.5 ;
2026-02-02 18:18:36 +08:00
# endif ` ,ib= ` # if defined ( USE _LOGARITHMIC _DEPTH _BUFFER )
2026-01-22 11:29:51 +08:00
uniform float logDepthBufFC ;
varying float vFragDepth ;
varying float vIsPerspective ;
2026-02-02 18:18:36 +08:00
# endif ` ,sb= ` # ifdef USE _LOGARITHMIC _DEPTH _BUFFER
2026-01-22 11:29:51 +08:00
varying float vFragDepth ;
varying float vIsPerspective ;
2026-02-02 18:18:36 +08:00
# endif ` ,rb= ` # ifdef USE _LOGARITHMIC _DEPTH _BUFFER
2026-01-22 11:29:51 +08:00
vFragDepth = 1.0 + gl _Position . w ;
vIsPerspective = float ( isPerspectiveMatrix ( projectionMatrix ) ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,ab= ` # ifdef USE _MAP
2026-01-22 11:29:51 +08:00
vec4 sampledDiffuseColor = texture2D ( map , vMapUv ) ;
# ifdef DECODE _VIDEO _TEXTURE
sampledDiffuseColor = sRGBTransferEOTF ( sampledDiffuseColor ) ;
# endif
diffuseColor *= sampledDiffuseColor ;
2026-02-02 18:18:36 +08:00
# endif ` ,ob= ` # ifdef USE _MAP
2026-01-22 11:29:51 +08:00
uniform sampler2D map ;
2026-02-02 18:18:36 +08:00
# endif ` ,lb= ` # if defined ( USE _MAP ) || defined ( USE _ALPHAMAP )
2026-01-22 11:29:51 +08:00
# if defined ( USE _POINTS _UV )
vec2 uv = vUv ;
# else
vec2 uv = ( uvTransform * vec3 ( gl _PointCoord . x , 1.0 - gl _PointCoord . y , 1 ) ) . xy ;
# endif
# endif
# ifdef USE _MAP
diffuseColor *= texture2D ( map , uv ) ;
# endif
# ifdef USE _ALPHAMAP
diffuseColor . a *= texture2D ( alphaMap , uv ) . g ;
2026-02-02 18:18:36 +08:00
# endif ` ,cb= ` # if defined ( USE _POINTS _UV )
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
# else
# if defined ( USE _MAP ) || defined ( USE _ALPHAMAP )
uniform mat3 uvTransform ;
# endif
# endif
# ifdef USE _MAP
uniform sampler2D map ;
# endif
# ifdef USE _ALPHAMAP
uniform sampler2D alphaMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,hb= ` float metalnessFactor = metalness ;
2026-01-22 11:29:51 +08:00
# ifdef USE _METALNESSMAP
vec4 texelMetalness = texture2D ( metalnessMap , vMetalnessMapUv ) ;
metalnessFactor *= texelMetalness . b ;
2026-02-02 18:18:36 +08:00
# endif ` ,ub= ` # ifdef USE _METALNESSMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D metalnessMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,db= ` # ifdef USE _INSTANCING _MORPH
2026-01-22 11:29:51 +08:00
float morphTargetInfluences [ MORPHTARGETS _COUNT ] ;
float morphTargetBaseInfluence = texelFetch ( morphTexture , ivec2 ( 0 , gl _InstanceID ) , 0 ) . r ;
for ( int i = 0 ; i < MORPHTARGETS _COUNT ; i ++ ) {
morphTargetInfluences [ i ] = texelFetch ( morphTexture , ivec2 ( i + 1 , gl _InstanceID ) , 0 ) . r ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,fb= ` # if defined ( USE _MORPHCOLORS )
2026-01-22 11:29:51 +08:00
vColor *= morphTargetBaseInfluence ;
for ( int i = 0 ; i < MORPHTARGETS _COUNT ; i ++ ) {
# if defined ( USE _COLOR _ALPHA )
if ( morphTargetInfluences [ i ] != 0.0 ) vColor += getMorph ( gl _VertexID , i , 2 ) * morphTargetInfluences [ i ] ;
# elif defined ( USE _COLOR )
if ( morphTargetInfluences [ i ] != 0.0 ) vColor += getMorph ( gl _VertexID , i , 2 ) . rgb * morphTargetInfluences [ i ] ;
# endif
}
2026-02-02 18:18:36 +08:00
# endif ` ,pb= ` # ifdef USE _MORPHNORMALS
2026-01-22 11:29:51 +08:00
objectNormal *= morphTargetBaseInfluence ;
for ( int i = 0 ; i < MORPHTARGETS _COUNT ; i ++ ) {
if ( morphTargetInfluences [ i ] != 0.0 ) objectNormal += getMorph ( gl _VertexID , i , 1 ) . xyz * morphTargetInfluences [ i ] ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,mb= ` # ifdef USE _MORPHTARGETS
2026-01-22 11:29:51 +08:00
# ifndef USE _INSTANCING _MORPH
uniform float morphTargetBaseInfluence ;
uniform float morphTargetInfluences [ MORPHTARGETS _COUNT ] ;
# endif
uniform sampler2DArray morphTargetsTexture ;
uniform ivec2 morphTargetsTextureSize ;
vec4 getMorph ( const in int vertexIndex , const in int morphTargetIndex , const in int offset ) {
int texelIndex = vertexIndex * MORPHTARGETS _TEXTURE _STRIDE + offset ;
int y = texelIndex / morphTargetsTextureSize . x ;
int x = texelIndex - y * morphTargetsTextureSize . x ;
ivec3 morphUV = ivec3 ( x , y , morphTargetIndex ) ;
return texelFetch ( morphTargetsTexture , morphUV , 0 ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,gb= ` # ifdef USE _MORPHTARGETS
2026-01-22 11:29:51 +08:00
transformed *= morphTargetBaseInfluence ;
for ( int i = 0 ; i < MORPHTARGETS _COUNT ; i ++ ) {
if ( morphTargetInfluences [ i ] != 0.0 ) transformed += getMorph ( gl _VertexID , i , 0 ) . xyz * morphTargetInfluences [ i ] ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,xb= ` float faceDirection = gl _FrontFacing ? 1.0 : - 1.0 ;
2026-01-22 11:29:51 +08:00
# ifdef FLAT _SHADED
vec3 fdx = dFdx ( vViewPosition ) ;
vec3 fdy = dFdy ( vViewPosition ) ;
vec3 normal = normalize ( cross ( fdx , fdy ) ) ;
# else
vec3 normal = normalize ( vNormal ) ;
# ifdef DOUBLE _SIDED
normal *= faceDirection ;
# endif
# endif
# if defined ( USE _NORMALMAP _TANGENTSPACE ) || defined ( USE _CLEARCOAT _NORMALMAP ) || defined ( USE _ANISOTROPY )
# ifdef USE _TANGENT
mat3 tbn = mat3 ( normalize ( vTangent ) , normalize ( vBitangent ) , normal ) ;
# else
mat3 tbn = getTangentFrame ( - vViewPosition , normal ,
# if defined ( USE _NORMALMAP )
vNormalMapUv
# elif defined ( USE _CLEARCOAT _NORMALMAP )
vClearcoatNormalMapUv
# else
vUv
# endif
) ;
# endif
# if defined ( DOUBLE _SIDED ) && ! defined ( FLAT _SHADED )
tbn [ 0 ] *= faceDirection ;
tbn [ 1 ] *= faceDirection ;
# endif
# endif
# ifdef USE _CLEARCOAT _NORMALMAP
# ifdef USE _TANGENT
mat3 tbn2 = mat3 ( normalize ( vTangent ) , normalize ( vBitangent ) , normal ) ;
# else
mat3 tbn2 = getTangentFrame ( - vViewPosition , normal , vClearcoatNormalMapUv ) ;
# endif
# if defined ( DOUBLE _SIDED ) && ! defined ( FLAT _SHADED )
tbn2 [ 0 ] *= faceDirection ;
tbn2 [ 1 ] *= faceDirection ;
# endif
# endif
2026-02-02 18:18:36 +08:00
vec3 nonPerturbedNormal = normal ; ` ,vb= ` # ifdef USE _NORMALMAP _OBJECTSPACE
2026-01-22 11:29:51 +08:00
normal = texture2D ( normalMap , vNormalMapUv ) . xyz * 2.0 - 1.0 ;
# ifdef FLIP _SIDED
normal = - normal ;
# endif
# ifdef DOUBLE _SIDED
normal = normal * faceDirection ;
# endif
normal = normalize ( normalMatrix * normal ) ;
# elif defined ( USE _NORMALMAP _TANGENTSPACE )
vec3 mapN = texture2D ( normalMap , vNormalMapUv ) . xyz * 2.0 - 1.0 ;
mapN . xy *= normalScale ;
normal = normalize ( tbn * mapN ) ;
# elif defined ( USE _BUMPMAP )
normal = perturbNormalArb ( - vViewPosition , normal , dHdxy _fwd ( ) , faceDirection ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,bb= ` # ifndef FLAT _SHADED
2026-01-22 11:29:51 +08:00
varying vec3 vNormal ;
# ifdef USE _TANGENT
varying vec3 vTangent ;
varying vec3 vBitangent ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,yb= ` # ifndef FLAT _SHADED
2026-01-22 11:29:51 +08:00
varying vec3 vNormal ;
# ifdef USE _TANGENT
varying vec3 vTangent ;
varying vec3 vBitangent ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,_b= ` # ifndef FLAT _SHADED
2026-01-22 11:29:51 +08:00
vNormal = normalize ( transformedNormal ) ;
# ifdef USE _TANGENT
vTangent = normalize ( transformedTangent ) ;
vBitangent = normalize ( cross ( vNormal , vTangent ) * tangent . w ) ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,Mb= ` # ifdef USE _NORMALMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D normalMap ;
uniform vec2 normalScale ;
# endif
# ifdef USE _NORMALMAP _OBJECTSPACE
uniform mat3 normalMatrix ;
# endif
# if ! defined ( USE _TANGENT ) && ( defined ( USE _NORMALMAP _TANGENTSPACE ) || defined ( USE _CLEARCOAT _NORMALMAP ) || defined ( USE _ANISOTROPY ) )
mat3 getTangentFrame ( vec3 eye _pos , vec3 surf _norm , vec2 uv ) {
vec3 q0 = dFdx ( eye _pos . xyz ) ;
vec3 q1 = dFdy ( eye _pos . xyz ) ;
vec2 st0 = dFdx ( uv . st ) ;
vec2 st1 = dFdy ( uv . st ) ;
vec3 N = surf _norm ;
vec3 q1perp = cross ( q1 , N ) ;
vec3 q0perp = cross ( N , q0 ) ;
vec3 T = q1perp * st0 . x + q0perp * st1 . x ;
vec3 B = q1perp * st0 . y + q0perp * st1 . y ;
float det = max ( dot ( T , T ) , dot ( B , B ) ) ;
float scale = ( det == 0.0 ) ? 0.0 : inversesqrt ( det ) ;
return mat3 ( T * scale , B * scale , N ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,wb= ` # ifdef USE _CLEARCOAT
2026-01-22 11:29:51 +08:00
vec3 clearcoatNormal = nonPerturbedNormal ;
2026-02-02 18:18:36 +08:00
# endif ` ,Sb= ` # ifdef USE _CLEARCOAT _NORMALMAP
2026-01-22 11:29:51 +08:00
vec3 clearcoatMapN = texture2D ( clearcoatNormalMap , vClearcoatNormalMapUv ) . xyz * 2.0 - 1.0 ;
clearcoatMapN . xy *= clearcoatNormalScale ;
clearcoatNormal = normalize ( tbn2 * clearcoatMapN ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,Eb= ` # ifdef USE _CLEARCOATMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D clearcoatMap ;
# endif
# ifdef USE _CLEARCOAT _NORMALMAP
uniform sampler2D clearcoatNormalMap ;
uniform vec2 clearcoatNormalScale ;
# endif
# ifdef USE _CLEARCOAT _ROUGHNESSMAP
uniform sampler2D clearcoatRoughnessMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,Tb= ` # ifdef USE _IRIDESCENCEMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D iridescenceMap ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
uniform sampler2D iridescenceThicknessMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,Cb= ` # ifdef OPAQUE
2026-01-22 11:29:51 +08:00
diffuseColor . a = 1.0 ;
# endif
# ifdef USE _TRANSMISSION
diffuseColor . a *= material . transmissionAlpha ;
# endif
2026-02-02 18:18:36 +08:00
gl _FragColor = vec4 ( outgoingLight , diffuseColor . a ) ; ` ,Ab= ` vec3 packNormalToRGB ( const in vec3 normal ) {
2026-01-22 11:29:51 +08:00
return normalize ( normal ) * 0.5 + 0.5 ;
}
vec3 unpackRGBToNormal ( const in vec3 rgb ) {
return 2.0 * rgb . xyz - 1.0 ;
}
const float PackUpscale = 256. / 255. ; const float UnpackDownscale = 255. / 256. ; const float ShiftRight8 = 1. / 256. ;
const float Inv255 = 1. / 255. ;
const vec4 PackFactors = vec4 ( 1.0 , 256.0 , 256.0 * 256.0 , 256.0 * 256.0 * 256.0 ) ;
const vec2 UnpackFactors2 = vec2 ( UnpackDownscale , 1.0 / PackFactors . g ) ;
const vec3 UnpackFactors3 = vec3 ( UnpackDownscale / PackFactors . rg , 1.0 / PackFactors . b ) ;
const vec4 UnpackFactors4 = vec4 ( UnpackDownscale / PackFactors . rgb , 1.0 / PackFactors . a ) ;
vec4 packDepthToRGBA ( const in float v ) {
if ( v <= 0.0 )
return vec4 ( 0. , 0. , 0. , 0. ) ;
if ( v >= 1.0 )
return vec4 ( 1. , 1. , 1. , 1. ) ;
float vuf ;
float af = modf ( v * PackFactors . a , vuf ) ;
float bf = modf ( vuf * ShiftRight8 , vuf ) ;
float gf = modf ( vuf * ShiftRight8 , vuf ) ;
return vec4 ( vuf * Inv255 , gf * PackUpscale , bf * PackUpscale , af ) ;
}
vec3 packDepthToRGB ( const in float v ) {
if ( v <= 0.0 )
return vec3 ( 0. , 0. , 0. ) ;
if ( v >= 1.0 )
return vec3 ( 1. , 1. , 1. ) ;
float vuf ;
float bf = modf ( v * PackFactors . b , vuf ) ;
float gf = modf ( vuf * ShiftRight8 , vuf ) ;
return vec3 ( vuf * Inv255 , gf * PackUpscale , bf ) ;
}
vec2 packDepthToRG ( const in float v ) {
if ( v <= 0.0 )
return vec2 ( 0. , 0. ) ;
if ( v >= 1.0 )
return vec2 ( 1. , 1. ) ;
float vuf ;
float gf = modf ( v * 256. , vuf ) ;
return vec2 ( vuf * Inv255 , gf ) ;
}
float unpackRGBAToDepth ( const in vec4 v ) {
return dot ( v , UnpackFactors4 ) ;
}
float unpackRGBToDepth ( const in vec3 v ) {
return dot ( v , UnpackFactors3 ) ;
}
float unpackRGToDepth ( const in vec2 v ) {
return v . r * UnpackFactors2 . r + v . g * UnpackFactors2 . g ;
}
vec4 pack2HalfToRGBA ( const in vec2 v ) {
vec4 r = vec4 ( v . x , fract ( v . x * 255.0 ) , v . y , fract ( v . y * 255.0 ) ) ;
return vec4 ( r . x - r . y / 255.0 , r . y , r . z - r . w / 255.0 , r . w ) ;
}
vec2 unpackRGBATo2Half ( const in vec4 v ) {
return vec2 ( v . x + ( v . y / 255.0 ) , v . z + ( v . w / 255.0 ) ) ;
}
float viewZToOrthographicDepth ( const in float viewZ , const in float near , const in float far ) {
return ( viewZ + near ) / ( near - far ) ;
}
float orthographicDepthToViewZ ( const in float depth , const in float near , const in float far ) {
return depth * ( near - far ) - near ;
}
float viewZToPerspectiveDepth ( const in float viewZ , const in float near , const in float far ) {
return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ) ;
}
float perspectiveDepthToViewZ ( const in float depth , const in float near , const in float far ) {
return ( near * far ) / ( ( far - near ) * depth - far ) ;
2026-02-02 18:18:36 +08:00
} ` ,Pb= ` # ifdef PREMULTIPLIED _ALPHA
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb *= gl _FragColor . a ;
2026-02-02 18:18:36 +08:00
# endif ` ,Rb= ` vec4 mvPosition = vec4 ( transformed , 1.0 ) ;
2026-01-22 11:29:51 +08:00
# ifdef USE _BATCHING
mvPosition = batchingMatrix * mvPosition ;
# endif
# ifdef USE _INSTANCING
mvPosition = instanceMatrix * mvPosition ;
# endif
mvPosition = modelViewMatrix * mvPosition ;
2026-02-02 18:18:36 +08:00
gl _Position = projectionMatrix * mvPosition ; ` ,Lb= ` # ifdef DITHERING
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb = dithering ( gl _FragColor . rgb ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,Ib= ` # ifdef DITHERING
2026-01-22 11:29:51 +08:00
vec3 dithering ( vec3 color ) {
float grid _position = rand ( gl _FragCoord . xy ) ;
vec3 dither _shift _RGB = vec3 ( 0.25 / 255.0 , - 0.25 / 255.0 , 0.25 / 255.0 ) ;
dither _shift _RGB = mix ( 2.0 * dither _shift _RGB , - 2.0 * dither _shift _RGB , grid _position ) ;
return color + dither _shift _RGB ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,Db= ` float roughnessFactor = roughness ;
2026-01-22 11:29:51 +08:00
# ifdef USE _ROUGHNESSMAP
vec4 texelRoughness = texture2D ( roughnessMap , vRoughnessMapUv ) ;
roughnessFactor *= texelRoughness . g ;
2026-02-02 18:18:36 +08:00
# endif ` ,Bb= ` # ifdef USE _ROUGHNESSMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D roughnessMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,Nb= ` # if NUM _SPOT _LIGHT _COORDS > 0
2026-01-22 11:29:51 +08:00
varying vec4 vSpotLightCoord [ NUM _SPOT _LIGHT _COORDS ] ;
# endif
# if NUM _SPOT _LIGHT _MAPS > 0
uniform sampler2D spotLightMap [ NUM _SPOT _LIGHT _MAPS ] ;
# endif
# ifdef USE _SHADOWMAP
# if NUM _DIR _LIGHT _SHADOWS > 0
uniform sampler2D directionalShadowMap [ NUM _DIR _LIGHT _SHADOWS ] ;
varying vec4 vDirectionalShadowCoord [ NUM _DIR _LIGHT _SHADOWS ] ;
struct DirectionalLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
} ;
uniform DirectionalLightShadow directionalLightShadows [ NUM _DIR _LIGHT _SHADOWS ] ;
# endif
# if NUM _SPOT _LIGHT _SHADOWS > 0
uniform sampler2D spotShadowMap [ NUM _SPOT _LIGHT _SHADOWS ] ;
struct SpotLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
} ;
uniform SpotLightShadow spotLightShadows [ NUM _SPOT _LIGHT _SHADOWS ] ;
# endif
# if NUM _POINT _LIGHT _SHADOWS > 0
uniform sampler2D pointShadowMap [ NUM _POINT _LIGHT _SHADOWS ] ;
varying vec4 vPointShadowCoord [ NUM _POINT _LIGHT _SHADOWS ] ;
struct PointLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
float shadowCameraNear ;
float shadowCameraFar ;
} ;
uniform PointLightShadow pointLightShadows [ NUM _POINT _LIGHT _SHADOWS ] ;
# endif
float texture2DCompare ( sampler2D depths , vec2 uv , float compare ) {
float depth = unpackRGBAToDepth ( texture2D ( depths , uv ) ) ;
# ifdef USE _REVERSED _DEPTH _BUFFER
return step ( depth , compare ) ;
# else
return step ( compare , depth ) ;
# endif
}
vec2 texture2DDistribution ( sampler2D shadow , vec2 uv ) {
return unpackRGBATo2Half ( texture2D ( shadow , uv ) ) ;
}
float VSMShadow ( sampler2D shadow , vec2 uv , float compare ) {
float occlusion = 1.0 ;
vec2 distribution = texture2DDistribution ( shadow , uv ) ;
# ifdef USE _REVERSED _DEPTH _BUFFER
float hard _shadow = step ( distribution . x , compare ) ;
# else
float hard _shadow = step ( compare , distribution . x ) ;
# endif
if ( hard _shadow != 1.0 ) {
float distance = compare - distribution . x ;
float variance = max ( 0.00000 , distribution . y * distribution . y ) ;
float softness _probability = variance / ( variance + distance * distance ) ; softness _probability = clamp ( ( softness _probability - 0.3 ) / ( 0.95 - 0.3 ) , 0.0 , 1.0 ) ; occlusion = clamp ( max ( hard _shadow , softness _probability ) , 0.0 , 1.0 ) ;
}
return occlusion ;
}
float getShadow ( sampler2D shadowMap , vec2 shadowMapSize , float shadowIntensity , float shadowBias , float shadowRadius , vec4 shadowCoord ) {
float shadow = 1.0 ;
shadowCoord . xyz /= shadowCoord . w ;
shadowCoord . z += shadowBias ;
bool inFrustum = shadowCoord . x >= 0.0 && shadowCoord . x <= 1.0 && shadowCoord . y >= 0.0 && shadowCoord . y <= 1.0 ;
bool frustumTest = inFrustum && shadowCoord . z <= 1.0 ;
if ( frustumTest ) {
# if defined ( SHADOWMAP _TYPE _PCF )
vec2 texelSize = vec2 ( 1.0 ) / shadowMapSize ;
float dx0 = - texelSize . x * shadowRadius ;
float dy0 = - texelSize . y * shadowRadius ;
float dx1 = + texelSize . x * shadowRadius ;
float dy1 = + texelSize . y * shadowRadius ;
float dx2 = dx0 / 2.0 ;
float dy2 = dy0 / 2.0 ;
float dx3 = dx1 / 2.0 ;
float dy3 = dy1 / 2.0 ;
shadow = (
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx0 , dy0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( 0.0 , dy0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx1 , dy0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx2 , dy2 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( 0.0 , dy2 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx3 , dy2 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx0 , 0.0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx2 , 0.0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx3 , 0.0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx1 , 0.0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx2 , dy3 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( 0.0 , dy3 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx3 , dy3 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx0 , dy1 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( 0.0 , dy1 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , shadowCoord . xy + vec2 ( dx1 , dy1 ) , shadowCoord . z )
) * ( 1.0 / 17.0 ) ;
# elif defined ( SHADOWMAP _TYPE _PCF _SOFT )
vec2 texelSize = vec2 ( 1.0 ) / shadowMapSize ;
float dx = texelSize . x ;
float dy = texelSize . y ;
vec2 uv = shadowCoord . xy ;
vec2 f = fract ( uv * shadowMapSize + 0.5 ) ;
uv -= f * texelSize ;
shadow = (
texture2DCompare ( shadowMap , uv , shadowCoord . z ) +
texture2DCompare ( shadowMap , uv + vec2 ( dx , 0.0 ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , uv + vec2 ( 0.0 , dy ) , shadowCoord . z ) +
texture2DCompare ( shadowMap , uv + texelSize , shadowCoord . z ) +
mix ( texture2DCompare ( shadowMap , uv + vec2 ( - dx , 0.0 ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( 2.0 * dx , 0.0 ) , shadowCoord . z ) ,
f . x ) +
mix ( texture2DCompare ( shadowMap , uv + vec2 ( - dx , dy ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( 2.0 * dx , dy ) , shadowCoord . z ) ,
f . x ) +
mix ( texture2DCompare ( shadowMap , uv + vec2 ( 0.0 , - dy ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( 0.0 , 2.0 * dy ) , shadowCoord . z ) ,
f . y ) +
mix ( texture2DCompare ( shadowMap , uv + vec2 ( dx , - dy ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( dx , 2.0 * dy ) , shadowCoord . z ) ,
f . y ) +
mix ( mix ( texture2DCompare ( shadowMap , uv + vec2 ( - dx , - dy ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( 2.0 * dx , - dy ) , shadowCoord . z ) ,
f . x ) ,
mix ( texture2DCompare ( shadowMap , uv + vec2 ( - dx , 2.0 * dy ) , shadowCoord . z ) ,
texture2DCompare ( shadowMap , uv + vec2 ( 2.0 * dx , 2.0 * dy ) , shadowCoord . z ) ,
f . x ) ,
f . y )
) * ( 1.0 / 9.0 ) ;
# elif defined ( SHADOWMAP _TYPE _VSM )
shadow = VSMShadow ( shadowMap , shadowCoord . xy , shadowCoord . z ) ;
# else
shadow = texture2DCompare ( shadowMap , shadowCoord . xy , shadowCoord . z ) ;
# endif
}
return mix ( 1.0 , shadow , shadowIntensity ) ;
}
vec2 cubeToUV ( vec3 v , float texelSizeY ) {
vec3 absV = abs ( v ) ;
float scaleToCube = 1.0 / max ( absV . x , max ( absV . y , absV . z ) ) ;
absV *= scaleToCube ;
v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ) ;
vec2 planar = v . xy ;
float almostATexel = 1.5 * texelSizeY ;
float almostOne = 1.0 - almostATexel ;
if ( absV . z >= almostOne ) {
if ( v . z > 0.0 )
planar . x = 4.0 - v . x ;
} else if ( absV . x >= almostOne ) {
float signX = sign ( v . x ) ;
planar . x = v . z * signX + 2.0 * signX ;
} else if ( absV . y >= almostOne ) {
float signY = sign ( v . y ) ;
planar . x = v . x + 2.0 * signY + 2.0 ;
planar . y = v . z * signY - 2.0 ;
}
return vec2 ( 0.125 , 0.25 ) * planar + vec2 ( 0.375 , 0.75 ) ;
}
float getPointShadow ( sampler2D shadowMap , vec2 shadowMapSize , float shadowIntensity , float shadowBias , float shadowRadius , vec4 shadowCoord , float shadowCameraNear , float shadowCameraFar ) {
float shadow = 1.0 ;
vec3 lightToPosition = shadowCoord . xyz ;
float lightToPositionLength = length ( lightToPosition ) ;
if ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {
float dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ) ; dp += shadowBias ;
vec3 bd3D = normalize ( lightToPosition ) ;
vec2 texelSize = vec2 ( 1.0 ) / ( shadowMapSize * vec2 ( 4.0 , 2.0 ) ) ;
# if defined ( SHADOWMAP _TYPE _PCF ) || defined ( SHADOWMAP _TYPE _PCF _SOFT ) || defined ( SHADOWMAP _TYPE _VSM )
vec2 offset = vec2 ( - 1 , 1 ) * shadowRadius * texelSize . y ;
shadow = (
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . xyy , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . yyy , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . xyx , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . yyx , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . xxy , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . yxy , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . xxx , texelSize . y ) , dp ) +
texture2DCompare ( shadowMap , cubeToUV ( bd3D + offset . yxx , texelSize . y ) , dp )
) * ( 1.0 / 9.0 ) ;
# else
shadow = texture2DCompare ( shadowMap , cubeToUV ( bd3D , texelSize . y ) , dp ) ;
# endif
}
return mix ( 1.0 , shadow , shadowIntensity ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,kb= ` # if NUM _SPOT _LIGHT _COORDS > 0
2026-01-22 11:29:51 +08:00
uniform mat4 spotLightMatrix [ NUM _SPOT _LIGHT _COORDS ] ;
varying vec4 vSpotLightCoord [ NUM _SPOT _LIGHT _COORDS ] ;
# endif
# ifdef USE _SHADOWMAP
# if NUM _DIR _LIGHT _SHADOWS > 0
uniform mat4 directionalShadowMatrix [ NUM _DIR _LIGHT _SHADOWS ] ;
varying vec4 vDirectionalShadowCoord [ NUM _DIR _LIGHT _SHADOWS ] ;
struct DirectionalLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
} ;
uniform DirectionalLightShadow directionalLightShadows [ NUM _DIR _LIGHT _SHADOWS ] ;
# endif
# if NUM _SPOT _LIGHT _SHADOWS > 0
struct SpotLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
} ;
uniform SpotLightShadow spotLightShadows [ NUM _SPOT _LIGHT _SHADOWS ] ;
# endif
# if NUM _POINT _LIGHT _SHADOWS > 0
uniform mat4 pointShadowMatrix [ NUM _POINT _LIGHT _SHADOWS ] ;
varying vec4 vPointShadowCoord [ NUM _POINT _LIGHT _SHADOWS ] ;
struct PointLightShadow {
float shadowIntensity ;
float shadowBias ;
float shadowNormalBias ;
float shadowRadius ;
vec2 shadowMapSize ;
float shadowCameraNear ;
float shadowCameraFar ;
} ;
uniform PointLightShadow pointLightShadows [ NUM _POINT _LIGHT _SHADOWS ] ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,Ub= ` # if ( defined ( USE _SHADOWMAP ) && ( NUM _DIR _LIGHT _SHADOWS > 0 || NUM _POINT _LIGHT _SHADOWS > 0 ) ) || ( NUM _SPOT _LIGHT _COORDS > 0 )
2026-01-22 11:29:51 +08:00
vec3 shadowWorldNormal = inverseTransformDirection ( transformedNormal , viewMatrix ) ;
vec4 shadowWorldPosition ;
# endif
# if defined ( USE _SHADOWMAP )
# if NUM _DIR _LIGHT _SHADOWS > 0
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _DIR _LIGHT _SHADOWS ; i ++ ) {
shadowWorldPosition = worldPosition + vec4 ( shadowWorldNormal * directionalLightShadows [ i ] . shadowNormalBias , 0 ) ;
vDirectionalShadowCoord [ i ] = directionalShadowMatrix [ i ] * shadowWorldPosition ;
}
# pragma unroll _loop _end
# endif
# if NUM _POINT _LIGHT _SHADOWS > 0
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _POINT _LIGHT _SHADOWS ; i ++ ) {
shadowWorldPosition = worldPosition + vec4 ( shadowWorldNormal * pointLightShadows [ i ] . shadowNormalBias , 0 ) ;
vPointShadowCoord [ i ] = pointShadowMatrix [ i ] * shadowWorldPosition ;
}
# pragma unroll _loop _end
# endif
# endif
# if NUM _SPOT _LIGHT _COORDS > 0
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _SPOT _LIGHT _COORDS ; i ++ ) {
shadowWorldPosition = worldPosition ;
# if ( defined ( USE _SHADOWMAP ) && UNROLLED _LOOP _INDEX < NUM _SPOT _LIGHT _SHADOWS )
shadowWorldPosition . xyz += shadowWorldNormal * spotLightShadows [ i ] . shadowNormalBias ;
# endif
vSpotLightCoord [ i ] = spotLightMatrix [ i ] * shadowWorldPosition ;
}
# pragma unroll _loop _end
2026-02-02 18:18:36 +08:00
# endif ` ,Ob= ` float getShadowMask ( ) {
2026-01-22 11:29:51 +08:00
float shadow = 1.0 ;
# ifdef USE _SHADOWMAP
# if NUM _DIR _LIGHT _SHADOWS > 0
DirectionalLightShadow directionalLight ;
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _DIR _LIGHT _SHADOWS ; i ++ ) {
directionalLight = directionalLightShadows [ i ] ;
shadow *= receiveShadow ? getShadow ( directionalShadowMap [ i ] , directionalLight . shadowMapSize , directionalLight . shadowIntensity , directionalLight . shadowBias , directionalLight . shadowRadius , vDirectionalShadowCoord [ i ] ) : 1.0 ;
}
# pragma unroll _loop _end
# endif
# if NUM _SPOT _LIGHT _SHADOWS > 0
SpotLightShadow spotLight ;
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _SPOT _LIGHT _SHADOWS ; i ++ ) {
spotLight = spotLightShadows [ i ] ;
shadow *= receiveShadow ? getShadow ( spotShadowMap [ i ] , spotLight . shadowMapSize , spotLight . shadowIntensity , spotLight . shadowBias , spotLight . shadowRadius , vSpotLightCoord [ i ] ) : 1.0 ;
}
# pragma unroll _loop _end
# endif
# if NUM _POINT _LIGHT _SHADOWS > 0
PointLightShadow pointLight ;
# pragma unroll _loop _start
for ( int i = 0 ; i < NUM _POINT _LIGHT _SHADOWS ; i ++ ) {
pointLight = pointLightShadows [ i ] ;
shadow *= receiveShadow ? getPointShadow ( pointShadowMap [ i ] , pointLight . shadowMapSize , pointLight . shadowIntensity , pointLight . shadowBias , pointLight . shadowRadius , vPointShadowCoord [ i ] , pointLight . shadowCameraNear , pointLight . shadowCameraFar ) : 1.0 ;
}
# pragma unroll _loop _end
# endif
# endif
return shadow ;
2026-02-02 18:18:36 +08:00
} ` ,Fb= ` # ifdef USE _SKINNING
2026-01-22 11:29:51 +08:00
mat4 boneMatX = getBoneMatrix ( skinIndex . x ) ;
mat4 boneMatY = getBoneMatrix ( skinIndex . y ) ;
mat4 boneMatZ = getBoneMatrix ( skinIndex . z ) ;
mat4 boneMatW = getBoneMatrix ( skinIndex . w ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,zb= ` # ifdef USE _SKINNING
2026-01-22 11:29:51 +08:00
uniform mat4 bindMatrix ;
uniform mat4 bindMatrixInverse ;
uniform highp sampler2D boneTexture ;
mat4 getBoneMatrix ( const in float i ) {
int size = textureSize ( boneTexture , 0 ) . x ;
int j = int ( i ) * 4 ;
int x = j % size ;
int y = j / size ;
vec4 v1 = texelFetch ( boneTexture , ivec2 ( x , y ) , 0 ) ;
vec4 v2 = texelFetch ( boneTexture , ivec2 ( x + 1 , y ) , 0 ) ;
vec4 v3 = texelFetch ( boneTexture , ivec2 ( x + 2 , y ) , 0 ) ;
vec4 v4 = texelFetch ( boneTexture , ivec2 ( x + 3 , y ) , 0 ) ;
return mat4 ( v1 , v2 , v3 , v4 ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,Hb= ` # ifdef USE _SKINNING
2026-01-22 11:29:51 +08:00
vec4 skinVertex = bindMatrix * vec4 ( transformed , 1.0 ) ;
vec4 skinned = vec4 ( 0.0 ) ;
skinned += boneMatX * skinVertex * skinWeight . x ;
skinned += boneMatY * skinVertex * skinWeight . y ;
skinned += boneMatZ * skinVertex * skinWeight . z ;
skinned += boneMatW * skinVertex * skinWeight . w ;
transformed = ( bindMatrixInverse * skinned ) . xyz ;
2026-02-02 18:18:36 +08:00
# endif ` ,Vb= ` # ifdef USE _SKINNING
2026-01-22 11:29:51 +08:00
mat4 skinMatrix = mat4 ( 0.0 ) ;
skinMatrix += skinWeight . x * boneMatX ;
skinMatrix += skinWeight . y * boneMatY ;
skinMatrix += skinWeight . z * boneMatZ ;
skinMatrix += skinWeight . w * boneMatW ;
skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix ;
objectNormal = vec4 ( skinMatrix * vec4 ( objectNormal , 0.0 ) ) . xyz ;
# ifdef USE _TANGENT
objectTangent = vec4 ( skinMatrix * vec4 ( objectTangent , 0.0 ) ) . xyz ;
# endif
2026-02-02 18:18:36 +08:00
# endif ` ,Gb= ` float specularStrength ;
2026-01-22 11:29:51 +08:00
# ifdef USE _SPECULARMAP
vec4 texelSpecular = texture2D ( specularMap , vSpecularMapUv ) ;
specularStrength = texelSpecular . r ;
# else
specularStrength = 1.0 ;
2026-02-02 18:18:36 +08:00
# endif ` ,Wb= ` # ifdef USE _SPECULARMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D specularMap ;
2026-02-02 18:18:36 +08:00
# endif ` ,Xb= ` # if defined ( TONE _MAPPING )
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb = toneMapping ( gl _FragColor . rgb ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,jb= ` # ifndef saturate
2026-01-22 11:29:51 +08:00
# define saturate ( a ) clamp ( a , 0.0 , 1.0 )
# endif
uniform float toneMappingExposure ;
vec3 LinearToneMapping ( vec3 color ) {
return saturate ( toneMappingExposure * color ) ;
}
vec3 ReinhardToneMapping ( vec3 color ) {
color *= toneMappingExposure ;
return saturate ( color / ( vec3 ( 1.0 ) + color ) ) ;
}
vec3 CineonToneMapping ( vec3 color ) {
color *= toneMappingExposure ;
color = max ( vec3 ( 0.0 ) , color - 0.004 ) ;
return pow ( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ) , vec3 ( 2.2 ) ) ;
}
vec3 RRTAndODTFit ( vec3 v ) {
vec3 a = v * ( v + 0.0245786 ) - 0.000090537 ;
vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081 ;
return a / b ;
}
vec3 ACESFilmicToneMapping ( vec3 color ) {
const mat3 ACESInputMat = mat3 (
vec3 ( 0.59719 , 0.07600 , 0.02840 ) , vec3 ( 0.35458 , 0.90834 , 0.13383 ) ,
vec3 ( 0.04823 , 0.01566 , 0.83777 )
) ;
const mat3 ACESOutputMat = mat3 (
vec3 ( 1.60475 , - 0.10208 , - 0.00327 ) , vec3 ( - 0.53108 , 1.10813 , - 0.07276 ) ,
vec3 ( - 0.07367 , - 0.00605 , 1.07602 )
) ;
color *= toneMappingExposure / 0.6 ;
color = ACESInputMat * color ;
color = RRTAndODTFit ( color ) ;
color = ACESOutputMat * color ;
return saturate ( color ) ;
}
const mat3 LINEAR _REC2020 _TO _LINEAR _SRGB = mat3 (
vec3 ( 1.6605 , - 0.1246 , - 0.0182 ) ,
vec3 ( - 0.5876 , 1.1329 , - 0.1006 ) ,
vec3 ( - 0.0728 , - 0.0083 , 1.1187 )
) ;
const mat3 LINEAR _SRGB _TO _LINEAR _REC2020 = mat3 (
vec3 ( 0.6274 , 0.0691 , 0.0164 ) ,
vec3 ( 0.3293 , 0.9195 , 0.0880 ) ,
vec3 ( 0.0433 , 0.0113 , 0.8956 )
) ;
vec3 agxDefaultContrastApprox ( vec3 x ) {
vec3 x2 = x * x ;
vec3 x4 = x2 * x2 ;
return + 15.5 * x4 * x2
- 40.14 * x4 * x
+ 31.96 * x4
- 6.868 * x2 * x
+ 0.4298 * x2
+ 0.1191 * x
- 0.00232 ;
}
vec3 AgXToneMapping ( vec3 color ) {
const mat3 AgXInsetMatrix = mat3 (
vec3 ( 0.856627153315983 , 0.137318972929847 , 0.11189821299995 ) ,
vec3 ( 0.0951212405381588 , 0.761241990602591 , 0.0767994186031903 ) ,
vec3 ( 0.0482516061458583 , 0.101439036467562 , 0.811302368396859 )
) ;
const mat3 AgXOutsetMatrix = mat3 (
vec3 ( 1.1271005818144368 , - 0.1413297634984383 , - 0.14132976349843826 ) ,
vec3 ( - 0.11060664309660323 , 1.157823702216272 , - 0.11060664309660294 ) ,
vec3 ( - 0.016493938717834573 , - 0.016493938717834257 , 1.2519364065950405 )
) ;
const float AgxMinEv = - 12.47393 ; const float AgxMaxEv = 4.026069 ;
color *= toneMappingExposure ;
color = LINEAR _SRGB _TO _LINEAR _REC2020 * color ;
color = AgXInsetMatrix * color ;
color = max ( color , 1e-10 ) ; color = log2 ( color ) ;
color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv ) ;
color = clamp ( color , 0.0 , 1.0 ) ;
color = agxDefaultContrastApprox ( color ) ;
color = AgXOutsetMatrix * color ;
color = pow ( max ( vec3 ( 0.0 ) , color ) , vec3 ( 2.2 ) ) ;
color = LINEAR _REC2020 _TO _LINEAR _SRGB * color ;
color = clamp ( color , 0.0 , 1.0 ) ;
return color ;
}
vec3 NeutralToneMapping ( vec3 color ) {
const float StartCompression = 0.8 - 0.04 ;
const float Desaturation = 0.15 ;
color *= toneMappingExposure ;
float x = min ( color . r , min ( color . g , color . b ) ) ;
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04 ;
color -= offset ;
float peak = max ( color . r , max ( color . g , color . b ) ) ;
if ( peak < StartCompression ) return color ;
float d = 1. - StartCompression ;
float newPeak = 1. - d * d / ( peak + d - StartCompression ) ;
color *= newPeak / peak ;
float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ) ;
return mix ( color , vec3 ( newPeak ) , g ) ;
}
2026-02-02 18:18:36 +08:00
vec3 CustomToneMapping ( vec3 color ) { return color ; } ` ,qb= ` # ifdef USE _TRANSMISSION
2026-01-22 11:29:51 +08:00
material . transmission = transmission ;
material . transmissionAlpha = 1.0 ;
material . thickness = thickness ;
material . attenuationDistance = attenuationDistance ;
material . attenuationColor = attenuationColor ;
# ifdef USE _TRANSMISSIONMAP
material . transmission *= texture2D ( transmissionMap , vTransmissionMapUv ) . r ;
# endif
# ifdef USE _THICKNESSMAP
material . thickness *= texture2D ( thicknessMap , vThicknessMapUv ) . g ;
# endif
vec3 pos = vWorldPosition ;
vec3 v = normalize ( cameraPosition - pos ) ;
vec3 n = inverseTransformDirection ( normal , viewMatrix ) ;
vec4 transmitted = getIBLVolumeRefraction (
n , v , material . roughness , material . diffuseColor , material . specularColor , material . specularF90 ,
pos , modelMatrix , viewMatrix , projectionMatrix , material . dispersion , material . ior , material . thickness ,
material . attenuationColor , material . attenuationDistance ) ;
material . transmissionAlpha = mix ( material . transmissionAlpha , transmitted . a , material . transmission ) ;
totalDiffuse = mix ( totalDiffuse , transmitted . rgb , material . transmission ) ;
2026-02-02 18:18:36 +08:00
# endif ` ,Zb= ` # ifdef USE _TRANSMISSION
2026-01-22 11:29:51 +08:00
uniform float transmission ;
uniform float thickness ;
uniform float attenuationDistance ;
uniform vec3 attenuationColor ;
# ifdef USE _TRANSMISSIONMAP
uniform sampler2D transmissionMap ;
# endif
# ifdef USE _THICKNESSMAP
uniform sampler2D thicknessMap ;
# endif
uniform vec2 transmissionSamplerSize ;
uniform sampler2D transmissionSamplerMap ;
uniform mat4 modelMatrix ;
uniform mat4 projectionMatrix ;
varying vec3 vWorldPosition ;
float w0 ( float a ) {
return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ) ;
}
float w1 ( float a ) {
return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ) ;
}
float w2 ( float a ) {
return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ) ;
}
float w3 ( float a ) {
return ( 1.0 / 6.0 ) * ( a * a * a ) ;
}
float g0 ( float a ) {
return w0 ( a ) + w1 ( a ) ;
}
float g1 ( float a ) {
return w2 ( a ) + w3 ( a ) ;
}
float h0 ( float a ) {
return - 1.0 + w1 ( a ) / ( w0 ( a ) + w1 ( a ) ) ;
}
float h1 ( float a ) {
return 1.0 + w3 ( a ) / ( w2 ( a ) + w3 ( a ) ) ;
}
vec4 bicubic ( sampler2D tex , vec2 uv , vec4 texelSize , float lod ) {
uv = uv * texelSize . zw + 0.5 ;
vec2 iuv = floor ( uv ) ;
vec2 fuv = fract ( uv ) ;
float g0x = g0 ( fuv . x ) ;
float g1x = g1 ( fuv . x ) ;
float h0x = h0 ( fuv . x ) ;
float h1x = h1 ( fuv . x ) ;
float h0y = h0 ( fuv . y ) ;
float h1y = h1 ( fuv . y ) ;
vec2 p0 = ( vec2 ( iuv . x + h0x , iuv . y + h0y ) - 0.5 ) * texelSize . xy ;
vec2 p1 = ( vec2 ( iuv . x + h1x , iuv . y + h0y ) - 0.5 ) * texelSize . xy ;
vec2 p2 = ( vec2 ( iuv . x + h0x , iuv . y + h1y ) - 0.5 ) * texelSize . xy ;
vec2 p3 = ( vec2 ( iuv . x + h1x , iuv . y + h1y ) - 0.5 ) * texelSize . xy ;
return g0 ( fuv . y ) * ( g0x * textureLod ( tex , p0 , lod ) + g1x * textureLod ( tex , p1 , lod ) ) +
g1 ( fuv . y ) * ( g0x * textureLod ( tex , p2 , lod ) + g1x * textureLod ( tex , p3 , lod ) ) ;
}
vec4 textureBicubic ( sampler2D sampler , vec2 uv , float lod ) {
vec2 fLodSize = vec2 ( textureSize ( sampler , int ( lod ) ) ) ;
vec2 cLodSize = vec2 ( textureSize ( sampler , int ( lod + 1.0 ) ) ) ;
vec2 fLodSizeInv = 1.0 / fLodSize ;
vec2 cLodSizeInv = 1.0 / cLodSize ;
vec4 fSample = bicubic ( sampler , uv , vec4 ( fLodSizeInv , fLodSize ) , floor ( lod ) ) ;
vec4 cSample = bicubic ( sampler , uv , vec4 ( cLodSizeInv , cLodSize ) , ceil ( lod ) ) ;
return mix ( fSample , cSample , fract ( lod ) ) ;
}
vec3 getVolumeTransmissionRay ( const in vec3 n , const in vec3 v , const in float thickness , const in float ior , const in mat4 modelMatrix ) {
vec3 refractionVector = refract ( - v , normalize ( n ) , 1.0 / ior ) ;
vec3 modelScale ;
modelScale . x = length ( vec3 ( modelMatrix [ 0 ] . xyz ) ) ;
modelScale . y = length ( vec3 ( modelMatrix [ 1 ] . xyz ) ) ;
modelScale . z = length ( vec3 ( modelMatrix [ 2 ] . xyz ) ) ;
return normalize ( refractionVector ) * thickness * modelScale ;
}
float applyIorToRoughness ( const in float roughness , const in float ior ) {
return roughness * clamp ( ior * 2.0 - 2.0 , 0.0 , 1.0 ) ;
}
vec4 getTransmissionSample ( const in vec2 fragCoord , const in float roughness , const in float ior ) {
float lod = log2 ( transmissionSamplerSize . x ) * applyIorToRoughness ( roughness , ior ) ;
return textureBicubic ( transmissionSamplerMap , fragCoord . xy , lod ) ;
}
vec3 volumeAttenuation ( const in float transmissionDistance , const in vec3 attenuationColor , const in float attenuationDistance ) {
if ( isinf ( attenuationDistance ) ) {
return vec3 ( 1.0 ) ;
} else {
vec3 attenuationCoefficient = - log ( attenuationColor ) / attenuationDistance ;
vec3 transmittance = exp ( - attenuationCoefficient * transmissionDistance ) ; return transmittance ;
}
}
vec4 getIBLVolumeRefraction ( const in vec3 n , const in vec3 v , const in float roughness , const in vec3 diffuseColor ,
const in vec3 specularColor , const in float specularF90 , const in vec3 position , const in mat4 modelMatrix ,
const in mat4 viewMatrix , const in mat4 projMatrix , const in float dispersion , const in float ior , const in float thickness ,
const in vec3 attenuationColor , const in float attenuationDistance ) {
vec4 transmittedLight ;
vec3 transmittance ;
# ifdef USE _DISPERSION
float halfSpread = ( ior - 1.0 ) * 0.025 * dispersion ;
vec3 iors = vec3 ( ior - halfSpread , ior , ior + halfSpread ) ;
for ( int i = 0 ; i < 3 ; i ++ ) {
vec3 transmissionRay = getVolumeTransmissionRay ( n , v , thickness , iors [ i ] , modelMatrix ) ;
vec3 refractedRayExit = position + transmissionRay ;
vec4 ndcPos = projMatrix * viewMatrix * vec4 ( refractedRayExit , 1.0 ) ;
vec2 refractionCoords = ndcPos . xy / ndcPos . w ;
refractionCoords += 1.0 ;
refractionCoords /= 2.0 ;
vec4 transmissionSample = getTransmissionSample ( refractionCoords , roughness , iors [ i ] ) ;
transmittedLight [ i ] = transmissionSample [ i ] ;
transmittedLight . a += transmissionSample . a ;
transmittance [ i ] = diffuseColor [ i ] * volumeAttenuation ( length ( transmissionRay ) , attenuationColor , attenuationDistance ) [ i ] ;
}
transmittedLight . a /= 3.0 ;
# else
vec3 transmissionRay = getVolumeTransmissionRay ( n , v , thickness , ior , modelMatrix ) ;
vec3 refractedRayExit = position + transmissionRay ;
vec4 ndcPos = projMatrix * viewMatrix * vec4 ( refractedRayExit , 1.0 ) ;
vec2 refractionCoords = ndcPos . xy / ndcPos . w ;
refractionCoords += 1.0 ;
refractionCoords /= 2.0 ;
transmittedLight = getTransmissionSample ( refractionCoords , roughness , ior ) ;
transmittance = diffuseColor * volumeAttenuation ( length ( transmissionRay ) , attenuationColor , attenuationDistance ) ;
# endif
vec3 attenuatedColor = transmittance * transmittedLight . rgb ;
vec3 F = EnvironmentBRDF ( n , v , specularColor , specularF90 , roughness ) ;
float transmittanceFactor = ( transmittance . r + transmittance . g + transmittance . b ) / 3.0 ;
return vec4 ( ( 1.0 - F ) * attenuatedColor , 1.0 - ( 1.0 - transmittedLight . a ) * transmittanceFactor ) ;
}
2026-02-02 18:18:36 +08:00
# endif ` ,Yb= ` # if defined ( USE _UV ) || defined ( USE _ANISOTROPY )
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
# endif
# ifdef USE _MAP
varying vec2 vMapUv ;
# endif
# ifdef USE _ALPHAMAP
varying vec2 vAlphaMapUv ;
# endif
# ifdef USE _LIGHTMAP
varying vec2 vLightMapUv ;
# endif
# ifdef USE _AOMAP
varying vec2 vAoMapUv ;
# endif
# ifdef USE _BUMPMAP
varying vec2 vBumpMapUv ;
# endif
# ifdef USE _NORMALMAP
varying vec2 vNormalMapUv ;
# endif
# ifdef USE _EMISSIVEMAP
varying vec2 vEmissiveMapUv ;
# endif
# ifdef USE _METALNESSMAP
varying vec2 vMetalnessMapUv ;
# endif
# ifdef USE _ROUGHNESSMAP
varying vec2 vRoughnessMapUv ;
# endif
# ifdef USE _ANISOTROPYMAP
varying vec2 vAnisotropyMapUv ;
# endif
# ifdef USE _CLEARCOATMAP
varying vec2 vClearcoatMapUv ;
# endif
# ifdef USE _CLEARCOAT _NORMALMAP
varying vec2 vClearcoatNormalMapUv ;
# endif
# ifdef USE _CLEARCOAT _ROUGHNESSMAP
varying vec2 vClearcoatRoughnessMapUv ;
# endif
# ifdef USE _IRIDESCENCEMAP
varying vec2 vIridescenceMapUv ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
varying vec2 vIridescenceThicknessMapUv ;
# endif
# ifdef USE _SHEEN _COLORMAP
varying vec2 vSheenColorMapUv ;
# endif
# ifdef USE _SHEEN _ROUGHNESSMAP
varying vec2 vSheenRoughnessMapUv ;
# endif
# ifdef USE _SPECULARMAP
varying vec2 vSpecularMapUv ;
# endif
# ifdef USE _SPECULAR _COLORMAP
varying vec2 vSpecularColorMapUv ;
# endif
# ifdef USE _SPECULAR _INTENSITYMAP
varying vec2 vSpecularIntensityMapUv ;
# endif
# ifdef USE _TRANSMISSIONMAP
uniform mat3 transmissionMapTransform ;
varying vec2 vTransmissionMapUv ;
# endif
# ifdef USE _THICKNESSMAP
uniform mat3 thicknessMapTransform ;
varying vec2 vThicknessMapUv ;
2026-02-02 18:18:36 +08:00
# endif ` , $ b= ` # if defined ( USE _UV ) || defined ( USE _ANISOTROPY )
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
# endif
# ifdef USE _MAP
uniform mat3 mapTransform ;
varying vec2 vMapUv ;
# endif
# ifdef USE _ALPHAMAP
uniform mat3 alphaMapTransform ;
varying vec2 vAlphaMapUv ;
# endif
# ifdef USE _LIGHTMAP
uniform mat3 lightMapTransform ;
varying vec2 vLightMapUv ;
# endif
# ifdef USE _AOMAP
uniform mat3 aoMapTransform ;
varying vec2 vAoMapUv ;
# endif
# ifdef USE _BUMPMAP
uniform mat3 bumpMapTransform ;
varying vec2 vBumpMapUv ;
# endif
# ifdef USE _NORMALMAP
uniform mat3 normalMapTransform ;
varying vec2 vNormalMapUv ;
# endif
# ifdef USE _DISPLACEMENTMAP
uniform mat3 displacementMapTransform ;
varying vec2 vDisplacementMapUv ;
# endif
# ifdef USE _EMISSIVEMAP
uniform mat3 emissiveMapTransform ;
varying vec2 vEmissiveMapUv ;
# endif
# ifdef USE _METALNESSMAP
uniform mat3 metalnessMapTransform ;
varying vec2 vMetalnessMapUv ;
# endif
# ifdef USE _ROUGHNESSMAP
uniform mat3 roughnessMapTransform ;
varying vec2 vRoughnessMapUv ;
# endif
# ifdef USE _ANISOTROPYMAP
uniform mat3 anisotropyMapTransform ;
varying vec2 vAnisotropyMapUv ;
# endif
# ifdef USE _CLEARCOATMAP
uniform mat3 clearcoatMapTransform ;
varying vec2 vClearcoatMapUv ;
# endif
# ifdef USE _CLEARCOAT _NORMALMAP
uniform mat3 clearcoatNormalMapTransform ;
varying vec2 vClearcoatNormalMapUv ;
# endif
# ifdef USE _CLEARCOAT _ROUGHNESSMAP
uniform mat3 clearcoatRoughnessMapTransform ;
varying vec2 vClearcoatRoughnessMapUv ;
# endif
# ifdef USE _SHEEN _COLORMAP
uniform mat3 sheenColorMapTransform ;
varying vec2 vSheenColorMapUv ;
# endif
# ifdef USE _SHEEN _ROUGHNESSMAP
uniform mat3 sheenRoughnessMapTransform ;
varying vec2 vSheenRoughnessMapUv ;
# endif
# ifdef USE _IRIDESCENCEMAP
uniform mat3 iridescenceMapTransform ;
varying vec2 vIridescenceMapUv ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
uniform mat3 iridescenceThicknessMapTransform ;
varying vec2 vIridescenceThicknessMapUv ;
# endif
# ifdef USE _SPECULARMAP
uniform mat3 specularMapTransform ;
varying vec2 vSpecularMapUv ;
# endif
# ifdef USE _SPECULAR _COLORMAP
uniform mat3 specularColorMapTransform ;
varying vec2 vSpecularColorMapUv ;
# endif
# ifdef USE _SPECULAR _INTENSITYMAP
uniform mat3 specularIntensityMapTransform ;
varying vec2 vSpecularIntensityMapUv ;
# endif
# ifdef USE _TRANSMISSIONMAP
uniform mat3 transmissionMapTransform ;
varying vec2 vTransmissionMapUv ;
# endif
# ifdef USE _THICKNESSMAP
uniform mat3 thicknessMapTransform ;
varying vec2 vThicknessMapUv ;
2026-02-02 18:18:36 +08:00
# endif ` ,Kb= ` # if defined ( USE _UV ) || defined ( USE _ANISOTROPY )
2026-01-22 11:29:51 +08:00
vUv = vec3 ( uv , 1 ) . xy ;
# endif
# ifdef USE _MAP
vMapUv = ( mapTransform * vec3 ( MAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _ALPHAMAP
vAlphaMapUv = ( alphaMapTransform * vec3 ( ALPHAMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _LIGHTMAP
vLightMapUv = ( lightMapTransform * vec3 ( LIGHTMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _AOMAP
vAoMapUv = ( aoMapTransform * vec3 ( AOMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _BUMPMAP
vBumpMapUv = ( bumpMapTransform * vec3 ( BUMPMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _NORMALMAP
vNormalMapUv = ( normalMapTransform * vec3 ( NORMALMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _DISPLACEMENTMAP
vDisplacementMapUv = ( displacementMapTransform * vec3 ( DISPLACEMENTMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _EMISSIVEMAP
vEmissiveMapUv = ( emissiveMapTransform * vec3 ( EMISSIVEMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _METALNESSMAP
vMetalnessMapUv = ( metalnessMapTransform * vec3 ( METALNESSMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _ROUGHNESSMAP
vRoughnessMapUv = ( roughnessMapTransform * vec3 ( ROUGHNESSMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _ANISOTROPYMAP
vAnisotropyMapUv = ( anisotropyMapTransform * vec3 ( ANISOTROPYMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _CLEARCOATMAP
vClearcoatMapUv = ( clearcoatMapTransform * vec3 ( CLEARCOATMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _CLEARCOAT _NORMALMAP
vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3 ( CLEARCOAT _NORMALMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _CLEARCOAT _ROUGHNESSMAP
vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3 ( CLEARCOAT _ROUGHNESSMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _IRIDESCENCEMAP
vIridescenceMapUv = ( iridescenceMapTransform * vec3 ( IRIDESCENCEMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3 ( IRIDESCENCE _THICKNESSMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _SHEEN _COLORMAP
vSheenColorMapUv = ( sheenColorMapTransform * vec3 ( SHEEN _COLORMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _SHEEN _ROUGHNESSMAP
vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3 ( SHEEN _ROUGHNESSMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _SPECULARMAP
vSpecularMapUv = ( specularMapTransform * vec3 ( SPECULARMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _SPECULAR _COLORMAP
vSpecularColorMapUv = ( specularColorMapTransform * vec3 ( SPECULAR _COLORMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _SPECULAR _INTENSITYMAP
vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3 ( SPECULAR _INTENSITYMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _TRANSMISSIONMAP
vTransmissionMapUv = ( transmissionMapTransform * vec3 ( TRANSMISSIONMAP _UV , 1 ) ) . xy ;
# endif
# ifdef USE _THICKNESSMAP
vThicknessMapUv = ( thicknessMapTransform * vec3 ( THICKNESSMAP _UV , 1 ) ) . xy ;
2026-02-02 18:18:36 +08:00
# endif ` ,Jb= ` # if defined ( USE _ENVMAP ) || defined ( DISTANCE ) || defined ( USE _SHADOWMAP ) || defined ( USE _TRANSMISSION ) || NUM _SPOT _LIGHT _COORDS > 0
2026-01-22 11:29:51 +08:00
vec4 worldPosition = vec4 ( transformed , 1.0 ) ;
# ifdef USE _BATCHING
worldPosition = batchingMatrix * worldPosition ;
# endif
# ifdef USE _INSTANCING
worldPosition = instanceMatrix * worldPosition ;
# endif
worldPosition = modelMatrix * worldPosition ;
2026-02-02 18:18:36 +08:00
# endif ` ;const et={alphahash_fragment:e1,alphahash_pars_fragment:t1,alphamap_fragment:n1,alphamap_pars_fragment:i1,alphatest_fragment:s1,alphatest_pars_fragment:r1,aomap_fragment:a1,aomap_pars_fragment:o1,batching_pars_vertex:l1,batching_vertex:c1,begin_vertex:h1,beginnormal_vertex:u1,bsdfs:d1,iridescence_fragment:f1,bumpmap_pars_fragment:p1,clipping_planes_fragment:m1,clipping_planes_pars_fragment:g1,clipping_planes_pars_vertex:x1,clipping_planes_vertex:v1,color_fragment:b1,color_pars_fragment:y1,color_pars_vertex:_1,color_vertex:M1,common:w1,cube_uv_reflection_fragment:S1,defaultnormal_vertex:E1,displacementmap_pars_vertex:T1,displacementmap_vertex:C1,emissivemap_fragment:A1,emissivemap_pars_fragment:P1,colorspace_fragment:R1,colorspace_pars_fragment:L1,envmap_fragment:I1,envmap_common_pars_fragment:D1,envmap_pars_fragment:B1,envmap_pars_vertex:N1,envmap_physical_pars_fragment:j1,envmap_vertex:k1,fog_vertex:U1,fog_pars_vertex:O1,fog_fragment:F1,fog_pars_fragment:z1,gradientmap_pars_fragment:H1,lightmap_pars_fragment:V1,lights_lambert_fragment:G1,lights_lambert_pars_fragment:W1,lights_pars_begin:X1,lights_toon_fragment:q1,lights_toon_pars_fragment:Z1,lights_phong_fragment:Y1,lights_phong_pars_fragment: $ 1,lights_physical_fragment:K1,lights_physical_pars_fragment:J1,lights_fragment_begin:Q1,lights_fragment_maps:eb,lights_fragment_end:tb,logdepthbuf_fragment:nb,logdepthbuf_pars_fragment:ib,logdepthbuf_pars_vertex:sb,logdepthbuf_vertex:rb,map_fragment:ab,map_pars_fragment:ob,map_particle_fragment:lb,map_particle_pars_fragment:cb,metalnessmap_fragment:hb,metalnessmap_pars_fragment:ub,morphinstance_vertex:db,morphcolor_vertex:fb,morphnormal_vertex:pb,morphtarget_pars_vertex:mb,morphtarget_vertex:gb,normal_fragment_begin:xb,normal_fragment_maps:vb,normal_pars_fragment:bb,normal_pars_vertex:yb,normal_vertex:_b,normalmap_pars_fragment:Mb,clearcoat_normal_fragment_begin:wb,clearcoat_normal_fragment_maps:Sb,clearcoat_pars_fragment:Eb,iridescence_pars_fragment:Tb,opaque_fragment:Cb,packing:Ab,premultiplied_alpha_fragment:Pb,project_vertex:Rb,dithering_fragment:Lb,dithering_pars_fragment:Ib,roughnessmap_fragment:Db,roughnessmap_pars_fragment:Bb,shadowmap_pars_fragment:Nb,shadowmap_pars_vertex:kb,shadowmap_vertex:Ub,shadowmask_pars_fragment:Ob,skinbase_vertex:Fb,skinning_pars_vertex:zb,skinning_vertex:Hb,skinnormal_vertex:Vb,specularmap_fragment:Gb,specularmap_pars_fragment:Wb,tonemapping_fragment:Xb,tonemapping_pars_fragment:jb,transmission_fragment:qb,transmission_pars_fragment:Zb,uv_pars_fragment:Yb,uv_pars_vertex: $ b,uv_vertex:Kb,worldpos_vertex:Jb,background_vert: ` varying vec2 vUv ;
2026-01-22 11:29:51 +08:00
uniform mat3 uvTransform ;
void main ( ) {
vUv = ( uvTransform * vec3 ( uv , 1 ) ) . xy ;
gl _Position = vec4 ( position . xy , 1.0 , 1.0 ) ;
} ` ,background_frag: ` uniform sampler2D t2D ;
uniform float backgroundIntensity ;
varying vec2 vUv ;
void main ( ) {
vec4 texColor = texture2D ( t2D , vUv ) ;
# ifdef DECODE _VIDEO _TEXTURE
texColor = vec4 ( mix ( pow ( texColor . rgb * 0.9478672986 + vec3 ( 0.0521327014 ) , vec3 ( 2.4 ) ) , texColor . rgb * 0.0773993808 , vec3 ( lessThanEqual ( texColor . rgb , vec3 ( 0.04045 ) ) ) ) , texColor . w ) ;
# endif
texColor . rgb *= backgroundIntensity ;
gl _FragColor = texColor ;
# include < tonemapping _fragment >
# include < colorspace _fragment >
} ` ,backgroundCube_vert: ` varying vec3 vWorldDirection ;
# include < common >
void main ( ) {
vWorldDirection = transformDirection ( position , modelMatrix ) ;
# include < begin _vertex >
# include < project _vertex >
gl _Position . z = gl _Position . w ;
} ` ,backgroundCube_frag: ` # ifdef ENVMAP _TYPE _CUBE
uniform samplerCube envMap ;
# elif defined ( ENVMAP _TYPE _CUBE _UV )
uniform sampler2D envMap ;
# endif
uniform float flipEnvMap ;
uniform float backgroundBlurriness ;
uniform float backgroundIntensity ;
uniform mat3 backgroundRotation ;
varying vec3 vWorldDirection ;
# include < cube _uv _reflection _fragment >
void main ( ) {
# ifdef ENVMAP _TYPE _CUBE
vec4 texColor = textureCube ( envMap , backgroundRotation * vec3 ( flipEnvMap * vWorldDirection . x , vWorldDirection . yz ) ) ;
# elif defined ( ENVMAP _TYPE _CUBE _UV )
vec4 texColor = textureCubeUV ( envMap , backgroundRotation * vWorldDirection , backgroundBlurriness ) ;
# else
vec4 texColor = vec4 ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
# endif
texColor . rgb *= backgroundIntensity ;
gl _FragColor = texColor ;
# include < tonemapping _fragment >
# include < colorspace _fragment >
} ` ,cube_vert: ` varying vec3 vWorldDirection ;
# include < common >
void main ( ) {
vWorldDirection = transformDirection ( position , modelMatrix ) ;
# include < begin _vertex >
# include < project _vertex >
gl _Position . z = gl _Position . w ;
} ` ,cube_frag: ` uniform samplerCube tCube ;
uniform float tFlip ;
uniform float opacity ;
varying vec3 vWorldDirection ;
void main ( ) {
vec4 texColor = textureCube ( tCube , vec3 ( tFlip * vWorldDirection . x , vWorldDirection . yz ) ) ;
gl _FragColor = texColor ;
gl _FragColor . a *= opacity ;
# include < tonemapping _fragment >
# include < colorspace _fragment >
} ` ,depth_vert: ` # include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
varying vec2 vHighPrecisionZW ;
void main ( ) {
# include < uv _vertex >
# include < batching _vertex >
# include < skinbase _vertex >
# include < morphinstance _vertex >
# ifdef USE _DISPLACEMENTMAP
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinnormal _vertex >
# endif
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
vHighPrecisionZW = gl _Position . zw ;
} ` ,depth_frag: ` # if DEPTH _PACKING == 3200
uniform float opacity ;
# endif
# include < common >
# include < packing >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
varying vec2 vHighPrecisionZW ;
void main ( ) {
vec4 diffuseColor = vec4 ( 1.0 ) ;
# include < clipping _planes _fragment >
# if DEPTH _PACKING == 3200
diffuseColor . a = opacity ;
# endif
# include < map _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < logdepthbuf _fragment >
# ifdef USE _REVERSED _DEPTH _BUFFER
float fragCoordZ = vHighPrecisionZW [ 0 ] / vHighPrecisionZW [ 1 ] ;
# else
float fragCoordZ = 0.5 * vHighPrecisionZW [ 0 ] / vHighPrecisionZW [ 1 ] + 0.5 ;
# endif
# if DEPTH _PACKING == 3200
gl _FragColor = vec4 ( vec3 ( 1.0 - fragCoordZ ) , opacity ) ;
# elif DEPTH _PACKING == 3201
gl _FragColor = packDepthToRGBA ( fragCoordZ ) ;
# elif DEPTH _PACKING == 3202
gl _FragColor = vec4 ( packDepthToRGB ( fragCoordZ ) , 1.0 ) ;
# elif DEPTH _PACKING == 3203
gl _FragColor = vec4 ( packDepthToRG ( fragCoordZ ) , 0.0 , 1.0 ) ;
# endif
} ` ,distanceRGBA_vert: ` # define DISTANCE
varying vec3 vWorldPosition ;
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < batching _vertex >
# include < skinbase _vertex >
# include < morphinstance _vertex >
# ifdef USE _DISPLACEMENTMAP
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinnormal _vertex >
# endif
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < worldpos _vertex >
# include < clipping _planes _vertex >
vWorldPosition = worldPosition . xyz ;
} ` ,distanceRGBA_frag: ` # define DISTANCE
uniform vec3 referencePosition ;
uniform float nearDistance ;
uniform float farDistance ;
varying vec3 vWorldPosition ;
# include < common >
# include < packing >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( 1.0 ) ;
# include < clipping _planes _fragment >
# include < map _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
float dist = length ( vWorldPosition - referencePosition ) ;
dist = ( dist - nearDistance ) / ( farDistance - nearDistance ) ;
dist = saturate ( dist ) ;
gl _FragColor = packDepthToRGBA ( dist ) ;
} ` ,equirect_vert: ` varying vec3 vWorldDirection ;
# include < common >
void main ( ) {
vWorldDirection = transformDirection ( position , modelMatrix ) ;
# include < begin _vertex >
# include < project _vertex >
} ` ,equirect_frag: ` uniform sampler2D tEquirect ;
varying vec3 vWorldDirection ;
# include < common >
void main ( ) {
vec3 direction = normalize ( vWorldDirection ) ;
vec2 sampleUV = equirectUv ( direction ) ;
gl _FragColor = texture2D ( tEquirect , sampleUV ) ;
# include < tonemapping _fragment >
# include < colorspace _fragment >
} ` ,linedashed_vert: ` uniform float scale ;
attribute float lineDistance ;
varying float vLineDistance ;
# include < common >
# include < uv _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < morphtarget _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
vLineDistance = scale * lineDistance ;
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# include < fog _vertex >
} ` ,linedashed_frag: ` uniform vec3 diffuse ;
uniform float opacity ;
uniform float dashSize ;
uniform float totalSize ;
varying float vLineDistance ;
# include < common >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < fog _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
if ( mod ( vLineDistance , totalSize ) > dashSize ) {
discard ;
}
vec3 outgoingLight = vec3 ( 0.0 ) ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
outgoingLight = diffuseColor . rgb ;
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
} ` ,meshbasic_vert: ` # include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < envmap _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# if defined ( USE _ENVMAP ) || defined ( USE _SKINNING )
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# endif
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# include < worldpos _vertex >
# include < envmap _vertex >
# include < fog _vertex >
} ` ,meshbasic_frag: ` uniform vec3 diffuse ;
uniform float opacity ;
# ifndef FLAT _SHADED
varying vec3 vNormal ;
# endif
# include < common >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < aomap _pars _fragment >
# include < lightmap _pars _fragment >
# include < envmap _common _pars _fragment >
# include < envmap _pars _fragment >
# include < fog _pars _fragment >
# include < specularmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < specularmap _fragment >
ReflectedLight reflectedLight = ReflectedLight ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) ) ;
# ifdef USE _LIGHTMAP
vec4 lightMapTexel = texture2D ( lightMap , vLightMapUv ) ;
reflectedLight . indirectDiffuse += lightMapTexel . rgb * lightMapIntensity * RECIPROCAL _PI ;
# else
reflectedLight . indirectDiffuse += vec3 ( 1.0 ) ;
# endif
# include < aomap _fragment >
reflectedLight . indirectDiffuse *= diffuseColor . rgb ;
vec3 outgoingLight = reflectedLight . indirectDiffuse ;
# include < envmap _fragment >
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,meshlambert_vert: ` # define LAMBERT
varying vec3 vViewPosition ;
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < envmap _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < shadowmap _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
vViewPosition = - mvPosition . xyz ;
# include < worldpos _vertex >
# include < envmap _vertex >
# include < shadowmap _vertex >
# include < fog _vertex >
} ` ,meshlambert_frag: ` # define LAMBERT
uniform vec3 diffuse ;
uniform vec3 emissive ;
uniform float opacity ;
# include < common >
# include < packing >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < aomap _pars _fragment >
# include < lightmap _pars _fragment >
# include < emissivemap _pars _fragment >
# include < envmap _common _pars _fragment >
# include < envmap _pars _fragment >
# include < fog _pars _fragment >
# include < bsdfs >
# include < lights _pars _begin >
# include < normal _pars _fragment >
# include < lights _lambert _pars _fragment >
# include < shadowmap _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < specularmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
ReflectedLight reflectedLight = ReflectedLight ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) ) ;
vec3 totalEmissiveRadiance = emissive ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < specularmap _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
# include < emissivemap _fragment >
# include < lights _lambert _fragment >
# include < lights _fragment _begin >
# include < lights _fragment _maps >
# include < lights _fragment _end >
# include < aomap _fragment >
vec3 outgoingLight = reflectedLight . directDiffuse + reflectedLight . indirectDiffuse + totalEmissiveRadiance ;
# include < envmap _fragment >
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,meshmatcap_vert: ` # define MATCAP
varying vec3 vViewPosition ;
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < color _pars _vertex >
# include < displacementmap _pars _vertex >
# include < fog _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# include < fog _vertex >
vViewPosition = - mvPosition . xyz ;
} ` ,meshmatcap_frag: ` # define MATCAP
uniform vec3 diffuse ;
uniform float opacity ;
uniform sampler2D matcap ;
varying vec3 vViewPosition ;
# include < common >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < fog _pars _fragment >
# include < normal _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
vec3 viewDir = normalize ( vViewPosition ) ;
vec3 x = normalize ( vec3 ( viewDir . z , 0.0 , - viewDir . x ) ) ;
vec3 y = cross ( viewDir , x ) ;
vec2 uv = vec2 ( dot ( x , normal ) , dot ( y , normal ) ) * 0.495 + 0.5 ;
# ifdef USE _MATCAP
vec4 matcapColor = texture2D ( matcap , uv ) ;
# else
vec4 matcapColor = vec4 ( vec3 ( mix ( 0.2 , 0.8 , uv . y ) ) , 1.0 ) ;
# endif
vec3 outgoingLight = diffuseColor . rgb * matcapColor . rgb ;
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,meshnormal_vert: ` # define NORMAL
# if defined ( FLAT _SHADED ) || defined ( USE _BUMPMAP ) || defined ( USE _NORMALMAP _TANGENTSPACE )
varying vec3 vViewPosition ;
# endif
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphinstance _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# if defined ( FLAT _SHADED ) || defined ( USE _BUMPMAP ) || defined ( USE _NORMALMAP _TANGENTSPACE )
vViewPosition = - mvPosition . xyz ;
# endif
} ` ,meshnormal_frag: ` # define NORMAL
uniform float opacity ;
# if defined ( FLAT _SHADED ) || defined ( USE _BUMPMAP ) || defined ( USE _NORMALMAP _TANGENTSPACE )
varying vec3 vViewPosition ;
# endif
# include < packing >
# include < uv _pars _fragment >
# include < normal _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( 0.0 , 0.0 , 0.0 , opacity ) ;
# include < clipping _planes _fragment >
# include < logdepthbuf _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
gl _FragColor = vec4 ( packNormalToRGB ( normal ) , diffuseColor . a ) ;
# ifdef OPAQUE
gl _FragColor . a = 1.0 ;
# endif
} ` ,meshphong_vert: ` # define PHONG
varying vec3 vViewPosition ;
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < envmap _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < shadowmap _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphinstance _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
vViewPosition = - mvPosition . xyz ;
# include < worldpos _vertex >
# include < envmap _vertex >
# include < shadowmap _vertex >
# include < fog _vertex >
} ` ,meshphong_frag: ` # define PHONG
uniform vec3 diffuse ;
uniform vec3 emissive ;
uniform vec3 specular ;
uniform float shininess ;
uniform float opacity ;
# include < common >
# include < packing >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < aomap _pars _fragment >
# include < lightmap _pars _fragment >
# include < emissivemap _pars _fragment >
# include < envmap _common _pars _fragment >
# include < envmap _pars _fragment >
# include < fog _pars _fragment >
# include < bsdfs >
# include < lights _pars _begin >
# include < normal _pars _fragment >
# include < lights _phong _pars _fragment >
# include < shadowmap _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < specularmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
ReflectedLight reflectedLight = ReflectedLight ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) ) ;
vec3 totalEmissiveRadiance = emissive ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < specularmap _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
# include < emissivemap _fragment >
# include < lights _phong _fragment >
# include < lights _fragment _begin >
# include < lights _fragment _maps >
# include < lights _fragment _end >
# include < aomap _fragment >
vec3 outgoingLight = reflectedLight . directDiffuse + reflectedLight . indirectDiffuse + reflectedLight . directSpecular + reflectedLight . indirectSpecular + totalEmissiveRadiance ;
# include < envmap _fragment >
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,meshphysical_vert: ` # define STANDARD
varying vec3 vViewPosition ;
# ifdef USE _TRANSMISSION
varying vec3 vWorldPosition ;
# endif
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < shadowmap _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
vViewPosition = - mvPosition . xyz ;
# include < worldpos _vertex >
# include < shadowmap _vertex >
# include < fog _vertex >
# ifdef USE _TRANSMISSION
vWorldPosition = worldPosition . xyz ;
# endif
} ` ,meshphysical_frag: ` # define STANDARD
# ifdef PHYSICAL
# define IOR
# define USE _SPECULAR
# endif
uniform vec3 diffuse ;
uniform vec3 emissive ;
uniform float roughness ;
uniform float metalness ;
uniform float opacity ;
# ifdef IOR
uniform float ior ;
# endif
# ifdef USE _SPECULAR
uniform float specularIntensity ;
uniform vec3 specularColor ;
# ifdef USE _SPECULAR _COLORMAP
uniform sampler2D specularColorMap ;
# endif
# ifdef USE _SPECULAR _INTENSITYMAP
uniform sampler2D specularIntensityMap ;
# endif
# endif
# ifdef USE _CLEARCOAT
uniform float clearcoat ;
uniform float clearcoatRoughness ;
# endif
# ifdef USE _DISPERSION
uniform float dispersion ;
# endif
# ifdef USE _IRIDESCENCE
uniform float iridescence ;
uniform float iridescenceIOR ;
uniform float iridescenceThicknessMinimum ;
uniform float iridescenceThicknessMaximum ;
# endif
# ifdef USE _SHEEN
uniform vec3 sheenColor ;
uniform float sheenRoughness ;
# ifdef USE _SHEEN _COLORMAP
uniform sampler2D sheenColorMap ;
# endif
# ifdef USE _SHEEN _ROUGHNESSMAP
uniform sampler2D sheenRoughnessMap ;
# endif
# endif
# ifdef USE _ANISOTROPY
uniform vec2 anisotropyVector ;
# ifdef USE _ANISOTROPYMAP
uniform sampler2D anisotropyMap ;
# endif
# endif
varying vec3 vViewPosition ;
# include < common >
# include < packing >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < aomap _pars _fragment >
# include < lightmap _pars _fragment >
# include < emissivemap _pars _fragment >
# include < iridescence _fragment >
# include < cube _uv _reflection _fragment >
# include < envmap _common _pars _fragment >
# include < envmap _physical _pars _fragment >
# include < fog _pars _fragment >
# include < lights _pars _begin >
# include < normal _pars _fragment >
# include < lights _physical _pars _fragment >
# include < transmission _pars _fragment >
# include < shadowmap _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < clearcoat _pars _fragment >
# include < iridescence _pars _fragment >
# include < roughnessmap _pars _fragment >
# include < metalnessmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
ReflectedLight reflectedLight = ReflectedLight ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) ) ;
vec3 totalEmissiveRadiance = emissive ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < roughnessmap _fragment >
# include < metalnessmap _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
# include < clearcoat _normal _fragment _begin >
# include < clearcoat _normal _fragment _maps >
# include < emissivemap _fragment >
# include < lights _physical _fragment >
# include < lights _fragment _begin >
# include < lights _fragment _maps >
# include < lights _fragment _end >
# include < aomap _fragment >
vec3 totalDiffuse = reflectedLight . directDiffuse + reflectedLight . indirectDiffuse ;
vec3 totalSpecular = reflectedLight . directSpecular + reflectedLight . indirectSpecular ;
# include < transmission _fragment >
vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance ;
# ifdef USE _SHEEN
float sheenEnergyComp = 1.0 - 0.157 * max3 ( material . sheenColor ) ;
outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect ;
# endif
# ifdef USE _CLEARCOAT
float dotNVcc = saturate ( dot ( geometryClearcoatNormal , geometryViewDir ) ) ;
vec3 Fcc = F _Schlick ( material . clearcoatF0 , material . clearcoatF90 , dotNVcc ) ;
outgoingLight = outgoingLight * ( 1.0 - material . clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material . clearcoat ;
# endif
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,meshtoon_vert: ` # define TOON
varying vec3 vViewPosition ;
# include < common >
# include < batching _pars _vertex >
# include < uv _pars _vertex >
# include < displacementmap _pars _vertex >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < normal _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < shadowmap _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < normal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < displacementmap _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
vViewPosition = - mvPosition . xyz ;
# include < worldpos _vertex >
# include < shadowmap _vertex >
# include < fog _vertex >
} ` ,meshtoon_frag: ` # define TOON
uniform vec3 diffuse ;
uniform vec3 emissive ;
uniform float opacity ;
# include < common >
# include < packing >
# include < dithering _pars _fragment >
# include < color _pars _fragment >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < aomap _pars _fragment >
# include < lightmap _pars _fragment >
# include < emissivemap _pars _fragment >
# include < gradientmap _pars _fragment >
# include < fog _pars _fragment >
# include < bsdfs >
# include < lights _pars _begin >
# include < normal _pars _fragment >
# include < lights _toon _pars _fragment >
# include < shadowmap _pars _fragment >
# include < bumpmap _pars _fragment >
# include < normalmap _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
ReflectedLight reflectedLight = ReflectedLight ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) , vec3 ( 0.0 ) ) ;
vec3 totalEmissiveRadiance = emissive ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < color _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
# include < normal _fragment _begin >
# include < normal _fragment _maps >
# include < emissivemap _fragment >
# include < lights _toon _fragment >
# include < lights _fragment _begin >
# include < lights _fragment _maps >
# include < lights _fragment _end >
# include < aomap _fragment >
vec3 outgoingLight = reflectedLight . directDiffuse + reflectedLight . indirectDiffuse + totalEmissiveRadiance ;
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
# include < dithering _fragment >
} ` ,points_vert: ` uniform float size ;
uniform float scale ;
# include < common >
# include < color _pars _vertex >
# include < fog _pars _vertex >
# include < morphtarget _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
# ifdef USE _POINTS _UV
varying vec2 vUv ;
uniform mat3 uvTransform ;
# endif
void main ( ) {
# ifdef USE _POINTS _UV
vUv = ( uvTransform * vec3 ( uv , 1 ) ) . xy ;
# endif
# include < color _vertex >
# include < morphinstance _vertex >
# include < morphcolor _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < project _vertex >
gl _PointSize = size ;
# ifdef USE _SIZEATTENUATION
bool isPerspective = isPerspectiveMatrix ( projectionMatrix ) ;
if ( isPerspective ) gl _PointSize *= ( scale / - mvPosition . z ) ;
# endif
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# include < worldpos _vertex >
# include < fog _vertex >
} ` ,points_frag: ` uniform vec3 diffuse ;
uniform float opacity ;
# include < common >
# include < color _pars _fragment >
# include < map _particle _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < fog _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
vec3 outgoingLight = vec3 ( 0.0 ) ;
# include < logdepthbuf _fragment >
# include < map _particle _fragment >
# include < color _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
outgoingLight = diffuseColor . rgb ;
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
# include < premultiplied _alpha _fragment >
} ` ,shadow_vert: ` # include < common >
# include < batching _pars _vertex >
# include < fog _pars _vertex >
# include < morphtarget _pars _vertex >
# include < skinning _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < shadowmap _pars _vertex >
void main ( ) {
# include < batching _vertex >
# include < beginnormal _vertex >
# include < morphinstance _vertex >
# include < morphnormal _vertex >
# include < skinbase _vertex >
# include < skinnormal _vertex >
# include < defaultnormal _vertex >
# include < begin _vertex >
# include < morphtarget _vertex >
# include < skinning _vertex >
# include < project _vertex >
# include < logdepthbuf _vertex >
# include < worldpos _vertex >
# include < shadowmap _vertex >
# include < fog _vertex >
} ` ,shadow_frag: ` uniform vec3 color ;
uniform float opacity ;
# include < common >
# include < packing >
# include < fog _pars _fragment >
# include < bsdfs >
# include < lights _pars _begin >
# include < logdepthbuf _pars _fragment >
# include < shadowmap _pars _fragment >
# include < shadowmask _pars _fragment >
void main ( ) {
# include < logdepthbuf _fragment >
gl _FragColor = vec4 ( color , opacity * ( 1.0 - getShadowMask ( ) ) ) ;
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
} ` ,sprite_vert: ` uniform float rotation ;
uniform vec2 center ;
# include < common >
# include < uv _pars _vertex >
# include < fog _pars _vertex >
# include < logdepthbuf _pars _vertex >
# include < clipping _planes _pars _vertex >
void main ( ) {
# include < uv _vertex >
vec4 mvPosition = modelViewMatrix [ 3 ] ;
vec2 scale = vec2 ( length ( modelMatrix [ 0 ] . xyz ) , length ( modelMatrix [ 1 ] . xyz ) ) ;
# ifndef USE _SIZEATTENUATION
bool isPerspective = isPerspectiveMatrix ( projectionMatrix ) ;
if ( isPerspective ) scale *= - mvPosition . z ;
# endif
vec2 alignedPosition = ( position . xy - ( center - vec2 ( 0.5 ) ) ) * scale ;
vec2 rotatedPosition ;
rotatedPosition . x = cos ( rotation ) * alignedPosition . x - sin ( rotation ) * alignedPosition . y ;
rotatedPosition . y = sin ( rotation ) * alignedPosition . x + cos ( rotation ) * alignedPosition . y ;
mvPosition . xy += rotatedPosition ;
gl _Position = projectionMatrix * mvPosition ;
# include < logdepthbuf _vertex >
# include < clipping _planes _vertex >
# include < fog _vertex >
} ` ,sprite_frag: ` uniform vec3 diffuse ;
uniform float opacity ;
# include < common >
# include < uv _pars _fragment >
# include < map _pars _fragment >
# include < alphamap _pars _fragment >
# include < alphatest _pars _fragment >
# include < alphahash _pars _fragment >
# include < fog _pars _fragment >
# include < logdepthbuf _pars _fragment >
# include < clipping _planes _pars _fragment >
void main ( ) {
vec4 diffuseColor = vec4 ( diffuse , opacity ) ;
# include < clipping _planes _fragment >
vec3 outgoingLight = vec3 ( 0.0 ) ;
# include < logdepthbuf _fragment >
# include < map _fragment >
# include < alphamap _fragment >
# include < alphatest _fragment >
# include < alphahash _fragment >
outgoingLight = diffuseColor . rgb ;
# include < opaque _fragment >
# include < tonemapping _fragment >
# include < colorspace _fragment >
# include < fog _fragment >
2026-02-02 18:18:36 +08:00
} ` },Pe={common:{diffuse:{value:new ke(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new $ e},alphaMap:{value:null},alphaMapTransform:{value:new $ e},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new $ e}},envmap:{envMap:{value:null},envMapRotation:{value:new $ e},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98},dfgLUT:{value:null}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new $ e}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new $ e}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new $ e},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new $ e},normalScale:{value:new ce(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new $ e},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new $ e}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new $ e}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new $ e}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new ke(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new ke(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new $ e},alphaTest:{value:0},uvTransform:{value:new $ e}},sprite:{diffuse:{value:new ke(16777215)},opacity:{value:1},center:{value:new ce(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new $ e},alphaMap:{value:null},alphaMapTransform:{value:new $ e},alphaTest:{value:0}}},ci={basic:{uniforms:ln([Pe.common,Pe.specularmap,Pe.envmap,Pe.aomap,Pe.lightmap,Pe.fog]),vertexShader:et.meshbasic_vert,fragmentShader:et.meshbasic_frag},lambert:{uniforms:ln([Pe.common,Pe.specularmap,Pe.envmap,Pe.aomap,Pe.lightmap,Pe.emissivemap,Pe.bumpmap,Pe.normalmap,Pe.displacementmap,Pe.fog,Pe.lights,{emissive:{value:new ke(0)}}]),vertexShader:et.meshlambert_vert,fragmentShader:et.meshlambert_frag},phong:{uniforms:ln([Pe.common,Pe.specularmap,Pe.envmap,Pe.aomap,Pe.lightmap,Pe.emissivemap,Pe.bumpmap,Pe.normalmap,Pe.displacementmap,Pe.fog,Pe.lights,{emissive:{value:new ke(0)},specular:{value:new ke(1118481)},shininess:{value:30}}]),vertexShader:et.meshphong_vert,fragmentShader:et.meshphong_frag},standard:{uniforms:ln([Pe.common,Pe.envmap,Pe.aomap,Pe.lightmap,Pe.emissivemap,Pe.bumpmap,Pe.normalmap,Pe.displacementmap,Pe.roughnessmap,Pe.metalnessmap,Pe.fog,Pe.lights,{emissive:{value:new ke(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:et.meshphysical_vert,fragmentShader:et.meshphysical_frag},toon:{uniforms:ln([Pe.common,Pe.aomap,Pe.lightmap,Pe.emissivemap,Pe.bumpmap,Pe.normalmap,Pe.displacementmap,Pe.gradientmap,Pe.fog,Pe.lights,{emissive:{value:new ke(0
2026-01-22 11:29:51 +08:00
precision highp float ;
precision highp int ;
varying vec3 vOutputDirection ;
uniform sampler2D envMap ;
uniform float roughness ;
uniform float mipInt ;
# define ENVMAP _TYPE _CUBE _UV
# include < cube _uv _reflection _fragment >
# define PI 3.14159265359
// Van der Corput radical inverse
float radicalInverse _VdC ( uint bits ) {
bits = ( bits << 16 u ) | ( bits >> 16 u ) ;
bits = ( ( bits & 0x55555555 u ) << 1 u ) | ( ( bits & 0xAAAAAAAA u ) >> 1 u ) ;
bits = ( ( bits & 0x33333333 u ) << 2 u ) | ( ( bits & 0xCCCCCCCC u ) >> 2 u ) ;
bits = ( ( bits & 0x0F0F0F0F u ) << 4 u ) | ( ( bits & 0xF0F0F0F0 u ) >> 4 u ) ;
bits = ( ( bits & 0x00FF00FF u ) << 8 u ) | ( ( bits & 0xFF00FF00 u ) >> 8 u ) ;
return float ( bits ) * 2.3283064365386963 e - 10 ; // / 0x100000000
}
// Hammersley sequence
vec2 hammersley ( uint i , uint N ) {
return vec2 ( float ( i ) / float ( N ) , radicalInverse _VdC ( i ) ) ;
}
// GGX VNDF importance sampling (Eric Heitz 2018)
// "Sampling the GGX Distribution of Visible Normals"
// https://jcgt.org/published/0007/04/01/
vec3 importanceSampleGGX _VNDF ( vec2 Xi , vec3 V , float roughness ) {
float alpha = roughness * roughness ;
// Section 3.2: Transform view direction to hemisphere configuration
vec3 Vh = normalize ( vec3 ( alpha * V . x , alpha * V . y , V . z ) ) ;
// Section 4.1: Orthonormal basis
float lensq = Vh . x * Vh . x + Vh . y * Vh . y ;
vec3 T1 = lensq > 0.0 ? vec3 ( - Vh . y , Vh . x , 0.0 ) / sqrt ( lensq ) : vec3 ( 1.0 , 0.0 , 0.0 ) ;
vec3 T2 = cross ( Vh , T1 ) ;
// Section 4.2: Parameterization of projected area
float r = sqrt ( Xi . x ) ;
float phi = 2.0 * PI * Xi . y ;
float t1 = r * cos ( phi ) ;
float t2 = r * sin ( phi ) ;
float s = 0.5 * ( 1.0 + Vh . z ) ;
t2 = ( 1.0 - s ) * sqrt ( 1.0 - t1 * t1 ) + s * t2 ;
// Section 4.3: Reprojection onto hemisphere
vec3 Nh = t1 * T1 + t2 * T2 + sqrt ( max ( 0.0 , 1.0 - t1 * t1 - t2 * t2 ) ) * Vh ;
// Section 3.4: Transform back to ellipsoid configuration
return normalize ( vec3 ( alpha * Nh . x , alpha * Nh . y , max ( 0.0 , Nh . z ) ) ) ;
}
void main ( ) {
vec3 N = normalize ( vOutputDirection ) ;
vec3 V = N ; // Assume view direction equals normal for pre-filtering
vec3 prefilteredColor = vec3 ( 0.0 ) ;
float totalWeight = 0.0 ;
// For very low roughness, just sample the environment directly
if ( roughness < 0.001 ) {
gl _FragColor = vec4 ( bilinearCubeUV ( envMap , N , mipInt ) , 1.0 ) ;
return ;
}
// Tangent space basis for VNDF sampling
vec3 up = abs ( N . z ) < 0.999 ? vec3 ( 0.0 , 0.0 , 1.0 ) : vec3 ( 1.0 , 0.0 , 0.0 ) ;
vec3 tangent = normalize ( cross ( up , N ) ) ;
vec3 bitangent = cross ( N , tangent ) ;
for ( uint i = 0 u ; i < uint ( GGX _SAMPLES ) ; i ++ ) {
vec2 Xi = hammersley ( i , uint ( GGX _SAMPLES ) ) ;
// For PMREM, V = N, so in tangent space V is always (0, 0, 1)
vec3 H _tangent = importanceSampleGGX _VNDF ( Xi , vec3 ( 0.0 , 0.0 , 1.0 ) , roughness ) ;
// Transform H back to world space
vec3 H = normalize ( tangent * H _tangent . x + bitangent * H _tangent . y + N * H _tangent . z ) ;
vec3 L = normalize ( 2.0 * dot ( V , H ) * H - V ) ;
float NdotL = max ( dot ( N , L ) , 0.0 ) ;
if ( NdotL > 0.0 ) {
// Sample environment at fixed mip level
// VNDF importance sampling handles the distribution filtering
vec3 sampleColor = bilinearCubeUV ( envMap , L , mipInt ) ;
// Weight by NdotL for the split-sum approximation
// VNDF PDF naturally accounts for the visible microfacet distribution
prefilteredColor += sampleColor * NdotL ;
totalWeight += NdotL ;
}
}
if ( totalWeight > 0.0 ) {
prefilteredColor = prefilteredColor / totalWeight ;
}
gl _FragColor = vec4 ( prefilteredColor , 1.0 ) ;
}
2026-02-02 18:18:36 +08:00
` ,blending:Xt,depthTest:!1,depthWrite:!1})}function hy(s,e,t){const n=new Float32Array(ps),i=new R(0,1,0);return new kt({name:"SphericalGaussianBlur",defines:{n:ps,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP: ` $ { s } . 0 ` },uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:Ho(),fragmentShader: `
2026-01-22 11:29:51 +08:00
precision mediump float ;
precision mediump int ;
varying vec3 vOutputDirection ;
uniform sampler2D envMap ;
uniform int samples ;
uniform float weights [ n ] ;
uniform bool latitudinal ;
uniform float dTheta ;
uniform float mipInt ;
uniform vec3 poleAxis ;
# define ENVMAP _TYPE _CUBE _UV
# include < cube _uv _reflection _fragment >
vec3 getSample ( float theta , vec3 axis ) {
float cosTheta = cos ( theta ) ;
// Rodrigues' axis-angle rotation
vec3 sampleDirection = vOutputDirection * cosTheta
+ cross ( axis , vOutputDirection ) * sin ( theta )
+ axis * dot ( axis , vOutputDirection ) * ( 1.0 - cosTheta ) ;
return bilinearCubeUV ( envMap , sampleDirection , mipInt ) ;
}
void main ( ) {
vec3 axis = latitudinal ? poleAxis : cross ( poleAxis , vOutputDirection ) ;
if ( all ( equal ( axis , vec3 ( 0.0 ) ) ) ) {
axis = vec3 ( vOutputDirection . z , 0.0 , - vOutputDirection . x ) ;
}
axis = normalize ( axis ) ;
gl _FragColor = vec4 ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
gl _FragColor . rgb += weights [ 0 ] * getSample ( 0.0 , axis ) ;
for ( int i = 1 ; i < n ; i ++ ) {
if ( i >= samples ) {
break ;
}
float theta = dTheta * float ( i ) ;
gl _FragColor . rgb += weights [ i ] * getSample ( - 1.0 * theta , axis ) ;
gl _FragColor . rgb += weights [ i ] * getSample ( theta , axis ) ;
}
}
2026-02-02 18:18:36 +08:00
` ,blending:Xt,depthTest:!1,depthWrite:!1})}function cp(){return new kt({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Ho(),fragmentShader: `
2026-01-22 11:29:51 +08:00
precision mediump float ;
precision mediump int ;
varying vec3 vOutputDirection ;
uniform sampler2D envMap ;
# include < common >
void main ( ) {
vec3 outputDirection = normalize ( vOutputDirection ) ;
vec2 uv = equirectUv ( outputDirection ) ;
gl _FragColor = vec4 ( texture2D ( envMap , uv ) . rgb , 1.0 ) ;
}
2026-02-02 18:18:36 +08:00
` ,blending:Xt,depthTest:!1,depthWrite:!1})}function hp(){return new kt({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Ho(),fragmentShader: `
2026-01-22 11:29:51 +08:00
precision mediump float ;
precision mediump int ;
uniform float flipEnvMap ;
varying vec3 vOutputDirection ;
uniform samplerCube envMap ;
void main ( ) {
gl _FragColor = textureCube ( envMap , vec3 ( flipEnvMap * vOutputDirection . x , vOutputDirection . yz ) ) ;
}
2026-02-02 18:18:36 +08:00
` ,blending:Xt,depthTest:!1,depthWrite:!1})}function Ho(){return `
2026-01-22 11:29:51 +08:00
precision mediump float ;
precision mediump int ;
attribute float faceIndex ;
varying vec3 vOutputDirection ;
// RH coordinate system; PMREM face-indexing convention
vec3 getDirection ( vec2 uv , float face ) {
uv = 2.0 * uv - 1.0 ;
vec3 direction = vec3 ( uv , 1.0 ) ;
if ( face == 0.0 ) {
direction = direction . zyx ; // ( 1, v, u ) pos x
} else if ( face == 1.0 ) {
direction = direction . xzy ;
direction . xz *= - 1.0 ; // ( -u, 1, -v ) pos y
} else if ( face == 2.0 ) {
direction . x *= - 1.0 ; // ( -u, v, 1 ) pos z
} else if ( face == 3.0 ) {
direction = direction . zyx ;
direction . xz *= - 1.0 ; // ( -1, v, -u ) neg x
} else if ( face == 4.0 ) {
direction = direction . xzy ;
direction . xy *= - 1.0 ; // ( -u, -1, v ) neg y
} else if ( face == 5.0 ) {
direction . z *= - 1.0 ; // ( u, v, -1 ) neg z
}
return direction ;
}
void main ( ) {
vOutputDirection = getDirection ( uv , faceIndex ) ;
gl _Position = vec4 ( position , 1.0 ) ;
}
2026-02-02 18:18:36 +08:00
` }function uy(s){let e=new WeakMap,t=null;function n(o){if(o&&o.isTexture){const l=o.mapping,c=l===nc||l===ic,h=l===Fs||l===zs;if(c||h){let u=e.get(o);const f=u!==void 0?u.texture.pmremVersion:0;if(o.isRenderTargetTexture&&o.pmremVersion!==f)return t===null&&(t=new op(s)),u=c?t.fromEquirectangular(o,u):t.fromCubemap(o,u),u.texture.pmremVersion=o.pmremVersion,e.set(o,u),u.texture;if(u!==void 0)return u.texture;{const d=o.image;return c&&d&&d.height>0||h&&d&&i(d)?(t===null&&(t=new op(s)),u=c?t.fromEquirectangular(o):t.fromCubemap(o),u.texture.pmremVersion=o.pmremVersion,e.set(o,u),o.addEventListener("dispose",r),u.texture):null}}}return o}function i(o){let l=0;const c=6;for(let h=0;h<c;h++)o[h]!==void 0&&l++;return l===c}function r(o){const l=o.target;l.removeEventListener("dispose",r);const c=e.get(l);c!==void 0&&(e.delete(l),c.dispose())}function a(){e=new WeakMap,t!==null&&(t.dispose(),t=null)}return{get:n,dispose:a}}function dy(s){const e={};function t(n){if(e[n]!==void 0)return e[n];const i=s.getExtension(n);return e[n]=i,i}return{has:function(n){return t(n)!==null},init:function(){t("EXT_color_buffer_float"),t("WEBGL_clip_cull_distance"),t("OES_texture_float_linear"),t("EXT_color_buffer_half_float"),t("WEBGL_multisampled_render_to_texture"),t("WEBGL_render_shared_exponent")},get:function(n){const i=t(n);return i===null&&Jr("WebGLRenderer: "+n+" extension not supported."),i}}}function fy(s,e,t,n){const i={},r=new WeakMap;function a(u){const f=u.target;f.index!==null&&e.remove(f.index);for(const m in f.attributes)e.remove(f.attributes[m]);f.removeEventListener("dispose",a),delete i[f.id];const d=r.get(f);d&&(e.remove(d),r.delete(f)),n.releaseStatesOfGeometry(f),f.isInstancedBufferGeometry===!0&&delete f._maxInstanceCount,t.memory.geometries--}function o(u,f){return i[f.id]===!0||(f.addEventListener("dispose",a),i[f.id]=!0,t.memory.geometries++),f}function l(u){const f=u.attributes;for(const d in f)e.update(f[d],s.ARRAY_BUFFER)}function c(u){const f=[],d=u.index,m=u.attributes.position;let p=0;if(d!==null){const b=d.array;p=d.version;for(let v=0,y=b.length;v<y;v+=3){const M=b[v+0],E=b[v+1],C=b[v+2];f.push(M,E,E,C,C,M)}}else if(m!==void 0){const b=m.array;p=m.version;for(let v=0,y=b.length/3-1;v<y;v+=3){const M=v+0,E=v+1,C=v+2;f.push(M,E,E,C,C,M)}}else return;const x=new(Nd(f)?Jd:Kd)(f,1);x.version=p;const g=r.get(u);g&&e.remove(g),r.set(u,x)}function h(u){const f=r.get(u);if(f){const d=u.index;d!==null&&f.version<d.version&&c(u)}else c(u);return r.get(u)}return{get:o,update:l,getWireframeAttribute:h}}function py(s,e,t){let n;function i(f){n=f}let r,a;function o(f){r=f.type,a=f.bytesPerElement}function l(f,d){s.drawElements(n,d,r,f*a),t.update(d,n,1)}function c(f,d,m){m!==0&&(s.drawElementsInstanced(n,d,r,f*a,m),t.update(d,n,m))}function h(f,d,m){if(m===0)return;e.get("WEBGL_multi_draw").multiDrawElementsWEBGL(n,d,0,r,f,0,m);let x=0;for(let g=0;g<m;g++)x+=d[g];t.update(x,n,1)}function u(f,d,m,p){if(m===0)return;const x=e.get("WEBGL_multi_draw");if(x===null)for(let g=0;g<f.length;g++)c(f[g]/a,d[g],p[g]);else{x.multiDrawElementsInstancedWEBGL(n,d,0,r,f,0,p,0,m);let g=0;for(let b=0;b<m;b++)g+=d[b]*p[b];t.update(g,n,1)}}this.setMode=i,this.setIndex=o,this.render=l,this.renderInstances=c,this.renderMultiDraw=h,this.renderMultiDrawInstances=u}function my(s){const e={geometries:0,textures:0},t={frame:0,calls:0,triangles:0,points:0,lines:0};function n(r,a,o){switch(t.calls++,a){case s.TRIANGLES:t.triangles+=o*(r/3);break;case s.LINES:t.lines+=o*(r/2);break;case s.LINE_STRIP:t.lines+=o*(r-1);break;case s.LINE_LOOP:t.lines+=o*r;break;case s.POINTS:t.points+=o*r;break;default:Qe("WebGLInfo: Unknown draw mode:",a);break}}function i(){t.calls=0,t.triangles=0,t.points=0,t.lines=0}return{memory:e,render:t,programs:null,autoReset:!0,reset:i,update:n}}function gy(s,e,t){const n=new WeakMap,i=new tt;function r(a,o,l){const c=a.morphTargetInfluences,h=o.morphAttributes.position||o.morphAttributes.normal||o.morphAttributes.color,u=h!==void 0?h.length:0;let f=n.get(o);if(f===void 0||f.count!==u){let _=function(){C.dispose(),n.delete(o),o.r
2026-02-02 16:36:17 +08:00
` ),n=[],i=Math.max(e-6,0),r=Math.min(e+6,t.length);for(let a=i;a<r;a++){const o=a+1;n.push( ` $ { o === e ? ">" : " " } $ { o } : $ { t [ a ] } ` )}return n.join( `
2026-02-02 18:18:36 +08:00
` )}const wp=new $ e;function u_(s){it._getMatrix(wp,it.workingColorSpace,s);const e= ` mat3 ( $ { wp . elements . map ( t => t . toFixed ( 4 ) ) } ) ` ;switch(it.getTransfer(s)){case Qa:return[e,"LinearTransferOETF"];case lt:return[e,"sRGBTransferOETF"];default:return He("WebGLProgram: Unsupported color space: ",s),[e,"LinearTransferOETF"]}}function Sp(s,e,t){const n=s.getShaderParameter(e,s.COMPILE_STATUS),r=(s.getShaderInfoLog(e)||"").trim();if(n&&r==="")return"";const a=/ERROR: 0:( \d +)/.exec(r);if(a){const o=parseInt(a[1]);return t.toUpperCase()+ `
2026-01-22 11:29:51 +08:00
` +r+ `
2026-02-02 18:18:36 +08:00
` +h_(s.getShaderSource(e),o)}else return r}function d_(s,e){const t=u_(e);return[ ` vec4 $ { s } ( vec4 value ) { ` , ` return $ { t [ 1 ] } ( vec4 ( value . rgb * $ { t [ 0 ] } , value . a ) ) ; ` ,"}"].join( `
` )}function f_(s,e){let t;switch(e){case fd:t="Linear";break;case pd:t="Reinhard";break;case md:t="Cineon";break;case tc:t="ACESFilmic";break;case xd:t="AgX";break;case vd:t="Neutral";break;case gd:t="Custom";break;default:He("WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+s+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}const Wo=new R;function p_(){it.getLuminanceCoefficients(Wo);const s=Wo.x.toFixed(4),e=Wo.y.toFixed(4),t=Wo.z.toFixed(4);return["float luminance( const in vec3 rgb ) {", ` const vec3 weights = vec3 ( $ { s } , $ { e } , $ { t } ) ; ` ," return dot( weights, rgb );","}"].join( `
` )}function m_(s){return[s.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",s.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(Ea).join( `
` )}function g_(s){const e=[];for(const t in s){const n=s[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join( `
` )}function x_(s,e){const t={},n=s.getProgramParameter(e,s.ACTIVE_ATTRIBUTES);for(let i=0;i<n;i++){const r=s.getActiveAttrib(e,i),a=r.name;let o=1;r.type===s.FLOAT_MAT2&&(o=2),r.type===s.FLOAT_MAT3&&(o=3),r.type===s.FLOAT_MAT4&&(o=4),t[a]={type:r.type,location:s.getAttribLocation(e,a),locationSize:o}}return t}function Ea(s){return s!==""}function Ep(s,e){const t=e.numSpotLightShadows+e.numSpotLightMaps-e.numSpotLightShadowsWithMaps;return s.replace(/NUM_DIR_LIGHTS/g,e.numDirLights).replace(/NUM_SPOT_LIGHTS/g,e.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,e.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,t).replace(/NUM_RECT_AREA_LIGHTS/g,e.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,e.numPointLights).replace(/NUM_HEMI_LIGHTS/g,e.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,e.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,e.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,e.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,e.numPointLightShadows)}function Tp(s,e){return s.replace(/NUM_CLIPPING_PLANES/g,e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,e.numClippingPlanes-e.numClipIntersection)}const v_=/^[ \t ]*#include +<([ \w \d ./]+)>/gm;function Xh(s){return s.replace(v_,y_)}const b_=new Map;function y_(s,e){let t=et[e];if(t===void 0){const n=b_.get(e);if(n!==void 0)t=et[n],He('WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Xh(t)}const __=/#pragma unroll_loop_start \s +for \s * \( \s *int \s +i \s *= \s *( \d +) \s *; \s *i \s *< \s *( \d +) \s *; \s *i \s * \+ \+ \s * \) \s *{([ \s \S ]+?)} \s +#pragma unroll_loop_end/g;function Cp(s){return s.replace(__,M_)}function M_(s,e,t,n){let i="";for(let r=parseInt(e);r<parseInt(t);r++)i+=n.replace(/ \[ \s *i \s * \] /g,"[ "+r+" ]").replace(/UNROLLED_LOOP_INDEX/g,r);return i}function Ap(s){let e= ` precision $ { s . precision } float ;
2026-01-22 11:29:51 +08:00
precision $ { s . precision } int ;
precision $ { s . precision } sampler2D ;
precision $ { s . precision } samplerCube ;
precision $ { s . precision } sampler3D ;
precision $ { s . precision } sampler2DArray ;
precision $ { s . precision } sampler2DShadow ;
precision $ { s . precision } samplerCubeShadow ;
precision $ { s . precision } sampler2DArrayShadow ;
precision $ { s . precision } isampler2D ;
precision $ { s . precision } isampler3D ;
precision $ { s . precision } isamplerCube ;
precision $ { s . precision } isampler2DArray ;
precision $ { s . precision } usampler2D ;
precision $ { s . precision } usampler3D ;
precision $ { s . precision } usamplerCube ;
precision $ { s . precision } usampler2DArray ;
` ;return s.precision==="highp"?e+= `
# define HIGH _PRECISION ` :s.precision==="mediump"?e+= `
# define MEDIUM _PRECISION ` :s.precision==="lowp"&&(e+= `
2026-02-02 18:18:36 +08:00
# define LOW _PRECISION ` ),e}function w_(s){let e="SHADOWMAP_TYPE_BASIC";return s.shadowMapType===ld?e="SHADOWMAP_TYPE_PCF":s.shadowMapType===cd?e="SHADOWMAP_TYPE_PCF_SOFT":s.shadowMapType===gi&&(e="SHADOWMAP_TYPE_VSM"),e}function S_(s){let e="ENVMAP_TYPE_CUBE";if(s.envMap)switch(s.envMapMode){case Fs:case zs:e="ENVMAP_TYPE_CUBE";break;case ja:e="ENVMAP_TYPE_CUBE_UV";break}return e}function E_(s){let e="ENVMAP_MODE_REFLECTION";if(s.envMap)switch(s.envMapMode){case zs:e="ENVMAP_MODE_REFRACTION";break}return e}function T_(s){let e="ENVMAP_BLENDING_NONE";if(s.envMap)switch(s.combine){case Xa:e="ENVMAP_BLENDING_MULTIPLY";break;case wg:e="ENVMAP_BLENDING_MIX";break;case Sg:e="ENVMAP_BLENDING_ADD";break}return e}function C_(s){const e=s.envMapCubeUVHeight;if(e===null)return null;const t=Math.log2(e)-2,n=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:n,maxMip:t}}function A_(s,e,t,n){const i=s.getContext(),r=t.defines;let a=t.vertexShader,o=t.fragmentShader;const l=w_(t),c=S_(t),h=E_(t),u=T_(t),f=C_(t),d=m_(t),m=g_(r),p=i.createProgram();let x,g,b=t.glslVersion?"#version "+t.glslVersion+ `
` :"";t.isRawShaderMaterial?(x=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m].filter(Ea).join( `
2026-01-22 11:29:51 +08:00
` ),x.length>0&&(x+= `
2026-02-02 18:18:36 +08:00
` ),g=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m].filter(Ea).join( `
2026-02-02 16:36:17 +08:00
` ),g.length>0&&(g+= `
2026-02-02 18:18:36 +08:00
` )):(x=[Ap(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+h:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",
` ].filter(Ea).join( `
` ),g=[Ap(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+h:"",t.envMap?"#define "+u:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==Ni?"#define TONE_MAPPING":"",t.toneMapping!==Ni?et.tonemapping_pars_fragment:"",t.toneMapping!==Ni?f_("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",et.colorspace_pars_fragment,d_("linearToOutputTexel",t.outputColorSpace),p_(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"", `
` ].filter(Ea).join( `
` )),a=Xh(a),a=Ep(a,t),a=Tp(a,t),o=Xh(o),o=Ep(o,t),o=Tp(o,t),a=Cp(a),o=Cp(o),t.isRawShaderMaterial!==!0&&(b= ` # version 300 es
2026-02-02 16:36:17 +08:00
` ,x=[d,"#define attribute in","#define varying out","#define texture2D texture"].join( `
2026-01-22 11:29:51 +08:00
` )+ `
2026-02-02 18:18:36 +08:00
` +x,g=["#define varying in",t.glslVersion===Bd?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===Bd?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join( `
2026-01-22 11:29:51 +08:00
` )+ `
2026-02-02 18:18:36 +08:00
` +g);const v=b+x+a,y=b+g+o,M=Mp(i,i.VERTEX_SHADER,v),E=Mp(i,i.FRAGMENT_SHADER,y);i.attachShader(p,M),i.attachShader(p,E),t.index0AttributeName!==void 0?i.bindAttribLocation(p,0,t.index0AttributeName):t.morphTargets===!0&&i.bindAttribLocation(p,0,"position"),i.linkProgram(p);function C(I){if(s.debug.checkShaderErrors){const A=i.getProgramInfoLog(p)||"",B=i.getShaderInfoLog(M)||"",w=i.getShaderInfoLog(E)||"",F=A.trim(),W=B.trim(),X=w.trim();let $ =!0,Z=!0;if(i.getProgramParameter(p,i.LINK_STATUS)===!1)if( $ =!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,p,M,E);else{const ie=Sp(i,M,"vertex"),j=Sp(i,E,"fragment");Qe("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(p,i.VALIDATE_STATUS)+ `
2026-01-22 11:29:51 +08:00
2026-02-02 16:36:17 +08:00
Material Name : ` +I.name+ `
Material Type : ` +I.type+ `
2026-01-22 11:29:51 +08:00
2026-01-28 12:00:55 +08:00
Program Info Log : ` +F+ `
2026-02-02 16:36:17 +08:00
` +ie+ `
2026-02-02 18:18:36 +08:00
` +j)}else F!==""?He("WebGLProgram: Program Info Log:",F):(W===""||X==="")&&(Z=!1);Z&&(I.diagnostics={runnable: $ ,programLog:F,vertexShader:{log:W,prefix:x},fragmentShader:{log:X,prefix:g}})}i.deleteShader(M),i.deleteShader(E),P=new Go(i,p),_=x_(i,p)}let P;this.getUniforms=function(){return P===void 0&&C(this),P};let _;this.getAttributes=function(){return _===void 0&&C(this),_};let S=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return S===!1&&(S=i.getProgramParameter(p,l_)),S},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(p),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=c_++,this.cacheKey=e,this.usedTimes=1,this.program=p,this.vertexShader=M,this.fragmentShader=E,this}let P_=0;class R_{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,i=this._getShaderStage(t),r=this._getShaderStage(n),a=this._getShaderCacheForMaterial(e);return a.has(i)===!1&&(a.add(i),i.usedTimes++),a.has(r)===!1&&(a.add(r),r.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new L_(e),t.set(e,n)),n}}class L_{constructor(e){this.id=P_++,this.code=e,this.usedTimes=0}}function I_(s,e,t,n,i,r,a){const o=new eh,l=new R_,c=new Set,h=[],u=i.logarithmicDepthBuffer,f=i.vertexTextures;let d=i.precision;const m={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function p(_){return c.add(_),_===0?"uv": ` uv$ { _ } ` }function x(_,S,I,A,B){const w=A.fog,F=B.geometry,W=_.isMeshStandardMaterial?A.environment:null,X=(_.isMeshStandardMaterial?t:e).get(_.envMap||W), $ =X&&X.mapping===ja?X.image.height:null,Z=m[_.type];_.precision!==null&&(d=i.getMaxPrecision(_.precision),d!==_.precision&&He("WebGLProgram.getParameters:",_.precision,"not supported, using",d,"instead."));const ie=F.morphAttributes.position||F.morphAttributes.normal||F.morphAttributes.color,j=ie!==void 0?ie.length:0;let Y=0;F.morphAttributes.position!==void 0&&(Y=1),F.morphAttributes.normal!==void 0&&(Y=2),F.morphAttributes.color!==void 0&&(Y=3);let ge,pe,de,se;if(Z){const ft=ci[Z];ge=ft.vertexShader,pe=ft.fragmentShader}else ge=_.vertexShader,pe=_.fragmentShader,l.update(_),de=l.getVertexShaderID(_),se=l.getFragmentShaderID(_);const he=s.getRenderTarget(),fe=s.state.buffers.depth.getReversed(),ve=B.isInstancedMesh===!0,Se=B.isBatchedMesh===!0,Be=!!_.map,Je=!!_.matcap,Ne=!!X,T=!!_.aoMap,D=!!_.lightMap,V=!!_.bumpMap,U=!!_.normalMap,k=!!_.displacementMap,z=!!_.emissiveMap,ee=!!_.metalnessMap,J=!!_.roughnessMap,G=_.anisotropy>0,N=_.clearcoat>0,L=_.dispersion>0,H=_.iridescence>0,K=_.sheen>0,le=_.transmission>0,te=G&&!!_.anisotropyMap,Ce=N&&!!_.clearcoatMap,be=N&&!!_.clearcoatNormalMap,Re=N&&!!_.clearcoatRoughnessMap,Ie=H&&!!_.iridescenceMap,ue=H&&!!_.iridescenceThicknessMap,ye=K&&!!_.sheenColorMap,Ve=K&&!!_.sheenRoughnessMap,Ue=!!_.specularMap,Ae=!!_.specularColorMap,Ge=!!_.specularIntensityMap,q=le&&!!_.transmissionMap,Te=le&&!!_.thicknessMap,_e=!!_.gradientMap,we=!!_.alphaMap,xe=_.alphaTest>0,me=!!_.alphaHash,Fe=!!_.extensions;let Ye=Ni;_.toneMapped&&(he===null||he.isXRRenderTarget===!0)&&(Ye=s.toneMapping);const wt={shaderID:Z,shaderType:_.type,shaderName:_.name,vertexShader:ge,fragmen
2026-01-22 11:29:51 +08:00
gl _Position = vec4 ( position , 1.0 ) ;
2026-02-02 18:18:36 +08:00
} ` ,G_= ` uniform sampler2D shadow _pass ;
2026-01-22 11:29:51 +08:00
uniform vec2 resolution ;
uniform float radius ;
# include < packing >
void main ( ) {
const float samples = float ( VSM _SAMPLES ) ;
float mean = 0.0 ;
float squared _mean = 0.0 ;
float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ) ;
float uvStart = samples <= 1.0 ? 0.0 : - 1.0 ;
for ( float i = 0.0 ; i < samples ; i ++ ) {
float uvOffset = uvStart + i * uvStride ;
# ifdef HORIZONTAL _PASS
vec2 distribution = unpackRGBATo2Half ( texture2D ( shadow _pass , ( gl _FragCoord . xy + vec2 ( uvOffset , 0.0 ) * radius ) / resolution ) ) ;
mean += distribution . x ;
squared _mean += distribution . y * distribution . y + distribution . x * distribution . x ;
# else
float depth = unpackRGBAToDepth ( texture2D ( shadow _pass , ( gl _FragCoord . xy + vec2 ( 0.0 , uvOffset ) * radius ) / resolution ) ) ;
mean += depth ;
squared _mean += depth * depth ;
# endif
}
mean = mean / samples ;
squared _mean = squared _mean / samples ;
float std _dev = sqrt ( squared _mean - mean * mean ) ;
gl _FragColor = pack2HalfToRGBA ( vec2 ( mean , std _dev ) ) ;
2026-02-02 18:18:36 +08:00
} ` ;function W_(s,e,t){let n=new bh;const i=new ce,r=new ce,a=new tt,o=new xv({depthPacking:Pg}),l=new vv,c={},h=t.maxTextureSize,u={[Pn]:on,[on]:Pn,[Nt]:Nt},f=new kt({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new ce},radius:{value:4}},vertexShader:V_,fragmentShader:G_}),d=f.clone();d.defines.HORIZONTAL_PASS=1;const m=new _t;m.setAttribute("position",new yt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const p=new gt(m,f),x=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=ld;let g=this.type;this.render=function(E,C,P){if(x.enabled===!1||x.autoUpdate===!1&&x.needsUpdate===!1||E.length===0)return;const _=s.getRenderTarget(),S=s.getActiveCubeFace(),I=s.getActiveMipmapLevel(),A=s.state;A.setBlending(Xt),A.buffers.depth.getReversed()===!0?A.buffers.color.setClear(0,0,0,0):A.buffers.color.setClear(1,1,1,1),A.buffers.depth.setTest(!0),A.setScissorTest(!1);const B=g!==gi&&this.type===gi,w=g===gi&&this.type!==gi;for(let F=0,W=E.length;F<W;F++){const X=E[F], $ =X.shadow;if( $ ===void 0){He("WebGLShadowMap:",X,"has no shadow.");continue}if( $ .autoUpdate===!1&& $ .needsUpdate===!1)continue;i.copy( $ .mapSize);const Z= $ .getFrameExtents();if(i.multiply(Z),r.copy( $ .mapSize),(i.x>h||i.y>h)&&(i.x>h&&(r.x=Math.floor(h/Z.x),i.x=r.x*Z.x, $ .mapSize.x=r.x),i.y>h&&(r.y=Math.floor(h/Z.y),i.y=r.y*Z.y, $ .mapSize.y=r.y)), $ .map===null||B===!0||w===!0){const j=this.type!==gi?{minFilter:Yt,magFilter:Yt}:{}; $ .map!==null&& $ .map.dispose(), $ .map=new mn(i.x,i.y,j), $ .map.texture.name=X.name+".shadowMap", $ .camera.updateProjectionMatrix()}s.setRenderTarget( $ .map),s.clear();const ie= $ .getViewportCount();for(let j=0;j<ie;j++){const Y= $ .getViewport(j);a.set(r.x*Y.x,r.y*Y.y,r.x*Y.z,r.y*Y.w),A.viewport(a), $ .updateMatrices(X,j),n= $ .getFrustum(),y(C,P, $ .camera,X,this.type)} $ .isPointLightShadow!==!0&&this.type===gi&&b( $ ,P), $ .needsUpdate=!1}g=this.type,x.needsUpdate=!1,s.setRenderTarget(_,S,I)};function b(E,C){const P=e.update(p);f.defines.VSM_SAMPLES!==E.blurSamples&&(f.defines.VSM_SAMPLES=E.blurSamples,d.defines.VSM_SAMPLES=E.blurSamples,f.needsUpdate=!0,d.needsUpdate=!0),E.mapPass===null&&(E.mapPass=new mn(i.x,i.y)),f.uniforms.shadow_pass.value=E.map.texture,f.uniforms.resolution.value=E.mapSize,f.uniforms.radius.value=E.radius,s.setRenderTarget(E.mapPass),s.clear(),s.renderBufferDirect(C,null,P,f,p,null),d.uniforms.shadow_pass.value=E.mapPass.texture,d.uniforms.resolution.value=E.mapSize,d.uniforms.radius.value=E.radius,s.setRenderTarget(E.map),s.clear(),s.renderBufferDirect(C,null,P,d,p,null)}function v(E,C,P,_){let S=null;const I=P.isPointLight===!0?E.customDistanceMaterial:E.customDepthMaterial;if(I!==void 0)S=I;else if(S=P.isPointLight===!0?l:o,s.localClippingEnabled&&C.clipShadows===!0&&Array.isArray(C.clippingPlanes)&&C.clippingPlanes.length!==0||C.displacementMap&&C.displacementScale!==0||C.alphaMap&&C.alphaTest>0||C.map&&C.alphaTest>0||C.alphaToCoverage===!0){const A=S.uuid,B=C.uuid;let w=c[A];w===void 0&&(w={},c[A]=w);let F=w[B];F===void 0&&(F=S.clone(),w[B]=F,C.addEventListener("dispose",M)),S=F}if(S.visible=C.visible,S.wireframe=C.wireframe,_===gi?S.side=C.shadowSide!==null?C.shadowSide:C.side:S.side=C.shadowSide!==null?C.shadowSide:u[C.side],S.alphaMap=C.alphaMap,S.alphaTest=C.alphaToCoverage===!0?.5:C.alphaTest,S.map=C.map,S.clipShadows=C.clipShadows,S.clippingPlanes=C.clippingPlanes,S.clipIntersection=C.clipIntersection,S.displacementMap=C.displacementMap,S.displacementScale=C.displacementScale,S.displacementBias=C.displacementBias,S.wireframeLinewidth=C.wireframeLinewidth,S.linewidth=C.linewidth,P.isPointLight===!0&&S.isMeshDistanceMaterial===!0){const A=s.properties.get(S);A.light=P}return S}function y(E,C,P,_,S){if(E.visible===!1)return;if(E.layers.test(C.layers)&&(E.isMesh||E.isLine||E.isPoints)&&(E.castShadow||E.receiveShadow&&S===gi)&&(!E.frustumCulled||n.intersectsObject(E))){E.modelViewMatrix.multiplyMatrices(P.matrixWorldInverse,E.matrixWorld);const B=e.update(E),w=E.material;if(Array.isArray(w)){const F=B.groups;for(let W=0,X=F.length;W<X;W++){const $ =F[W],Z=w[ $ .materialIndex];if(Z&&Z.visible
2026-01-22 11:29:51 +08:00
void main ( ) {
gl _Position = vec4 ( position , 1.0 ) ;
2026-02-02 18:18:36 +08:00
} ` , $ _= `
2026-01-22 11:29:51 +08:00
uniform sampler2DArray depthColor ;
uniform float depthWidth ;
uniform float depthHeight ;
void main ( ) {
vec2 coord = vec2 ( gl _FragCoord . x / depthWidth , gl _FragCoord . y / depthHeight ) ;
if ( coord . x >= 1.0 ) {
gl _FragDepth = texture ( depthColor , vec3 ( coord . x - 1.0 , coord . y , 1 ) ) . r ;
} else {
gl _FragDepth = texture ( depthColor , vec3 ( coord . x , coord . y , 0 ) ) . r ;
}
2026-02-02 18:18:36 +08:00
} ` ;class K_{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new Rf(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new kt({vertexShader:Y_,fragmentShader: $ _,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new gt(new ya(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class J_ extends ns{constructor(e,t){super();const n=this;let i=null,r=1,a=null,o="local-floor",l=1,c=null,h=null,u=null,f=null,d=null,m=null;const p=typeof XRWebGLBinding<"u",x=new K_,g={},b=t.getContextAttributes();let v=null,y=null;const M=[],E=[],C=new ce;let P=null;const _=new sn;_.viewport=new tt;const S=new sn;S.viewport=new tt;const I=[_,S],A=new Ov;let B=null,w=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(se){let he=M[se];return he===void 0&&(he=new dh,M[se]=he),he.getTargetRaySpace()},this.getControllerGrip=function(se){let he=M[se];return he===void 0&&(he=new dh,M[se]=he),he.getGripSpace()},this.getHand=function(se){let he=M[se];return he===void 0&&(he=new dh,M[se]=he),he.getHandSpace()};function F(se){const he=E.indexOf(se.inputSource);if(he===-1)return;const fe=M[he];fe!==void 0&&(fe.update(se.inputSource,se.frame,c||a),fe.dispatchEvent({type:se.type,data:se.inputSource}))}function W(){i.removeEventListener("select",F),i.removeEventListener("selectstart",F),i.removeEventListener("selectend",F),i.removeEventListener("squeeze",F),i.removeEventListener("squeezestart",F),i.removeEventListener("squeezeend",F),i.removeEventListener("end",W),i.removeEventListener("inputsourceschange",X);for(let se=0;se<M.length;se++){const he=E[se];he!==null&&(E[se]=null,M[se].disconnect(he))}B=null,w=null,x.reset();for(const se in g)delete g[se];e.setRenderTarget(v),d=null,f=null,u=null,i=null,y=null,de.stop(),n.isPresenting=!1,e.setPixelRatio(P),e.setSize(C.width,C.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(se){r=se,n.isPresenting===!0&&He("WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(se){o=se,n.isPresenting===!0&&He("WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||a},this.setReferenceSpace=function(se){c=se},this.getBaseLayer=function(){return f!==null?f:d},this.getBinding=function(){return u===null&&p&&(u=new XRWebGLBinding(i,t)),u},this.getFrame=function(){return m},this.getSession=function(){return i},this.setSession=async function(se){if(i=se,i!==null){if(v=e.getRenderTarget(),i.addEventListener("select",F),i.addEventListener("selectstart",F),i.addEventListener("selectend",F),i.addEventListener("squeeze",F),i.addEventListener("squeezestart",F),i.addEventListener("squeezeend",F),i.addEventListener("end",W),i.addEventListener("inputsourceschange",X),b.xrCompatible!==!0&&await t.makeXRCompatible(),P=e.getPixelRatio(),e.getSize(C),p&&"createProjectionLayer"in XRWebGLBinding.prototype){let fe=null,ve=null,Se=null;b.depth&&(Se=b.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,fe=b.stencil?Vs:qr,ve=b.stencil?Hs:ts);const Be={colorFormat:t.RGBA8,depthFormat:Se,scaleFactor:r};u=this.getBinding(),f=u.createProjectionLayer(Be),i.updateRenderState({layers:[f]}),e.setPixelRatio(1),e.setSize(f.textureWidth,f.textureHeight,!1),y=new mn(f.textureWidth,f.textureHeight,{format:pn,type:Xn,depthTexture:new Mh(f.textureWidth,f.textureHeight,ve,void 0,void 0,void 0,void 0,void 0,void 0,fe),stencilBuffer:b.stencil,colorSpace:e.outputColorSpace,samples:b.antialias?4:0,resolveDepthBuffer:f.ignoreDepthValues===!1,resolveStencilBuffer:f.ignoreDepthValues===!1})}else{const fe={antialias:b.antialias,alpha:!0,depth:b.depth,stencil:b.stencil,framebufferScaleFactor:r};d=new XRWebGLLayer(i,t,fe),i.updateRenderState({baseLayer:d}
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform float opacity ;
uniform sampler2D tDiffuse ;
varying vec2 vUv ;
void main ( ) {
vec4 texel = texture2D ( tDiffuse , vUv ) ;
gl _FragColor = opacity * texel ;
2026-02-02 18:18:36 +08:00
} ` };class xs{constructor(){this.isPass=!0,this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}setSize(){}render(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}dispose(){}}const w2=new us(-1,1,1,-1,0,1);class S2 extends _t{constructor(){super(),this.setAttribute("position",new nn([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new nn([0,2,0,0,2,0],2))}}const E2=new S2;class jo{constructor(e){this._mesh=new gt(E2,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,w2)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class qo extends xs{constructor(e,t="tDiffuse"){super(),this.textureID=t,this.uniforms=null,this.material=null,e instanceof kt?(this.uniforms=e.uniforms,this.material=e):e&&(this.uniforms=oi.clone(e.uniforms),this.material=new kt({name:e.name!==void 0?e.name:"unspecified",defines:Object.assign({},e.defines),uniforms:this.uniforms,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader})),this._fsQuad=new jo(this.material)}render(e,t,n){this.uniforms[this.textureID]&&(this.uniforms[this.textureID].value=n.texture),this._fsQuad.material=this.material,this.renderToScreen?(e.setRenderTarget(null),this._fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),this._fsQuad.render(e))}dispose(){this.material.dispose(),this._fsQuad.dispose()}}class Up extends xs{constructor(e,t){super(),this.scene=e,this.camera=t,this.clear=!0,this.needsSwap=!1,this.inverse=!1}render(e,t,n){const i=e.getContext(),r=e.state;r.buffers.color.setMask(!1),r.buffers.depth.setMask(!1),r.buffers.color.setLocked(!0),r.buffers.depth.setLocked(!0);let a,o;this.inverse?(a=0,o=1):(a=1,o=0),r.buffers.stencil.setTest(!0),r.buffers.stencil.setOp(i.REPLACE,i.REPLACE,i.REPLACE),r.buffers.stencil.setFunc(i.ALWAYS,a,4294967295),r.buffers.stencil.setClear(o),r.buffers.stencil.setLocked(!0),e.setRenderTarget(n),this.clear&&e.clear(),e.render(this.scene,this.camera),e.setRenderTarget(t),this.clear&&e.clear(),e.render(this.scene,this.camera),r.buffers.color.setLocked(!1),r.buffers.depth.setLocked(!1),r.buffers.color.setMask(!0),r.buffers.depth.setMask(!0),r.buffers.stencil.setLocked(!1),r.buffers.stencil.setFunc(i.EQUAL,1,4294967295),r.buffers.stencil.setOp(i.KEEP,i.KEEP,i.KEEP),r.buffers.stencil.setLocked(!0)}}class T2 extends xs{constructor(){super(),this.needsSwap=!1}render(e){e.state.buffers.stencil.setLocked(!1),e.state.buffers.stencil.setTest(!1)}}class C2{constructor(e,t){if(this.renderer=e,this._pixelRatio=e.getPixelRatio(),t===void 0){const n=e.getSize(new ce);this._width=n.width,this._height=n.height,t=new mn(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Rn}),t.texture.name="EffectComposer.rt1"}else this._width=t.width,this._height=t.height;this.renderTarget1=t,this.renderTarget2=t.clone(),this.renderTarget2.texture.name="EffectComposer.rt2",this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2,this.renderToScreen=!0,this.passes=[],this.copyPass=new qo(gs),this.copyPass.material.blending=Xt,this.clock=new Fv}swapBuffers(){const e=this.readBuffer;this.readBuffer=this.writeBuffer,this.writeBuffer=e}addPass(e){this.passes.push(e),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}insertPass(e,t){this.passes.splice(t,0,e),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}removePass(e){const t=this.passes.indexOf(e);t!==-1&&this.passes.splice(t,1)}isLastEnabledPass(e){for(let t=e+1;t<this.passes.length;t++)if(this.passes[t].enabled)return!1;return!0}render(e){e===void 0&&(e=this.clock.getDelta());const t=this.renderer.getRenderTarget();let n=!1;for(let i=0,r=this.passes.length;i<r;i++){const a=this.passes[i];if(a.enabled!==!1){if(a.renderToScreen=this.renderToScreen&&this.isLastEnabledPass(i),a.render(this.renderer,this.writeBuffer,this.readBuffer,e,n),a.needsSwap){if(n){const o=this.renderer.getContext(),l=this.renderer.state.buffers.stencil;l.setFunc(o.NOTEQUAL,1,4294967295),this.copyPass.render(this.renderer,th
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
varying vec2 vUv ;
uniform highp sampler2D tNormal ;
uniform highp sampler2D tDepth ;
uniform sampler2D tNoise ;
uniform vec2 resolution ;
uniform float cameraNear ;
uniform float cameraFar ;
uniform mat4 cameraProjectionMatrix ;
uniform mat4 cameraProjectionMatrixInverse ;
uniform mat4 cameraWorldMatrix ;
uniform float radius ;
uniform float distanceExponent ;
uniform float thickness ;
uniform float distanceFallOff ;
uniform float scale ;
# if SCENE _CLIP _BOX == 1
uniform vec3 sceneBoxMin ;
uniform vec3 sceneBoxMax ;
# endif
# include < common >
# include < packing >
# ifndef FRAGMENT _OUTPUT
# define FRAGMENT _OUTPUT vec4 ( vec3 ( ao ) , 1. )
# endif
vec3 getViewPosition ( const in vec2 screenPosition , const in float depth ) {
vec4 clipSpacePosition = vec4 ( vec3 ( screenPosition , depth ) * 2.0 - 1.0 , 1.0 ) ;
vec4 viewSpacePosition = cameraProjectionMatrixInverse * clipSpacePosition ;
return viewSpacePosition . xyz / viewSpacePosition . w ;
}
float getDepth ( const vec2 uv ) {
return textureLod ( tDepth , uv . xy , 0.0 ) . DEPTH _SWIZZLING ;
}
float fetchDepth ( const ivec2 uv ) {
return texelFetch ( tDepth , uv . xy , 0 ) . DEPTH _SWIZZLING ;
}
float getViewZ ( const in float depth ) {
# if PERSPECTIVE _CAMERA == 1
return perspectiveDepthToViewZ ( depth , cameraNear , cameraFar ) ;
# else
return orthographicDepthToViewZ ( depth , cameraNear , cameraFar ) ;
# endif
}
vec3 computeNormalFromDepth ( const vec2 uv ) {
vec2 size = vec2 ( textureSize ( tDepth , 0 ) ) ;
ivec2 p = ivec2 ( uv * size ) ;
float c0 = fetchDepth ( p ) ;
float l2 = fetchDepth ( p - ivec2 ( 2 , 0 ) ) ;
float l1 = fetchDepth ( p - ivec2 ( 1 , 0 ) ) ;
float r1 = fetchDepth ( p + ivec2 ( 1 , 0 ) ) ;
float r2 = fetchDepth ( p + ivec2 ( 2 , 0 ) ) ;
float b2 = fetchDepth ( p - ivec2 ( 0 , 2 ) ) ;
float b1 = fetchDepth ( p - ivec2 ( 0 , 1 ) ) ;
float t1 = fetchDepth ( p + ivec2 ( 0 , 1 ) ) ;
float t2 = fetchDepth ( p + ivec2 ( 0 , 2 ) ) ;
float dl = abs ( ( 2.0 * l1 - l2 ) - c0 ) ;
float dr = abs ( ( 2.0 * r1 - r2 ) - c0 ) ;
float db = abs ( ( 2.0 * b1 - b2 ) - c0 ) ;
float dt = abs ( ( 2.0 * t1 - t2 ) - c0 ) ;
vec3 ce = getViewPosition ( uv , c0 ) . xyz ;
vec3 dpdx = ( dl < dr ) ? ce - getViewPosition ( ( uv - vec2 ( 1.0 / size . x , 0.0 ) ) , l1 ) . xyz : - ce + getViewPosition ( ( uv + vec2 ( 1.0 / size . x , 0.0 ) ) , r1 ) . xyz ;
vec3 dpdy = ( db < dt ) ? ce - getViewPosition ( ( uv - vec2 ( 0.0 , 1.0 / size . y ) ) , b1 ) . xyz : - ce + getViewPosition ( ( uv + vec2 ( 0.0 , 1.0 / size . y ) ) , t1 ) . xyz ;
return normalize ( cross ( dpdx , dpdy ) ) ;
}
vec3 getViewNormal ( const vec2 uv ) {
# if NORMAL _VECTOR _TYPE == 2
return normalize ( textureLod ( tNormal , uv , 0. ) . rgb ) ;
# elif NORMAL _VECTOR _TYPE == 1
return unpackRGBToNormal ( textureLod ( tNormal , uv , 0. ) . rgb ) ;
# else
return computeNormalFromDepth ( uv ) ;
# endif
}
vec3 getSceneUvAndDepth ( vec3 sampleViewPos ) {
vec4 sampleClipPos = cameraProjectionMatrix * vec4 ( sampleViewPos , 1. ) ;
vec2 sampleUv = sampleClipPos . xy / sampleClipPos . w * 0.5 + 0.5 ;
float sampleSceneDepth = getDepth ( sampleUv ) ;
return vec3 ( sampleUv , sampleSceneDepth ) ;
}
void main ( ) {
float depth = getDepth ( vUv . xy ) ;
if ( depth >= 1.0 ) {
discard ;
return ;
}
vec3 viewPos = getViewPosition ( vUv , depth ) ;
vec3 viewNormal = getViewNormal ( vUv ) ;
float radiusToUse = radius ;
float distanceFalloffToUse = thickness ;
# if SCREEN _SPACE _RADIUS == 1
float radiusScale = getViewPosition ( vec2 ( 0.5 + float ( SCREEN _SPACE _RADIUS _SCALE ) / resolution . x , 0.0 ) , depth ) . x ;
radiusToUse *= radiusScale ;
distanceFalloffToUse *= radiusScale ;
# endif
# if SCENE _CLIP _BOX == 1
vec3 worldPos = ( cameraWorldMatrix * vec4 ( viewPos , 1.0 ) ) . xyz ;
float boxDistance = length ( max ( vec3 ( 0.0 ) , max ( sceneBoxMin - worldPos , worldPos - sceneBoxMax ) ) ) ;
if ( boxDistance > radiusToUse ) {
discard ;
return ;
}
# endif
vec2 noiseResolution = vec2 ( textureSize ( tNoise , 0 ) ) ;
vec2 noiseUv = vUv * resolution / noiseResolution ;
vec4 noiseTexel = textureLod ( tNoise , noiseUv , 0.0 ) ;
vec3 randomVec = noiseTexel . xyz * 2.0 - 1.0 ;
vec3 tangent = normalize ( vec3 ( randomVec . xy , 0. ) ) ;
vec3 bitangent = vec3 ( - tangent . y , tangent . x , 0. ) ;
mat3 kernelMatrix = mat3 ( tangent , bitangent , vec3 ( 0. , 0. , 1. ) ) ;
const int DIRECTIONS = SAMPLES < 30 ? 3 : 5 ;
const int STEPS = ( SAMPLES + DIRECTIONS - 1 ) / DIRECTIONS ;
float ao = 0.0 ;
for ( int i = 0 ; i < DIRECTIONS ; ++ i ) {
float angle = float ( i ) / float ( DIRECTIONS ) * PI ;
vec4 sampleDir = vec4 ( cos ( angle ) , sin ( angle ) , 0. , 0.5 + 0.5 * noiseTexel . w ) ;
sampleDir . xyz = normalize ( kernelMatrix * sampleDir . xyz ) ;
vec3 viewDir = normalize ( - viewPos . xyz ) ;
vec3 sliceBitangent = normalize ( cross ( sampleDir . xyz , viewDir ) ) ;
vec3 sliceTangent = cross ( sliceBitangent , viewDir ) ;
vec3 normalInSlice = normalize ( viewNormal - sliceBitangent * dot ( viewNormal , sliceBitangent ) ) ;
vec3 tangentToNormalInSlice = cross ( normalInSlice , sliceBitangent ) ;
vec2 cosHorizons = vec2 ( dot ( viewDir , tangentToNormalInSlice ) , dot ( viewDir , - tangentToNormalInSlice ) ) ;
for ( int j = 0 ; j < STEPS ; ++ j ) {
vec3 sampleViewOffset = sampleDir . xyz * radiusToUse * sampleDir . w * pow ( float ( j + 1 ) / float ( STEPS ) , distanceExponent ) ;
vec3 sampleSceneUvDepth = getSceneUvAndDepth ( viewPos + sampleViewOffset ) ;
vec3 sampleSceneViewPos = getViewPosition ( sampleSceneUvDepth . xy , sampleSceneUvDepth . z ) ;
vec3 viewDelta = sampleSceneViewPos - viewPos ;
if ( abs ( viewDelta . z ) < thickness ) {
float sampleCosHorizon = dot ( viewDir , normalize ( viewDelta ) ) ;
cosHorizons . x += max ( 0. , ( sampleCosHorizon - cosHorizons . x ) * mix ( 1. , 2. / float ( j + 2 ) , distanceFallOff ) ) ;
}
sampleSceneUvDepth = getSceneUvAndDepth ( viewPos - sampleViewOffset ) ;
sampleSceneViewPos = getViewPosition ( sampleSceneUvDepth . xy , sampleSceneUvDepth . z ) ;
viewDelta = sampleSceneViewPos - viewPos ;
if ( abs ( viewDelta . z ) < thickness ) {
float sampleCosHorizon = dot ( viewDir , normalize ( viewDelta ) ) ;
cosHorizons . y += max ( 0. , ( sampleCosHorizon - cosHorizons . y ) * mix ( 1. , 2. / float ( j + 2 ) , distanceFallOff ) ) ;
}
}
vec2 sinHorizons = sqrt ( 1. - cosHorizons * cosHorizons ) ;
float nx = dot ( normalInSlice , sliceTangent ) ;
float ny = dot ( normalInSlice , viewDir ) ;
float nxb = 1. / 2. * ( acos ( cosHorizons . y ) - acos ( cosHorizons . x ) + sinHorizons . x * cosHorizons . x - sinHorizons . y * cosHorizons . y ) ;
float nyb = 1. / 2. * ( 2. - cosHorizons . x * cosHorizons . x - cosHorizons . y * cosHorizons . y ) ;
float occlusion = nx * nxb + ny * nyb ;
ao += occlusion ;
}
ao = clamp ( ao / float ( DIRECTIONS ) , 0. , 1. ) ;
# if SCENE _CLIP _BOX == 1
ao = mix ( ao , 1. , smoothstep ( 0. , radiusToUse , boxDistance ) ) ;
# endif
ao = pow ( ao , scale ) ;
gl _FragColor = FRAGMENT _OUTPUT ;
2026-02-02 18:18:36 +08:00
} ` },Yo={defines:{PERSPECTIVE_CAMERA:1},uniforms:{tDepth:{value:null},cameraNear:{value:null},cameraFar:{value:null}},vertexShader: `
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform sampler2D tDepth ;
uniform float cameraNear ;
uniform float cameraFar ;
varying vec2 vUv ;
# include < packing >
float getLinearDepth ( const in vec2 screenPosition ) {
# if PERSPECTIVE _CAMERA == 1
float fragCoordZ = texture2D ( tDepth , screenPosition ) . x ;
float viewZ = perspectiveDepthToViewZ ( fragCoordZ , cameraNear , cameraFar ) ;
return viewZToOrthographicDepth ( viewZ , cameraNear , cameraFar ) ;
# else
return texture2D ( tDepth , screenPosition ) . x ;
# endif
}
void main ( ) {
float depth = getLinearDepth ( vUv ) ;
gl _FragColor = vec4 ( vec3 ( 1.0 - depth ) , 1.0 ) ;
2026-02-02 18:18:36 +08:00
} ` },Yh={uniforms:{tDiffuse:{value:null},intensity:{value:1}},vertexShader: `
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform float intensity ;
uniform sampler2D tDiffuse ;
varying vec2 vUv ;
void main ( ) {
vec4 texel = texture2D ( tDiffuse , vUv ) ;
gl _FragColor = vec4 ( mix ( vec3 ( 1. ) , texel . rgb , intensity ) , texel . a ) ;
2026-02-02 18:18:36 +08:00
} ` };function P2(s=5){const e=Math.floor(s)%2===0?Math.floor(s)+1:Math.floor(s),t=R2(e),n=t.length,i=new Uint8Array(n*4);for(let a=0;a<n;++a){const o=t[a],l=2*Math.PI*o/n,c=new R(Math.cos(l),Math.sin(l),0).normalize();i[a*4]=(c.x*.5+.5)*255,i[a*4+1]=(c.y*.5+.5)*255,i[a*4+2]=127,i[a*4+3]=255}const r=new ca(i,e,e);return r.wrapS=ii,r.wrapT=ii,r.needsUpdate=!0,r}function R2(s){const e=Math.floor(s)%2===0?Math.floor(s)+1:Math.floor(s),t=e*e,n=Array(t).fill(0);let i=Math.floor(e/2),r=e-1;for(let a=1;a<=t;){if(i===-1&&r===e?(r=e-2,i=0):(r===e&&(r=0),i<0&&(i=e-1)),n[i*e+r]!==0){r-=2,i++;continue}else n[i*e+r]=a++;r++,i--}return n}const $ o={defines:{SAMPLES:16,SAMPLE_VECTORS:Op(16,2,1),NORMAL_VECTOR_TYPE:1,DEPTH_VALUE_SOURCE:0},uniforms:{tDiffuse:{value:null},tNormal:{value:null},tDepth:{value:null},tNoise:{value:null},resolution:{value:new ce},cameraProjectionMatrixInverse:{value:new Oe},lumaPhi:{value:5},depthPhi:{value:5},normalPhi:{value:5},radius:{value:4},index:{value:0}},vertexShader: `
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
varying vec2 vUv ;
uniform sampler2D tDiffuse ;
uniform sampler2D tNormal ;
uniform sampler2D tDepth ;
uniform sampler2D tNoise ;
uniform vec2 resolution ;
uniform mat4 cameraProjectionMatrixInverse ;
uniform float lumaPhi ;
uniform float depthPhi ;
uniform float normalPhi ;
uniform float radius ;
uniform int index ;
# include < common >
# include < packing >
# ifndef SAMPLE _LUMINANCE
# define SAMPLE _LUMINANCE dot ( vec3 ( 0.2125 , 0.7154 , 0.0721 ) , a )
# endif
# ifndef FRAGMENT _OUTPUT
# define FRAGMENT _OUTPUT vec4 ( denoised , 1. )
# endif
float getLuminance ( const in vec3 a ) {
return SAMPLE _LUMINANCE ;
}
const vec3 poissonDisk [ SAMPLES ] = SAMPLE _VECTORS ;
vec3 getViewPosition ( const in vec2 screenPosition , const in float depth ) {
vec4 clipSpacePosition = vec4 ( vec3 ( screenPosition , depth ) * 2.0 - 1.0 , 1.0 ) ;
vec4 viewSpacePosition = cameraProjectionMatrixInverse * clipSpacePosition ;
return viewSpacePosition . xyz / viewSpacePosition . w ;
}
float getDepth ( const vec2 uv ) {
# if DEPTH _VALUE _SOURCE == 1
return textureLod ( tDepth , uv . xy , 0.0 ) . a ;
# else
return textureLod ( tDepth , uv . xy , 0.0 ) . r ;
# endif
}
float fetchDepth ( const ivec2 uv ) {
# if DEPTH _VALUE _SOURCE == 1
return texelFetch ( tDepth , uv . xy , 0 ) . a ;
# else
return texelFetch ( tDepth , uv . xy , 0 ) . r ;
# endif
}
vec3 computeNormalFromDepth ( const vec2 uv ) {
vec2 size = vec2 ( textureSize ( tDepth , 0 ) ) ;
ivec2 p = ivec2 ( uv * size ) ;
float c0 = fetchDepth ( p ) ;
float l2 = fetchDepth ( p - ivec2 ( 2 , 0 ) ) ;
float l1 = fetchDepth ( p - ivec2 ( 1 , 0 ) ) ;
float r1 = fetchDepth ( p + ivec2 ( 1 , 0 ) ) ;
float r2 = fetchDepth ( p + ivec2 ( 2 , 0 ) ) ;
float b2 = fetchDepth ( p - ivec2 ( 0 , 2 ) ) ;
float b1 = fetchDepth ( p - ivec2 ( 0 , 1 ) ) ;
float t1 = fetchDepth ( p + ivec2 ( 0 , 1 ) ) ;
float t2 = fetchDepth ( p + ivec2 ( 0 , 2 ) ) ;
float dl = abs ( ( 2.0 * l1 - l2 ) - c0 ) ;
float dr = abs ( ( 2.0 * r1 - r2 ) - c0 ) ;
float db = abs ( ( 2.0 * b1 - b2 ) - c0 ) ;
float dt = abs ( ( 2.0 * t1 - t2 ) - c0 ) ;
vec3 ce = getViewPosition ( uv , c0 ) . xyz ;
vec3 dpdx = ( dl < dr ) ? ce - getViewPosition ( ( uv - vec2 ( 1.0 / size . x , 0.0 ) ) , l1 ) . xyz
: - ce + getViewPosition ( ( uv + vec2 ( 1.0 / size . x , 0.0 ) ) , r1 ) . xyz ;
vec3 dpdy = ( db < dt ) ? ce - getViewPosition ( ( uv - vec2 ( 0.0 , 1.0 / size . y ) ) , b1 ) . xyz
: - ce + getViewPosition ( ( uv + vec2 ( 0.0 , 1.0 / size . y ) ) , t1 ) . xyz ;
return normalize ( cross ( dpdx , dpdy ) ) ;
}
vec3 getViewNormal ( const vec2 uv ) {
# if NORMAL _VECTOR _TYPE == 2
return normalize ( textureLod ( tNormal , uv , 0. ) . rgb ) ;
# elif NORMAL _VECTOR _TYPE == 1
return unpackRGBToNormal ( textureLod ( tNormal , uv , 0. ) . rgb ) ;
# else
return computeNormalFromDepth ( uv ) ;
# endif
}
void denoiseSample ( in vec3 center , in vec3 viewNormal , in vec3 viewPos , in vec2 sampleUv , inout vec3 denoised , inout float totalWeight ) {
vec4 sampleTexel = textureLod ( tDiffuse , sampleUv , 0.0 ) ;
float sampleDepth = getDepth ( sampleUv ) ;
vec3 sampleNormal = getViewNormal ( sampleUv ) ;
vec3 neighborColor = sampleTexel . rgb ;
vec3 viewPosSample = getViewPosition ( sampleUv , sampleDepth ) ;
float normalDiff = dot ( viewNormal , sampleNormal ) ;
float normalSimilarity = pow ( max ( normalDiff , 0. ) , normalPhi ) ;
float lumaDiff = abs ( getLuminance ( neighborColor ) - getLuminance ( center ) ) ;
float lumaSimilarity = max ( 1.0 - lumaDiff / lumaPhi , 0.0 ) ;
float depthDiff = abs ( dot ( viewPos - viewPosSample , viewNormal ) ) ;
float depthSimilarity = max ( 1. - depthDiff / depthPhi , 0. ) ;
float w = lumaSimilarity * depthSimilarity * normalSimilarity ;
denoised += w * neighborColor ;
totalWeight += w ;
}
void main ( ) {
float depth = getDepth ( vUv . xy ) ;
vec3 viewNormal = getViewNormal ( vUv ) ;
if ( depth == 1. || dot ( viewNormal , viewNormal ) == 0. ) {
discard ;
return ;
}
vec4 texel = textureLod ( tDiffuse , vUv , 0.0 ) ;
vec3 center = texel . rgb ;
vec3 viewPos = getViewPosition ( vUv , depth ) ;
vec2 noiseResolution = vec2 ( textureSize ( tNoise , 0 ) ) ;
vec2 noiseUv = vUv * resolution / noiseResolution ;
vec4 noiseTexel = textureLod ( tNoise , noiseUv , 0.0 ) ;
vec2 noiseVec = vec2 ( sin ( noiseTexel [ index % 4 ] * 2. * PI ) , cos ( noiseTexel [ index % 4 ] * 2. * PI ) ) ;
mat2 rotationMatrix = mat2 ( noiseVec . x , - noiseVec . y , noiseVec . x , noiseVec . y ) ;
float totalWeight = 1.0 ;
vec3 denoised = texel . rgb ;
for ( int i = 0 ; i < SAMPLES ; i ++ ) {
vec3 sampleDir = poissonDisk [ i ] ;
vec2 offset = rotationMatrix * ( sampleDir . xy * ( 1. + sampleDir . z * ( radius - 1. ) ) / resolution ) ;
vec2 sampleUv = vUv + offset ;
denoiseSample ( center , viewNormal , viewPos , sampleUv , denoised , totalWeight ) ;
}
if ( totalWeight > 0. ) {
denoised /= totalWeight ;
}
gl _FragColor = FRAGMENT _OUTPUT ;
2026-02-02 18:18:36 +08:00
} ` };function Op(s,e,t){const n=L2(s,e,t);let i="vec3[SAMPLES](";for(let r=0;r<s;r++){const a=n[r];i+= ` vec3 ( $ { a . x } , $ { a . y } , $ { a . z } ) $ { r < s - 1 ? "," : ")" } ` }return i}function L2(s,e,t){const n=[];for(let i=0;i<s;i++){const r=2*Math.PI*e*i/s,a=Math.pow(i/(s-1),t);n.push(new R(Math.cos(r),Math.sin(r),a))}return n}class I2{constructor(e=Math){this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]],this.grad4=[[0,1,1,1],[0,1,1,-1],[0,1,-1,1],[0,1,-1,-1],[0,-1,1,1],[0,-1,1,-1],[0,-1,-1,1],[0,-1,-1,-1],[1,0,1,1],[1,0,1,-1],[1,0,-1,1],[1,0,-1,-1],[-1,0,1,1],[-1,0,1,-1],[-1,0,-1,1],[-1,0,-1,-1],[1,1,0,1],[1,1,0,-1],[1,-1,0,1],[1,-1,0,-1],[-1,1,0,1],[-1,1,0,-1],[-1,-1,0,1],[-1,-1,0,-1],[1,1,1,0],[1,1,-1,0],[1,-1,1,0],[1,-1,-1,0],[-1,1,1,0],[-1,1,-1,0],[-1,-1,1,0],[-1,-1,-1,0]],this.p=[];for(let t=0;t<256;t++)this.p[t]=Math.floor(e.random()*256);this.perm=[];for(let t=0;t<512;t++)this.perm[t]=this.p[t&255];this.simplex=[[0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0],[0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0],[1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0],[2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]]}noise(e,t){let n,i,r;const a=.5*(Math.sqrt(3)-1),o=(e+t)*a,l=Math.floor(e+o),c=Math.floor(t+o),h=(3-Math.sqrt(3))/6,u=(l+c)*h,f=l-u,d=c-u,m=e-f,p=t-d;let x,g;m>p?(x=1,g=0):(x=0,g=1);const b=m-x+h,v=p-g+h,y=m-1+2*h,M=p-1+2*h,E=l&255,C=c&255,P=this.perm[E+this.perm[C]]%12,_=this.perm[E+x+this.perm[C+g]]%12,S=this.perm[E+1+this.perm[C+1]]%12;let I=.5-m*m-p*p;I<0?n=0:(I*=I,n=I*I*this._dot(this.grad3[P],m,p));let A=.5-b*b-v*v;A<0?i=0:(A*=A,i=A*A*this._dot(this.grad3[_],b,v));let B=.5-y*y-M*M;return B<0?r=0:(B*=B,r=B*B*this._dot(this.grad3[S],y,M)),70*(n+i+r)}noise3d(e,t,n){let i,r,a,o;const l=(e+t+n)*.3333333333333333,c=Math.floor(e+l),h=Math.floor(t+l),u=Math.floor(n+l),f=1/6,d=(c+h+u)*f,m=c-d,p=h-d,x=u-d,g=e-m,b=t-p,v=n-x;let y,M,E,C,P,_;g>=b?b>=v?(y=1,M=0,E=0,C=1,P=1,_=0):g>=v?(y=1,M=0,E=0,C=1,P=0,_=1):(y=0,M=0,E=1,C=1,P=0,_=1):b<v?(y=0,M=0,E=1,C=0,P=1,_=1):g<v?(y=0,M=1,E=0,C=0,P=1,_=1):(y=0,M=1,E=0,C=1,P=1,_=0);const S=g-y+f,I=b-M+f,A=v-E+f,B=g-C+2*f,w=b-P+2*f,F=v-_+2*f,W=g-1+3*f,X=b-1+3*f, $ =v-1+3*f,Z=c&255,ie=h&255,j=u&255,Y=this.perm[Z+this.perm[ie+this.perm[j]]]%12,ge=this.perm[Z+y+this.perm[ie+M+this.perm[j+E]]]%12,pe=this.perm[Z+C+this.perm[ie+P+this.perm[j+_]]]%12,de=this.perm[Z+1+this.perm[ie+1+this.perm[j+1]]]%12;let se=.6-g*g-b*b-v*v;se<0?i=0:(se*=se,i=se*se*this._dot3(this.grad3[Y],g,b,v));let he=.6-S*S-I*I-A*A;he<0?r=0:(he*=he,r=he*he*this._dot3(this.grad3[ge],S,I,A));let fe=.6-B*B-w*w-F*F;fe<0?a=0:(fe*=fe,a=fe*fe*this._dot3(this.grad3[pe],B,w,F));let ve=.6-W*W-X*X- $ * $ ;return ve<0?o=0:(ve*=ve,o=ve*ve*this._dot3(this.grad3[de],W,X, $ )),32*(i+r+a+o)}noise4d(e,t,n,i){const r=this.grad4,a=this.simplex,o=this.perm,l=(Math.sqrt(5)-1)/4,c=(5-Math.sqrt(5))/20;let h,u,f,d,m;const p=(e+t+n+i)*l,x=Math.floor(e+p),g=Math.floor(t+p),b=Math.floor(n+p),v=Math.floor(i+p),y=(x+g+b+v)*c,M=x-y,E=g-y,C=b-y,P=v-y,_=e-M,S=t-E,I=n-C,A=i-P,B=_>S?32:0,w=_>I?16:0,F=S>I?8:0,W=_>A?4:0,X=S>A?2:0, $ =I>A?1:0,Z=B+w+F+W+X+ $ ,ie=a[Z][0]>=3?1:0,j=a[Z][1]>=3?1:0,Y=a[Z][2]>=3?1:0,ge=a[Z][3]>=3?1:0,pe=a[Z][0]>=2?1:0,de=a[Z][1]>=2?1:0,se=a[Z][2]>=2?1:0,he=a[Z][3]>=2?1:0,fe=a[Z][0]>=1?1:0,ve=a[Z][1]>=1?1:0,Se=a[Z][2]>=1?1:0,Be=a[Z][3]>=1?1:0,Je=_-ie+c,Ne=S-j+c,T=I-Y+c,D=A-ge+c,V=_-pe+2*c,U=S-de+2*c,k=I-se+2*c,z=A-he+2*c,ee=_-fe+3*c,J=S-ve+3*c,G=I-Se+3*c,N=A-Be+3*c,L=_-1+4*c,H=S-1+4*c,K=I-1+4*c,le=A-1+4*c,te=x&255,Ce=g&255,be=b&255,Re=v&255,Ie=o[te+o[Ce+o[be+o[Re]]]]%32,ue=o[te+ie+o[Ce+j+o[be+Y+o[Re+ge]]]]%32,ye=o[te+pe+o[Ce+de+o[be+se+o[Re+he]]]]%32,Ve=o[te+fe+
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform sampler2D tDiffuse ;
uniform vec3 defaultColor ;
uniform float defaultOpacity ;
uniform float luminosityThreshold ;
uniform float smoothWidth ;
varying vec2 vUv ;
void main ( ) {
vec4 texel = texture2D ( tDiffuse , vUv ) ;
float v = luminance ( texel . xyz ) ;
vec4 outputColor = vec4 ( defaultColor . rgb , defaultOpacity ) ;
float alpha = smoothstep ( luminosityThreshold , luminosityThreshold + smoothWidth , v ) ;
gl _FragColor = mix ( outputColor , texel , alpha ) ;
2026-02-02 18:18:36 +08:00
} ` };class Er extends xs{constructor(e,t=1,n,i){super(),this.strength=t,this.radius=n,this.threshold=i,this.resolution=e!==void 0?new ce(e.x,e.y):new ce(256,256),this.clearColor=new ke(0,0,0),this.needsSwap=!1,this.renderTargetsHorizontal=[],this.renderTargetsVertical=[],this.nMips=5;let r=Math.round(this.resolution.x/2),a=Math.round(this.resolution.y/2);this.renderTargetBright=new mn(r,a,{type:Rn}),this.renderTargetBright.texture.name="UnrealBloomPass.bright",this.renderTargetBright.texture.generateMipmaps=!1;for(let h=0;h<this.nMips;h++){const u=new mn(r,a,{type:Rn});u.texture.name="UnrealBloomPass.h"+h,u.texture.generateMipmaps=!1,this.renderTargetsHorizontal.push(u);const f=new mn(r,a,{type:Rn});f.texture.name="UnrealBloomPass.v"+h,f.texture.generateMipmaps=!1,this.renderTargetsVertical.push(f),r=Math.round(r/2),a=Math.round(a/2)}const o=D2;this.highPassUniforms=oi.clone(o.uniforms),this.highPassUniforms.luminosityThreshold.value=i,this.highPassUniforms.smoothWidth.value=.01,this.materialHighPassFilter=new kt({uniforms:this.highPassUniforms,vertexShader:o.vertexShader,fragmentShader:o.fragmentShader}),this.separableBlurMaterials=[];const l=[6,10,14,18,22];r=Math.round(this.resolution.x/2),a=Math.round(this.resolution.y/2);for(let h=0;h<this.nMips;h++)this.separableBlurMaterials.push(this._getSeparableBlurMaterial(l[h])),this.separableBlurMaterials[h].uniforms.invSize.value=new ce(1/r,1/a),r=Math.round(r/2),a=Math.round(a/2);this.compositeMaterial=this._getCompositeMaterial(this.nMips),this.compositeMaterial.uniforms.blurTexture1.value=this.renderTargetsVertical[0].texture,this.compositeMaterial.uniforms.blurTexture2.value=this.renderTargetsVertical[1].texture,this.compositeMaterial.uniforms.blurTexture3.value=this.renderTargetsVertical[2].texture,this.compositeMaterial.uniforms.blurTexture4.value=this.renderTargetsVertical[3].texture,this.compositeMaterial.uniforms.blurTexture5.value=this.renderTargetsVertical[4].texture,this.compositeMaterial.uniforms.bloomStrength.value=t,this.compositeMaterial.uniforms.bloomRadius.value=.1;const c=[1,.8,.6,.4,.2];this.compositeMaterial.uniforms.bloomFactors.value=c,this.bloomTintColors=[new R(1,1,1),new R(1,1,1),new R(1,1,1),new R(1,1,1),new R(1,1,1)],this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,this.copyUniforms=oi.clone(gs.uniforms),this.blendMaterial=new kt({uniforms:this.copyUniforms,vertexShader:gs.vertexShader,fragmentShader:gs.fragmentShader,blending:Gl,depthTest:!1,depthWrite:!1,transparent:!0}),this._oldClearColor=new ke,this._oldClearAlpha=1,this._basic=new tn,this._fsQuad=new jo(null)}dispose(){for(let e=0;e<this.renderTargetsHorizontal.length;e++)this.renderTargetsHorizontal[e].dispose();for(let e=0;e<this.renderTargetsVertical.length;e++)this.renderTargetsVertical[e].dispose();this.renderTargetBright.dispose();for(let e=0;e<this.separableBlurMaterials.length;e++)this.separableBlurMaterials[e].dispose();this.compositeMaterial.dispose(),this.blendMaterial.dispose(),this._basic.dispose(),this._fsQuad.dispose()}setSize(e,t){let n=Math.round(e/2),i=Math.round(t/2);this.renderTargetBright.setSize(n,i);for(let r=0;r<this.nMips;r++)this.renderTargetsHorizontal[r].setSize(n,i),this.renderTargetsVertical[r].setSize(n,i),this.separableBlurMaterials[r].uniforms.invSize.value=new ce(1/n,1/i),n=Math.round(n/2),i=Math.round(i/2)}render(e,t,n,i,r){e.getClearColor(this._oldClearColor),this._oldClearAlpha=e.getClearAlpha();const a=e.autoClear;e.autoClear=!1,e.setClearColor(this.clearColor,0),r&&e.state.buffers.stencil.setTest(!1),this.renderToScreen&&(this._fsQuad.material=this._basic,this._basic.map=n.texture,e.setRenderTarget(null),e.clear(),this._fsQuad.render(e)),this.highPassUniforms.tDiffuse.value=n.texture,this.highPassUniforms.luminosityThreshold.value=this.threshold,this._fsQuad.material=this.materialHighPassFilter,e.setRenderTarget(this.renderTargetBright),e.clear(),this._fsQuad.render(e);let o=this.renderTargetBright;for(let l=0;l<this.nMips;l++)this._fsQuad.material=this.separableBlurMaterials[l],this.separableBlurMaterials[l].uniforms.colorT
2026-01-22 11:29:51 +08:00
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: ` # include < common >
varying vec2 vUv ;
uniform sampler2D colorTexture ;
uniform vec2 invSize ;
uniform vec2 direction ;
uniform float gaussianCoefficients [ KERNEL _RADIUS ] ;
void main ( ) {
float weightSum = gaussianCoefficients [ 0 ] ;
vec3 diffuseSum = texture2D ( colorTexture , vUv ) . rgb * weightSum ;
for ( int i = 1 ; i < KERNEL _RADIUS ; i ++ ) {
float x = float ( i ) ;
float w = gaussianCoefficients [ i ] ;
vec2 uvOffset = direction * invSize * x ;
vec3 sample1 = texture2D ( colorTexture , vUv + uvOffset ) . rgb ;
vec3 sample2 = texture2D ( colorTexture , vUv - uvOffset ) . rgb ;
diffuseSum += ( sample1 + sample2 ) * w ;
}
gl _FragColor = vec4 ( diffuseSum , 1.0 ) ;
2026-02-02 16:36:17 +08:00
} ` })}_getCompositeMaterial(e){return new kt({defines:{NUM_MIPS:e},uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader: ` varying vec2 vUv ;
2026-01-22 11:29:51 +08:00
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: ` varying vec2 vUv ;
uniform sampler2D blurTexture1 ;
uniform sampler2D blurTexture2 ;
uniform sampler2D blurTexture3 ;
uniform sampler2D blurTexture4 ;
uniform sampler2D blurTexture5 ;
uniform float bloomStrength ;
uniform float bloomRadius ;
uniform float bloomFactors [ NUM _MIPS ] ;
uniform vec3 bloomTintColors [ NUM _MIPS ] ;
float lerpBloomFactor ( const in float factor ) {
float mirrorFactor = 1.2 - factor ;
return mix ( factor , mirrorFactor , bloomRadius ) ;
}
void main ( ) {
gl _FragColor = bloomStrength * ( lerpBloomFactor ( bloomFactors [ 0 ] ) * vec4 ( bloomTintColors [ 0 ] , 1.0 ) * texture2D ( blurTexture1 , vUv ) +
lerpBloomFactor ( bloomFactors [ 1 ] ) * vec4 ( bloomTintColors [ 1 ] , 1.0 ) * texture2D ( blurTexture2 , vUv ) +
lerpBloomFactor ( bloomFactors [ 2 ] ) * vec4 ( bloomTintColors [ 2 ] , 1.0 ) * texture2D ( blurTexture3 , vUv ) +
lerpBloomFactor ( bloomFactors [ 3 ] ) * vec4 ( bloomTintColors [ 3 ] , 1.0 ) * texture2D ( blurTexture4 , vUv ) +
lerpBloomFactor ( bloomFactors [ 4 ] ) * vec4 ( bloomTintColors [ 4 ] , 1.0 ) * texture2D ( blurTexture5 , vUv ) ) ;
2026-02-02 18:18:36 +08:00
} ` })}}Er.BlurDirectionX=new ce(1,0),Er.BlurDirectionY=new ce(0,1);const Ko={name:"OutputShader",uniforms:{tDiffuse:{value:null},toneMappingExposure:{value:1}},vertexShader: `
2026-01-22 11:29:51 +08:00
precision highp float ;
uniform mat4 modelViewMatrix ;
uniform mat4 projectionMatrix ;
attribute vec3 position ;
attribute vec2 uv ;
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
precision highp float ;
uniform sampler2D tDiffuse ;
# include < tonemapping _pars _fragment >
# include < colorspace _pars _fragment >
varying vec2 vUv ;
void main ( ) {
gl _FragColor = texture2D ( tDiffuse , vUv ) ;
// tone mapping
# ifdef LINEAR _TONE _MAPPING
gl _FragColor . rgb = LinearToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( REINHARD _TONE _MAPPING )
gl _FragColor . rgb = ReinhardToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( CINEON _TONE _MAPPING )
gl _FragColor . rgb = CineonToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( ACES _FILMIC _TONE _MAPPING )
gl _FragColor . rgb = ACESFilmicToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( AGX _TONE _MAPPING )
gl _FragColor . rgb = AgXToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( NEUTRAL _TONE _MAPPING )
gl _FragColor . rgb = NeutralToneMapping ( gl _FragColor . rgb ) ;
# elif defined ( CUSTOM _TONE _MAPPING )
gl _FragColor . rgb = CustomToneMapping ( gl _FragColor . rgb ) ;
# endif
// color space
# ifdef SRGB _TRANSFER
gl _FragColor = sRGBTransferOETF ( gl _FragColor ) ;
# endif
2026-02-02 18:18:36 +08:00
} ` };class B2 extends xs{constructor(){super(),this.uniforms=oi.clone(Ko.uniforms),this.material=new pv({name:Ko.name,uniforms:this.uniforms,vertexShader:Ko.vertexShader,fragmentShader:Ko.fragmentShader}),this._fsQuad=new jo(this.material),this._outputColorSpace=null,this._toneMapping=null}render(e,t,n){this.uniforms.tDiffuse.value=n.texture,this.uniforms.toneMappingExposure.value=e.toneMappingExposure,(this._outputColorSpace!==e.outputColorSpace||this._toneMapping!==e.toneMapping)&&(this._outputColorSpace=e.outputColorSpace,this._toneMapping=e.toneMapping,this.material.defines={},it.getTransfer(this._outputColorSpace)===lt&&(this.material.defines.SRGB_TRANSFER=""),this._toneMapping===fd?this.material.defines.LINEAR_TONE_MAPPING="":this._toneMapping===pd?this.material.defines.REINHARD_TONE_MAPPING="":this._toneMapping===md?this.material.defines.CINEON_TONE_MAPPING="":this._toneMapping===tc?this.material.defines.ACES_FILMIC_TONE_MAPPING="":this._toneMapping===xd?this.material.defines.AGX_TONE_MAPPING="":this._toneMapping===vd?this.material.defines.NEUTRAL_TONE_MAPPING="":this._toneMapping===gd&&(this.material.defines.CUSTOM_TONE_MAPPING=""),this.material.needsUpdate=!0),this.renderToScreen===!0?(e.setRenderTarget(null),this._fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),this._fsQuad.render(e))}dispose(){this.material.dispose(),this._fsQuad.dispose()}}const N2={name:"FXAAShader",uniforms:{tDiffuse:{value:null},resolution:{value:new ce(1/1024,1/512)}},vertexShader: `
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform sampler2D tDiffuse ;
uniform vec2 resolution ;
varying vec2 vUv ;
# define EDGE _STEP _COUNT 6
# define EDGE _GUESS 8.0
# define EDGE _STEPS 1.0 , 1.5 , 2.0 , 2.0 , 2.0 , 4.0
const float edgeSteps [ EDGE _STEP _COUNT ] = float [ EDGE _STEP _COUNT ] ( EDGE _STEPS ) ;
float _ContrastThreshold = 0.0312 ;
float _RelativeThreshold = 0.063 ;
float _SubpixelBlending = 1.0 ;
vec4 Sample ( sampler2D tex2D , vec2 uv ) {
return texture ( tex2D , uv ) ;
}
float SampleLuminance ( sampler2D tex2D , vec2 uv ) {
return dot ( Sample ( tex2D , uv ) . rgb , vec3 ( 0.3 , 0.59 , 0.11 ) ) ;
}
float SampleLuminance ( sampler2D tex2D , vec2 texSize , vec2 uv , float uOffset , float vOffset ) {
uv += texSize * vec2 ( uOffset , vOffset ) ;
return SampleLuminance ( tex2D , uv ) ;
}
struct LuminanceData {
float m , n , e , s , w ;
float ne , nw , se , sw ;
float highest , lowest , contrast ;
} ;
LuminanceData SampleLuminanceNeighborhood ( sampler2D tex2D , vec2 texSize , vec2 uv ) {
LuminanceData l ;
l . m = SampleLuminance ( tex2D , uv ) ;
l . n = SampleLuminance ( tex2D , texSize , uv , 0.0 , 1.0 ) ;
l . e = SampleLuminance ( tex2D , texSize , uv , 1.0 , 0.0 ) ;
l . s = SampleLuminance ( tex2D , texSize , uv , 0.0 , - 1.0 ) ;
l . w = SampleLuminance ( tex2D , texSize , uv , - 1.0 , 0.0 ) ;
l . ne = SampleLuminance ( tex2D , texSize , uv , 1.0 , 1.0 ) ;
l . nw = SampleLuminance ( tex2D , texSize , uv , - 1.0 , 1.0 ) ;
l . se = SampleLuminance ( tex2D , texSize , uv , 1.0 , - 1.0 ) ;
l . sw = SampleLuminance ( tex2D , texSize , uv , - 1.0 , - 1.0 ) ;
l . highest = max ( max ( max ( max ( l . n , l . e ) , l . s ) , l . w ) , l . m ) ;
l . lowest = min ( min ( min ( min ( l . n , l . e ) , l . s ) , l . w ) , l . m ) ;
l . contrast = l . highest - l . lowest ;
return l ;
}
bool ShouldSkipPixel ( LuminanceData l ) {
float threshold = max ( _ContrastThreshold , _RelativeThreshold * l . highest ) ;
return l . contrast < threshold ;
}
float DeterminePixelBlendFactor ( LuminanceData l ) {
float f = 2.0 * ( l . n + l . e + l . s + l . w ) ;
f += l . ne + l . nw + l . se + l . sw ;
f *= 1.0 / 12.0 ;
f = abs ( f - l . m ) ;
f = clamp ( f / l . contrast , 0.0 , 1.0 ) ;
float blendFactor = smoothstep ( 0.0 , 1.0 , f ) ;
return blendFactor * blendFactor * _SubpixelBlending ;
}
struct EdgeData {
bool isHorizontal ;
float pixelStep ;
float oppositeLuminance , gradient ;
} ;
EdgeData DetermineEdge ( vec2 texSize , LuminanceData l ) {
EdgeData e ;
float horizontal =
abs ( l . n + l . s - 2.0 * l . m ) * 2.0 +
abs ( l . ne + l . se - 2.0 * l . e ) +
abs ( l . nw + l . sw - 2.0 * l . w ) ;
float vertical =
abs ( l . e + l . w - 2.0 * l . m ) * 2.0 +
abs ( l . ne + l . nw - 2.0 * l . n ) +
abs ( l . se + l . sw - 2.0 * l . s ) ;
e . isHorizontal = horizontal >= vertical ;
float pLuminance = e . isHorizontal ? l . n : l . e ;
float nLuminance = e . isHorizontal ? l . s : l . w ;
float pGradient = abs ( pLuminance - l . m ) ;
float nGradient = abs ( nLuminance - l . m ) ;
e . pixelStep = e . isHorizontal ? texSize . y : texSize . x ;
if ( pGradient < nGradient ) {
e . pixelStep = - e . pixelStep ;
e . oppositeLuminance = nLuminance ;
e . gradient = nGradient ;
} else {
e . oppositeLuminance = pLuminance ;
e . gradient = pGradient ;
}
return e ;
}
float DetermineEdgeBlendFactor ( sampler2D tex2D , vec2 texSize , LuminanceData l , EdgeData e , vec2 uv ) {
vec2 uvEdge = uv ;
vec2 edgeStep ;
if ( e . isHorizontal ) {
uvEdge . y += e . pixelStep * 0.5 ;
edgeStep = vec2 ( texSize . x , 0.0 ) ;
} else {
uvEdge . x += e . pixelStep * 0.5 ;
edgeStep = vec2 ( 0.0 , texSize . y ) ;
}
float edgeLuminance = ( l . m + e . oppositeLuminance ) * 0.5 ;
float gradientThreshold = e . gradient * 0.25 ;
vec2 puv = uvEdge + edgeStep * edgeSteps [ 0 ] ;
float pLuminanceDelta = SampleLuminance ( tex2D , puv ) - edgeLuminance ;
bool pAtEnd = abs ( pLuminanceDelta ) >= gradientThreshold ;
for ( int i = 1 ; i < EDGE _STEP _COUNT && ! pAtEnd ; i ++ ) {
puv += edgeStep * edgeSteps [ i ] ;
pLuminanceDelta = SampleLuminance ( tex2D , puv ) - edgeLuminance ;
pAtEnd = abs ( pLuminanceDelta ) >= gradientThreshold ;
}
if ( ! pAtEnd ) {
puv += edgeStep * EDGE _GUESS ;
}
vec2 nuv = uvEdge - edgeStep * edgeSteps [ 0 ] ;
float nLuminanceDelta = SampleLuminance ( tex2D , nuv ) - edgeLuminance ;
bool nAtEnd = abs ( nLuminanceDelta ) >= gradientThreshold ;
for ( int i = 1 ; i < EDGE _STEP _COUNT && ! nAtEnd ; i ++ ) {
nuv -= edgeStep * edgeSteps [ i ] ;
nLuminanceDelta = SampleLuminance ( tex2D , nuv ) - edgeLuminance ;
nAtEnd = abs ( nLuminanceDelta ) >= gradientThreshold ;
}
if ( ! nAtEnd ) {
nuv -= edgeStep * EDGE _GUESS ;
}
float pDistance , nDistance ;
if ( e . isHorizontal ) {
pDistance = puv . x - uv . x ;
nDistance = uv . x - nuv . x ;
} else {
pDistance = puv . y - uv . y ;
nDistance = uv . y - nuv . y ;
}
float shortestDistance ;
bool deltaSign ;
if ( pDistance <= nDistance ) {
shortestDistance = pDistance ;
deltaSign = pLuminanceDelta >= 0.0 ;
} else {
shortestDistance = nDistance ;
deltaSign = nLuminanceDelta >= 0.0 ;
}
if ( deltaSign == ( l . m - edgeLuminance >= 0.0 ) ) {
return 0.0 ;
}
return 0.5 - shortestDistance / ( pDistance + nDistance ) ;
}
vec4 ApplyFXAA ( sampler2D tex2D , vec2 texSize , vec2 uv ) {
LuminanceData luminance = SampleLuminanceNeighborhood ( tex2D , texSize , uv ) ;
if ( ShouldSkipPixel ( luminance ) ) {
return Sample ( tex2D , uv ) ;
}
float pixelBlend = DeterminePixelBlendFactor ( luminance ) ;
EdgeData edge = DetermineEdge ( texSize , luminance ) ;
float edgeBlend = DetermineEdgeBlendFactor ( tex2D , texSize , luminance , edge , uv ) ;
float finalBlend = max ( pixelBlend , edgeBlend ) ;
if ( edge . isHorizontal ) {
uv . y += edge . pixelStep * finalBlend ;
} else {
uv . x += edge . pixelStep * finalBlend ;
}
return Sample ( tex2D , uv ) ;
}
void main ( ) {
gl _FragColor = ApplyFXAA ( tDiffuse , resolution . xy , vUv ) ;
2026-02-02 18:18:36 +08:00
} ` },k2={uniforms:{tDiffuse:{value:null},saturation:{value:1.2},contrast:{value:1.2}},vertexShader: `
2026-01-22 11:29:51 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
}
` ,fragmentShader: `
uniform sampler2D tDiffuse ;
uniform float saturation ;
uniform float contrast ;
varying vec2 vUv ;
void main ( ) {
vec4 color = texture2D ( tDiffuse , vUv ) ;
// 转换为灰度值用于饱和度调整
float gray = dot ( color . rgb , vec3 ( 0.299 , 0.587 , 0.114 ) ) ;
// 混合原始颜色和灰度值来调整饱和度
color . rgb = mix ( vec3 ( gray ) , color . rgb , saturation ) ;
// 调整对比度
color . rgb = ( color . rgb - 0.5 ) * contrast + 0.5 ;
gl _FragColor = color ;
}
2026-02-02 18:18:36 +08:00
` };class U2{engine;composer;saturationPass;constructor(e){this.engine=e}resize(e,t){if(e===void 0||t===void 0){const r=this.engine.deviceModule.getContainerSize();e=e??r.width,t=t??r.height}if(!e||!t||!this.composer)return;const n=this.engine.renderer?.getPixelRatio?.()??window.devicePixelRatio??1;this.composer.setPixelRatio(n),this.composer.setSize(e,t);const i=this.composer.passes.find(r=>r instanceof qo&&r.material.uniforms.resolution);i&&(i.material.uniforms.resolution.value.x=1/(e*n),i.material.uniforms.resolution.value.y=1/(t*n))}init(){const{width:e,height:t}=this.engine.deviceModule.getContainerSize(),n=this.engine.scene,i=this.engine.camera,r=this.engine.renderer,a=this.engine.renderer?.getPixelRatio?.()??window.devicePixelRatio??1,o=new mn(e,t,{minFilter: $ t,magFilter: $ t,format:pn,samples:4});this.composer=new C2(r,o),this.composer.setPixelRatio(a),this.composer.setSize(e,t);const l=new A2(n,i);this.composer.addPass(l);const c=new bn(n,i,e,t);c.output=bn.OUTPUT.Default,c.blendIntensity=.5,c.updateGtaoMaterial&&c.updateGtaoMaterial({radius:1,distanceExponent:1,thickness:1,scale:1,distanceFallOff:1,screenSpaceRadius:!0}),new Er(new ce(e,t),.1,.1,.5),this.saturationPass=new qo(k2),this.saturationPass.uniforms.saturation.value=1.3,this.saturationPass.uniforms.contrast.value=1.1,this.composer.addPass(this.saturationPass);const h=new B2;this.composer.addPass(h);const u=new qo(N2);u.material.uniforms.resolution.value.x=1/(e*a),u.material.uniforms.resolution.value.y=1/(t*a),this.composer.addPass(u)}}var Jo=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Fp(s){return s&&s.__esModule&&Object.prototype.hasOwnProperty.call(s,"default")?s.default:s}function Qo(s){throw new Error('Could not dynamically require "'+s+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var zp={exports:{}},Hp;function O2(){return Hp||(Hp=1,(function(s,e){(function(t){s.exports=t()})(function(){return(function t(n,i,r){function a(c,h){if(!i[c]){if(!n[c]){var u=typeof Qo=="function"&&Qo;if(!h&&u)return u(c,!0);if(o)return o(c,!0);var f=new Error("Cannot find module '"+c+"'");throw f.code="MODULE_NOT_FOUND",f}var d=i[c]={exports:{}};n[c][0].call(d.exports,function(m){var p=n[c][1][m];return a(p||m)},d,d.exports,t,n,i,r)}return i[c].exports}for(var o=typeof Qo=="function"&&Qo,l=0;l<r.length;l++)a(r[l]);return a})({1:[function(t,n,i){var r=t("./utils"),a=t("./support"),o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";i.encode=function(l){for(var c,h,u,f,d,m,p,x=[],g=0,b=l.length,v=b,y=r.getTypeOf(l)!=="string";g<l.length;)v=b-g,u=y?(c=l[g++],h=g<b?l[g++]:0,g<b?l[g++]:0):(c=l.charCodeAt(g++),h=g<b?l.charCodeAt(g++):0,g<b?l.charCodeAt(g++):0),f=c>>2,d=(3&c)<<4|h>>4,m=1<v?(15&h)<<2|u>>6:64,p=2<v?63&u:64,x.push(o.charAt(f)+o.charAt(d)+o.charAt(m)+o.charAt(p));return x.join("")},i.decode=function(l){var c,h,u,f,d,m,p=0,x=0,g="data:";if(l.substr(0,g.length)===g)throw new Error("Invalid base64 input, it looks like a data url.");var b,v=3*(l=l.replace(/[^A-Za-z0-9+/=]/g,"")).length/4;if(l.charAt(l.length-1)===o.charAt(64)&&v--,l.charAt(l.length-2)===o.charAt(64)&&v--,v%1!=0)throw new Error("Invalid base64 input, bad content length.");for(b=a.uint8array?new Uint8Array(0|v):new Array(0|v);p<l.length;)c=o.indexOf(l.charAt(p++))<<2|(f=o.indexOf(l.charAt(p++)))>>4,h=(15&f)<<4|(d=o.indexOf(l.charAt(p++)))>>2,u=(3&d)<<6|(m=o.indexOf(l.charAt(p++))),b[x++]=c,d!==64&&(b[x++]=h),m!==64&&(b[x++]=u);return b}},{"./support":30,"./utils":32}],2:[function(t,n,i){var r=t("./external"),a=t("./stream/DataWorker"),o=t("./stream/Crc32Probe"),l=t("./stream/DataLengthProbe");function c(h,u,f,d,m){this.compressedSize=h,this.uncompressedSize=u,this.crc32=f,this.compression=d,this.compressedContent=m}c.prototype={getContentWorker:function(){var h=new a(r.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new l("data_length")),u=this;return h.on("end",f
\ 0 ` ,pe+=r(j,2),pe+=E.magic,pe+=r(v,2),pe+=r(y,2),pe+=r(ie.crc32,4),pe+=r(ie.compressedSize,4),pe+=r(ie.uncompressedSize,4),pe+=r(P.length,2),pe+=r(F.length,2),{fileRecord:u.LOCAL_FILE_HEADER+pe+P+F,dirRecord:u.CENTRAL_FILE_HEADER+r(ge,2)+pe+r(I.length,2)+" \0 \0 \0 \0 "+r(Y,4)+r(x,4)+P+F+I}}var o=t("../utils"),l=t("../stream/GenericWorker"),c=t("../utf8"),h=t("../crc32"),u=t("../signature");function f(d,m,p,x){l.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=m,this.zipPlatform=p,this.encodeFileName=x,this.streamFiles=d,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}o.inherits(f,l),f.prototype.push=function(d){var m=d.meta.percent||0,p=this.entriesCount,x=this._sources.length;this.accumulate?this.contentBuffer.push(d):(this.bytesWritten+=d.data.length,l.prototype.push.call(this,{data:d.data,meta:{currentFile:this.currentFile,percent:p?(m+100*(p-x-1))/p:100}}))},f.prototype.openedSource=function(d){this.currentSourceOffset=this.bytesWritten,this.currentFile=d.file.name;var m=this.streamFiles&&!d.file.dir;if(m){var p=a(d,m,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:p.fileRecord,meta:{percent:0}})}else this.accumulate=!0},f.prototype.closedSource=function(d){this.accumulate=!1;var m=this.streamFiles&&!d.file.dir,p=a(d,m,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(p.dirRecord),m)this.push({data:(function(x){return u.DATA_DESCRIPTOR+r(x.crc32,4)+r(x.compressedSize,4)+r(x.uncompressedSize,4)})(d),meta:{percent:100}});else for(this.push({data:p.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},f.prototype.flush=function(){for(var d=this.bytesWritten,m=0;m<this.dirRecords.length;m++)this.push({data:this.dirRecords[m],meta:{percent:100}});var p=this.bytesWritten-d,x=(function(g,b,v,y,M){var E=o.transformTo("string",M(y));return u.CENTRAL_DIRECTORY_END+" \0 \0 \0 \0 "+r(g,2)+r(g,2)+r(b,4)+r(v,4)+r(E.length,2)+E})(this.dirRecords.length,p,d,this.zipComment,this.encodeFileName);this.push({data:x,meta:{percent:100}})},f.prototype.prepareNextSource=function(){this.previous=this._sources.shift(),this.openedSource(this.previous.streamInfo),this.isPaused?this.previous.pause():this.previous.resume()},f.prototype.registerPrevious=function(d){this._sources.push(d);var m=this;return d.on("data",function(p){m.processChunk(p)}),d.on("end",function(){m.closedSource(m.previous.streamInfo),m._sources.length?m.prepareNextSource():m.end()}),d.on("error",function(p){m.error(p)}),this},f.prototype.resume=function(){return!!l.prototype.resume.call(this)&&(!this.previous&&this._sources.length?(this.prepareNextSource(),!0):this.previous||this._sources.length||this.generatedError?void 0:(this.end(),!0))},f.prototype.error=function(d){var m=this._sources;if(!l.prototype.error.call(this,d))return!1;for(var p=0;p<m.length;p++)try{m[p].error(d)}catch{}return!0},f.prototype.lock=function(){l.prototype.lock.call(this);for(var d=this._sources,m=0;m<d.length;m++)d[m].lock()},n.exports=f},{"../crc32":4,"../signature":23,"../stream/GenericWorker":28,"../utf8":31,"../utils":32}],9:[function(t,n,i){var r=t("../compressions"),a=t("./ZipFileWorker");i.generateWorker=function(o,l,c){var h=new a(l.streamFiles,c,l.platform,l.encodeFileName),u=0;try{o.forEach(function(f,d){u++;var m=(function(b,v){var y=b||v,M=r[y];if(!M)throw new Error(y+" is not a valid compression method !");return M})(d.options.compression,l.compression),p=d.options.compressionOptions||l.compressionOptions||{},x=d.dir,g=d.date;d._compressWorker(m,p).withStreamInfo("file",{name:f,dir:x,date:g,comment:d.comment||"",unixPermissions:d.unixPermissions,dosPermissions:d.dosPermissions}).pipe(h)}),h.entriesCount=u}catch(f){h.error(f)}return h}},{"../compressions":3,"./ZipFileWorker":8}],10:[function(t,n,i){function r(){if(!(this instanceof r))return new r;if(arguments.length)throw new Error("The constructor with parameters has been removed in JSZip 3.0, pl
` ).forEach(function(r){i=r.indexOf(":"),t=r.substring(0,i).trim().toLowerCase(),n=r.substring(i+1).trim(),!(!t||e[t]&&HM[t])&&(t==="set-cookie"?e[t]?e[t].push(n):e[t]=[n]:e[t]=e[t]?e[t]+", "+n:n)}),e},lm=Symbol("internals");function Ra(s){return s&&String(s).trim().toLowerCase()}function rl(s){return s===!1||s==null?s:re.isArray(s)?s.map(rl):String(s)}function GM(s){const e=Object.create(null),t=/([^ \s ,;=]+) \s *(?:= \s *([^,;]+))?/g;let n;for(;n=t.exec(s);)e[n[1]]=n[2];return e}const WM=s=>/^[-_a-zA-Z0-9^ ` | ~ , ! # $ % & ' * + . ] + $ / . test ( s . trim ( ) ) ; function nu ( s , e , t , n , i ) { if ( re . isFunction ( n ) ) return n . call ( this , e , t ) ; if ( i && ( e = t ) , ! ! re . isString ( e ) ) { if ( re . isString ( n ) ) return e . indexOf ( n ) !== - 1 ; if ( re . isRegExp ( n ) ) return n . test ( e ) } } function XM ( s ) { return s . trim ( ) . toLowerCase ( ) . replace ( /([a-z\d])(\w*)/g , ( e , t , n ) => t . toUpperCase ( ) + n ) } function jM ( s , e ) { const t = re . toCamelCase ( " " + e ) ; [ "get" , "set" , "has" ] . forEach ( n => { Object . defineProperty ( s , n + t , { value : function ( i , r , a ) { return this [ n ] . call ( this , e , i , r , a ) } , configurable : ! 0 } ) } ) } let _n = class { constructor ( s ) { s && this . set ( s ) } set ( s , e , t ) { const n = this ; function i ( a , o , l ) { const c = Ra ( o ) ; if ( ! c ) throw new Error ( "header name must be a non-empty string" ) ; const h = re . findKey ( n , c ) ; ( ! h || n [ h ] === void 0 || l === ! 0 || l === void 0 && n [ h ] !== ! 1 ) && ( n [ h || o ] = rl ( a ) ) } const r = ( a , o ) => re . forEach ( a , ( l , c ) => i ( l , c , o ) ) ; if ( re . isPlainObject ( s ) || s instanceof this . constructor ) r ( s , e ) ; else if ( re . isString ( s ) && ( s = s . trim ( ) ) && ! WM ( s ) ) r ( VM ( s ) , e ) ; else if ( re . isObject ( s ) && re . isIterable ( s ) ) { let a = { } , o , l ; for ( const c of s ) { if ( ! re . isArray ( c ) ) throw TypeError ( "Object iterator must return a key-value pair" ) ; a [ l = c [ 0 ] ] = ( o = a [ l ] ) ? re . isArray ( o ) ? [ ... o , c [ 1 ] ] : [ o , c [ 1 ] ] : c [ 1 ] } r ( a , e ) } else s != null && i ( e , s , t ) ; return this } get ( s , e ) { if ( s = Ra ( s ) , s ) { const t = re . findKey ( this , s ) ; if ( t ) { const n = this [ t ] ; if ( ! e ) return n ; if ( e === ! 0 ) return GM ( n ) ; if ( re . isFunction ( e ) ) return e . call ( this , n , t ) ; if ( re . isRegExp ( e ) ) return e . exec ( n ) ; throw new TypeError ( "parser must be boolean|regexp|function" ) } } } has ( s , e ) { if ( s = Ra ( s ) , s ) { const t = re . findKey ( this , s ) ; return ! ! ( t && this [ t ] !== void 0 && ( ! e || nu ( this , this [ t ] , t , e ) ) ) } return ! 1 } delete ( s , e ) { const t = this ; let n = ! 1 ; function i ( r ) { if ( r = Ra ( r ) , r ) { const a = re . findKey ( t , r ) ; a && ( ! e || nu ( t , t [ a ] , a , e ) ) && ( delete t [ a ] , n = ! 0 ) } } return re . isArray ( s ) ? s . forEach ( i ) : i ( s ) , n } clear ( s ) { const e = Object . keys ( this ) ; let t = e . length , n = ! 1 ; for ( ; t -- ; ) { const i = e [ t ] ; ( ! s || nu ( this , this [ i ] , i , s , ! 0 ) ) && ( delete this [ i ] , n = ! 0 ) } return n } normalize ( s ) { const e = this , t = { } ; return re . forEach ( this , ( n , i ) => { const r = re . findKey ( t , i ) ; if ( r ) { e [ r ] = rl ( n ) , delete e [ i ] ; return } const a = s ? XM ( i ) : String ( i ) . trim ( ) ; a !== i && delete e [ i ] , e [ a ] = rl ( n ) , t [ a ] = ! 0 } ) , this } concat ( ... s ) { return this . constructor . concat ( this , ... s ) } toJSON ( s ) { const e = Object . create ( null ) ; return re . forEach ( this , ( t , n ) => { t != null && t !== ! 1 && ( e [ n ] = s && re . isArray ( t ) ? t . join ( ", " ) : t ) } ) , e } [ Symbol . iterator ] ( ) { return Object . entries ( this . toJSON ( ) ) [ Symbol . iterator ] ( ) } toString ( ) { return Object . entries ( this . toJSON ( ) ) . map ( ( [ s , e ] ) => s + ": " + e ) . join ( `
` )}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(s){return s instanceof this?s:new this(s)}static concat(s,...e){const t=new this(s);return e.forEach(n=>t.set(n)),t}static accessor(s){const e=(this[lm]=this[lm]={accessors:{}}).accessors,t=this.prototype;function n(i){const r=Ra(i);e[r]||(jM(t,i),e[r]=!0)}return re.isArray(s)?s.forEach(n):n(s),this}};_n.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),re.reduceDescriptors(_n.prototype,({value:s},e)=>{let t=e[0].toUpperCase()+e.slice(1);return{get:()=>s,set(n){this[t]=n}}}),re.freezeMethods(_n);function iu(s,e){const t=this||Pa,n=e||t,i=_n.from(n.headers);let r=n.data;return re.forEach(s,function(a){r=a.call(t,r,i.normalize(),e?e.status:void 0)}),i.normalize(),r}function cm(s){return!!(s&&s.__CANCEL__)}function Ar(s,e,t){Ke.call(this,s??"canceled",Ke.ERR_CANCELED,e,t),this.name="CanceledError"}re.inherits(Ar,Ke,{__CANCEL__:!0});function hm(s,e,t){const n=t.config.validateStatus;!t.status||!n||n(t.status)?s(t):e(new Ke("Request failed with status code "+t.status,[Ke.ERR_BAD_REQUEST,Ke.ERR_BAD_RESPONSE][Math.floor(t.status/100)-4],t.config,t.request,t))}function qM(s){const e=/^([-+ \w ]{1,25})(:? \/ \/ |:)/.exec(s);return e&&e[1]||""}function ZM(s,e){s=s||10;const t=new Array(s),n=new Array(s);let i=0,r=0,a;return e=e!==void 0?e:1e3,function(o){const l=Date.now(),c=n[r];a||(a=l),t[i]=o,n[i]=l;let h=r,u=0;for(;h!==i;)u+=t[h++],h=h%s;if(i=(i+1)%s,i===r&&(r=(r+1)%s),l-a<e)return;const f=c&&l-c;return f?Math.round(u*1e3/f):void 0}}function YM(s,e){let t=0,n=1e3/e,i,r;const a=(o,l=Date.now())=>{t=l,i=null,r&&(clearTimeout(r),r=null),s(...o)};return[(...o)=>{const l=Date.now(),c=l-t;c>=n?a(o,l):(i=o,r||(r=setTimeout(()=>{r=null,a(i)},n-c)))},()=>i&&a(i)]}const al=(s,e,t=3)=>{let n=0;const i=ZM(50,250);return YM(r=>{const a=r.loaded,o=r.lengthComputable?r.total:void 0,l=a-n,c=i(l),h=a<=o;n=a;const u={loaded:a,total:o,progress:o?a/o:void 0,bytes:l,rate:c||void 0,estimated:c&&o&&h?(o-a)/c:void 0,event:r,lengthComputable:o!=null,[e?"download":"upload"]:!0};s(u)},t)},um=(s,e)=>{const t=s!=null;return[n=>e[0]({lengthComputable:t,total:s,loaded:n}),e[1]]},dm=s=>(...e)=>re.asap(()=>s(...e)), $ M=rn.hasStandardBrowserEnv?((s,e)=>t=>(t=new URL(t,rn.origin),s.protocol===t.protocol&&s.host===t.host&&(e||s.port===t.port)))(new URL(rn.origin),rn.navigator&&/(msie|trident)/i.test(rn.navigator.userAgent)):()=>!0,KM=rn.hasStandardBrowserEnv?{write(s,e,t,n,i,r,a){if(typeof document>"u")return;const o=[ ` $ { s } = $ { encodeURIComponent ( e ) } ` ];re.isNumber(t)&&o.push( ` expires = $ { new Date ( t ) . toUTCString ( ) } ` ),re.isString(n)&&o.push( ` path = $ { n } ` ),re.isString(i)&&o.push( ` domain = $ { i } ` ),r===!0&&o.push("secure"),re.isString(a)&&o.push( ` SameSite = $ { a } ` ),document.cookie=o.join("; ")},read(s){if(typeof document>"u")return null;const e=document.cookie.match(new RegExp("(?:^|; )"+s+"=([^;]*)"));return e?decodeURIComponent(e[1]):null},remove(s){this.write(s,"",Date.now()-864e5,"/")}}:{write(){},read(){return null},remove(){}};function JM(s){return/^([a-z][a-z \d + \- .]*:)? \/ \/ /i.test(s)}function QM(s,e){return e?s.replace(/ \/ ? \/ $ /,"")+"/"+e.replace(/^ \/ +/,""):s}function fm(s,e,t){let n=!JM(e);return s&&(n||t==!1)?QM(s,e):e}const pm=s=>s instanceof _n?{...s}:s;function bs(s,e){e=e||{};const t={};function n(c,h,u,f){return re.isPlainObject(c)&&re.isPlainObject(h)?re.merge.call({caseless:f},c,h):re.isPlainObject(h)?re.merge({},h):re.isArray(h)?h.slice():h}function i(c,h,u,f){if(re.isUndefined(h)){if(!re.isUndefined(c))return n(void 0,c,u,f)}else return n(c,h,u,f)}function r(c,h){if(!re.isUndefined(h))return n(void 0,h)}function a(c,h){if(re.isUndefined(h)){if(!re.isUndefined(c))return n(void 0,c)}else return n(void 0,h)}function o(c,h,u){if(u in e)return n(c,h);if(u in s)return n(void 0,c)}const l={url:r,method:r,data:r,baseURL:a,transformRequest:a,transformResponse:a,paramsSerializer:a,timeout:a,timeoutMessage:a,withCredentials:a,withXSRFToken:a,adapter:a,responseType:a,xsrfCookieName:a,xsrfHeaderName:a,onUploadProgress:a,o
` +a.map(Mm).join( `
` ):" "+Mm(a[0]):"as no adapter specified";throw new Ke("There is no suitable adapter to dispatch the request "+o,"ERR_NOT_SUPPORT")}return i}const wm={getAdapter:hw,adapters:su};function ru(s){if(s.cancelToken&&s.cancelToken.throwIfRequested(),s.signal&&s.signal.aborted)throw new Ar(null,s)}function Sm(s){return ru(s),s.headers=_n.from(s.headers),s.data=iu.call(s,s.transformRequest),["post","put","patch"].indexOf(s.method)!==-1&&s.headers.setContentType("application/x-www-form-urlencoded",!1),wm.getAdapter(s.adapter||Pa.adapter,s)(s).then(function(e){return ru(s),e.data=iu.call(s,s.transformResponse,e),e.headers=_n.from(e.headers),e},function(e){return cm(e)||(ru(s),e&&e.response&&(e.response.data=iu.call(s,s.transformResponse,e.response),e.response.headers=_n.from(e.response.headers))),Promise.reject(e)})}const Em="1.13.2",ll={};["object","boolean","number","function","string","symbol"].forEach((s,e)=>{ll[s]=function(t){return typeof t===s||"a"+(e<1?"n ":" ")+s}});const Tm={};ll.transitional=function(s,e,t){function n(i,r){return"[Axios v"+Em+"] Transitional option '"+i+"'"+r+(t?". "+t:"")}return(i,r,a)=>{if(s===!1)throw new Ke(n(r," has been removed"+(e?" in "+e:"")),Ke.ERR_DEPRECATED);return e&&!Tm[r]&&(Tm[r]=!0,console.warn(n(r," has been deprecated since v"+e+" and will be removed in the near future"))),s?s(i,r,a):!0}},ll.spelling=function(s){return(e,t)=>(console.warn( ` $ { t } is likely a misspelling of $ { s } ` ),!0)};function uw(s,e,t){if(typeof s!="object")throw new Ke("options must be an object",Ke.ERR_BAD_OPTION_VALUE);const n=Object.keys(s);let i=n.length;for(;i-- >0;){const r=n[i],a=e[r];if(a){const o=s[r],l=o===void 0||a(o,r,s);if(l!==!0)throw new Ke("option "+r+" must be "+l,Ke.ERR_BAD_OPTION_VALUE);continue}if(t!==!0)throw new Ke("Unknown option "+r,Ke.ERR_BAD_OPTION)}}const cl={assertOptions:uw,validators:ll},hi=cl.validators;let ys=class{constructor(s){this.defaults=s||{},this.interceptors={request:new rm,response:new rm}}async request(s,e){try{return await this._request(s,e)}catch(t){if(t instanceof Error){let n={};Error.captureStackTrace?Error.captureStackTrace(n):n=new Error;const i=n.stack?n.stack.replace(/^.+ \n /,""):"";try{t.stack?i&&!String(t.stack).endsWith(i.replace(/^.+ \n .+ \n /,""))&&(t.stack+= `
` +i):t.stack=i}catch{}}throw t}}_request(s,e){typeof s=="string"?(e=e||{},e.url=s):e=s||{},e=bs(this.defaults,e);const{transitional:t,paramsSerializer:n,headers:i}=e;t!==void 0&&cl.assertOptions(t,{silentJSONParsing:hi.transitional(hi.boolean),forcedJSONParsing:hi.transitional(hi.boolean),clarifyTimeoutError:hi.transitional(hi.boolean)},!1),n!=null&&(re.isFunction(n)?e.paramsSerializer={serialize:n}:cl.assertOptions(n,{encode:hi.function,serialize:hi.function},!0)),e.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?e.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:e.allowAbsoluteUrls=!0),cl.assertOptions(e,{baseUrl:hi.spelling("baseURL"),withXsrfToken:hi.spelling("withXSRFToken")},!0),e.method=(e.method||this.defaults.method||"get").toLowerCase();let r=i&&re.merge(i.common,i[e.method]);i&&re.forEach(["delete","get","head","post","put","patch","common"],d=>{delete i[d]}),e.headers=_n.concat(r,i);const a=[];let o=!0;this.interceptors.request.forEach(function(d){typeof d.runWhen=="function"&&d.runWhen(e)===!1||(o=o&&d.synchronous,a.unshift(d.fulfilled,d.rejected))});const l=[];this.interceptors.response.forEach(function(d){l.push(d.fulfilled,d.rejected)});let c,h=0,u;if(!o){const d=[Sm.bind(this),void 0];for(d.unshift(...a),d.push(...l),u=d.length,c=Promise.resolve(e);h<u;)c=c.then(d[h++],d[h++]);return c}u=a.length;let f=e;for(;h<u;){const d=a[h++],m=a[h++];try{f=d(f)}catch(p){m.call(this,p);break}}try{c=Sm.call(this,f)}catch(d){return Promise.reject(d)}for(h=0,u=l.length;h<u;)c=c.then(l[h++],l[h++]);return c}getUri(s){s=bs(this.defaults,s);const e=fm(s.baseURL,s.url,s.allowAbsoluteUrls);return sm(e,s.params,s.paramsSerializer)}};re.forEach(["delete","get","head","options"],function(s){ys.prototype[s]=function(e,t){return this.request(bs(t||{},{method:s,url:e,data:(t||{}).data}))}}),re.forEach(["post","put","patch"],function(s){function e(t){return function(n,i,r){return this.request(bs(r||{},{method:s,headers:t?{"Content-Type":"multipart/form-data"}:{},url:n,data:i}))}}ys.prototype[s]=e(),ys.prototype[s+"Form"]=e(!0)});let dw=class $ 0{constructor(e){if(typeof e!="function")throw new TypeError("executor must be a function.");let t;this.promise=new Promise(function(i){t=i});const n=this;this.promise.then(i=>{if(!n._listeners)return;let r=n._listeners.length;for(;r-- >0;)n._listeners[r](i);n._listeners=null}),this.promise.then=i=>{let r;const a=new Promise(o=>{n.subscribe(o),r=o}).then(i);return a.cancel=function(){n.unsubscribe(r)},a},e(function(i,r,a){n.reason||(n.reason=new Ar(i,r,a),t(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const t=this._listeners.indexOf(e);t!==-1&&this._listeners.splice(t,1)}toAbortSignal(){const e=new AbortController,t=n=>{e.abort(n)};return this.subscribe(t),e.signal.unsubscribe=()=>this.unsubscribe(t),e.signal}static source(){let e;return{token:new $ 0(function(t){e=t}),cancel:e}}};function fw(s){return function(e){return s.apply(null,e)}}function pw(s){return re.isObject(s)&&s.isAxiosError===!0}const au={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:4
` );this.workerSourceURL=URL.createObjectURL(new Blob([a]))}),this.decoderPending}_getWorker(e,t){return this._initDecoder().then(()=>{if(this.workerPool.length<this.workerLimit){const i=new Worker(this.workerSourceURL);i._callbacks={},i._taskCosts={},i._taskLoad=0,i.postMessage({type:"init",decoderConfig:this.decoderConfig}),i.onmessage=function(r){const a=r.data;switch(a.type){case"decode":i._callbacks[a.id].resolve(a);break;case"error":i._callbacks[a.id].reject(a);break;default:console.error('THREE.DRACOLoader: Unexpected message, "'+a.type+'"')}},this.workerPool.push(i)}else this.workerPool.sort(function(i,r){return i._taskLoad>r._taskLoad?-1:1});const n=this.workerPool[this.workerPool.length-1];return n._taskCosts[e]=t,n._taskLoad+=t,n})}_releaseTask(e,t){e._taskLoad-=e._taskCosts[t],delete e._callbacks[t],delete e._taskCosts[t]}debug(){console.log("Task load: ",this.workerPool.map(e=>e._taskLoad))}dispose(){for(let e=0;e<this.workerPool.length;++e)this.workerPool[e].terminate();return this.workerPool.length=0,this.workerSourceURL!==""&&URL.revokeObjectURL(this.workerSourceURL),this}}function xw(){let s,e;onmessage=function(a){const o=a.data;switch(o.type){case"init":s=o.decoderConfig,e=new Promise(function(h){s.onModuleLoaded=function(u){h({draco:u})},DracoDecoderModule(s)});break;case"decode":const l=o.buffer,c=o.taskConfig;e.then(h=>{const u=h.draco,f=new u.Decoder;try{const d=t(u,f,new Int8Array(l),c),m=d.attributes.map(p=>p.array.buffer);d.index&&m.push(d.index.array.buffer),self.postMessage({type:"decode",id:o.id,geometry:d},m)}catch(d){console.error(d),self.postMessage({type:"error",id:o.id,error:d.message})}finally{u.destroy(f)}});break}};function t(a,o,l,c){const h=c.attributeIDs,u=c.attributeTypes;let f,d;const m=o.GetEncodedGeometryType(l);if(m===a.TRIANGULAR_MESH)f=new a.Mesh,d=o.DecodeArrayToMesh(l,l.byteLength,f);else if(m===a.POINT_CLOUD)f=new a.PointCloud,d=o.DecodeArrayToPointCloud(l,l.byteLength,f);else throw new Error("THREE.DRACOLoader: Unexpected geometry type.");if(!d.ok()||f.ptr===0)throw new Error("THREE.DRACOLoader: Decoding failed: "+d.error_msg());const p={index:null,attributes:[]};for(const x in h){const g=self[u[x]];let b,v;if(c.useUniqueIDs)v=h[x],b=o.GetAttributeByUniqueId(f,v);else{if(v=o.GetAttributeId(f,a[h[x]]),v===-1)continue;b=o.GetAttribute(f,v)}const y=i(a,o,f,x,g,b);x==="color"&&(y.vertexColorSpace=c.vertexColorSpace),p.attributes.push(y)}return m===a.TRIANGULAR_MESH&&(p.index=n(a,o,f)),a.destroy(f),p}function n(a,o,l){const c=l.num_faces()*3,h=c*4,u=a._malloc(h);o.GetTrianglesUInt32Array(l,h,u);const f=new Uint32Array(a.HEAPF32.buffer,u,c).slice();return a._free(u),{array:f,itemSize:1}}function i(a,o,l,c,h,u){const f=l.num_points(),d=u.num_components(),m=r(a,h),p=d*h.BYTES_PER_ELEMENT,x=Math.ceil(p/4)*4,g=x/h.BYTES_PER_ELEMENT,b=f*p,v=f*x,y=a._malloc(b);o.GetAttributeDataArrayForAllPoints(l,u,m,b,y);const M=new h(a.HEAPF32.buffer,y,b/h.BYTES_PER_ELEMENT);let E;if(p===x)E=M.slice();else{E=new h(v/h.BYTES_PER_ELEMENT);let C=0;for(let P=0,_=M.length;P<_;P++){for(let S=0;S<d;S++)E[C+S]=M[P*d+S];C+=g}}return a._free(y),{name:c,count:f,itemSize:d,array:E,stride:g}}function r(a,o){switch(o){case Float32Array:return a.DT_FLOAT32;case Int8Array:return a.DT_INT8;case Int16Array:return a.DT_INT16;case Int32Array:return a.DT_INT32;case Uint8Array:return a.DT_UINT8;case Uint16Array:return a.DT_UINT16;case Uint32Array:return a.DT_UINT32}}}var Pr=(s=>(s.ModelLoadStart="model-load-start",s.ModelLoadProgress="model-load-progress",s.ModelLoaded="model-loaded",s.ModelError="model-error",s.SelectionChanged="selection-changed",s.HoverChanged="hover-changed",s.Click="click",s.MouseMove="mouse-move",s.CameraChanged="camera-changed",s.CameraIdle="camera-idle",s.ViewportResize="viewport-resize",s.EngineFree="engine-free",s.EngineBusy="engine-busy",s.MeasureChanged="measure-changed",s.SectionMove="section-move",s))(Pr||{});function vw(s,e,t,n){let i=0,r=0,a=0,o=s.models.find(d=>d.url==t),l=e.circularMeps,c=e.rectMeps.filter(d=>d.type==="风管"),h=e.rectMeps.filter(d=>d.type==="桥架"),u=e.ellipseMep
2026-01-28 12:00:55 +08:00
1. 网络连接
2. API地址是否正确
2026-02-02 16:36:17 +08:00
3. 是否有CORS限制 ` ):i}}async chatStream(e,t){const n=new AbortController,i=setTimeout(()=>n.abort(),this.config.timeout);try{const r=await fetch( ` $ { this . config . baseURL } / chat / completions ` ,{method:"POST",headers:{"Content-Type":"application/json",Authorization: ` Bearer $ { this . config . apiKey } ` },body:JSON.stringify({model:this.config.model,messages:e,temperature:this.config.temperature,max_tokens:this.config.maxTokens,stream:!0}),signal:n.signal});if(clearTimeout(i),!r.ok){const c=await r.json().catch(()=>({}));throw new Error( ` API请求失败 ( $ { r . status } ) : $ { c . error ? . message || c . message || r . statusText } ` )}const a=r.body?.getReader();if(!a)throw new Error("无法读取响应流");const o=new TextDecoder;let l="";for(;;){const{done:c,value:h}=await a.read();if(c){t("",!0);break}l+=o.decode(h,{stream:!0});const u=l.split( `
2026-02-02 18:18:36 +08:00
` );l=u.pop()||"";for(const f of u){const d=f.trim();if(!d||!d.startsWith("data: "))continue;const m=d.slice(6);if(m!=="[DONE]")try{const p=JSON.parse(m).choices?.[0]?.delta?.content;p&&t(p,!1)}catch(p){console.warn("解析流式数据失败:",p)}}}}catch(r){throw clearTimeout(i),r.name==="AbortError"?new Error("请求超时,请重试"):r.message.includes("Failed to fetch")?new Error("网络请求失败,请检查网络连接"):r}}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}}class DE{engine;steps=[];stepResults=new Map;conversationHistory=[];state="idle";llmApi=null;config=null;_callback_message;_callback_question;_callback_content;prompts={};constructor(e){this.engine=e}async init(e,t,n){this._callback_message=e,this._callback_question=t,this._callback_content=n,this.conversationHistory=[];let i={llmConfig:{baseURL:"https://open.bigmodel.cn/api/coding/paas/v4",apiKey:"4041336a72f14d8fa3800bd651a80fec.vZWUxssXOXB37vlV",model:"GLM-4.5-Air",temperature:.7,maxTokens:2e3},debug:!0,stepExecution:{maxRetries:5},prompts:{main:"",step:"",apiDoc:""}};try{this.config=i,this.llmApi=new IE(i.llmConfig);try{const r=await Promise.resolve().then(()=>MT);this.prompts.main=r.default;const a=await Promise.resolve().then(()=>wT);this.prompts.step=a.default;const o=await Promise.resolve().then(()=>ST);this.prompts.apiDoc=o.default}catch(r){throw console.error("[AI Manager] 提示词文件加载失败:",r),new Error( ` 提示词文件加载失败 : $ { r . message || "未知错误" } ` )}}catch(r){throw console.error("[AI Manager] 初始化失败:",r),r}}async conversationV2(e){if(this.conversationHistory.length===0){const i={role:"system",content: ` $ { this . prompts . main } ` },r={role:"system",content: ` # # BIM引擎API文档
2026-02-02 16:36:17 +08:00
$ { this . prompts . apiDoc } ` };this.conversationHistory.push(i),this.conversationHistory.push(r)}this.conversationHistory.push({role:"user",content:e});const t=await this.llmApi.chat(this.conversationHistory);this.conversationHistory.push({role:"assistant",content:t}),this.config?.debug&&console.log("[AI Manager] 大模型响应:",t);let n=await this.parseAnalysisResponse(t);n&&n.questions&&n.questions.length>0&&this._callback_question(n.questions)}async parseAnalysisResponse(e){try{if(e.includes("##question##")){const t=e.match(/##question## \s *([ \s \S ]*?)(?=##| $ )/);if(t){let n=t[1].trim();n=n.replace(/^ ` ` ` json \ n ? /,"").replace(/ ^ ` ` ` \n ?/,"").replace(/ \n ? ` ` ` $ / , "" ) ; const i = n . match ( /(\[[\s\S]*\])/ ) ; i && ( n = i [ 1 ] ) ; const r = JSON . parse ( n ) ; return this . state = "waiting_answer" , { state : "waiting_answer" , questions : r } } } if ( e . includes ( "##steps##" ) ) { const t = e . match ( /##steps##\s*([\s\S]*?)(?=##|$)/ ) ; if ( t ) { let n = t [ 1 ] . trim ( ) ; n = n . replace ( /^```json\n?/ , "" ) . replace ( /^```\n?/ , "" ) . replace ( /\n?```$/ , "" ) ; const i = n . match ( /(\[[\s\S]*\])/ ) ; return i && ( n = i [ 1 ] ) , this . steps = JSON . parse ( n ) , this . config ? . debug && console . log ( "[AI Manager] 步骤规划完成,共" , this . steps . length , "个步骤" ) , this . _callback _message ( this . steps ) , await this . executeSteps ( ) } } return { state : "completed" , data : e } } catch ( t ) { return console . error ( "[AI Manager] 解析响应失败:" , t ) , { state : "error" , error : "解析大模型响应失败: " + t . message } } } async executeSteps ( ) { try { this . state = "executing" , this . stepResults . clear ( ) ; for ( const e of this . steps ) { this . _callback _message ( e ) , this . config ? . debug && console . log ( ` [AI Manager] 执行步骤 ${ e . id } : ${ e . content } ` ) ; const t = await this . getDependenciesOutput ( e . dependencies ) , n = await this . executeStep ( e , t ) ; this . stepResults . set ( e . id , n ) , this . config ? . debug && console . log ( ` [AI Manager] 步骤 ${ e . id } 执行完成: ` , n ) } return this . state = "completed" , { state : "completed" , steps : this . steps , result : Array . from ( this . stepResults . values ( ) ) } } catch ( e ) { return console . error ( "[AI Manager] 步骤执行失败:" , e ) , { state : "error" , error : "步骤执行失败: " + e . message } } } async getDependenciesOutput ( e ) { return e . length === 0 ? null : e . length === 1 ? this . stepResults . get ( e [ 0 ] ) : e . map ( t => this . stepResults . get ( t ) ) } async executeStep ( e , t ) { const n = this . config ? . stepExecution ? . maxRetries ? ? 1 , i = [ ] ; let r = null , a = ! 1 ; for ( let o = 0 ; o <= n ; o ++ ) try { const l = i . length > 0 ? i [ i . length - 1 ] : "" , c = await ( o === 0 ? this . generateCode ( e , t ) : a ? this . regenerateCodeAfterFailure ( e , t , l , r , o ) : this . generateCode ( e , t ) ) ; i . push ( c ) , this . config ? . debug && console . log ( ` [AI Manager] 步骤 ${ e . id } 第 ${ o + 1 } 次生成的代码:
$ { c } ` );try{const h=await this.executeCode(c,t);if(h instanceof Object&&h.success==!1||h instanceof String&&(h.includes("undefined")||h.includes("not"))){r=h,a=!0;debugger;throw h}debugger;return h}catch(h){debugger;throw r=h,a=!0,h}}catch(l){if(a||(r=l),o>=n)throw console.error( ` [ AI Manager ] 执行步骤 $ { e . id } 失败 ( 已达重试上限 ) : ` ,l),new Error( ` 步骤 $ { e . id } ( $ { e . content } ) 执行失败 : $ { l . message } ` );console.warn( ` [ AI Manager ] 步骤 $ { e . id } 第 $ { o + 1 } 次执行失败 , 将尝试让AI修复后重试 ( 剩余重试次数 : $ { n - o } ) : ` ,l)}throw new Error( ` 步骤 $ { e . id } ( $ { e . content } ) 执行失败 : 未知错误 ` )}extractCodeFromResponse(e){const t=e.match(/##code## \s *([ \s \S ]*?)(?=##| $ )/);if(t){let a=t[1].trim();if(a=a.replace(/^ ` ` ` javascript \ n ? /,"").replace(/ ^ ` ` ` js \n ?/,"").replace(/^ ` ` ` \ n ? /,"").replace(/ \ n ? ` ` ` $ /,""),a.length>0)return a}const n=[/ ` ` ` javascript \ s * ( [ \ s \ S ] * ? ) ` ` ` /i,/ ` ` ` js \ s * ( [ \ s \ S ] * ? ) ` ` ` /i,/ ` ` ` \ s * ( [ \ s \ S ] * ? ) ` ` ` /];for(const a of n){const o=e.match(a);if(o&&o[1]){const l=o[1].trim();if(l.length>0)return this.config?.debug&&console.warn("[AI Manager] 未找到 ##code## 标记,从 markdown 代码块中提取代码"),l}}const i=/[请|说明|注意|需要|应该|可以|如果|但是|因为|所以|例如|比如]/i.test(e),r=/(function|const|let|var|return|async|await|=>|engine \. |previousStepOutput)/.test(e);if(!i&&r){const a=e.trim().replace(/^[,。:;!? \s ]+/,"").replace(/[,。:;!? \s ]+ $ /,"");if(a.length>10)return this.config?.debug&&console.warn("[AI Manager] 未找到 ##code## 标记和代码块,尝试使用整个响应作为代码"),a}throw new Error( ` 无法从大模型响应中提取代码 。 响应内容 : $ { e . substring ( 0 , 200 ) } ... ` )}async generateCode(e,t){try{const n={role:"system",content: ` $ { this . prompts . step } ` },i={role:"system",content: `
2026-01-28 12:00:55 +08:00
# # BIM引擎API文档
$ { this . prompts . apiDoc } ` },r={role:"user",content: ` 请根据以下步骤描述生成可执行的JavaScript代码 :
步骤信息 :
$ { JSON . stringify ( e , null , 2 ) }
前序步骤输出数据 :
$ { t ? JSON . stringify ( t , null , 2 ) : "null" }
2026-02-02 16:36:17 +08:00
请严格按照 # # code # # 格式输出代码 。 ` },a=[n,i,r],o=await this.llmApi.chat(a);return this.extractCodeFromResponse(o)}catch(n){throw console.error("[AI Manager] 代码生成失败:",n),n}}async regenerateCodeAfterFailure(e,t,n,i,r){try{const a={role:"system",content: ` $ { this . prompts . step } ` },o={role:"system",content: `
2026-01-28 12:00:55 +08:00
# # BIM引擎API文档
$ { this . prompts . apiDoc } ` },l={message:i?.message||(i instanceof Object?JSON.stringify(i):String(i)),name:i?.name,stack:i?.stack},c={role:"user",content: ` 上一次生成的代码在执行时失败了 , 请你修复后重新输出完整可执行的 JavaScript 代码 ( 仍然要严格按 # # code # # 格式输出 ) 。
当前步骤信息 :
$ { JSON . stringify ( e , null , 2 ) }
前序步骤输出数据 :
$ { t ? JSON . stringify ( t , null , 2 ) : "null" }
上一次生成的代码 :
$ { n ? `
\ ` \` \` javascript
$ { n }
\ ` \` \`
` : `
( 无 )
` }
执行错误信息 ( 第 $ { r } 次重试前 ) :
$ { JSON . stringify ( l , null , 2 ) }
修复要求 ( 请务必遵守 ) :
1 ) 不要输出解释文字 , 只输出 # # code # # 段落里的代码
2 ) 如果是语法错误 / 引用未定义 / 缺少 await / 返回值不一致 , 请直接修复
3 ) 尽量保持与步骤目标一致 , 避免引入与步骤无关的副作用
2026-02-02 16:36:17 +08:00
4 ) 代码需要能在浏览器环境运行 ( 不要使用 Node 专属 API ) ` },h=await this.llmApi.chat([a,o,c]);try{return this.extractCodeFromResponse(h)}catch(u){throw new Error( ` 无法从大模型响应中提取代码 ( 修复重试阶段 ) : $ { u . message } ` )}}catch(a){throw console.error("[AI Manager] 修复后代码生成失败:",a),a}}async executeCode(e,t){try{const n=this.engine;let i=e;i=i.replace(/ \b (const|let|var) \s +previousStepOutput \s *= \s *[^;]*;/g,""),i=i.replace(/ \b (const|let|var) \s +previousStepOutput \s *;/g,"");const r=new Function("engine","previousStepOutput", `
2026-01-28 12:00:55 +08:00
'use strict' ;
$ { i }
2026-02-02 18:18:36 +08:00
` )(n,t);return r&&typeof r.then=="function"?await r:r}catch(n){return console.error("[AI Manager] 代码执行失败:",n),"error"+n.message}}reset(){this.conversationHistory=[],this.steps=[],this.stepResults.clear(),this.state="idle",this.config?.debug&&console.log("[AI Manager] 对话已重置")}getState(){return this.state}getHistory(){return[...this.conversationHistory]}getSteps(){return[...this.steps]}getStepResults(){return new Map(this.stepResults)}}class BE{options;DeviceType;animationId=null;isRenderingPaused=!1;controlsEnabledBeforePause=!0;animate;onWindowResize;scene;camera;renderer;sceneModule;cameraModule;deviceModule;renderModule;controlModule;composerModule;loaderModule;engineStatus;events;lightModule;interactionModule;modelToolModule;worldToScreen;handelBehaved;octreeBox;controls;stats;catchSvg;viewCube;rangeScale;setting;measure;clipping;modelTree;engineInfo;modelProperties;modelMapperBatch;modelEdge;ai;models=[];reactBoundingClientRect={left:0,top:0};container;constructor(e){if(this.options=e,this.container=document.getElementById(e.containerId),!this.container)throw new Error( ` Container $ { e . containerId } not found ` );this.ai=new DE(this),this.deviceModule=new a2(this),this.DeviceType=this.deviceModule.getDeviceType(),this.cameraModule=new r2(this),this.sceneModule=new s2(this),this.scene=this.sceneModule.scene,this.renderModule=new o2(this),this.renderer=this.renderModule.createRenderer(),this.camera=this.cameraModule.orthographicCamera,this.scene.camera=this.camera,this.controlModule=new M2(this),this.controlModule.switchDefaultMode(),this.controls=this.controlModule.orbitControls,this.composerModule=new U2(this),this.composerModule.init(),this.events=new l3,this.engineStatus=new o3(this),this.engineStatus.init(),this.loaderModule=new a3(this),this.lightModule=new c3(this),this.lightModule.init(),this.viewCube=new _3(this),this.viewCube.init(),this.options.showViewCube==!1&&this.viewCube.hide(),this.octreeBox=M3(this),this.rangeScale=new w3(this),this.rangeScale.init(),this.clipping=new TE(this),this.clipping.init(),this.setting=new S3(this),this.setting.init(),this.handelBehaved=Zh(this),this.modelMapperBatch=new RE(this),this.measure=new D3(this),this.modelToolModule=new u3(this),this.modelProperties=new PE(this),this.interactionModule=new h3(this),this.interactionModule.init(),this.interactionModule.active(),this.modelEdge=new LE(this),this.modelTree=new CE(this),this.engineInfo=new AE(this),this.worldToScreen=new Un(this.camera,this.renderer,this.scene),this.options.showStats&&(this.stats=new m3,this.stats.showPanel(0),this.stats.dom.style.position="absolute",this.stats.dom.style.top="0px",this.stats.dom.style.left="0px",this.stats.dom.style.zIndex="1000",this.container.appendChild(this.stats.dom));let t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.style.position="absolute",t.style.width="100%",t.style.height="100%",t.style.zIndex="1000",t.style.left="0px",t.style.top="0px",t.style.pointerEvents="none";const n=this.renderer?.domElement.width||1920,i=this.renderer?.domElement.height||1080;t.setAttribute("viewBox", ` 0 0 $ { n } $ { i } ` ),t.setAttribute("preserveAspectRatio","none"),this.container.appendChild(t),this.catchSvg=t,this.onWindowResize=()=>{this.handleWindowResize()},window.addEventListener("resize",this.onWindowResize),this.animate=()=>{if(!this.isRenderingPaused)this.animationId=requestAnimationFrame(this.animate);else{this.animationId=null;return}this.stats&&this.stats.begin(),this.composerModule&&this.composerModule.composer.render(),this.viewCube&&this.viewCube.cubeTool.RenderScene(),this.measure.update(),this.controlModule.update(),this.stats&&this.stats.end()},this.animate()}pauseRendering(){if(this.isRenderingPaused){console.warn("[BimEngine] Rendering is already paused");return}this.isRenderingPaused=!0,this.controls&&(this.controlsEnabledBeforePause=this.controls.enabled,this.controls.enabled=!1)}resumeRendering(){if(!this.isRenderingPaused){console.warn("[BimEngine] Rendering is not paused");return}this.isRenderingPaused=!1,this.controls&&(this.controls.en
2026-01-22 11:29:51 +08:00
< svg viewBox = "0 0 24 24" aria - hidden = "true" >
< circle cx = "12" cy = "12" r = "9" > < / c i r c l e >
< / s v g >
2026-02-02 18:18:36 +08:00
` ;for(let m=0;m<z0.length;m++){const p=z0[m],x=Ls[p],g=document.createElement("button");g.type="button",g.className="bim-measure-tool-btn",g.dataset.mode=p;const b=document.createElement("span");b.className="bim-measure-tool-icon",b.innerHTML=x.icon||i,g.appendChild(b),g.addEventListener("click",()=>{this.setActiveMode(p)}),this.toolButtons.set(p,g),n.appendChild(g)}t.appendChild(n);const r=document.createElement("div");r.className="bim-measure-toggle",this.toggleBtn=document.createElement("button"),this.toggleBtn.type="button",this.toggleBtn.className="bim-measure-toggle-btn",this.toggleTextEl=document.createElement("span"),this.toggleTextEl.className="bim-measure-toggle-text";const a=document.createElement("span");a.className="bim-measure-toggle-icon",a.innerHTML= `
2026-01-22 11:29:51 +08:00
< svg viewBox = "0 0 24 24" aria - hidden = "true" >
< path d = "M7 10l5 5 5-5z" > < / p a t h >
< / s v g >
2026-02-02 18:18:36 +08:00
` ,this.toggleBtn.appendChild(this.toggleTextEl),this.toggleBtn.appendChild(a),this.toggleBtn.addEventListener("click",()=>{this.isExpanded=!this.isExpanded,this.applyExpandedState(),this.setLocales(),this.options.onExpandedChange&&this.options.onExpandedChange(this.isExpanded)}),r.appendChild(this.toggleBtn),t.appendChild(r),this.mainViewEl.appendChild(t);const o=document.createElement("div");o.className="bim-measure-result";const l=document.createElement("div");l.className="bim-measure-row";const c=document.createElement("span");c.className="label",this.mainValueLabelEl=c;const h=document.createElement("span");h.className="value",this.mainValueValueEl=h,this.mainNumberEl=document.createElement("span"),this.mainNumberEl.className="bim-measure-main-number",this.mainUnitEl=document.createElement("span"),this.mainUnitEl.className="bim-measure-main-unit",this.mainValueValueEl.appendChild(this.mainNumberEl),this.mainValueValueEl.appendChild(document.createTextNode(" ")),this.mainValueValueEl.appendChild(this.mainUnitEl),l.appendChild(c),l.appendChild(h),o.appendChild(l);const u=document.createElement("div");u.className="bim-measure-xyz",this.xyzBoxEl=u;const f=(m,p,x)=>{const g=document.createElement("div");g.className="bim-measure-row";const b=document.createElement("span");b.className="label",b.dataset.i18nKey=m;const v=document.createElement("span");return v.className= ` value $ { p } ` ,x(v),g.appendChild(b),g.appendChild(v),g};u.appendChild(f("measure.labels.x","bim-measure-xyz-x",m=>this.xyzXEl=m)),u.appendChild(f("measure.labels.y","bim-measure-xyz-y",m=>this.xyzYEl=m)),u.appendChild(f("measure.labels.z","bim-measure-xyz-z",m=>this.xyzZEl=m)),o.appendChild(u),this.mainViewEl.appendChild(o);const d=document.createElement("div");return d.className="bim-measure-footer",this.clearBtn=document.createElement("button"),this.clearBtn.type="button",this.clearBtn.className="bim-measure-clear-btn",this.clearBtn.addEventListener("click",()=>{this.clearAll()}),this.settingsBtn=document.createElement("button"),this.settingsBtn.type="button",this.settingsBtn.className="bim-measure-settings-btn",this.settingsBtn.innerHTML= `
2026-01-22 11:29:51 +08:00
< svg viewBox = "0 0 24 24" aria - hidden = "true" >
< path d = "M19.14 12.94c.04-.31.06-.63.06-.94s-.02-.63-.06-.94l2.03-1.58a.5.5 0 0 0 .12-.64l-1.92-3.32a.5.5 0 0 0-.6-.22l-2.39.96a7.27 7.27 0 0 0-1.63-.94l-.36-2.54A.5.5 0 0 0 13.9 1h-3.8a.5.5 0 0 0-.49.42l-.36 2.54c-.58.23-1.12.54-1.63.94l-2.39-.96a.5.5 0 0 0-.6.22L2.71 7.48a.5.5 0 0 0 .12.64l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94L2.83 14.52a.5.5 0 0 0-.12.64l1.92 3.32c.13.22.39.3.6.22l2.39-.96c.5.4 1.05.71 1.63.94l.36 2.54c.04.24.25.42.49.42h3.8c.24 0 .45-.18.49-.42l.36-2.54c.58-.23 1.12-.54 1.63-.94l2.39.96c.22.09.47 0 .6-.22l1.92-3.32a.5.5 0 0 0-.12-.64l-2.03-1.58zM12 15.5A3.5 3.5 0 1 1 12 8a3.5 3.5 0 0 1 0 7.5z" > < / p a t h >
< / s v g >
2026-02-02 18:18:36 +08:00
` ,this.settingsBtn.addEventListener("click",()=>{this.openSettings()}),d.appendChild(this.clearBtn),d.appendChild(this.settingsBtn),this.mainViewEl.appendChild(d),this.settingsViewEl=this.createSettingsDom(),e.appendChild(this.mainViewEl),e.appendChild(this.settingsViewEl),e}createSettingsDom(){const e=document.createElement("div");e.className="bim-measure-settings";const t=document.createElement("div");t.className="bim-measure-settings-title",t.dataset.i18nKey="measure.settings.title",e.appendChild(t);const n=document.createElement("div");n.className="bim-measure-settings-row";const i=document.createElement("div");i.className="label",i.dataset.i18nKey="measure.settings.unit",this.unitSelectEl=document.createElement("select"),this.unitSelectEl.className="bim-measure-settings-select",this.unitSelectEl.appendChild(this.makeOption("m")),this.unitSelectEl.appendChild(this.makeOption("cm")),this.unitSelectEl.appendChild(this.makeOption("mm")),this.unitSelectEl.appendChild(this.makeOption("km")),n.appendChild(i),n.appendChild(this.unitSelectEl),e.appendChild(n);const r=document.createElement("div");r.className="bim-measure-settings-hint",r.dataset.i18nKey="measure.settings.hint",e.appendChild(r);const a=document.createElement("div");a.className="bim-measure-settings-row";const o=document.createElement("div");o.className="label",o.dataset.i18nKey="measure.settings.precision",this.precisionSelectEl=document.createElement("select"),this.precisionSelectEl.className="bim-measure-settings-select",this.precisionSelectEl.appendChild(this.makePrecisionOption(0)),this.precisionSelectEl.appendChild(this.makePrecisionOption(1)),this.precisionSelectEl.appendChild(this.makePrecisionOption(2)),this.precisionSelectEl.appendChild(this.makePrecisionOption(3)),a.appendChild(o),a.appendChild(this.precisionSelectEl),e.appendChild(a);const l=document.createElement("div");return l.className="bim-measure-settings-actions",this.saveSettingsBtn=document.createElement("button"),this.saveSettingsBtn.type="button",this.saveSettingsBtn.className="bim-measure-settings-save",this.saveSettingsBtn.addEventListener("click",()=>{this.saveSettings()}),this.cancelSettingsBtn=document.createElement("button"),this.cancelSettingsBtn.type="button",this.cancelSettingsBtn.className="bim-measure-settings-cancel",this.cancelSettingsBtn.addEventListener("click",()=>{this.cancelSettings()}),l.appendChild(this.saveSettingsBtn),l.appendChild(this.cancelSettingsBtn),e.appendChild(l),this.syncSettingsFormFromConfig(this.config),e}makeOption(e){const t=document.createElement("option");return t.value=e,t.textContent=e,t}makePrecisionOption(e){const t=document.createElement("option");return t.value=String(e),t.textContent=e===0?"0": ` 0. $ { "0" . repeat ( e ) } ` ,t}enterSettingsView(){this.draftConfig={...this.config},this.view="settings",this.syncSettingsFormFromConfig(this.config),this.applyViewState()}saveSettings(){const e=this.unitSelectEl.value||this.config.unit,t=Number(this.precisionSelectEl.value),n={unit:e,precision:this.isValidPrecision(t)?t:this.config.precision};this.config=n,this.saveConfigToCache(n),this.draftConfig=null,this.view="main",this.applyViewState(),this.renderResult(),this.options.onConfigSave?.(n),this.options.onExpandedChange?.(this.isExpanded)}cancelSettings(){this.draftConfig&&(this.config={...this.draftConfig}),this.draftConfig=null,this.view="main",this.applyViewState(),this.renderResult(),this.options.onExpandedChange&&this.options.onExpandedChange(this.isExpanded)}syncSettingsFormFromConfig(e){this.unitSelectEl.value=e.unit,this.precisionSelectEl.value=String(e.precision)}applyViewState(){this.view==="settings"?(this.mainViewEl.style.display="none",this.settingsViewEl.style.display="block"):(this.mainViewEl.style.display="block",this.settingsViewEl.style.display="none")}loadConfigFromCache(){try{const e=localStorage.getItem(Ga.CONFIG_CACHE_KEY);if(!e)return null;const t=JSON.parse(e);if(!t||typeof t!="object")return null;const n=t.unit,i=t.precision;return!this.isValidUnit(n)||!this.isValidPrecision(i)?null:{unit:n,precision:i}}catch{return null}}saveCo
2026-01-28 17:19:36 +08:00
# $ { this . dialogId } . bim - collapse - header {
background - color : var ( -- bim - component - bg - hover ) ! important ;
}
# $ { this . dialogId } . bim - collapse - header : hover {
background - color : var ( -- bim - component - bg - active ) ! important ;
}
2026-02-02 18:18:36 +08:00
` ,e.appendChild(i),e}createMaterialsPanel(){const e=document.createElement("div");e.style.cssText="height:100%;overflow-y:auto;";const t=this.propertiesData?.materials||[];if(t.length===0)return e.innerHTML='<div style="padding:20px;text-align:center;color:var(--bim-text-secondary,#999);">无材质数据</div>',e;const n=t.map((r,a)=>({id: ` material - $ { a } ` ,title:r.name|| ` 材质 $ { a + 1 } ` ,content:this.createCategoryContent(r.children||r.properties||[])}));new V0({container:e,accordion:!1,ghost:!0,activeIds:n.length>0?[n[0].id]:[],items:n});const i=document.createElement("style");return i.textContent= `
2026-01-28 17:19:36 +08:00
# $ { this . dialogId } . bim - collapse - header {
background - color : var ( -- bim - component - bg - hover ) ! important ;
}
# $ { this . dialogId } . bim - collapse - header : hover {
background - color : var ( -- bim - component - bg - active ) ! important ;
}
` ,e.appendChild(i),e}createCategoryContent(e){const t=document.createElement("div");return e.forEach((n,i)=>{const r=document.createElement("div");r.style.cssText= `
display : flex ;
border - bottom : 1 px solid var ( -- bim - border - default , rgba ( 255 , 255 , 255 , 0.15 ) ) ;
2026-02-02 16:36:17 +08:00
` ,i===e.length-1&&(r.style.borderBottom="none");const a=document.createElement("div");a.style.cssText= `
2026-01-28 17:19:36 +08:00
width : 120 px ;
flex - shrink : 0 ;
color : var ( -- bim - text - secondary , # 999 ) ;
font - size : 13 px ;
padding : 8 px 12 px ;
border - right : 1 px solid var ( -- bim - border - default , rgba ( 255 , 255 , 255 , 0.15 ) ) ;
2026-02-02 16:36:17 +08:00
` ,a.textContent=n.name||"-";const o=document.createElement("div");o.style.cssText= `
2026-01-28 17:19:36 +08:00
flex : 1 ;
color : var ( -- bim - text - primary , # fff ) ;
font - size : 13 px ;
padding : 8 px 12 px ;
word - break : break - all ;
2026-02-02 18:18:36 +08:00
` ,o.textContent=String(n.value??"-"),r.appendChild(a),r.appendChild(o),t.appendChild(r)}),t}isOpen(){return this.dialog!==null}hide(){this.tabInstance&&(this.tabInstance.destroy(),this.tabInstance=null),this.dialog&&(this.dialog.destroy(),this.dialog=null)}destroy(){this.unsubscribeSelected&&(this.unsubscribeSelected(),this.unsubscribeSelected=null),this.unsubscribeDeselected&&(this.unsubscribeDeselected(),this.unsubscribeDeselected=null),this.hide(),super.destroy()}}class rT{element;options;container;messagesContainer=null;textarea=null;messages=[];_isDestroyed=!1;_isVisible=!1;unsubscribeTheme=null;unsubscribeLocale=null;rafId=null;constructor(e){this.options={width:440,title:"aiChat.title",placeholder:"aiChat.placeholder",quickPrompts:[{id:"summarize",label:"aiChat.quickPrompt.summarize"},{id:"explain",label:"aiChat.quickPrompt.explain"},{id:"generate",label:"aiChat.quickPrompt.generate"}],...e},this.container=e.container,this.element=this.createDom(),this.init()}init(){this.container.appendChild(this.element),this.hide(),this.unsubscribeTheme=rt.subscribe(e=>{this.setTheme(e)}),this.unsubscribeLocale=Wt.subscribe(()=>{this.setLocales()}),this.setTheme(rt.getTheme()),this.setLocales()}setTheme(e){const t=e.name==="dark"||e.name?.includes("dark");this.element.classList.toggle("light",!t);const n=this.element.style;n.setProperty("--bim-ai-accent",e.primary),n.setProperty("--bim-ai-text",e.textPrimary),n.setProperty("--bim-ai-muted",e.textTertiary),n.setProperty("--bim-ai-border",e.borderDefault),n.setProperty("--bim-ai-shadow",e.shadowLg)}setLocales(){const e=this.element.querySelector(".bim-ai-chat-title");e&&this.options.title&&(e.textContent=Me(this.options.title));const t=this.element.querySelector(".bim-ai-textarea");t&&this.options.placeholder&&(t.placeholder=Me(this.options.placeholder));const n=this.element.querySelector(".bim-ai-helper-left");n&&(n.textContent=Me("aiChat.helper.newline"));const i=this.element.querySelector(".bim-ai-helper-right");i&&(i.textContent=Me("aiChat.helper.send")),this.updateQuickPrompts(),this.renderMessages()}show(){this._isVisible=!0,this.element.style.display="flex",this.initPosition(),this.scrollToBottom()}initPosition(){if(this.element.style.left)return;const e=this.container.clientWidth,t=this.element.offsetWidth,n=Math.max(50,e-t-50);this.element.style.left= ` $ { n } px ` ,this.element.style.top="50px"}hide(){this._isVisible=!1,this.element.style.display="none"}toggle(){this._isVisible?this.hide():this.show()}isVisible(){return this._isVisible}addMessage(e){this.messages.push(e),this.renderMessages(),this.scrollToBottom()}updateMessage(e,t){const n=this.messages.findIndex(i=>i.id===e);n!==-1&&(this.messages[n]={...this.messages[n],...t},this.renderMessages())}removeMessage(e){this.messages=this.messages.filter(t=>t.id!==e),this.renderMessages()}clearMessages(){this.messages=[],this.renderMessages()}addUserMessage(e){const t= ` user - $ { Date . now ( ) } ` ;return this.addMessage({id:t,type:"user",content:e,timestamp:Date.now()}),t}addAiMessage(e){const t= ` ai - $ { Date . now ( ) } ` ;return this.addMessage({id:t,type:"ai",content:e,timestamp:Date.now()}),t}addStepMessage(e,t){const n= ` step - $ { Date . now ( ) } ` ;return this.addMessage({id:n,type:"step",status:e,content:t,timestamp:Date.now()}),n}addThinkingMessage(){const e= ` thinking - $ { Date . now ( ) } ` ;return this.addMessage({id:e,type:"thinking",timestamp:Date.now()}),e}addQuestionMessage(e,t,n){const i= ` question - $ { Date . now ( ) } ` ;return this.addMessage({id:i,type:"question",title:e,question:t,options:n,answered:!1,timestamp:Date.now()}),i}createDom(){const e=document.createElement("div");return e.className="bim-ai-chat",e.style.width= ` $ { this . options . width } px ` ,e.innerHTML= `
2026-02-02 16:36:17 +08:00
< div class = "bim-ai-chat-header" >
< span class = "bim-ai-chat-title" > < / s p a n >
< div class = "bim-ai-chat-actions" >
2026-02-02 18:18:36 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "new" title = "${Me(" aiChat . action . new ")}" >
2026-02-02 16:36:17 +08:00
$ { at ( "plus" ) }
< / b u t t o n >
2026-02-02 18:18:36 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "history" title = "${Me(" aiChat . action . history ")}" >
2026-02-02 16:36:17 +08:00
$ { at ( "history" ) }
< / b u t t o n >
2026-02-02 18:18:36 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "settings" title = "${Me(" aiChat . action . settings ")}" >
2026-02-02 16:36:17 +08:00
$ { at ( "settings" ) }
< / b u t t o n >
2026-02-02 18:18:36 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "close" title = "${Me(" aiChat . action . close ")}" >
2026-02-02 16:36:17 +08:00
$ { at ( "close" ) }
< / b u t t o n >
< / d i v >
< / d i v >
< div class = "bim-ai-chat-messages" > < / d i v >
< div class = "bim-ai-chat-composer" >
< div class = "bim-ai-quick-prompts" > < / d i v >
< div class = "bim-ai-input-row" >
< div class = "bim-ai-textbox" >
< textarea class = "bim-ai-textarea" rows = "1" > < / t e x t a r e a >
< div class = "bim-ai-helper" >
< span class = "bim-ai-helper-left" > < / s p a n >
< span class = "bim-ai-helper-right" > < / s p a n >
< / d i v >
< / d i v >
< button class = "bim-ai-send-btn" >
$ { at ( "arrowUpBold" ) }
< / b u t t o n >
< / d i v >
< / d i v >
` ,this.messagesContainer=e.querySelector(".bim-ai-chat-messages"),this.textarea=e.querySelector(".bim-ai-textarea"),this.bindEvents(e),this.updateQuickPrompts(e),e}bindEvents(e){e.querySelectorAll(".bim-ai-chat-action-btn").forEach(a=>{a.addEventListener("click",o=>{switch(o.currentTarget.dataset.action){case"new":this.options.onNewChat?.();break;case"history":this.options.onHistory?.();break;case"settings":this.options.onSettings?.();break;case"close":this.hide(),this.options.onClose?.();break}})});const t=e.querySelector(".bim-ai-chat-header");t&&this.initDrag(t),e.querySelector(".bim-ai-send-btn")?.addEventListener("click",()=>this.handleSend()),this.textarea?.addEventListener("keydown",a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),this.handleSend())}),this.textarea?.addEventListener("input",()=>{this.textarea&&(this.textarea.style.height="auto",this.textarea.style.height=Math.min(this.textarea.scrollHeight,100)+"px")});const i=a=>a.stopPropagation();["click","dblclick","mousedown","mouseup","mousemove","wheel","touchstart","touchend","touchmove"].forEach(a=>{e.addEventListener(a,i,{passive:!1})})}handleSend(){if(!this.textarea)return;const e=this.textarea.value.trim();e&&(this.textarea.value="",this.textarea.style.height="auto",this.options.onSend?.(e))}initDrag(e){let t=0,n=0,i=0,r=0,a=0,o=0,l=0,c=0;const h=d=>{d.target.closest(".bim-ai-chat-action-btn")||(d.preventDefault(),d.stopPropagation(),t=d.clientX,n=d.clientY,i=this.element.offsetLeft,r=this.element.offsetTop,a=this.container.clientWidth,o=this.container.clientHeight,l=this.element.offsetWidth,c=this.element.offsetHeight,document.addEventListener("mousemove",u,{capture:!0}),document.addEventListener("mouseup",f,{capture:!0}))},u=d=>{d.preventDefault(),d.stopPropagation(),!this.rafId&&(this.rafId=requestAnimationFrame(()=>{const m=d.clientX-t,p=d.clientY-n;let x=i+m,g=r+p;const b=a-l,v=o-c;x=Math.max(0,Math.min(x,b)),g=Math.max(0,Math.min(g,v)),this.element.style.left= ` $ { x } px ` ,this.element.style.top= ` $ { g } px ` ,this.rafId=null}))},f=()=>{this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),document.removeEventListener("mousemove",u,{capture:!0}),document.removeEventListener("mouseup",f,{capture:!0})};e.addEventListener("mousedown",h)}updateQuickPrompts(e){const n=(e||this.element).querySelector(".bim-ai-quick-prompts");!n||!this.options.quickPrompts||(n.innerHTML=this.options.quickPrompts.map(i=> `
< button class = "bim-ai-quick-prompt" data - prompt - id = "${i.id}" >
2026-02-02 18:18:36 +08:00
$ { Me ( i . label ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
2026-02-02 18:18:36 +08:00
` ).join(""),n.querySelectorAll(".bim-ai-quick-prompt").forEach(i=>{i.addEventListener("click",r=>{const a=r.currentTarget.dataset.promptId,o=this.options.quickPrompts?.find(l=>l.id===a);o&&this.textarea&&(this.textarea.value=Me(o.label),this.textarea.focus())})}))}renderMessages(){this.messagesContainer&&(this.messagesContainer.innerHTML=this.messages.map(e=>{switch(e.type){case"user":return this.renderUserMessage(e.content);case"ai":return this.renderAiMessage(e.content);case"step":return this.renderStepMessage(e.status,e.content);case"thinking":return this.renderThinkingMessage();case"question":return e.answered?this.renderAnsweredQuestion(e):this.renderActiveQuestion(e);default:return""}}).join(""),this.bindQuestionEvents())}renderUserMessage(e){return `
2026-02-02 16:36:17 +08:00
< div class = "bim-ai-msg-user" >
< div class = "bim-ai-bubble" >
< div class = "bim-ai-bubble-content" > $ { this . escapeHtml ( e ) } < / d i v >
< / d i v >
< / d i v >
` }renderAiMessage(e){return `
< div class = "bim-ai-msg-ai" >
< div class = "bim-ai-bubble" >
< div class = "bim-ai-bubble-content" > $ { this . escapeHtml ( e ) } < / d i v >
< / d i v >
< / d i v >
` }renderStepMessage(e,t){return `
< div class = "bim-ai-step bim-ai-step-${e}" >
< span class = "bim-ai-step-icon" > $ { at ( { running : "loader" , done : "check" , error : "error" } [ e ] ) } < / s p a n >
< span class = "bim-ai-step-text" > $ { this . escapeHtml ( t ) } < / s p a n >
< / d i v >
` }renderThinkingMessage(){return `
< div class = "bim-ai-thinking" >
< span class = "bim-ai-thinking-icon" > $ { at ( "loader" ) } < / s p a n >
2026-02-02 18:18:36 +08:00
< span class = "bim-ai-thinking-text" > $ { Me ( "aiChat.thinking" ) } < / s p a n >
2026-02-02 16:36:17 +08:00
< / d i v >
` }renderActiveQuestion(e){const t=e.options.map(n=> `
< div class = "bim-ai-option ${e.selectedOptionId===n.id?" selected ":" "}"
data - question - id = "${e.id}" data - option - id = "${n.id}" data - is - other = "${n.isOther||!1}" >
< div class = "bim-ai-option-radio" >
< div class = "bim-ai-option-radio-dot" > < / d i v >
< / d i v >
2026-02-02 18:18:36 +08:00
< span class = "bim-ai-option-text" > $ { n . isOther ? Me ( "aiChat.other" ) : this . escapeHtml ( n . label ) } < / s p a n >
2026-02-02 16:36:17 +08:00
< / d i v >
$ { n . isOther && e . selectedOptionId === n . id ? `
< input type = "text" class = "bim-ai-option-input"
data - question - id = "${e.id}"
2026-02-02 18:18:36 +08:00
placeholder = "${Me(" aiChat . otherPlaceholder ")}"
2026-02-02 16:36:17 +08:00
value = "${e.customAnswer||" "}" >
` :""}
` ).join("");return `
< div class = "bim-ai-question-active" data - question - id = "${e.id}" >
< div class = "bim-ai-question-header" >
< div class = "bim-ai-question-icon" > $ { at ( "bot" ) } < / d i v >
< span class = "bim-ai-question-title" > $ { this . escapeHtml ( e . title ) } < / s p a n >
< / d i v >
< div class = "bim-ai-question-content" >
< div class = "bim-ai-question-text" > $ { this . escapeHtml ( e . question ) } < / d i v >
< div class = "bim-ai-question-options" > $ { t } < / d i v >
< / d i v >
< div class = "bim-ai-question-footer" >
< button class = "bim-ai-question-submit" data - question - id = "${e.id}" >
2026-02-02 18:18:36 +08:00
< span > $ { Me ( "aiChat.submit" ) } < / s p a n >
2026-02-02 16:36:17 +08:00
$ { at ( "send" ) }
< / b u t t o n >
< / d i v >
< / d i v >
` }renderAnsweredQuestion(e){const t=e.options.find(i=>i.id===e.selectedOptionId),n=t?.isOther?e.customAnswer:t?.label;return `
< div class = "bim-ai-question-answered" >
< div class = "bim-ai-qa-row" >
< div class = "bim-ai-qa-badge bim-ai-qa-badge-q" > Q < / d i v >
< span class = "bim-ai-qa-question" > $ { this . escapeHtml ( e . question ) } < / s p a n >
< / d i v >
< div class = "bim-ai-qa-row" >
< div class = "bim-ai-qa-badge bim-ai-qa-badge-a" > A < / d i v >
< span class = "bim-ai-qa-answer" > $ { this . escapeHtml ( n || "" ) } < / s p a n >
< / d i v >
< / d i v >
2026-02-02 18:18:36 +08:00
` }bindQuestionEvents(){this.messagesContainer?.querySelectorAll(".bim-ai-option").forEach(e=>{e.addEventListener("click",t=>{const n=t.currentTarget,i=n.dataset.questionId,r=n.dataset.optionId;if(i&&r){const a=this.messages.find(o=>o.id===i);a&&!a.answered&&(a.selectedOptionId=r,this.renderMessages())}})}),this.messagesContainer?.querySelectorAll(".bim-ai-option-input").forEach(e=>{e.addEventListener("input",t=>{const n=t.target,i=n.dataset.questionId;if(i){const r=this.messages.find(a=>a.id===i);r&&(r.customAnswer=n.value)}})}),this.messagesContainer?.querySelectorAll(".bim-ai-question-submit").forEach(e=>{e.addEventListener("click",t=>{const i=t.currentTarget.dataset.questionId;if(i){const r=this.messages.find(a=>a.id===i);r&&r.selectedOptionId&&(r.answered=!0,this.renderMessages(),this.options.onQuestionSubmit?.(i,r.selectedOptionId,r.customAnswer))}})})}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}destroy(){this._isDestroyed||(this.unsubscribeTheme&&(this.unsubscribeTheme(),this.unsubscribeTheme=null),this.unsubscribeLocale&&(this.unsubscribeLocale(),this.unsubscribeLocale=null),this.element.remove(),this._isDestroyed=!0)}}class aT{aiChat=null;registry;initialized=!1;constructor(){this.registry=vt.getInstance()}init(){if(this.initialized)return;const e=this.registry.wrapper;if(!e){console.warn("[AiChatManager] wrapper 不存在,无法初始化");return}this.aiChat=new rT({container:e,width:440,title:"aiChat.title",placeholder:"aiChat.placeholder",quickPrompts:[{id:"summarize",label:"aiChat.quickPrompt.summarize"},{id:"explain",label:"aiChat.quickPrompt.explain"},{id:"generate",label:"aiChat.quickPrompt.generate"}],onSend:t=>{console.log("[AiChatManager] 用户发送消息:",t),this.aiChat?.addUserMessage(t),this.registry.emit("aiChat:message-sent",{message:t})},onQuestionSubmit:(t,n,i)=>{console.log("[AiChatManager] 用户回答问题:",{questionId:t,optionId:n,customAnswer:i}),this.registry.emit("aiChat:question-answered",{questionId:t,optionId:n,customAnswer:i})},onNewChat:()=>{console.log("[AiChatManager] 新建对话"),this.registry.emit("aiChat:new-chat",{})},onHistory:()=>{console.log("[AiChatManager] 打开历史"),this.registry.emit("aiChat:history-opened",{})},onSettings:()=>{console.log("[AiChatManager] 打开设置"),this.registry.emit("aiChat:settings-opened",{})},onClose:()=>{console.log("[AiChatManager] 关闭 AI 聊天"),this.registry.emit("aiChat:closed",{}),this.registry.toolbar?.setBtnActive("aiChat",!1)}}),this.initialized=!0}show(){this.aiChat||this.init(),this.aiChat?.show(),this.registry.emit("aiChat:opened",{}),this.registry.toolbar?.setBtnActive("aiChat",!0)}hide(){this.aiChat?.hide(),this.registry.emit("aiChat:closed",{}),this.registry.toolbar?.setBtnActive("aiChat",!1)}toggle(){this.aiChat?.isVisible()?this.hide():this.show()}isVisible(){return this.aiChat?.isVisible()??!1}addUserMessage(e){return this.aiChat?.addUserMessage(e)??""}addAiMessage(e){return this.aiChat?.addAiMessage(e)??""}addStepMessage(e,t){return this.aiChat?.addStepMessage(e,t)??""}addThinkingMessage(){return this.aiChat?.addThinkingMessage()??""}addQuestionMessage(e,t,n){return this.aiChat?.addQuestionMessage(e,t,n)??""}updateMessage(e,t){this.aiChat?.updateMessage(e,t)}removeMessage(e){this.aiChat?.removeMessage(e)}clearMessages(){this.aiChat?.clearMessages()}destroy(){this.aiChat&&(this.aiChat.destroy(),this.aiChat=null),this.initialized=!1}}class oT{container;wrapper=null;registry;toolbar=null;constructTreeBtn=null;buttonGroup=null;dialog=null;engine=null;rightKey=null;measure=null;sectionPlane=null;sectionAxis=null;sectionBox=null;walkControl=null;map=null;componentDetail=null;aiChat=null;constructor(e,t){const n=typeof e=="string"?document.getElementById(e):e;if(!n)throw new Error("Container not found");this.container=n,this.registry=vt.getInstance(),t?.locale&&Wt.setLocale(t.locale),t?.theme&&(t.theme==="custom"?console.warn("Custom theme should be set vi
# # 角色定位
你是一位资深的 * * AI + BIM轻量化引擎架构专家 * * , 具备以下核心能力 :
1. * * 深度理解BIM引擎架构 * * : 精通BIM引擎的模块化设计 、 API体系 、 数据结构和交互模式
2. * * 需求分析能力 * * : 能够准确理解用户意图 , 识别模糊需求 , 提出精准的澄清问题
3. * * 任务分解能力 * * : 将复杂需求拆解为可执行的 、 原子化的操作步骤
4. * * 技术决策能力 * * : 根据需求特点选择最优的API组合和实现路径
你的职责是通过分析用户需求 , 生成结构化的执行步骤 , 指导代码生成模块完成BIM引擎的功能实现 。
# # 工作流程
如果存在疑问 , 你就不能输出最终的步骤 , 只有当你把所有的疑问清楚后 , 你才可以输出步骤 , 如果存在疑问 , 你要以bim模型为载体 , 不能问一下和bim模型不想干的问题 , 尽量没有或减少问题
# # # 阶段一 : 需求理解与分析
当接收到用户需求时 , 你需要 :
1. * * 深度分析需求 * * :
- 理解用户的核心目标
- 识别涉及到的BIM引擎模块 ( 场景 、 相机 、 模型 、 测量 、 剖切等 )
- 分析数据流向和依赖关系
- 评估需求的复杂度和可行性
2. * * 识别模糊点 * * :
- 检查需求中是否存在歧义 、 缺失信息或边界条件不明确的情况
- 判断是否需要用户澄清才能继续
3. * * 决策是否需要提问 * * :
- * * 仅在必要时提问 * * : 如果需求足够清晰 , 直接进入步骤规划阶段
- * * 避免过度提问 * * : 不要为了提问而提问 , 不要询问可以从上下文推断的信息
- * * 精准提问 * * : 每个问题都应该针对关键决策点 , 影响后续实现路径
# # # 阶段二 : 需求澄清 ( 如需要 )
如果需要用户澄清 , 请按照以下格式输出 :
* * 输出格式 * * :
\ ` \` \`
# # question # #
json内容
\ ` \` \`
* * JSON格式规范 * * :
\ ` \` \` json
[
{
"id" : 0 ,
"question" : "您是否需要设置所有的构件?" ,
"answers" : [
"A. 是的,设置所有构件" ,
"B. 只设置1F层的构件" ,
"C. 根据特定条件筛选构件"
]
} ,
{
"id" : 1 ,
"question" : "颜色设置的优先级是什么?" ,
"answers" : [
"A. 按构件类型设置" ,
"B. 按楼层设置" ,
"C. 按自定义属性设置"
]
}
]
\ ` \` \`
* * 提问原则 * * :
- 每个问题必须针对一个明确的决策点
- 答案选项应该互斥且覆盖主要场景
- 问题数量控制在3个以内 , 优先询问最关键的问题
- 问题描述清晰 、 具体 , 避免模糊表述
- 不要强行提问 , 尽量减少或不提问题
# # # 阶段三 : 步骤规划
当需求清晰后 , 你需要将用户意图拆解为一系列可执行的步骤 。
* * 输出格式 * * :
\ ` \` \`
# # steps # #
json内容
\ ` \` \`
* * JSON格式规范 * * :
\ ` \` \` json
[
{
"id" : 0 ,
"content" : "获取所有桩基模型" ,
"description" : "通过modelTree模块遍历模型树, 筛选出类型为'桩基'的所有构件, 返回构件ID数组和构件对象数组" ,
"output" : "{\\" modelIds \ \ ": [\\" id1 \ \ ", \\" id2 \ \ ", ...], \\" models \ \ ": [modelObject1, modelObject2, ...]}" ,
"dependencies" : [ ] ,
"apiModules" : [ "modelTree" , "dataModule" ]
} ,
{
"id" : 1 ,
"content" : "设置桩基模型颜色为红色" ,
"description" : "使用modelMapperBatch模块的批量设置方法, 将上一步获取的所有桩基模型的颜色属性设置为红色( RGB: 255, 0, 0) " ,
"output" : "{\\" success \ \ ": true, \\" count \ \ ": 10, \\" failedIds \ \ ": []}" ,
"dependencies" : [ 0 ] ,
"apiModules" : [ "modelMapperBatch" ]
}
]
\ ` \` \`
* * 字段说明 * * :
- \ ` id \` : 步骤唯一标识符, 从0开始递增
- \ ` content \` : 步骤的简短描述(一句话概括)
- \ ` description \` : 步骤的详细功能说明,包括:
- 具体要做什么
- 使用哪些API模块
- 如何处理数据
- 可能的边界情况
- \ ` output \` : 步骤输出的数据格式说明( JSON Schema格式) , 用于:
- 指导代码生成模块返回正确的数据结构
- 确保步骤间的数据传递正确
- \ ` dependencies \` : 依赖的步骤ID数组, 表示此步骤需要等待哪些步骤完成
- \ ` apiModules \` : 此步骤涉及到的BIM引擎模块名称数组( 如: modelTree, cameraModule, measure等)
* * 步骤规划原则 * * :
1. * * 原子化 * * : 每个步骤应该只完成一个明确的功能点
2. * * 可执行 * * : 每个步骤都应该能够独立生成可执行的代码
3. * * 依赖清晰 * * : 明确标注步骤间的依赖关系 , 确保执行顺序正确
4. * * 数据流转 * * : 每个步骤的输出格式要明确 , 便于后续步骤使用
5. * * 模块化 * * : 合理利用BIM引擎的模块化设计 , 选择最合适的API
6. * * 错误处理 * * : 在关键步骤中考虑异常情况的处理
# # 硬性要求
# # # 1. 输出格式规范
- * * 必须严格遵循 * * 上述JSON格式 , 字段名称和类型不能改变
- JSON必须是有效的 、 可解析的格式
- 步骤ID必须连续且从0开始
- 依赖关系必须正确 , 不能出现循环依赖
# # # 2. 需求理解要求
- * * 深度理解 * * : 不能停留在表面理解 , 要理解用户的真实意图和业务场景
- * * 上下文感知 * * : 结合BIM引擎的特性 , 理解每个需求在BIM场景下的实际意义
- * * 技术可行性 * * : 确保规划的步骤在BIM引擎API能力范围内
# # # 3. 步骤质量要求
- * * 完整性 * * : 步骤应该覆盖用户需求的所有方面 , 不能遗漏关键环节
- * * 准确性 * * : 步骤描述要准确 , 不能有歧义或错误
- * * 可执行性 * * : 每个步骤都应该能够生成可执行的代码
- * * 效率性 * * : 优先选择高效的API组合 , 避免不必要的中间步骤
# # # 4. 错误预防
- 检查步骤间的数据格式是否匹配
- 确保依赖关系正确 , 避免执行顺序错误
- 验证API模块名称是否正确
- 考虑边界情况和异常处理
# # # 5. 代码生成友好
- 步骤描述要足够详细 , 让代码生成模块能够准确理解意图
- 输出格式说明要具体 , 使用JSON Schema或示例数据
- 明确标注使用的API模块 , 便于代码生成时快速定位
# # 最佳实践
1. * * 先理解后规划 * * : 充分理解需求后再开始规划步骤 , 避免返工
2. * * 模块优先 * * : 优先使用BIM引擎提供的功能模块 , 而不是底层API
3. * * 数据驱动 * * : 明确每个步骤的输入输出 , 确保数据流清晰
4. * * 可扩展性 * * : 考虑未来可能的扩展需求 , 设计灵活的步骤结构
5. * * 用户友好 * * : 步骤描述要清晰易懂 , 便于用户理解整个执行流程
'' ` },Symbol.toStringTag,{value:"Module"})),wT=Object.freeze(Object.defineProperty({__proto__:null,default: ` # BIM引擎AI助手 - 代码生成专家
# # 角色定位
你是一位资深的 * * BIM引擎代码生成专家 * * , 具备以下核心能力 :
1. * * BIM引擎API精通 * * : 深度掌握BIM引擎的所有模块API 、 方法签名 、 参数类型和返回值
2. * * 代码生成能力 * * : 能够根据步骤描述 , 生成高质量 、 可执行 、 符合规范的JavaScript代码
3. * * 上下文理解 * * : 能够理解步骤间的数据流转 , 正确处理前序步骤的输出结果
4. * * 错误处理能力 * * : 具备完善的异常处理和边界情况处理能力
5. * * 代码质量意识 * * : 生成的代码应该具备良好的可读性 、 可维护性和性能
你的职责是根据步骤规划模块提供的步骤描述 , 生成可直接在BIM引擎环境中执行的JavaScript代码片段 。
# # 工作流程
# # # 阶段一 : 理解步骤要求
当接收到步骤执行请求时 , 你需要 :
1. * * 解析步骤信息 * * :
- 理解步骤的 \ ` content \` (简短描述)和 \` description \` (详细说明)
- 识别步骤涉及到的BIM引擎模块 ( \ ` apiModules \` 字段)
- 理解步骤的依赖关系 ( \ ` dependencies \` 字段)
- 明确步骤的预期输出格式 ( \ ` output \` 字段)
2. * * 分析上下文数据 * * :
- 如果有前序步骤的输出结果 , 分析其数据结构
- 理解当前步骤需要使用的输入数据
- 验证数据格式是否匹配步骤要求
3. * * 确定实现方案 * * :
- 根据步骤描述 , 选择最合适的BIM引擎API
- 设计数据转换和处理逻辑
- 规划错误处理策略
# # # 阶段二 : 生成代码
根据步骤要求生成可执行的JavaScript代码 。
* * 输出格式 * * :
\ ` \` \`
# # code # #
[ 可执行的JavaScript代码 ]
\ ` \` \`
* * 代码生成规范 * * :
1. * * 代码结构 * * :
- 代码必须是一个完整的 、 可执行的JavaScript代码片段
- 可以是函数 、 立即执行函数 ( IIFE ) 或代码块
- 代码应该能够直接运行 , 不需要额外的包装
2. * * 引擎实例访问 * * :
- 假设BIM引擎实例通过变量 \ ` engine \` 访问(全局作用域)
- 通过 \ ` engine.moduleName \` 访问各个功能模块
- 例如 : \ ` engine.modelTree \` 、 \` engine.cameraModule \` 、 \` engine.measure \` 等
3. * * 数据输入处理 * * :
- 如果步骤有依赖 , 使用前序步骤的输出数据
- 假设前序步骤的输出数据存储在变量 \ ` previousStepOutput \` 中(如果是第一步,则为 \` null \` )
- 需要根据 \ ` output \` 字段的格式说明,正确解析和使用输入数据
4. * * API调用规范 * * :
- 严格按照BIM引擎API文档使用API
- 参数类型和数量必须正确
- 处理API的返回值和可能的异常
5. * * 数据输出规范 * * :
- 代码执行后 , 必须返回符合步骤 \ ` output \` 字段要求的数据格式
- 使用 \ ` return \` 语句返回结果
- 返回的数据必须是可序列化的 ( JSON格式 )
6. * * 错误处理 * * :
- 必须包含完善的错误处理逻辑
- 使用try - catch捕获可能的异常
- 对于关键操作 , 添加参数验证
- 错误信息要清晰 , 便于调试
7. * * 代码质量要求 * * :
- 代码要有清晰的注释 , 说明关键逻辑
- 变量命名要有意义 , 符合JavaScript命名规范
- 避免使用过于复杂的嵌套结构
- 优先使用可读性高的写法 , 而不是过于 "高级" 的技巧
# # 硬性要求
# # # 1. 代码格式要求
- * * 单一代码块 * * : 输出必须且只能包含一个JavaScript代码片段
- * * 可执行性 * * : 代码必须能够直接执行 , 不需要额外的依赖或配置
- * * 完整性 * * : 代码必须完整 , 不能有语法错误或未定义的变量
# # # 2. 数据格式要求
- * * 输入解析 * * : 正确解析和使用前序步骤的输出数据
- * * 输出格式 * * : 严格按照步骤 \ ` output \` 字段的格式要求返回数据
- * * 类型安全 * * : 确保数据类型正确 , 必要时进行类型转换
# # # 3. API使用要求
- * * 准确性 * * : API调用必须准确 , 参数必须正确
- * * 模块识别 * * : 正确识别和使用BIM引擎的各个模块
- * * 方法调用 * * : 使用正确的方法名和参数签名
# # # 4. 错误处理要求
- * * 异常捕获 * * : 所有可能抛出异常的操作都要有try - catch保护
- * * 参数验证 * * : 对关键参数进行验证 , 避免无效输入
- * * 错误信息 * * : 错误信息要清晰 , 包含足够的上下文信息
- * * 优雅降级 * * : 在可能的情况下 , 提供降级方案
# # # 5. 代码质量要求
- * * 可读性 * * : 代码结构清晰 , 逻辑易懂
- * * 注释完整 * * : 关键逻辑要有注释说明
- * * 命名规范 * * : 变量和函数命名要有意义
- * * 性能考虑 * * : 避免不必要的循环和计算
# # 代码生成示例
# # # 示例1 : 获取模型数据
* * 步骤描述 * * :
\ ` \` \` json
{
"id" : 0 ,
"content" : "获取所有桩基模型" ,
"description" : "通过modelTree模块遍历模型树, 筛选出类型为'桩基'的所有构件" ,
"output" : "{\\" modelIds \ \ ": [\\" id1 \ \ ", \\" id2 \ \ "], \\" models \ \ ": [modelObject1, modelObject2]}" ,
"dependencies" : [ ] ,
"apiModules" : [ "modelTree" ]
}
\ ` \` \`
* * 生成代码 * * :
\ ` \` \` javascript
// 获取所有桩基模型
try {
// 获取模型树模块
const modelTree = engine . modelTree ;
if ( ! modelTree ) {
throw new Error ( '模型树模块未初始化' ) ;
}
// 获取所有模型
const allModels = modelTree . getAllModels ( ) ;
if ( ! allModels || allModels . length === 0 ) {
return {
modelIds : [ ] ,
models : [ ]
} ;
}
// 筛选桩基模型
const pileModels = [ ] ;
const pileModelIds = [ ] ;
for ( let i = 0 ; i < allModels . length ; i ++ ) {
const model = allModels [ i ] ;
// 根据模型属性判断是否为桩基
const modelType = model . getProperty ( '类型' ) || model . getProperty ( 'category' ) ;
if ( modelType && ( modelType . includes ( '桩基' ) || modelType . includes ( 'Pile' ) ) ) {
pileModels . push ( model ) ;
pileModelIds . push ( model . id || model . uuid ) ;
}
}
// 返回结果
return {
modelIds : pileModelIds ,
models : pileModels
} ;
} catch ( error ) {
console . error ( '获取桩基模型失败:' , error ) ;
return {
modelIds : [ ] ,
models : [ ] ,
error : error . message
} ;
}
\ ` \` \`
# # # 示例2 : 使用前序步骤的输出
* * 步骤描述 * * :
\ ` \` \` json
{
"id" : 1 ,
"content" : "设置桩基模型颜色为红色" ,
"description" : "使用modelMapperBatch模块批量设置上一步获取的桩基模型颜色" ,
"output" : "{\\" success \ \ ": true, \\" count \ \ ": 10}" ,
"dependencies" : [ 0 ] ,
"apiModules" : [ "modelMapperBatch" ]
}
\ ` \` \`
* * 生成代码 * * :
\ ` \` \` javascript
// 设置桩基模型颜色为红色
try {
// 获取前序步骤的输出数据
if ( ! previousStepOutput || ! previousStepOutput . modelIds ) {
throw new Error ( '前序步骤输出数据无效, 缺少modelIds字段' ) ;
}
const modelIds = previousStepOutput . modelIds ;
if ( modelIds . length === 0 ) {
return {
success : true ,
count : 0 ,
message : '没有需要设置的模型'
} ;
}
// 获取批量映射模块
const modelMapperBatch = engine . modelMapperBatch ;
if ( ! modelMapperBatch ) {
throw new Error ( '批量映射模块未初始化' ) ;
}
// 设置颜色为红色 (RGB: 255, 0, 0)
const redColor = { r : 255 , g : 0 , b : 0 } ;
// 批量设置模型颜色
const result = modelMapperBatch . setModelColor ( modelIds , redColor ) ;
return {
success : result . success !== false ,
count : result . count || modelIds . length ,
failedIds : result . failedIds || [ ]
} ;
} catch ( error ) {
console . error ( '设置模型颜色失败:' , error ) ;
return {
success : false ,
count : 0 ,
error : error . message
} ;
}
\ ` \` \`
# # 最佳实践
1. * * 充分理解步骤 * * : 仔细阅读步骤描述 , 确保理解每个细节
2. * * 查阅API文档 * * : 不确定的API用法 , 参考BIM引擎API文档
3. * * 数据验证优先 * * : 在处理数据前 , 先验证数据的有效性
4. * * 错误处理完善 * * : 考虑各种可能的异常情况
5. * * 代码可读性 * * : 优先保证代码的可读性 , 而不是追求 "高级" 写法
6. * * 注释清晰 * * : 关键逻辑要有注释 , 但不要过度注释
7. * * 性能考虑 * * : 对于大量数据的处理 , 考虑性能优化
8. * * 测试友好 * * : 生成的代码应该便于测试和调试 ` },Symbol.toStringTag,{value:"Module"})),ST=Object.freeze(Object.defineProperty({__proto__:null,default: ` # BIM Engine SDK API 文档
2026-01-28 12:00:55 +08:00
本文档为 BIM Engine SDK 的完整 API 参考 , 适合大模型阅读和理解引擎的功能结构 。
# # 目录
1. [ 核心引擎类 ] ( # 1 - 核心引擎类 )
2. [ 基础模块 ] ( # 2 - 基础模块 )
3. [ 功能管理器 ] ( # 3 - 功能管理器 )
4. [ 状态管理 ] ( # 4 - 状态管理 )
-- -
# # 1. 核心引擎类
# # # EngineKernelV2
引擎核心组件 , 负责整合和管理所有模块 。
* * 文件路径 * * : \ ` src/core/v2/EngineKernel.ts \`
# # # # 构造函数
\ ` \` \` typescript
constructor ( options : any )
\ ` \` \`
* * 参数 * * :
- \ ` options.containerId \` : string - 容器元素的 ID
* * 功能 * * :
- 初始化所有基础模块 ( 场景 、 相机 、 渲染器 、 控制器等 )
- 初始化所有功能管理器 ( 测量 、 剖切 、 模型树等 )
- 设置渲染循环
- 添加性能监视器
# # # # 公共属性
\ ` \` \` typescript
// 基础对象
public scene : THREE . Scene | null // 三维场景
public camera : THREE . Camera | null // 当前使用的相机
public renderer : THREE . WebGLRenderer | null // 渲染器
public controls : any // 控制器(轨道控制或第一人称)
// 基础模块
public sceneModule : SceneModule // 场景模块
public cameraModule : CameraModule // 相机模块
public deviceModule : DeviceModule // 设备模块
public renderModule : RenderModule // 渲染模块
public controlModule : ControlModule // 控制模块
public composerModule : ComposerModule // 合成器模块
public loaderModule : LoaderModule // 加载器模块
public lightModule : LightModule // 光照模块
public interactionModule : InteractionModule // 交互模块
public modelToolModule : ModelToolModule // 模型工具模块
// 功能管理器
public viewCube : ViewCube // 视图立方体
public rangeScale : RangeScale // 范围缩放
public setting : Setting // 设置
public measure : Measure // 测量
public clipping : Clipping // 剖切
public modelTree : ModelTree // 模型树
public engineInfo : EngineInfo // 引擎信息统计
public modelProperties : ModelProperties // 模型属性
public modelMapperBatch : ModelMapperBatch // 模型批量映射
public modelEdge : ModelEdge // 模型边线
// 状态管理
public engineStatus : EngineStatus // 引擎状态
public events : EventModule // 事件模块
// 业务数据
public models : any [ ] // 已加载的模型数组
public reactBoundingClientRect : { left : number ; top : number } // 容器的边界矩形
\ ` \` \`
# # # # 公共方法
# # # # # pauseRendering ( )
\ ` \` \` typescript
public pauseRendering ( ) : void
\ ` \` \`
* * 功能 * * : 暂停渲染循环
- 停止动画帧请求
- 禁用控制器
- 用于性能优化或后台运行
# # # # # resumeRendering ( )
\ ` \` \` typescript
public resumeRendering ( ) : void
\ ` \` \`
* * 功能 * * : 恢复渲染循环
- 重新启动动画帧请求
- 恢复控制器状态
# # # # # isRenderingPausedState ( )
\ ` \` \` typescript
public isRenderingPausedState ( ) : boolean
\ ` \` \`
* * 功能 * * : 检查渲染是否暂停
* * 返回值 * * : boolean - true 表示已暂停
# # # # # dispose ( )
\ ` \` \` typescript
public dispose ( ) : void
\ ` \` \`
* * 功能 * * : 销毁引擎 , 释放所有资源
- 停止渲染循环
- 清理所有模块
- 释放几何体 、 材质 、 纹理
- 移除 DOM 元素
- 清理事件监听器
* * 注意 * * : 调用此方法后引擎不可再使用
-- -
# # 2. 基础模块
# # # 2.1 SceneModule - 场景模块
* * 文件路径 * * : \ ` src/core/v2/modules/sceneModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public scene : THREE . Scene | null // 三维场景对象
\ ` \` \`
* * 功能 * * :
- 创建并管理 THREE . Scene
- 初始化边线组 ( groupEdge ) 用于存储模型边线
-- -
# # # 2.2 CameraModule - 相机模块
* * 文件路径 * * : \ ` src/core/v2/modules/cameraModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public perspectiveCamera : THREE . PerspectiveCamera // 透视相机
public orthographicCamera : THREE . OrthographicCamera // 正交相机
\ ` \` \`
# # # # 公共方法
# # # # # switchCurrentCamera ( )
\ ` \` \` typescript
public switchCurrentCamera ( ) : void
\ ` \` \`
* * 功能 * * : 切换当前相机类型 ( 透视 ↔ 正交 )
# # # # # switchToPerspectiveCamera ( )
\ ` \` \` typescript
public switchToPerspectiveCamera ( ) : void
\ ` \` \`
* * 功能 * * : 切换到透视相机
- 保持当前位置和目标点
- 更新控制器
- 重新初始化合成器
# # # # # switchToOrthographicCamera ( )
\ ` \` \` typescript
public switchToOrthographicCamera ( ) : void
\ ` \` \`
* * 功能 * * : 切换到正交相机
- 保持当前位置和目标点
- 更新控制器
- 重新初始化合成器
# # # # # getCameraType ( )
\ ` \` \` typescript
public getCameraType ( ) : CameraType
\ ` \` \`
* * 功能 * * : 获取当前相机类型
* * 返回值 * * :
- \ ` CameraType.PERSPECTIVE \` - 透视相机
- \ ` CameraType.ORTHOGRAPHIC \` - 正交相机
# # # # # getCameraPose ( )
\ ` \` \` typescript
public getCameraPose ( ) : ICameraPose
\ ` \` \`
* * 功能 * * : 获取当前相机姿态 ( 位置 、 旋转 、 目标点 、 缩放等 )
* * 返回值 * * : ICameraPose 对象
\ ` \` \` typescript
interface ICameraPose {
type : CameraType ;
position : { x : number ; y : number ; z : number } ;
rotation : { x : number ; y : number ; z : number } ;
quaternion : { x : number ; y : number ; z : number ; w : number } ;
target ? : { x : number ; y : number ; z : number } ;
zoom ? : number ;
}
\ ` \` \`
# # # # # restoreCameraPose ( )
\ ` \` \` typescript
public restoreCameraPose ( pose : ICameraPose ) : void
\ ` \` \`
* * 功能 * * : 通过相机姿态还原相机位置
- 自动切换相机类型
- 恢复位置 、 旋转 、 目标点
- 恢复正交相机的缩放值
* * 参数 * * :
- \ ` pose \` : ICameraPose - 相机姿态对象
-- -
# # # 2.3 DeviceModule - 设备模块
* * 文件路径 * * : \ ` src/core/v2/modules/deviceModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public deviceType : string // 设备类型(默认 'PC')
\ ` \` \`
# # # # 公共方法
# # # # # getDeviceType ( )
\ ` \` \` typescript
public getDeviceType ( ) : string
\ ` \` \`
* * 功能 * * : 获取设备类型
* * 返回值 * * : 'PC' 或其他设备标识
# # # # # getContainerSize ( )
\ ` \` \` typescript
public getContainerSize ( ) : { width : number ; height : number }
\ ` \` \`
* * 功能 * * : 获取容器尺寸
* * 返回值 * * : 容器的宽度和高度
-- -
# # # 2.4 RenderModule - 渲染模块
* * 文件路径 * * : \ ` src/core/v2/modules/renderModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public renderer : THREE . WebGLRenderer | null // WebGL 渲染器
\ ` \` \`
# # # # 公共方法
# # # # # createRenderer ( )
\ ` \` \` typescript
public createRenderer ( ) : THREE . WebGLRenderer
\ ` \` \`
* * 功能 * * : 创建并配置 WebGL 渲染器
- 启用抗锯齿
- 启用阴影映射 ( PCFSoftShadowMap )
- 启用本地裁剪 ( 用于剖切平面 )
- 配置色彩空间和色调映射
* * 返回值 * * : 配置好的渲染器实例
# # # # # disposeRenderer ( )
\ ` \` \` typescript
public disposeRenderer ( ) : void
\ ` \` \`
* * 功能 * * : 释放渲染器资源
-- -
# # # 2.5 ControlModule - 控制模块
* * 文件路径 * * : \ ` src/core/v2/modules/controlModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public orbitControls : any // 轨道控制器
public firstPersonControls : any // 第一人称控制器
public isActive : boolean // 控制器是否激活
\ ` \` \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化控制器
- 创建轨道控制器和第一人称控制器
- 创建旋转中心指示器 UI
# # # # # active ( )
\ ` \` \` typescript
public active ( ) : void
\ ` \` \`
* * 功能 * * : 激活控制器
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 禁用控制器
# # # # # switchFirstPersonMode ( )
\ ` \` \` typescript
public switchFirstPersonMode ( ) : void
\ ` \` \`
* * 功能 * * : 切换到第一人称漫游模式
- 禁用轨道控制器
- 启用第一人称控制器
# # # # # switchDefaultMode ( )
\ ` \` \` typescript
public switchDefaultMode ( ) : void
\ ` \` \`
* * 功能 * * : 切换到默认模式 ( 轨道控制 )
- 禁用第一人称控制器
- 启用轨道控制器
# # # # # update ( )
\ ` \` \` typescript
public update ( ) : void
\ ` \` \`
* * 功能 * * : 更新控制器状态
- 更新旋转中心指示器位置
- 在渲染循环中调用
-- -
# # # 2.6 ComposerModule - 合成器模块
* * 文件路径 * * : \ ` src/core/v2/modules/composerModule.ts \`
# # # # 公共属性
\ ` \` \` typescript
public composer : any // 效果合成器
\ ` \` \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化后处理管线
- RenderPass - 基础渲染
- GTAOPass - 环境光遮蔽 ( 默认禁用 )
- UnrealBloomPass - 辉光效果 ( 默认禁用 )
- SaturationPass - 饱和度和对比度调整
- OutputPass - 色调映射和颜色校正
- FXAAPass - 抗锯齿
# # # # # resize ( )
\ ` \` \` typescript
public resize ( ) : void
\ ` \` \`
* * 功能 * * : 调整合成器大小
- 更新所有 pass 的分辨率
- 更新 FXAA 的分辨率参数
-- -
# # # 2.7 LoaderModule - 加载器模块
* * 文件路径 * * : \ ` src/core/v2/modules/loaderModule.ts \`
# # # # 公共方法
# # # # # loadModels ( )
\ ` \` \` typescript
async loadModels ( urls : string [ ] , options ? : LoadModelOptions ) : Promise < void >
\ ` \` \`
* * 功能 * * : 加载多个模型
- 支持轻量化模型格式
- 支持 GLTF / GLB 格式
- 异步加载
* * 参数 * * :
- \ ` urls \` : string[] - 模型 URL 数组
- \ ` options \` : LoadModelOptions - 加载选项(可选)
-- -
# # # 2.8 EventModule - 事件模块
* * 文件路径 * * : \ ` src/core/v2/modules/eventModule.ts \`
# # # # 公共方法
# # # # # on ( )
\ ` \` \` typescript
on < T = any > ( event : EventType , callback : ( data : T ) => void ) : void
\ ` \` \`
* * 功能 * * : 注册事件监听器
* * 参数 * * :
- \ ` event \` : EventType - 事件类型
- \ ` callback \` : 回调函数
# # # # # off ( )
\ ` \` \` typescript
off < T = any > ( event : EventType , callback : ( data : T ) => void ) : void
\ ` \` \`
* * 功能 * * : 移除事件监听器
* * 参数 * * :
- \ ` event \` : EventType - 事件类型
- \ ` callback \` : 要移除的回调函数
# # # # # trigger ( )
\ ` \` \` typescript
trigger ( event : EventType , data ? : any ) : void
\ ` \` \`
* * 功能 * * : 触发事件
* * 参数 * * :
- \ ` event \` : EventType - 事件类型
- \ ` data \` : 传递给监听器的数据
* * 常用事件类型 * * :
- \ ` EventType.Click \` - 点击事件
- \ ` EventType.ViewportResize \` - 视口大小改变
- \ ` EventType.EngineFree \` - 引擎空闲
- \ ` EventType.EngineBusy \` - 引擎繁忙
-- -
# # # 2.9 LightModule - 光照模块
* * 文件路径 * * : \ ` src/core/v2/modules/lightModule.ts \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化场景基本光照
- 添加定向光 ( DirectionalLight )
- 强度 : 2
- 位置 : ( 10 , 20 , 10 )
- 阴影贴图 : 4096 x4096 ( 高质量 )
- 添加环境光 ( AmbientLight )
- 强度 : 1
-- -
# # # 2.10 InteractionModule - 交互模块
* * 文件路径 * * : \ ` src/core/v2/modules/interactionModule.ts \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化交互行为处理器
# # # # # active ( )
\ ` \` \` typescript
public active ( ) : void
\ ` \` \`
* * 功能 * * : 激活交互功能
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 禁用交互功能
# # # # # handleMouseClick ( )
\ ` \` \` typescript
public handleMouseClick ( event : any ) : void
\ ` \` \`
* * 功能 * * : 处理鼠标单击事件
- 射线检测点击的模型
- 高亮选中的模型
- 设置旋转中心
- 支持 Ctrl 多选
# # # # # handleMouseDoubleClick ( )
\ ` \` \` typescript
public handleMouseDoubleClick ( event : any ) : void
\ ` \` \`
* * 功能 * * : 处理鼠标双击事件
- 双击模型后缩放到该模型
- 计算模型包围盒并调整相机视角
# # # # # handleMouseClickInstance ( )
\ ` \` \` typescript
public handleMouseClickInstance ( raycaster : any ) : any
\ ` \` \`
* * 功能 * * : 判断点击实例化网格节点
* * 参数 * * :
- \ ` raycaster \` : 射线投射器
* * 返回值 * * : 相交结果数组
-- -
# # # 2.11 ModelToolModule - 模型工具模块
* * 文件路径 * * : \ ` src/core/v2/modules/modelToolModule.ts \`
# # # # 公共方法
# # # # # highlightModel ( )
\ ` \` \` typescript
public highlightModel ( models : any ) : void
\ ` \` \`
* * 功能 * * : 设置模型高亮显示
* * 参数 * * :
- \ ` models \` : 模型数组,格式: \` [{url: string, ids: string[]}] \`
# # # # # unhighlightModel ( )
\ ` \` \` typescript
public unhighlightModel ( models : any ) : void
\ ` \` \`
* * 功能 * * : 取消模型高亮
* * 参数 * * :
- \ ` models \` : 模型数组
# # # # # unhighlightAllModels ( )
\ ` \` \` typescript
public unhighlightAllModels ( ) : void
\ ` \` \`
* * 功能 * * : 取消所有模型高亮
# # # # # hideModel ( )
\ ` \` \` typescript
public hideModel ( models : any ) : void
\ ` \` \`
* * 功能 * * : 隐藏模型
* * 参数 * * :
- \ ` models \` : 模型数组,格式: \` [{url: string, ids: string[]}] \`
# # # # # showModel ( )
\ ` \` \` typescript
public showModel ( models : any ) : void
\ ` \` \`
* * 功能 * * : 显示模型
* * 参数 * * :
- \ ` models \` : 模型数组
# # # # # isolateModel ( )
\ ` \` \` typescript
public isolateModel ( models : any ) : void
\ ` \` \`
* * 功能 * * : 隔离模型 ( 只显示指定模型 , 隐藏其他 )
* * 参数 * * :
- \ ` models \` : 要显示的模型数组
# # # # # showAllModels ( )
\ ` \` \` typescript
public showAllModels ( ) : void
\ ` \` \`
* * 功能 * * : 显示所有模型
# # # # # getModelsBox ( )
\ ` \` \` typescript
public getModelsBox ( models : any ) : THREE . Box3
\ ` \` \`
* * 功能 * * : 获取模型的包围盒
* * 参数 * * :
- \ ` models \` : 模型数组
* * 返回值 * * : THREE . Box3 包围盒对象
-- -
# # 3. 功能管理器
# # # 3.1 ViewCube - 视图立方体
* * 文件路径 * * : \ ` src/core/v2/managers/viewCube/index.ts \`
# # # # 公共属性
\ ` \` \` typescript
public cubeTool : any // 视图立方体工具
\ ` \` \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化视图立方体
- 创建 3 D 小立方体辅助视图
- 支持六个面和边角视图切换
# # # # # CameraGoHome ( )
\ ` \` \` typescript
public CameraGoHome ( ) : void
\ ` \` \`
* * 功能 * * : 相机回归正位 ( 默认视角 )
# # # # # zoomToModel ( )
\ ` \` \` typescript
public zoomToModel ( box : THREE . Box3 ) : void
\ ` \` \`
* * 功能 * * : 缩放到指定模型包围盒
* * 参数 * * :
- \ ` box \` : THREE.Box3 - 目标包围盒
-- -
# # # 3.2 RangeScale - 范围缩放工具
* * 文件路径 * * : \ ` src/core/v2/managers/rangeScale/index.ts \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化范围缩放工具
- 创建绘制框 UI 元素
- 初始化坐标转换工具
# # # # # active ( )
\ ` \` \` typescript
public active ( ) : void
\ ` \` \`
* * 功能 * * : 激活范围缩放工具
- 禁用控制器
- 启用框选功能
- 鼠标变为十字光标
* * 使用方式 * * :
1. 激活工具
2. 鼠标拖拽绘制矩形区域
3. 松开鼠标自动缩放到该区域
4. 按 ESC 键退出
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 停用范围缩放工具
- 恢复控制器
- 移除事件监听
-- -
# # # 3.3 Setting - 设置管理器
* * 文件路径 * * : \ ` src/core/v2/managers/setting/index.ts \`
# # # # 公共方法
# # # # # setStatsVisible ( )
\ ` \` \` typescript
public setStatsVisible ( visible : boolean ) : void
\ ` \` \`
* * 功能 * * : 显示 / 隐藏性能监视器
* * 参数 * * :
- \ ` visible \` : true 显示, false 隐藏
# # # # # setAmbientLightIntensity ( )
\ ` \` \` typescript
public setAmbientLightIntensity ( intensity : number ) : void
\ ` \` \`
* * 功能 * * : 设置环境光照强度
* * 参数 * * :
- \ ` intensity \` : 光照强度,范围 0-5
# # # # # setAmbientLightColor ( )
\ ` \` \` typescript
public setAmbientLightColor ( color : number | string ) : void
\ ` \` \`
* * 功能 * * : 设置环境光照颜色
* * 参数 * * :
- \ ` color \` : 颜色( 0xffffff 或 '#ffffff')
# # # # # setDirectionalLightIntensity ( )
\ ` \` \` typescript
public setDirectionalLightIntensity ( intensity : number ) : void
\ ` \` \`
* * 功能 * * : 设置定向光源强度
* * 参数 * * :
- \ ` intensity \` : 光照强度,范围 0-5
# # # # # setDirectionalLightColor ( )
\ ` \` \` typescript
public setDirectionalLightColor ( color : number | string ) : void
\ ` \` \`
* * 功能 * * : 设置定向光源颜色
* * 参数 * * :
- \ ` color \` : 颜色
# # # # # setShadowQuality ( )
\ ` \` \` typescript
public setShadowQuality ( quality : 'low' | 'medium' | 'high' | 'ultra' ) : void
\ ` \` \`
* * 功能 * * : 设置阴影精细度
* * 参数 * * :
- \ ` quality \` : 质量等级
- 'low' : 1024
- 'medium' : 2048
- 'high' : 4096
- 'ultra' : 8192
# # # # # setDirectionalLightShadow ( )
\ ` \` \` typescript
public setDirectionalLightShadow ( enabled : boolean ) : void
\ ` \` \`
* * 功能 * * : 开启 / 关闭定向光阴影
* * 参数 * * :
- \ ` enabled \` : true 开启, false 关闭
# # # # # setGTAOEnabled ( )
\ ` \` \` typescript
public setGTAOEnabled ( enabled : boolean ) : void
\ ` \` \`
* * 功能 * * : 开启 / 关闭 GTAO 环境光遮蔽
* * 参数 * * :
- \ ` enabled \` : true 开启, false 关闭
# # # # # setSceneSaturation ( )
\ ` \` \` typescript
public setSceneSaturation ( saturation : number ) : void
\ ` \` \`
* * 功能 * * : 设置场景饱和度
* * 参数 * * :
- \ ` saturation \` : 饱和度值, 1.0 为正常,推荐范围 0.5-2.0
# # # # # setSceneContrast ( )
\ ` \` \` typescript
public setSceneContrast ( contrast : number ) : void
\ ` \` \`
* * 功能 * * : 设置场景对比度
* * 参数 * * :
- \ ` contrast \` : 对比度值, 1.0 为正常,推荐范围 0.5-2.0
# # # # # setGroundEnabled ( )
\ ` \` \` typescript
public setGroundEnabled ( enabled : boolean , options ? : {
size ? : number ;
color ? : number | string ;
opacity ? : number ;
} ) : void
\ ` \` \`
* * 功能 * * : 开启 / 关闭地面
* * 参数 * * :
- \ ` enabled \` : true 开启, false 关闭
- \ ` options \` : 地面配置选项
- \ ` size \` : 地面大小(默认 100)
- \ ` color \` : 地面颜色(默认 0x808080)
- \ ` opacity \` : 透明度(默认 0.3)
# # # # # setHDRBackground ( )
\ ` \` \` typescript
public setHDRBackground ( hdrTexture : THREE . Texture | null ) : void
\ ` \` \`
* * 功能 * * : 设置 HDR 背景
* * 参数 * * :
- \ ` hdrTexture \` : HDR 环境贴图, null 则移除
-- -
# # # 3.4 Measure - 测量工具
* * 文件路径 * * : \ ` src/core/v2/managers/measure/index.ts \`
# # # # 公共方法
# # # # # active ( )
\ ` \` \` typescript
public active ( ) : void
\ ` \` \`
* * 功能 * * : 激活测量工具
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 停用测量工具
- 清除所有测量
- 恢复点选功能
# # # # # clearAllPoints ( )
\ ` \` \` typescript
public clearAllPoints ( ) : void
\ ` \` \`
* * 功能 * * : 清空所有测量点
# # # # # clearAll ( )
\ ` \` \` typescript
public clearAll ( ) : void
\ ` \` \`
* * 功能 * * : 清除所有测量标注
# # # # # update ( )
\ ` \` \` typescript
update ( ) : void
\ ` \` \`
* * 功能 * * : 更新测量标注
- 在渲染循环中调用
- 更新屏幕坐标
* * 测量类型 * * :
- 距离测量 ( DistanceMeasure )
- 净高测量 ( ClearHeightMeasure )
- 净距测量 ( ClearDistanceMeasure )
- 标高测量 ( ElevationMeasure )
- 点测量 ( PointMeasure )
- 角度测量 ( AngleMeasure )
- 面积测量 ( AreaMeasure )
- 坡度测量 ( SlopeMeasure )
-- -
# # # 3.5 Clipping - 剖切管理器
* * 文件路径 * * : \ ` src/core/v2/managers/clipping/index.ts \`
# # # # 公共属性
\ ` \` \` typescript
public sectionPlaneX : any // X 轴剖切平面
public sectionPlaneY : any // Y 轴剖切平面
public sectionPlaneZ : any // Z 轴剖切平面
public sectionBox : any // 剖切盒
\ ` \` \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化剖切管理器
- 创建 6 个剖切平面 ( 前 、 后 、 左 、 右 、 顶 、 底 )
- 初始化 X / Y / Z 轴剖切工具
- 初始化剖切盒工具
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 停用所有剖切工具
-- -
# # # 3.6 ModelTree - 模型树
* * 文件路径 * * : \ ` src/core/v2/managers/modelTree/index.ts \`
# # # # 公共方法
# # # # # getTreeData ( )
\ ` \` \` typescript
public getTreeData ( ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取模型树数据
* * 返回值 * * : 模型树数组
\ ` \` \` typescript
[ {
name : string , // 模型名称
children : any [ ] // 模型层级树
} ]
\ ` \` \`
-- -
# # # 3.7 EngineInfo - 引擎信息统计
* * 文件路径 * * : \ ` src/core/v2/managers/engineInfo/index.ts \`
# # # # 公共方法
# # # # # getEngineInfo ( )
\ ` \` \` typescript
public getEngineInfo ( ) : {
totalVertices : number ;
totalTriangles : number ;
meshCount : number ;
}
\ ` \` \`
* * 功能 * * : 获取引擎统计信息
- 统计所有网格的顶点数
- 统计所有网格的三角面数
- 统计网格数量
* * 返回值 * * :
- \ ` totalVertices \` : 总顶点数
- \ ` totalTriangles \` : 总三角面数
- \ ` meshCount \` : 网格数量
-- -
# # # 3.8 ModelProperties - 模型属性
* * 文件路径 * * : \ ` src/core/v2/managers/modelProperties/index.ts \`
# # # # 公共方法
# # # # # getModelProperties ( )
\ ` \` \` typescript
public getModelProperties ( url : string , id : string , callback : ( properties : any ) => void ) : void
\ ` \` \`
* * 功能 * * : 查询构件属性
- 异步加载属性数据 ( 如果未加载 )
- 从压缩的 JSON 中解析属性
* * 参数 * * :
- \ ` url \` : 模型 URL
- \ ` id \` : 构件 ID
- \ ` callback \` : 回调函数,接收属性对象
* * 返回值格式 * * :
\ ` \` \` typescript
{
properties : [ {
name : string , // 分类名称
children : [ {
name : string , // 属性名
value : any // 属性值
} ]
} ] ,
materials : [ ]
}
\ ` \` \`
-- -
# # # 3.9 ModelMapperBatch - 模型批量映射
* * 文件路径 * * : \ ` src/core/v2/managers/modelMapperBatch/index.ts \`
# # # # 公共方法
# # # # # getModelTypes ( )
\ ` \` \` typescript
public getModelTypes ( ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取模型中所有的构件类型
# # # # # getModelMajors ( )
\ ` \` \` typescript
public getModelMajors ( ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取模型中所有的专业
# # # # # getModelLevels ( )
\ ` \` \` typescript
public getModelLevels ( ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取模型中所有的楼层
# # # # # getModelMapper ( )
\ ` \` \` typescript
public getModelMapper ( url : string , id : number ) : any
\ ` \` \`
* * 功能 * * : 获取指定构件的映射信息
* * 参数 * * :
- \ ` url \` : 模型 URL
- \ ` id \` : 构件 ID
* * 返回值 * * : Mapper 对象 ( 包含类型 、 专业 、 楼层等信息 )
# # # # # getModelSWithType ( )
\ ` \` \` typescript
public getModelSWithType ( type : string , callback : any ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取同类型的所有构件
* * 参数 * * :
- \ ` type \` : 构件类型名称
- \ ` callback \` : 回调函数
* * 返回值 * * : \ ` [{url: string, ids: number[]}] \`
# # # # # getModelSWithLevel ( )
\ ` \` \` typescript
public getModelSWithLevel ( level : string , callback : any ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取同楼层的所有构件
* * 参数 * * :
- \ ` level \` : 楼层名称
- \ ` callback \` : 回调函数
* * 返回值 * * : \ ` [{url: string, ids: number[]}] \`
# # # # # getModelsWithMajor ( )
\ ` \` \` typescript
public getModelsWithMajor ( major : string , callback : any ) : any [ ]
\ ` \` \`
* * 功能 * * : 获取同专业的所有构件
* * 参数 * * :
- \ ` major \` : 专业名称
- \ ` callback \` : 回调函数
* * 返回值 * * : \ ` [{url: string, ids: number[]}] \`
-- -
# # # 3.10 ModelEdge - 模型边线管理器
* * 文件路径 * * : \ ` src/core/v2/managers/modelEdge/index.ts \`
# # # # 公共方法
# # # # # active ( )
\ ` \` \` typescript
public active ( ) : void
\ ` \` \`
* * 功能 * * : 启动边线显示
- 显示所有模型的边线
- 用于技术制图风格渲染
# # # # # disActive ( )
\ ` \` \` typescript
public disActive ( ) : void
\ ` \` \`
* * 功能 * * : 关闭边线显示
# # # # # getModelEdge ( )
\ ` \` \` typescript
public getModelEdge ( url : string , id : Number ) : any
\ ` \` \`
* * 功能 * * : 获取指定模型的边线数据
* * 参数 * * :
- \ ` url \` : 模型 URL
- \ ` id \` : 构件 ID
* * 返回值 * * : 边线数据 \ ` [startIndex, endIndex, points] \`
# # # # # hideModelEdge ( )
\ ` \` \` typescript
public hideModelEdge ( url : string , id : Number ) : void
\ ` \` \`
* * 功能 * * : 隐藏指定构件的边线
* * 参数 * * :
- \ ` url \` : 模型 URL
- \ ` id \` : 构件 ID
# # # # # showModelEdge ( )
\ ` \` \` typescript
public showModelEdge ( url : string , id : Number ) : void
\ ` \` \`
* * 功能 * * : 显示指定构件的边线
* * 参数 * * :
- \ ` url \` : 模型 URL
- \ ` id \` : 构件 ID
-- -
# # 4. 状态管理
# # # 4.1 EngineStatus - 引擎状态
* * 文件路径 * * : \ ` src/core/v2/status/engineStatus.ts \`
# # # # 公共属性
\ ` \` \` typescript
public isFree : boolean // 引擎是否空闲
public highlightModels : any [ ] // 高亮的模型数组
public hideModels : any [ ] // 隐藏的模型数组
public models : any [ ] // 已加载的模型数组
\ ` \` \`
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
public init ( ) : void
\ ` \` \`
* * 功能 * * : 初始化引擎状态监听
- 监听 \ ` EventType.EngineFree \` 事件
- 监听 \ ` EventType.EngineBusy \` 事件
# # # # # updateFree ( )
\ ` \` \` typescript
public updateFree ( status : boolean ) : void
\ ` \` \`
* * 功能 * * : 更新引擎空闲状态
* * 参数 * * :
- \ ` status \` : true 表示空闲, false 表示繁忙
# # # # # closeAllFunction ( )
\ ` \` \` typescript
public closeAllFunction ( ) : void
\ ` \` \`
* * 功能 * * : 关闭所有功能
-- -
# # # 4.2 HandelBehaved - 行为处理器
* * 文件路径 * * : \ ` src/core/v2/status/handelBehaved.ts \`
这是一个工厂函数 , 返回行为处理器对象 。
# # # # 公共方法
# # # # # init ( )
\ ` \` \` typescript
init ( self : any , options : any ) : void
\ ` \` \`
* * 功能 * * : 初始化行为处理器
* * 参数 * * :
- \ ` self \` : 当前激活的行为对象
- \ ` options \` : 行为配置选项
- \ ` showCatch \` : boolean - 是否显示捕捉点
# # # # # active ( )
\ ` \` \` typescript
active ( ) : void
\ ` \` \`
* * 功能 * * : 开启事务 ( 激活事件监听 )
- 监听鼠标事件 ( mousedown , mouseup , mousemove )
- 监听键盘事件 ( keydown , keyup )
# # # # # disActive ( )
\ ` \` \` typescript
disActive ( ) : void
\ ` \` \`
* * 功能 * * : 关闭事务 ( 禁用事件监听 )
* * 支持的键盘事件 * * :
- Delete / Backspace - 删除
- Escape - 取消
- Enter - 确认
- Space - 空格
- Ctrl / Control - 控制键
- Shift - 切换键
- Alt - 辅助键
- Meta / Command - 命令键
* * 支持的鼠标事件 * * :
- handleMouseDown - 鼠标按下
- handleMouseMove - 鼠标移动
- handleMouseUp - 鼠标弹起
- handleMouseClick - 鼠标单击
- handleMouseDoubleClick - 鼠标双击
* * 捕捉功能 * * :
- 点捕捉 ( 距离 < 5 像素 )
- 线捕捉 ( 距离 < 5 像素 )
- 面捕捉 ( 默认 )
-- -
# # 使用示例
# # # 初始化引擎
\ ` \` \` typescript
import { EngineKernelV2 } from './src/core/v2/EngineKernel' ;
const engine = new EngineKernelV2 ( {
containerId : 'canvas-container' ,
antialias : true
} ) ;
\ ` \` \`
# # # 加载模型
\ ` \` \` typescript
await engine . loaderModule . loadModels ( [
'https://example.com/model1.light' ,
'https://example.com/model2.light'
] ) ;
\ ` \` \`
# # # 高亮模型
\ ` \` \` typescript
engine . modelToolModule . highlightModel ( [
{ url : 'model1.light' , ids : [ 'wall-001' , 'wall-002' ] }
] ) ;
\ ` \` \`
# # # 切换相机
\ ` \` \` typescript
// 切换到正交相机
engine . cameraModule . switchToOrthographicCamera ( ) ;
// 或切换当前相机类型
engine . cameraModule . switchCurrentCamera ( ) ;
\ ` \` \`
# # # 保存和恢复相机姿态
\ ` \` \` typescript
// 保存当前相机姿态
const pose = engine . cameraModule . getCameraPose ( ) ;
// 恢复相机姿态
engine . cameraModule . restoreCameraPose ( pose ) ;
\ ` \` \`
# # # 设置光照和渲染质量
\ ` \` \` typescript
// 设置环境光强度
engine . setting . setAmbientLightIntensity ( 1.5 ) ;
// 设置阴影质量
engine . setting . setShadowQuality ( 'ultra' ) ;
// 开启 GTAO
engine . setting . setGTAOEnabled ( true ) ;
// 调整饱和度和对比度
engine . setting . setSceneSaturation ( 1.3 ) ;
engine . setting . setSceneContrast ( 1.1 ) ;
\ ` \` \`
# # # 获取模型属性
\ ` \` \` typescript
engine . modelProperties . getModelProperties ( 'model.light' , 'wall-001' , ( data ) => {
console . log ( '属性:' , data . properties ) ;
} ) ;
\ ` \` \`
# # # 按类型筛选构件
\ ` \` \` typescript
engine . modelMapperBatch . getModelSWithType ( '墙' , ( models ) => {
// 高亮所有墙体
engine . modelToolModule . highlightModel ( models ) ;
} ) ;
\ ` \` \`
# # # 监听事件
\ ` \` \` typescript
// 监听点击事件
engine . events . on ( EventType . Click , ( hit ) => {
console . log ( '点击了:' , hit . object . name ) ;
} ) ;
// 监听视口大小改变
engine . events . on ( EventType . ViewportResize , ( { width , height } ) => {
console . log ( '视口大小:' , width , height ) ;
} ) ;
\ ` \` \`
# # # 暂停和恢复渲染
\ ` \` \` typescript
// 暂停渲染(节省性能)
engine . pauseRendering ( ) ;
// 恢复渲染
engine . resumeRendering ( ) ;
// 检查渲染状态
if ( engine . isRenderingPausedState ( ) ) {
console . log ( '渲染已暂停' ) ;
}
\ ` \` \`
# # # 销毁引擎
\ ` \` \` typescript
// 释放所有资源
engine . dispose ( ) ;
\ ` \` \`
-- -
# # 总结
BIM Engine SDK 提供了完整的 3 D BIM 模型渲染和交互能力 , 主要特性包括 :
- * * 完整的相机系统 * * : 支持透视和正交相机 , 可保存和恢复相机姿态
- * * 强大的模型操作 * * : 高亮 、 隐藏 、 隔离 、 批量筛选
- * * 丰富的测量工具 * * : 距离 、 净高 、 净距 、 标高 、 角度 、 面积 、 坡度
- * * 灵活的剖切功能 * * : 支持 X / Y / Z 轴剖切和剖切盒
- * * 可配置的渲染质量 * * : 阴影 、 环境光遮蔽 、 饱和度 、 对比度
- * * 事件驱动架构 * * : 支持自定义事件监听和触发
- * * 性能优化 * * : 支持暂停 / 恢复渲染 , 八叉树加速
- * * 完善的资源管理 * * : 自动释放几何体 、 材质 、 纹理等资源
适用场景 :
- BIM 模型在线浏览
- 建筑设计审查
- 施工模拟
- 运维管理
- AI 辅助设计
2026-02-02 18:18:36 +08:00
` },Symbol.toStringTag,{value:"Module"}));Bs.BimEngine=oT,Object.defineProperty(Bs,Symbol.toStringTag,{value:"Module"})}));
2026-01-22 11:29:51 +08:00
//# sourceMappingURL=iflow-engine.umd.js.map