2026-03-04 16:40:35 +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 - engine - version { position : absolute ; bottom : 6 px ; left : 10 px ; font - size : 11 px ; color : # 00000040 ; pointer - events : none ; - webkit - user - select : none ; user - select : none ; z - index : 1 ; font - family : system - ui , - apple - system , sans - serif ; letter - spacing : . 3 px } . bim - btn - group - root { display : flex ; gap : 8 px ; z - index : 1000 ; position : absolute ; pointer - events : auto ; background : transparent } . 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 { co
2026-03-05 17:43:50 +08:00
( function ( js , Zr ) { typeof exports == "object" && typeof module < "u" ? Zr ( exports ) : typeof define == "function" && define . amd ? define ( [ "exports" ] , Zr ) : ( js = typeof globalThis < "u" ? globalThis : js || self , Zr ( js . IflowEngine = { } ) ) } ) ( this , ( function ( js ) { "use strict" ; const Zr = { 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 : "剖切盒" , cameraSwitch : "相机切换" } , dialog : { testTitle : "测试弹窗" , testContent : '<div style="padding: 10px;">这是一个 <b>可拖拽</b> 且 <b>可缩放</b> 的弹窗。<br><br>你可以尝试拖动标题栏,或者拖动右下角改变大小。</div>' } , menu : { info : "信息" , home : "首页" , componentDetail : "构件详情" , hideSelected : "隐藏选中构件" , transparentSelected : "半透明选中构件" , cancelTranslucent : "取消半透明" , isolateSelected : "隔离选中构件" , hideOthers : "其他构件隐藏" , transparentOthers : "其他构件半透明" , fitSectionBox : "剖切盒适应" , showAll : "显示全部" , quickSelect : "快速选择" , selectSameType : "选择同类模型" , selectSameLevel : "选择同层模型" , selectSameLevelType : "选择同层同类模型" } , 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 : "坡度:" } } , settings : { title : "设置" , unit : "单位:" , precision : "精度:" , hint : "距离、净距、净高和标高默认使用该单位;角度和面积有各自默认单位。" , save : "保存设置" , cancel : "取消" } , clearHeight : { direction : "朝向:" , directionDown : "朝下" , directionUp : "朝上" , selectType : "选择对象:" , selectPoint : "选择点" , selectElement : "选择构件" } } , 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 : "路径漫游" , duration : "漫游时间" , durationUnit : "秒" , loop : "循环播放" , addPoint : "添加漫游点" , deleteAll : "删除全部" , point : "漫游点" , play : "播放漫游" , stop : "停止漫游" , noPoints : "暂无漫游点,请添加" } } , info : { dialogTitle : "基本信息" , meshCount : "构件数量" , totalTriangles : "三角面数量" , totalVertices : "顶点数量" } , aiChat : { title : "AI 助手" , placeholder : "输入你的问题..." , quickPrompt : { summarize : "总结这个模型" , explain : "解释选中的构件" , generate : "生成报告" } , action : { new : "新建对话" , history : "历史记录" , settings : "设置" , close : "关闭" } , helper : { newline : "Shift + Enter 换行" , send : "Enter 发送" } , th
2026-01-22 11:29:51 +08:00
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
2026-03-04 16:40:35 +08:00
} ` ,Gx= ` void main ( ) {
2026-01-22 11:29:51 +08:00
gl _FragColor = vec4 ( 1.0 , 0.0 , 0.0 , 1.0 ) ;
2026-03-05 17:43:50 +08:00
} ` ;class Lt extends Ln{constructor(e){super(),this.isShaderMaterial=!0,this.type="ShaderMaterial",this.defines={},this.uniforms={},this.uniformsGroups=[],this.vertexShader=Vx,this.fragmentShader=Gx,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=ur(e.uniforms),this.uniformsGroups=Hx(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 bp extends Et{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new Ie,this.projectionMatrix=new Ie,this.projectionMatrixInverse=new Ie,this.coordinateSystem=oi,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 Yi=new P,yp=new he,_p=new he;class on extends bp{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=er*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(ia*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return er*2*Math.atan(Math.tan(ia*.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){Yi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(Yi.x,Yi.y).multiplyScalar(-e/Yi.z),Yi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(Yi.x,Yi.y).multiplyScalar(-e/Yi.z)}getViewSize(e,t){return this.getViewBounds(e,yp,_p),t.subVectors(_p,yp)}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-03-05 17:43:50 +08:00
` },i=new Zi(5,5,5),r=new Lt({name:"CubemapFromEquirect",uniforms:ur(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:sn,blending:St});r.uniforms.tEquirect.value=t;const a=new at(i,r),o=t.minFilter;return t.minFilter===ai&&(t.minFilter=Pt),new Wx(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 ln extends Et{constructor(){super(),this.isGroup=!0,this.type="Group"}}const jx={type:"move"};class Mh{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new ln,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 ln,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new P,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new P),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new ln,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new P,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new P),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 f of e.hand.values()){const x=t.getJointPose(f,n),m=this._getHandJoint(c,f);x!==null&&(m.matrix.fromArray(x.transform.matrix),m.matrix.decompose(m.position,m.rotation,m.scale),m.matrixWorldNeedsUpdate=!0,m.jointRadius=x.radius),m.visible=x!==null}const h=c.joints["index-finger-tip"],d=c.joints["thumb-tip"],p=h.position.distanceTo(d.position),u=.02,g=.005;c.inputState.pinching&&p>u+g?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&p<=u-g&&(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(jx)))}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 ln;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class wp extends Et{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 Rn,thi
2026-01-22 11:29:51 +08:00
if ( diffuseColor . a < getAlphaHashThreshold ( vPosition ) ) discard ;
2026-03-04 16:40:35 +08:00
# endif ` ,_v= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Mv= ` # ifdef USE _ALPHAMAP
2026-03-02 09:45:59 +08:00
diffuseColor . a *= texture2D ( alphaMap , vAlphaMapUv ) . g ;
2026-03-04 16:40:35 +08:00
# endif ` ,wv= ` # ifdef USE _ALPHAMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D alphaMap ;
2026-03-04 16:40:35 +08:00
# endif ` ,Sv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Ev= ` # ifdef USE _ALPHATEST
2026-01-22 11:29:51 +08:00
uniform float alphaTest ;
2026-03-05 11:15:57 +08:00
# endif ` ,Cv= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Tv= ` # ifdef USE _AOMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D aoMap ;
uniform float aoMapIntensity ;
2026-03-04 16:40:35 +08:00
# endif ` ,Av= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Pv= ` # ifdef USE _BATCHING
2026-01-22 11:29:51 +08:00
mat4 batchingMatrix = getBatchingMatrix ( getIndirectIndex ( gl _DrawID ) ) ;
2026-03-04 16:40:35 +08:00
# endif ` ,Rv= ` vec3 transformed = vec3 ( position ) ;
2026-01-22 11:29:51 +08:00
# ifdef USE _ALPHAHASH
vPosition = vec3 ( position ) ;
2026-03-04 16:40:35 +08:00
# endif ` ,Lv= ` vec3 objectNormal = vec3 ( normal ) ;
2026-01-22 11:29:51 +08:00
# ifdef USE _TANGENT
vec3 objectTangent = vec3 ( tangent . xyz ) ;
2026-03-05 17:43:50 +08:00
# endif ` ,Iv= ` 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-03-05 17:43:50 +08:00
} // validated`,Dv=`#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-03-04 16:40:35 +08:00
# endif ` ,Nv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Bv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,kv= ` # if NUM _CLIPPING _PLANES > 0
2026-02-04 18:20:30 +08:00
varying vec3 vClipPosition ;
2026-03-02 09:45:59 +08:00
uniform vec4 clippingPlanes [ NUM _CLIPPING _PLANES ] ;
2026-03-04 16:40:35 +08:00
# endif ` ,Uv= ` # if NUM _CLIPPING _PLANES > 0
2026-03-02 09:45:59 +08:00
varying vec3 vClipPosition ;
2026-03-04 16:40:35 +08:00
# endif ` ,Ov= ` # if NUM _CLIPPING _PLANES > 0
2026-01-22 11:29:51 +08:00
vClipPosition = - mvPosition . xyz ;
2026-03-04 16:40:35 +08:00
# endif ` ,zv= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
diffuseColor *= vColor ;
# elif defined ( USE _COLOR )
diffuseColor . rgb *= vColor ;
2026-03-04 16:40:35 +08:00
# endif ` ,Fv= ` # if defined ( USE _COLOR _ALPHA )
2026-01-22 11:29:51 +08:00
varying vec4 vColor ;
# elif defined ( USE _COLOR )
varying vec3 vColor ;
2026-03-04 16:40:35 +08:00
# endif ` ,Hv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Vv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Gv= ` # 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-03-04 16:40:35 +08:00
} // validated`,Wv=`#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-03-04 16:40:35 +08:00
# endif ` ,Xv= ` 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-03-04 16:40:35 +08:00
# endif ` ,jv= ` # ifdef USE _DISPLACEMENTMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D displacementMap ;
uniform float displacementScale ;
uniform float displacementBias ;
2026-03-04 16:40:35 +08:00
# endif ` ,qv= ` # ifdef USE _DISPLACEMENTMAP
2026-01-22 11:29:51 +08:00
transformed += normalize ( objectNormal ) * ( texture2D ( displacementMap , vDisplacementMapUv ) . x * displacementScale + displacementBias ) ;
2026-03-04 16:40:35 +08:00
# endif ` ,Zv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Yv= ` # ifdef USE _EMISSIVEMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D emissiveMap ;
2026-03-04 16:40:35 +08:00
# endif ` , $ v="gl_FragColor = linearToOutputTexel( gl_FragColor );",Kv= ` 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-03-04 16:40:35 +08:00
} ` ,Jv= ` # 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-03-04 16:40:35 +08:00
# endif ` ,Qv= ` # 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-03-05 11:15:57 +08:00
# endif ` ,eb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,tb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,nb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ib= ` # ifdef USE _FOG
2026-03-02 09:45:59 +08:00
vFogDepth = - mvPosition . z ;
2026-03-05 11:15:57 +08:00
# endif ` ,sb= ` # ifdef USE _FOG
2026-03-02 09:45:59 +08:00
varying float vFogDepth ;
2026-03-05 11:15:57 +08:00
# endif ` ,rb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ab= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ob= ` # 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-03-05 11:15:57 +08:00
} ` ,lb= ` # ifdef USE _LIGHTMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D lightMap ;
uniform float lightMapIntensity ;
2026-03-05 11:15:57 +08:00
# endif ` ,cb= ` LambertMaterial material ;
2026-01-22 11:29:51 +08:00
material . diffuseColor = diffuseColor . rgb ;
2026-03-05 11:15:57 +08:00
material . specularStrength = specularStrength ; ` ,hb= ` 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-03-05 17:43:50 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _Lambert ` ,db= ` 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-03-05 17:43:50 +08:00
# endif ` ,ub= ` # 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-03-05 11:15:57 +08:00
# endif ` ,pb= ` ToonMaterial material ;
material . diffuseColor = diffuseColor . rgb ; ` ,fb= ` 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-03-05 11:15:57 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _Toon ` ,mb= ` BlinnPhongMaterial material ;
2026-01-22 11:29:51 +08:00
material . diffuseColor = diffuseColor . rgb ;
material . specularColor = specular ;
material . specularShininess = shininess ;
2026-03-05 11:15:57 +08:00
material . specularStrength = specularStrength ; ` ,gb= ` 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-03-05 11:15:57 +08:00
# define RE _IndirectDiffuse RE _IndirectDiffuse _BlinnPhong ` ,xb= ` 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-03-05 11:15:57 +08:00
# endif ` ,vb= ` 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-03-05 11:15:57 +08:00
} ` ,bb= `
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-03-05 11:15:57 +08:00
# endif ` ,yb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,_b= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Mb= ` # if defined ( USE _LOGARITHMIC _DEPTH _BUFFER )
2026-03-02 09:45:59 +08:00
gl _FragDepth = vIsPerspective == 0.0 ? gl _FragCoord . z : log2 ( vFragDepth ) * logDepthBufFC * 0.5 ;
2026-03-05 11:15:57 +08:00
# endif ` ,wb= ` # if defined ( USE _LOGARITHMIC _DEPTH _BUFFER )
2026-01-22 11:29:51 +08:00
uniform float logDepthBufFC ;
varying float vFragDepth ;
varying float vIsPerspective ;
2026-03-05 11:15:57 +08:00
# endif ` ,Sb= ` # ifdef USE _LOGARITHMIC _DEPTH _BUFFER
2026-01-22 11:29:51 +08:00
varying float vFragDepth ;
varying float vIsPerspective ;
2026-03-05 11:15:57 +08:00
# endif ` ,Eb= ` # ifdef USE _LOGARITHMIC _DEPTH _BUFFER
2026-01-22 11:29:51 +08:00
vFragDepth = 1.0 + gl _Position . w ;
vIsPerspective = float ( isPerspectiveMatrix ( projectionMatrix ) ) ;
2026-03-05 11:15:57 +08:00
# endif ` ,Cb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Tb= ` # ifdef USE _MAP
2026-01-22 11:29:51 +08:00
uniform sampler2D map ;
2026-03-05 11:15:57 +08:00
# endif ` ,Ab= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Pb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Rb= ` float metalnessFactor = metalness ;
2026-01-22 11:29:51 +08:00
# ifdef USE _METALNESSMAP
vec4 texelMetalness = texture2D ( metalnessMap , vMetalnessMapUv ) ;
metalnessFactor *= texelMetalness . b ;
2026-03-05 11:15:57 +08:00
# endif ` ,Lb= ` # ifdef USE _METALNESSMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D metalnessMap ;
2026-03-05 17:43:50 +08:00
# endif ` ,Ib= ` # 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-03-05 17:43:50 +08:00
# endif ` ,Db= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Nb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Bb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,kb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Ub= ` 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-03-05 11:15:57 +08:00
vec3 nonPerturbedNormal = normal ; ` ,Ob= ` # 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-03-05 11:15:57 +08:00
# endif ` ,zb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Fb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Hb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Vb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Gb= ` # ifdef USE _CLEARCOAT
2026-01-22 11:29:51 +08:00
vec3 clearcoatNormal = nonPerturbedNormal ;
2026-03-05 11:15:57 +08:00
# endif ` ,Wb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Xb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,jb= ` # ifdef USE _IRIDESCENCEMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D iridescenceMap ;
# endif
# ifdef USE _IRIDESCENCE _THICKNESSMAP
uniform sampler2D iridescenceThicknessMap ;
2026-03-05 11:15:57 +08:00
# endif ` ,qb= ` # ifdef OPAQUE
2026-01-22 11:29:51 +08:00
diffuseColor . a = 1.0 ;
# endif
# ifdef USE _TRANSMISSION
diffuseColor . a *= material . transmissionAlpha ;
# endif
2026-03-05 11:15:57 +08:00
gl _FragColor = vec4 ( outgoingLight , diffuseColor . a ) ; ` ,Zb= ` 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-03-05 11:15:57 +08:00
} ` ,Yb= ` # ifdef PREMULTIPLIED _ALPHA
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb *= gl _FragColor . a ;
2026-03-05 11:15:57 +08:00
# endif ` , $ b= ` 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-03-05 11:15:57 +08:00
gl _Position = projectionMatrix * mvPosition ; ` ,Kb= ` # ifdef DITHERING
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb = dithering ( gl _FragColor . rgb ) ;
2026-03-05 11:15:57 +08:00
# endif ` ,Jb= ` # 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-03-05 11:15:57 +08:00
# endif ` ,Qb= ` float roughnessFactor = roughness ;
2026-01-22 11:29:51 +08:00
# ifdef USE _ROUGHNESSMAP
vec4 texelRoughness = texture2D ( roughnessMap , vRoughnessMapUv ) ;
roughnessFactor *= texelRoughness . g ;
2026-03-05 11:15:57 +08:00
# endif ` ,ey= ` # ifdef USE _ROUGHNESSMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D roughnessMap ;
2026-03-05 11:15:57 +08:00
# endif ` ,ty= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ny= ` # 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-03-05 11:15:57 +08:00
# endif ` ,iy= ` # 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-03-05 11:15:57 +08:00
# endif ` ,sy= ` 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-03-05 11:15:57 +08:00
} ` ,ry= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ay= ` # 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-03-05 11:15:57 +08:00
# endif ` ,oy= ` # 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-03-05 11:15:57 +08:00
# endif ` ,ly= ` # 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-03-05 11:15:57 +08:00
# endif ` ,cy= ` 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-03-05 11:15:57 +08:00
# endif ` ,hy= ` # ifdef USE _SPECULARMAP
2026-01-22 11:29:51 +08:00
uniform sampler2D specularMap ;
2026-03-05 17:43:50 +08:00
# endif ` ,dy= ` # if defined ( TONE _MAPPING )
2026-01-22 11:29:51 +08:00
gl _FragColor . rgb = toneMapping ( gl _FragColor . rgb ) ;
2026-03-05 17:43:50 +08:00
# endif ` ,uy= ` # 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-03-05 11:15:57 +08:00
vec3 CustomToneMapping ( vec3 color ) { return color ; } ` ,py= ` # 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-03-05 11:15:57 +08:00
# endif ` ,fy= ` # 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-03-05 11:15:57 +08:00
# endif ` ,my= ` # 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-03-05 11:15:57 +08:00
# endif ` ,gy= ` # 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-03-05 11:15:57 +08:00
# endif ` ,xy= ` # 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-03-05 11:15:57 +08:00
# endif ` ,vy= ` # 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-03-05 17:43:50 +08:00
# endif ` ;const et={alphahash_fragment:yv,alphahash_pars_fragment:_v,alphamap_fragment:Mv,alphamap_pars_fragment:wv,alphatest_fragment:Sv,alphatest_pars_fragment:Ev,aomap_fragment:Cv,aomap_pars_fragment:Tv,batching_pars_vertex:Av,batching_vertex:Pv,begin_vertex:Rv,beginnormal_vertex:Lv,bsdfs:Iv,iridescence_fragment:Dv,bumpmap_pars_fragment:Nv,clipping_planes_fragment:Bv,clipping_planes_pars_fragment:kv,clipping_planes_pars_vertex:Uv,clipping_planes_vertex:Ov,color_fragment:zv,color_pars_fragment:Fv,color_pars_vertex:Hv,color_vertex:Vv,common:Gv,cube_uv_reflection_fragment:Wv,defaultnormal_vertex:Xv,displacementmap_pars_vertex:jv,displacementmap_vertex:qv,emissivemap_fragment:Zv,emissivemap_pars_fragment:Yv,colorspace_fragment: $ v,colorspace_pars_fragment:Kv,envmap_fragment:Jv,envmap_common_pars_fragment:Qv,envmap_pars_fragment:eb,envmap_pars_vertex:tb,envmap_physical_pars_fragment:ub,envmap_vertex:nb,fog_vertex:ib,fog_pars_vertex:sb,fog_fragment:rb,fog_pars_fragment:ab,gradientmap_pars_fragment:ob,lightmap_pars_fragment:lb,lights_lambert_fragment:cb,lights_lambert_pars_fragment:hb,lights_pars_begin:db,lights_toon_fragment:pb,lights_toon_pars_fragment:fb,lights_phong_fragment:mb,lights_phong_pars_fragment:gb,lights_physical_fragment:xb,lights_physical_pars_fragment:vb,lights_fragment_begin:bb,lights_fragment_maps:yb,lights_fragment_end:_b,logdepthbuf_fragment:Mb,logdepthbuf_pars_fragment:wb,logdepthbuf_pars_vertex:Sb,logdepthbuf_vertex:Eb,map_fragment:Cb,map_pars_fragment:Tb,map_particle_fragment:Ab,map_particle_pars_fragment:Pb,metalnessmap_fragment:Rb,metalnessmap_pars_fragment:Lb,morphinstance_vertex:Ib,morphcolor_vertex:Db,morphnormal_vertex:Nb,morphtarget_pars_vertex:Bb,morphtarget_vertex:kb,normal_fragment_begin:Ub,normal_fragment_maps:Ob,normal_pars_fragment:zb,normal_pars_vertex:Fb,normal_vertex:Hb,normalmap_pars_fragment:Vb,clearcoat_normal_fragment_begin:Gb,clearcoat_normal_fragment_maps:Wb,clearcoat_pars_fragment:Xb,iridescence_pars_fragment:jb,opaque_fragment:qb,packing:Zb,premultiplied_alpha_fragment:Yb,project_vertex: $ b,dithering_fragment:Kb,dithering_pars_fragment:Jb,roughnessmap_fragment:Qb,roughnessmap_pars_fragment:ey,shadowmap_pars_fragment:ty,shadowmap_pars_vertex:ny,shadowmap_vertex:iy,shadowmask_pars_fragment:sy,skinbase_vertex:ry,skinning_pars_vertex:ay,skinning_vertex:oy,skinnormal_vertex:ly,specularmap_fragment:cy,specularmap_pars_fragment:hy,tonemapping_fragment:dy,tonemapping_pars_fragment:uy,transmission_fragment:py,transmission_pars_fragment:fy,uv_pars_fragment:my,uv_pars_vertex:gy,uv_vertex:xy,worldpos_vertex:vy,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-03-05 17:43:50 +08:00
} ` },Pe={common:{diffuse:{value:new Fe(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 he(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 Fe(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 Fe(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 Fe(16777215)},opacity:{value:1},center:{value:new he(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new $ e},alphaMap:{value:null},alphaMapTransform:{value:new $ e},alphaTest:{value:0}}},di={basic:{uniforms:un([Pe.common,Pe.specularmap,Pe.envmap,Pe.aomap,Pe.lightmap,Pe.fog]),vertexShader:et.meshbasic_vert,fragmentShader:et.meshbasic_frag},lambert:{uniforms:un([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 Fe(0)}}]),vertexShader:et.meshlambert_vert,fragmentShader:et.meshlambert_frag},phong:{uniforms:un([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 Fe(0)},specular:{value:new Fe(1118481)},shininess:{value:30}}]),vertexShader:et.meshphong_vert,fragmentShader:et.meshphong_frag},standard:{uniforms:un([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 Fe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:et.meshphysical_vert,fragmentShader:et.meshphysical_frag},toon:{uniforms:un([Pe.common,Pe.aomap,Pe.lightmap,Pe.emissivemap,Pe.bumpmap,Pe.normalmap,Pe.displacementmap,Pe.gradientmap,Pe.fog,Pe.lights,{emissive:{value:new Fe(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-03-05 11:15:57 +08:00
` ,blending:St,depthTest:!1,depthWrite:!1})}function Ry(s,e,t){const n=new Float32Array(Cs),i=new P(0,1,0);return new Lt({name:"SphericalGaussianBlur",defines:{n:Cs,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:Yo(),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-03-04 16:40:35 +08:00
` ,blending:St,depthTest:!1,depthWrite:!1})}function Sf(){return new Lt({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Yo(),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-03-04 16:40:35 +08:00
` ,blending:St,depthTest:!1,depthWrite:!1})}function Ef(){return new Lt({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Yo(),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-03-04 16:40:35 +08:00
` ,blending:St,depthTest:!1,depthWrite:!1})}function Yo(){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-03-05 17:43:50 +08:00
` }function Ly(s){let e=new WeakMap,t=null;function n(o){if(o&&o.isTexture){const l=o.mapping,c=l=== $ a||l===fc,h=l===Ks||l===Js;if(c||h){let d=e.get(o);const p=d!==void 0?d.texture.pmremVersion:0;if(o.isRenderTargetTexture&&o.pmremVersion!==p)return t===null&&(t=new id(s)),d=c?t.fromEquirectangular(o,d):t.fromCubemap(o,d),d.texture.pmremVersion=o.pmremVersion,e.set(o,d),d.texture;if(d!==void 0)return d.texture;{const u=o.image;return c&&u&&u.height>0||h&&u&&i(u)?(t===null&&(t=new id(s)),d=c?t.fromEquirectangular(o):t.fromCubemap(o),d.texture.pmremVersion=o.pmremVersion,e.set(o,d),o.addEventListener("dispose",r),d.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 Iy(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&&na("WebGLRenderer: "+n+" extension not supported."),i}}}function Dy(s,e,t,n){const i={},r=new WeakMap;function a(d){const p=d.target;p.index!==null&&e.remove(p.index);for(const g in p.attributes)e.remove(p.attributes[g]);p.removeEventListener("dispose",a),delete i[p.id];const u=r.get(p);u&&(e.remove(u),r.delete(p)),n.releaseStatesOfGeometry(p),p.isInstancedBufferGeometry===!0&&delete p._maxInstanceCount,t.memory.geometries--}function o(d,p){return i[p.id]===!0||(p.addEventListener("dispose",a),i[p.id]=!0,t.memory.geometries++),p}function l(d){const p=d.attributes;for(const u in p)e.update(p[u],s.ARRAY_BUFFER)}function c(d){const p=[],u=d.index,g=d.attributes.position;let f=0;if(u!==null){const b=u.array;f=u.version;for(let v=0,y=b.length;v<y;v+=3){const _=b[v+0],M=b[v+1],T=b[v+2];p.push(_,M,M,T,T,_)}}else if(g!==void 0){const b=g.array;f=g.version;for(let v=0,y=b.length/3-1;v<y;v+=3){const _=v+0,M=v+1,T=v+2;p.push(_,M,M,T,T,_)}}else return;const x=new(Ku(p)?fp:pp)(p,1);x.version=f;const m=r.get(d);m&&e.remove(m),r.set(d,x)}function h(d){const p=r.get(d);if(p){const u=d.index;u!==null&&p.version<u.version&&c(d)}else c(d);return r.get(d)}return{get:o,update:l,getWireframeAttribute:h}}function Ny(s,e,t){let n;function i(p){n=p}let r,a;function o(p){r=p.type,a=p.bytesPerElement}function l(p,u){s.drawElements(n,u,r,p*a),t.update(u,n,1)}function c(p,u,g){g!==0&&(s.drawElementsInstanced(n,u,r,p*a,g),t.update(u,n,g))}function h(p,u,g){if(g===0)return;e.get("WEBGL_multi_draw").multiDrawElementsWEBGL(n,u,0,r,p,0,g);let x=0;for(let m=0;m<g;m++)x+=u[m];t.update(x,n,1)}function d(p,u,g,f){if(g===0)return;const x=e.get("WEBGL_multi_draw");if(x===null)for(let m=0;m<p.length;m++)c(p[m]/a,u[m],f[m]);else{x.multiDrawElementsInstancedWEBGL(n,u,0,r,p,0,f,0,g);let m=0;for(let b=0;b<g;b++)m+=u[b]*f[b];t.update(m,n,1)}}this.setMode=i,this.setIndex=o,this.render=l,this.renderInstances=c,this.renderMultiDraw=h,this.renderMultiDrawInstances=d}function By(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 ky(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,d=h!==void 0?h.length:0;let p=n.get(o);if(p===void 0||p.count!==d){let w=function(){T.dispose(),n.delete(o),o.r
2026-03-04 16:40:35 +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( `
` )}const Of=new $ e;function L2(s){it._getMatrix(Of,it.workingColorSpace,s);const e= ` mat3 ( $ { Of . elements . map ( t => t . toFixed ( 4 ) ) } ) ` ;switch(it.getTransfer(s)){case ao:return[e,"LinearTransferOETF"];case ct:return[e,"sRGBTransferOETF"];default:return He("WebGLProgram: Unsupported color space: ",s),[e,"LinearTransferOETF"]}}function zf(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-03-05 17:43:50 +08:00
` +R2(s.getShaderSource(e),o)}else return r}function I2(s,e){const t=L2(e);return[ ` vec4 $ { s } ( vec4 value ) { ` , ` return $ { t [ 1 ] } ( vec4 ( value . rgb * $ { t [ 0 ] } , value . a ) ) ; ` ,"}"].join( `
` )}function D2(s,e){let t;switch(e){case Au:t="Linear";break;case Pu:t="Reinhard";break;case Ru:t="Cineon";break;case Lu:t="ACESFilmic";break;case Du:t="AgX";break;case Nu:t="Neutral";break;case Iu:t="Custom";break;default:He("WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+s+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}const Jo=new P;function N2(){it.getLuminanceCoefficients(Jo);const s=Jo.x.toFixed(4),e=Jo.y.toFixed(4),t=Jo.z.toFixed(4);return["float luminance( const in vec3 rgb ) {", ` const vec3 weights = vec3 ( $ { s } , $ { e } , $ { t } ) ; ` ," return dot( weights, rgb );","}"].join( `
2026-03-05 11:15:57 +08:00
` )}function B2(s){return[s.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",s.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(Ca).join( `
2026-03-04 16:40:35 +08:00
` )}function k2(s){const e=[];for(const t in s){const n=s[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join( `
2026-03-05 17:43:50 +08:00
` )}function U2(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 Ca(s){return s!==""}function Ff(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 Hf(s,e){return s.replace(/NUM_CLIPPING_PLANES/g,e.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,e.numClippingPlanes-e.numClipIntersection)}const O2=/^[ \t ]*#include +<([ \w \d ./]+)>/gm;function rd(s){return s.replace(O2,F2)}const z2=new Map;function F2(s,e){let t=et[e];if(t===void 0){const n=z2.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 rd(t)}const H2=/#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 Vf(s){return s.replace(H2,V2)}function V2(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 Gf(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-03-05 17:43:50 +08:00
# define LOW _PRECISION ` ),e}function G2(s){let e="SHADOWMAP_TYPE_BASIC";return s.shadowMapType===Su?e="SHADOWMAP_TYPE_PCF":s.shadowMapType===Eu?e="SHADOWMAP_TYPE_PCF_SOFT":s.shadowMapType===vi&&(e="SHADOWMAP_TYPE_VSM"),e}function W2(s){let e="ENVMAP_TYPE_CUBE";if(s.envMap)switch(s.envMapMode){case Ks:case Js:e="ENVMAP_TYPE_CUBE";break;case Ka:e="ENVMAP_TYPE_CUBE_UV";break}return e}function X2(s){let e="ENVMAP_MODE_REFLECTION";if(s.envMap)switch(s.envMapMode){case Js:e="ENVMAP_MODE_REFRACTION";break}return e}function j2(s){let e="ENVMAP_BLENDING_NONE";if(s.envMap)switch(s.combine){case pc:e="ENVMAP_BLENDING_MULTIPLY";break;case Vg:e="ENVMAP_BLENDING_MIX";break;case Gg:e="ENVMAP_BLENDING_ADD";break}return e}function q2(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 Z2(s,e,t,n){const i=s.getContext(),r=t.defines;let a=t.vertexShader,o=t.fragmentShader;const l=G2(t),c=W2(t),h=X2(t),d=j2(t),p=q2(t),u=B2(t),g=k2(r),f=i.createProgram();let x,m,b=t.glslVersion?"#version "+t.glslVersion+ `
` :"";t.isRawShaderMaterial?(x=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g].filter(Ca).join( `
2026-01-22 11:29:51 +08:00
` ),x.length>0&&(x+= `
2026-03-05 17:43:50 +08:00
` ),m=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g].filter(Ca).join( `
` ),m.length>0&&(m+= `
` )):(x=[Gf(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,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":"",
2026-03-05 11:15:57 +08:00
` ].filter(Ca).join( `
2026-03-05 17:43:50 +08:00
` ),m=[Gf(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,g,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 "+d:"",p?"#define CUBEUV_TEXEL_WIDTH "+p.texelWidth:"",p?"#define CUBEUV_TEXEL_HEIGHT "+p.texelHeight:"",p?"#define CUBEUV_MAX_MIP "+p.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!==Fi?"#define TONE_MAPPING":"",t.toneMapping!==Fi?et.tonemapping_pars_fragment:"",t.toneMapping!==Fi?D2("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",et.colorspace_pars_fragment,I2("linearToOutputTexel",t.outputColorSpace),N2(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"", `
2026-03-05 11:15:57 +08:00
` ].filter(Ca).join( `
2026-03-05 17:43:50 +08:00
` )),a=rd(a),a=Ff(a,t),a=Hf(a,t),o=rd(o),o=Ff(o,t),o=Hf(o,t),a=Vf(a),o=Vf(o),t.isRawShaderMaterial!==!0&&(b= ` # version 300 es
` ,x=[u,"#define attribute in","#define varying out","#define texture2D texture"].join( `
2026-01-22 11:29:51 +08:00
` )+ `
2026-03-05 17:43:50 +08:00
` +x,m=["#define varying in",t.glslVersion=== $ u?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion=== $ u?"":"#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-03-05 17:43:50 +08:00
` +m);const v=b+x+a,y=b+m+o,_=Uf(i,i.VERTEX_SHADER,v),M=Uf(i,i.FRAGMENT_SHADER,y);i.attachShader(f,_),i.attachShader(f,M),t.index0AttributeName!==void 0?i.bindAttribLocation(f,0,t.index0AttributeName):t.morphTargets===!0&&i.bindAttribLocation(f,0,"position"),i.linkProgram(f);function T(I){if(s.debug.checkShaderErrors){const A=i.getProgramInfoLog(f)||"",B=i.getShaderInfoLog(_)||"",S=i.getShaderInfoLog(M)||"",U=A.trim(),H=B.trim(),G=S.trim();let Z=!0,j=!0;if(i.getProgramParameter(f,i.LINK_STATUS)===!1)if(Z=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,f,_,M);else{const ie=zf(i,_,"vertex"),X=zf(i,M,"fragment");Qe("THREE.WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(f,i.VALIDATE_STATUS)+ `
2026-01-22 11:29:51 +08:00
2026-03-05 17:43:50 +08:00
Material Name : ` +I.name+ `
Material Type : ` +I.type+ `
2026-01-22 11:29:51 +08:00
2026-03-05 17:43:50 +08:00
Program Info Log : ` +U+ `
2026-02-02 16:36:17 +08:00
` +ie+ `
2026-03-05 17:43:50 +08:00
` +X)}else U!==""?He("WebGLProgram: Program Info Log:",U):(H===""||G==="")&&(j=!1);j&&(I.diagnostics={runnable:Z,programLog:U,vertexShader:{log:H,prefix:x},fragmentShader:{log:G,prefix:m}})}i.deleteShader(_),i.deleteShader(M),R=new Ko(i,f),w=U2(i,f)}let R;this.getUniforms=function(){return R===void 0&&T(this),R};let w;this.getAttributes=function(){return w===void 0&&T(this),w};let E=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return E===!1&&(E=i.getProgramParameter(f,A2)),E},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(f),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=P2++,this.cacheKey=e,this.usedTimes=1,this.program=f,this.vertexShader=_,this.fragmentShader=M,this}let Y2=0;class $ 2{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 K2(e),t.set(e,n)),n}}class K2{constructor(e){this.id=Y2++,this.code=e,this.usedTimes=0}}function J2(s,e,t,n,i,r,a){const o=new hh,l=new $ 2,c=new Set,h=[],d=i.logarithmicDepthBuffer,p=i.vertexTextures;let u=i.precision;const g={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 f(w){return c.add(w),w===0?"uv": ` uv$ { w } ` }function x(w,E,I,A,B){const S=A.fog,U=B.geometry,H=w.isMeshStandardMaterial?A.environment:null,G=(w.isMeshStandardMaterial?t:e).get(w.envMap||H),Z=G&&G.mapping===Ka?G.image.height:null,j=g[w.type];w.precision!==null&&(u=i.getMaxPrecision(w.precision),u!==w.precision&&He("WebGLProgram.getParameters:",w.precision,"not supported, using",u,"instead."));const ie=U.morphAttributes.position||U.morphAttributes.normal||U.morphAttributes.color,X=ie!==void 0?ie.length:0;let $ =0;U.morphAttributes.position!==void 0&&( $ =1),U.morphAttributes.normal!==void 0&&( $ =2),U.morphAttributes.color!==void 0&&( $ =3);let ue,pe,fe,se;if(j){const mt=di[j];ue=mt.vertexShader,pe=mt.fragmentShader}else ue=w.vertexShader,pe=w.fragmentShader,l.update(w),fe=l.getVertexShaderID(w),se=l.getFragmentShaderID(w);const ce=s.getRenderTarget(),me=s.state.buffers.depth.getReversed(),be=B.isInstancedMesh===!0,Se=B.isBatchedMesh===!0,Be=!!w.map,Je=!!w.matcap,ke=!!G,C=!!w.aoMap,D=!!w.lightMap,W=!!w.bumpMap,O=!!w.normalMap,k=!!w.displacementMap,F=!!w.emissiveMap,ee=!!w.metalnessMap,J=!!w.roughnessMap,q=w.anisotropy>0,N=w.clearcoat>0,L=w.dispersion>0,V=w.iridescence>0,K=w.sheen>0,le=w.transmission>0,te=q&&!!w.anisotropyMap,Te=N&&!!w.clearcoatMap,ye=N&&!!w.clearcoatNormalMap,Re=N&&!!w.clearcoatRoughnessMap,De=V&&!!w.iridescenceMap,de=V&&!!w.iridescenceThicknessMap,_e=K&&!!w.sheenColorMap,Ve=K&&!!w.sheenRoughnessMap,Ue=!!w.specularMap,Ae=!!w.specularColorMap,Ge=!!w.specularIntensityMap,Y=le&&!!w.transmissionMap,Ce=le&&!!w.thicknessMap,Me=!!w.gradientMap,we=!!w.alphaMap,ve=w.alphaTest>0,ge=!!w.alphaHash,Oe=!!w.extensions;let Ye=Fi;w.toneMapped&&(ce===null||ce.isXRRenderTarget===!0)&&(Ye=s.toneMapping);const wt={shaderID:j,shaderType:w.type,shaderName:w.name,vertexShader:ue,fragmen
2026-01-22 11:29:51 +08:00
gl _Position = vec4 ( position , 1.0 ) ;
2026-03-04 16:40:35 +08:00
} ` ,c3= ` 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-03-05 17:43:50 +08:00
} ` ;function h3(s,e,t){let n=new Rh;const i=new he,r=new he,a=new tt,o=new U1({depthPacking:Zg}),l=new O1,c={},h=t.maxTextureSize,d={[kn]:sn,[sn]:kn,[yt]:yt},p=new Lt({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new he},radius:{value:4}},vertexShader:l3,fragmentShader:c3}),u=p.clone();u.defines.HORIZONTAL_PASS=1;const g=new pt;g.setAttribute("position",new bt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const f=new at(g,p),x=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=Su;let m=this.type;this.render=function(M,T,R){if(x.enabled===!1||x.autoUpdate===!1&&x.needsUpdate===!1||M.length===0)return;const w=s.getRenderTarget(),E=s.getActiveCubeFace(),I=s.getActiveMipmapLevel(),A=s.state;A.setBlending(St),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=m!==vi&&this.type===vi,S=m===vi&&this.type!==vi;for(let U=0,H=M.length;U<H;U++){const G=M[U],Z=G.shadow;if(Z===void 0){He("WebGLShadowMap:",G,"has no shadow.");continue}if(Z.autoUpdate===!1&&Z.needsUpdate===!1)continue;i.copy(Z.mapSize);const j=Z.getFrameExtents();if(i.multiply(j),r.copy(Z.mapSize),(i.x>h||i.y>h)&&(i.x>h&&(r.x=Math.floor(h/j.x),i.x=r.x*j.x,Z.mapSize.x=r.x),i.y>h&&(r.y=Math.floor(h/j.y),i.y=r.y*j.y,Z.mapSize.y=r.y)),Z.map===null||B===!0||S===!0){const X=this.type!==vi?{minFilter:Xt,magFilter:Xt}:{};Z.map!==null&&Z.map.dispose(),Z.map=new An(i.x,i.y,X),Z.map.texture.name=G.name+".shadowMap",Z.camera.updateProjectionMatrix()}s.setRenderTarget(Z.map),s.clear();const ie=Z.getViewportCount();for(let X=0;X<ie;X++){const $ =Z.getViewport(X);a.set(r.x* $ .x,r.y* $ .y,r.x* $ .z,r.y* $ .w),A.viewport(a),Z.updateMatrices(G,X),n=Z.getFrustum(),y(T,R,Z.camera,G,this.type)}Z.isPointLightShadow!==!0&&this.type===vi&&b(Z,R),Z.needsUpdate=!1}m=this.type,x.needsUpdate=!1,s.setRenderTarget(w,E,I)};function b(M,T){const R=e.update(f);p.defines.VSM_SAMPLES!==M.blurSamples&&(p.defines.VSM_SAMPLES=M.blurSamples,u.defines.VSM_SAMPLES=M.blurSamples,p.needsUpdate=!0,u.needsUpdate=!0),M.mapPass===null&&(M.mapPass=new An(i.x,i.y)),p.uniforms.shadow_pass.value=M.map.texture,p.uniforms.resolution.value=M.mapSize,p.uniforms.radius.value=M.radius,s.setRenderTarget(M.mapPass),s.clear(),s.renderBufferDirect(T,null,R,p,f,null),u.uniforms.shadow_pass.value=M.mapPass.texture,u.uniforms.resolution.value=M.mapSize,u.uniforms.radius.value=M.radius,s.setRenderTarget(M.map),s.clear(),s.renderBufferDirect(T,null,R,u,f,null)}function v(M,T,R,w){let E=null;const I=R.isPointLight===!0?M.customDistanceMaterial:M.customDepthMaterial;if(I!==void 0)E=I;else if(E=R.isPointLight===!0?l:o,s.localClippingEnabled&&T.clipShadows===!0&&Array.isArray(T.clippingPlanes)&&T.clippingPlanes.length!==0||T.displacementMap&&T.displacementScale!==0||T.alphaMap&&T.alphaTest>0||T.map&&T.alphaTest>0||T.alphaToCoverage===!0){const A=E.uuid,B=T.uuid;let S=c[A];S===void 0&&(S={},c[A]=S);let U=S[B];U===void 0&&(U=E.clone(),S[B]=U,T.addEventListener("dispose",_)),E=U}if(E.visible=T.visible,E.wireframe=T.wireframe,w===vi?E.side=T.shadowSide!==null?T.shadowSide:T.side:E.side=T.shadowSide!==null?T.shadowSide:d[T.side],E.alphaMap=T.alphaMap,E.alphaTest=T.alphaToCoverage===!0?.5:T.alphaTest,E.map=T.map,E.clipShadows=T.clipShadows,E.clippingPlanes=T.clippingPlanes,E.clipIntersection=T.clipIntersection,E.displacementMap=T.displacementMap,E.displacementScale=T.displacementScale,E.displacementBias=T.displacementBias,E.wireframeLinewidth=T.wireframeLinewidth,E.linewidth=T.linewidth,R.isPointLight===!0&&E.isMeshDistanceMaterial===!0){const A=s.properties.get(E);A.light=R}return E}function y(M,T,R,w,E){if(M.visible===!1)return;if(M.layers.test(T.layers)&&(M.isMesh||M.isLine||M.isPoints)&&(M.castShadow||M.receiveShadow&&E===vi)&&(!M.frustumCulled||n.intersectsObject(M))){M.modelViewMatrix.multiplyMatrices(R.matrixWorldInverse,M.matrixWorld);const B=e.update(M),S=M.material;if(Array.isArray(S)){const U=B.groups;for(let H=0,G=U.length;H<G;H++){const Z=U[H],j=S[Z.materialIndex];if(j&&j.visible
2026-01-22 11:29:51 +08:00
void main ( ) {
gl _Position = vec4 ( position , 1.0 ) ;
2026-03-04 16:40:35 +08:00
} ` ,g3= `
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-03-05 17:43:50 +08:00
} ` ;class x3{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new jp(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 Lt({vertexShader:m3,fragmentShader:g3,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new at(new Ss(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class v3 extends gs{constructor(e,t){super();const n=this;let i=null,r=1,a=null,o="local-floor",l=1,c=null,h=null,d=null,p=null,u=null,g=null;const f=typeof XRWebGLBinding<"u",x=new x3,m={},b=t.getContextAttributes();let v=null,y=null;const _=[],M=[],T=new he;let R=null;const w=new on;w.viewport=new tt;const E=new on;E.viewport=new tt;const I=[w,E],A=new rv;let B=null,S=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(se){let ce=_[se];return ce===void 0&&(ce=new Mh,_[se]=ce),ce.getTargetRaySpace()},this.getControllerGrip=function(se){let ce=_[se];return ce===void 0&&(ce=new Mh,_[se]=ce),ce.getGripSpace()},this.getHand=function(se){let ce=_[se];return ce===void 0&&(ce=new Mh,_[se]=ce),ce.getHandSpace()};function U(se){const ce=M.indexOf(se.inputSource);if(ce===-1)return;const me=_[ce];me!==void 0&&(me.update(se.inputSource,se.frame,c||a),me.dispatchEvent({type:se.type,data:se.inputSource}))}function H(){i.removeEventListener("select",U),i.removeEventListener("selectstart",U),i.removeEventListener("selectend",U),i.removeEventListener("squeeze",U),i.removeEventListener("squeezestart",U),i.removeEventListener("squeezeend",U),i.removeEventListener("end",H),i.removeEventListener("inputsourceschange",G);for(let se=0;se<_.length;se++){const ce=M[se];ce!==null&&(M[se]=null,_[se].disconnect(ce))}B=null,S=null,x.reset();for(const se in m)delete m[se];e.setRenderTarget(v),u=null,p=null,d=null,i=null,y=null,fe.stop(),n.isPresenting=!1,e.setPixelRatio(R),e.setSize(T.width,T.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 p!==null?p:u},this.getBinding=function(){return d===null&&f&&(d=new XRWebGLBinding(i,t)),d},this.getFrame=function(){return g},this.getSession=function(){return i},this.setSession=async function(se){if(i=se,i!==null){if(v=e.getRenderTarget(),i.addEventListener("select",U),i.addEventListener("selectstart",U),i.addEventListener("selectend",U),i.addEventListener("squeeze",U),i.addEventListener("squeezestart",U),i.addEventListener("squeezeend",U),i.addEventListener("end",H),i.addEventListener("inputsourceschange",G),b.xrCompatible!==!0&&await t.makeXRCompatible(),R=e.getPixelRatio(),e.getSize(T),f&&"createProjectionLayer"in XRWebGLBinding.prototype){let me=null,be=null,Se=null;b.depth&&(Se=b.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,me=b.stencil?ms:Jr,be=b.stencil?fs:ps);const Be={colorFormat:t.RGBA8,depthFormat:Se,scaleFactor:r};d=this.getBinding(),p=d.createProjectionLayer(Be),i.updateRenderState({layers:[p]}),e.setPixelRatio(1),e.setSize(p.textureWidth,p.textureHeight,!1),y=new An(p.textureWidth,p.textureHeight,{format:vn,type: $ n,depthTexture:new Fo(p.textureWidth,p.textureHeight,be,void 0,void 0,void 0,void 0,void 0,void 0,me),stencilBuffer:b.stencil,colorSpace:e.outputColorSpace,samples:b.antialias?4:0,resolveDepthBuffer:p.ignoreDepthValues===!1,resolveStencilBuffer:p.ignoreDepthValues===!1})}else{const me={antialias:b.antialias,alpha:!0,depth:b.depth,stencil:b.stencil,framebufferScaleFactor:r};u=new XRWebGLLayer(i,t,me),i.updateRenderState({baseLayer:u}
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-03-05 17:43:50 +08:00
} ` };class Ps{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 G3=new Ai(-1,1,1,-1,0,1);class W3 extends pt{constructor(){super(),this.setAttribute("position",new jt([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new jt([0,2,0,0,2,0],2))}}const X3=new W3;class el{constructor(e){this._mesh=new at(X3,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,G3)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class tl extends Ps{constructor(e,t="tDiffuse"){super(),this.textureID=t,this.uniforms=null,this.material=null,e instanceof Lt?(this.uniforms=e.uniforms,this.material=e):e&&(this.uniforms=Hn.clone(e.uniforms),this.material=new Lt({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 el(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 Kf extends Ps{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 j3 extends Ps{constructor(){super(),this.needsSwap=!1}render(e){e.state.buffers.stencil.setLocked(!1),e.state.buffers.stencil.setTest(!1)}}class q3{constructor(e,t){if(this.renderer=e,this._pixelRatio=e.getPixelRatio(),t===void 0){const n=e.getSize(new he);this._width=n.width,this._height=n.height,t=new An(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:dn}),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 tl(As),this.copyPass.material.blending=St,this.clock=new mf}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-03-04 16:40:35 +08:00
} ` },il={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-03-05 17:43:50 +08:00
} ` },hd={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-03-05 17:43:50 +08:00
} ` };function Y3(s=5){const e=Math.floor(s)%2===0?Math.floor(s)+1:Math.floor(s),t= $ 3(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 P(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 ys(i,e,e);return r.wrapS=Tn,r.wrapT=Tn,r.needsUpdate=!0,r}function $ 3(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 sl={defines:{SAMPLES:16,SAMPLE_VECTORS:Jf(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 he},cameraProjectionMatrixInverse:{value:new Ie},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-03-05 17:43:50 +08:00
} ` };function Jf(s,e,t){const n=K3(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 K3(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 P(Math.cos(r),Math.sin(r),a))}return n}class Qf{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,d=(l+c)*h,p=l-d,u=c-d,g=e-p,f=t-u;let x,m;g>f?(x=1,m=0):(x=0,m=1);const b=g-x+h,v=f-m+h,y=g-1+2*h,_=f-1+2*h,M=l&255,T=c&255,R=this.perm[M+this.perm[T]]%12,w=this.perm[M+x+this.perm[T+m]]%12,E=this.perm[M+1+this.perm[T+1]]%12;let I=.5-g*g-f*f;I<0?n=0:(I*=I,n=I*I*this._dot(this.grad3[R],g,f));let A=.5-b*b-v*v;A<0?i=0:(A*=A,i=A*A*this._dot(this.grad3[w],b,v));let B=.5-y*y-_*_;return B<0?r=0:(B*=B,r=B*B*this._dot(this.grad3[E],y,_)),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),d=Math.floor(n+l),p=1/6,u=(c+h+d)*p,g=c-u,f=h-u,x=d-u,m=e-g,b=t-f,v=n-x;let y,_,M,T,R,w;m>=b?b>=v?(y=1,_=0,M=0,T=1,R=1,w=0):m>=v?(y=1,_=0,M=0,T=1,R=0,w=1):(y=0,_=0,M=1,T=1,R=0,w=1):b<v?(y=0,_=0,M=1,T=0,R=1,w=1):m<v?(y=0,_=1,M=0,T=0,R=1,w=1):(y=0,_=1,M=0,T=1,R=1,w=0);const E=m-y+p,I=b-_+p,A=v-M+p,B=m-T+2*p,S=b-R+2*p,U=v-w+2*p,H=m-1+3*p,G=b-1+3*p,Z=v-1+3*p,j=c&255,ie=h&255,X=d&255, $ =this.perm[j+this.perm[ie+this.perm[X]]]%12,ue=this.perm[j+y+this.perm[ie+_+this.perm[X+M]]]%12,pe=this.perm[j+T+this.perm[ie+R+this.perm[X+w]]]%12,fe=this.perm[j+1+this.perm[ie+1+this.perm[X+1]]]%12;let se=.6-m*m-b*b-v*v;se<0?i=0:(se*=se,i=se*se*this._dot3(this.grad3[ $ ],m,b,v));let ce=.6-E*E-I*I-A*A;ce<0?r=0:(ce*=ce,r=ce*ce*this._dot3(this.grad3[ue],E,I,A));let me=.6-B*B-S*S-U*U;me<0?a=0:(me*=me,a=me*me*this._dot3(this.grad3[pe],B,S,U));let be=.6-H*H-G*G-Z*Z;return be<0?o=0:(be*=be,o=be*be*this._dot3(this.grad3[fe],H,G,Z)),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,d,p,u,g;const f=(e+t+n+i)*l,x=Math.floor(e+f),m=Math.floor(t+f),b=Math.floor(n+f),v=Math.floor(i+f),y=(x+m+b+v)*c,_=x-y,M=m-y,T=b-y,R=v-y,w=e-_,E=t-M,I=n-T,A=i-R,B=w>E?32:0,S=w>I?16:0,U=E>I?8:0,H=w>A?4:0,G=E>A?2:0,Z=I>A?1:0,j=B+S+U+H+G+Z,ie=a[j][0]>=3?1:0,X=a[j][1]>=3?1:0, $ =a[j][2]>=3?1:0,ue=a[j][3]>=3?1:0,pe=a[j][0]>=2?1:0,fe=a[j][1]>=2?1:0,se=a[j][2]>=2?1:0,ce=a[j][3]>=2?1:0,me=a[j][0]>=1?1:0,be=a[j][1]>=1?1:0,Se=a[j][2]>=1?1:0,Be=a[j][3]>=1?1:0,Je=w-ie+c,ke=E-X+c,C=I- $ +c,D=A-ue+c,W=w-pe+2*c,O=E-fe+2*c,k=I-se+2*c,F=A-ce+2*c,ee=w-me+3*c,J=E-be+3*c,q=I-Se+3*c,N=A-Be+3*c,L=w-1+4*c,V=E-1+4*c,K=I-1+4*c,le=A-1+4*c,te=x&255,Te=m&255,ye=b&255,Re=v&255,De=o[te+o[Te+o[ye+o[Re]]]]%32,de=o[te+ie+o[Te+X+o[ye+ $ +o[Re+ue]]]]%32,_e=o[te+pe+o[Te+fe+o[ye+se+o[Re+ce]]]]%32,Ve=o[te+me+
2026-03-04 16:40:35 +08:00
varying vec2 vUv ;
void main ( ) {
vUv = uv ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( position , 1.0 ) ;
} ` ,fragmentShader: `
uniform highp sampler2D tNormal ;
uniform highp sampler2D tDepth ;
uniform sampler2D tNoise ;
uniform vec3 kernel [ KERNEL _SIZE ] ;
uniform vec2 resolution ;
uniform float cameraNear ;
uniform float cameraFar ;
uniform mat4 cameraProjectionMatrix ;
uniform mat4 cameraInverseProjectionMatrix ;
uniform float kernelRadius ;
uniform float minDistance ; // avoid artifacts caused by neighbour fragments with minimal depth difference
uniform float maxDistance ; // avoid the influence of fragments which are too far away
varying vec2 vUv ;
# include < packing >
float getDepth ( const in vec2 screenPosition ) {
return texture2D ( tDepth , screenPosition ) . x ;
}
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
}
float getViewZ ( const in float depth ) {
# if PERSPECTIVE _CAMERA == 1
return perspectiveDepthToViewZ ( depth , cameraNear , cameraFar ) ;
# else
return orthographicDepthToViewZ ( depth , cameraNear , cameraFar ) ;
# endif
}
vec3 getViewPosition ( const in vec2 screenPosition , const in float depth , const in float viewZ ) {
float clipW = cameraProjectionMatrix [ 2 ] [ 3 ] * viewZ + cameraProjectionMatrix [ 3 ] [ 3 ] ;
vec4 clipPosition = vec4 ( ( vec3 ( screenPosition , depth ) - 0.5 ) * 2.0 , 1.0 ) ;
clipPosition *= clipW ; // unprojection.
return ( cameraInverseProjectionMatrix * clipPosition ) . xyz ;
}
vec3 getViewNormal ( const in vec2 screenPosition ) {
return unpackRGBToNormal ( texture2D ( tNormal , screenPosition ) . xyz ) ;
}
void main ( ) {
float depth = getDepth ( vUv ) ;
if ( depth == 1.0 ) {
gl _FragColor = vec4 ( 1.0 ) ; // don't influence background
} else {
float viewZ = getViewZ ( depth ) ;
vec3 viewPosition = getViewPosition ( vUv , depth , viewZ ) ;
vec3 viewNormal = getViewNormal ( vUv ) ;
vec2 noiseScale = vec2 ( resolution . x / 4.0 , resolution . y / 4.0 ) ;
vec3 random = vec3 ( texture2D ( tNoise , vUv * noiseScale ) . r ) ;
// compute matrix used to reorient a kernel vector
vec3 tangent = normalize ( random - viewNormal * dot ( random , viewNormal ) ) ;
vec3 bitangent = cross ( viewNormal , tangent ) ;
mat3 kernelMatrix = mat3 ( tangent , bitangent , viewNormal ) ;
float occlusion = 0.0 ;
for ( int i = 0 ; i < KERNEL _SIZE ; i ++ ) {
vec3 sampleVector = kernelMatrix * kernel [ i ] ; // reorient sample vector in view space
vec3 samplePoint = viewPosition + ( sampleVector * kernelRadius ) ; // calculate sample point
vec4 samplePointNDC = cameraProjectionMatrix * vec4 ( samplePoint , 1.0 ) ; // project point and calculate NDC
samplePointNDC /= samplePointNDC . w ;
vec2 samplePointUv = samplePointNDC . xy * 0.5 + 0.5 ; // compute uv coordinates
float realDepth = getLinearDepth ( samplePointUv ) ; // get linear depth from depth texture
float sampleDepth = viewZToOrthographicDepth ( samplePoint . z , cameraNear , cameraFar ) ; // compute linear depth of the sample view Z value
float delta = sampleDepth - realDepth ;
if ( delta > minDistance && delta < maxDistance ) { // if fragment is before sample point, increase occlusion
occlusion += 1.0 ;
}
}
occlusion = clamp ( occlusion / float ( KERNEL _SIZE ) , 0.0 , 1.0 ) ;
gl _FragColor = vec4 ( vec3 ( 1.0 - occlusion ) , 1.0 ) ;
}
} ` },al={defines:{PERSPECTIVE_CAMERA:1},uniforms:{tDepth:{value:null},cameraNear:{value:null},cameraFar:{value:null}},vertexShader: ` 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 ) ;
} ` },ol={uniforms:{tDiffuse:{value:null},resolution:{value:new he}},vertexShader: ` 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 ;
void main ( ) {
vec2 texelSize = ( 1.0 / resolution ) ;
float result = 0.0 ;
for ( int i = - 2 ; i <= 2 ; i ++ ) {
for ( int j = - 2 ; j <= 2 ; j ++ ) {
vec2 offset = ( vec2 ( float ( i ) , float ( j ) ) ) * texelSize ;
result += texture2D ( tDiffuse , vUv + offset ) . r ;
}
}
gl _FragColor = vec4 ( vec3 ( result / ( 5.0 * 5.0 ) ) , 1.0 ) ;
2026-03-05 17:43:50 +08:00
} ` };class Li extends Ps{constructor(e,t,n=512,i=512,r=32){super(),this.width=n,this.height=i,this.clear=!0,this.needsSwap=!1,this.camera=t,this.scene=e,this.kernelRadius=8,this.kernel=[],this.noiseTexture=null,this.output=0,this.minDistance=.005,this.maxDistance=.1,this._visibilityCache=[],this._generateSampleKernel(r),this._generateRandomKernelRotations();const a=new Fo;a.format=ms,a.type=fs,this.normalRenderTarget=new An(this.width,this.height,{minFilter:Xt,magFilter:Xt,type:dn,depthTexture:a}),this.ssaoRenderTarget=new An(this.width,this.height,{type:dn}),this.blurRenderTarget=this.ssaoRenderTarget.clone(),this.ssaoMaterial=new Lt({defines:Object.assign({},rl.defines),uniforms:Hn.clone(rl.uniforms),vertexShader:rl.vertexShader,fragmentShader:rl.fragmentShader,blending:St}),this.ssaoMaterial.defines.KERNEL_SIZE=r,this.ssaoMaterial.uniforms.tNormal.value=this.normalRenderTarget.texture,this.ssaoMaterial.uniforms.tDepth.value=this.normalRenderTarget.depthTexture,this.ssaoMaterial.uniforms.tNoise.value=this.noiseTexture,this.ssaoMaterial.uniforms.kernel.value=this.kernel,this.ssaoMaterial.uniforms.cameraNear.value=this.camera.near,this.ssaoMaterial.uniforms.cameraFar.value=this.camera.far,this.ssaoMaterial.uniforms.resolution.value.set(this.width,this.height),this.ssaoMaterial.uniforms.cameraProjectionMatrix.value.copy(this.camera.projectionMatrix),this.ssaoMaterial.uniforms.cameraInverseProjectionMatrix.value.copy(this.camera.projectionMatrixInverse),this.normalMaterial=new lf,this.normalMaterial.blending=St,this.blurMaterial=new Lt({defines:Object.assign({},ol.defines),uniforms:Hn.clone(ol.uniforms),vertexShader:ol.vertexShader,fragmentShader:ol.fragmentShader}),this.blurMaterial.uniforms.tDiffuse.value=this.ssaoRenderTarget.texture,this.blurMaterial.uniforms.resolution.value.set(this.width,this.height),this.depthRenderMaterial=new Lt({defines:Object.assign({},al.defines),uniforms:Hn.clone(al.uniforms),vertexShader:al.vertexShader,fragmentShader:al.fragmentShader,blending:St}),this.depthRenderMaterial.uniforms.tDepth.value=this.normalRenderTarget.depthTexture,this.depthRenderMaterial.uniforms.cameraNear.value=this.camera.near,this.depthRenderMaterial.uniforms.cameraFar.value=this.camera.far,this.copyMaterial=new Lt({uniforms:Hn.clone(As.uniforms),vertexShader:As.vertexShader,fragmentShader:As.fragmentShader,transparent:!0,depthTest:!1,depthWrite:!1,blendSrc:Ya,blendDst:us,blendEquation:Cn,blendSrcAlpha:Za,blendDstAlpha:us,blendEquationAlpha:Cn}),this._fsQuad=new el(null),this._originalClearColor=new Fe}dispose(){this.normalRenderTarget.dispose(),this.ssaoRenderTarget.dispose(),this.blurRenderTarget.dispose(),this.normalMaterial.dispose(),this.blurMaterial.dispose(),this.copyMaterial.dispose(),this.depthRenderMaterial.dispose(),this._fsQuad.dispose()}render(e,t,n){switch(this._overrideVisibility(),this._renderOverride(e,this.normalMaterial,this.normalRenderTarget,7829503,1),this._restoreVisibility(),this.ssaoMaterial.uniforms.kernelRadius.value=this.kernelRadius,this.ssaoMaterial.uniforms.minDistance.value=this.minDistance,this.ssaoMaterial.uniforms.maxDistance.value=this.maxDistance,this._renderPass(e,this.ssaoMaterial,this.ssaoRenderTarget),this._renderPass(e,this.blurMaterial,this.blurRenderTarget),this.output){case Li.OUTPUT.SSAO:this.copyMaterial.uniforms.tDiffuse.value=this.ssaoRenderTarget.texture,this.copyMaterial.blending=St,this._renderPass(e,this.copyMaterial,this.renderToScreen?null:n);break;case Li.OUTPUT.Blur:this.copyMaterial.uniforms.tDiffuse.value=this.blurRenderTarget.texture,this.copyMaterial.blending=St,this._renderPass(e,this.copyMaterial,this.renderToScreen?null:n);break;case Li.OUTPUT.Depth:this._renderPass(e,this.depthRenderMaterial,this.renderToScreen?null:n);break;case Li.OUTPUT.Normal:this.copyMaterial.uniforms.tDiffuse.value=this.normalRenderTarget.texture,this.copyMaterial.blending=St,this._renderPass(e,this.copyMaterial,this.renderToScreen?null:n);break;case Li.OUTPUT.Default:this.copyMaterial.uniforms.tDiffuse.value=this.blurRenderTarget.texture,this.copyMaterial.blending=ic,this._render
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-03-05 17:43:50 +08:00
} ` };class J3 extends Ps{constructor(){super(),this.uniforms=Hn.clone(ll.uniforms),this.material=new B1({name:ll.name,uniforms:this.uniforms,vertexShader:ll.vertexShader,fragmentShader:ll.fragmentShader}),this._fsQuad=new el(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)===ct&&(this.material.defines.SRGB_TRANSFER=""),this._toneMapping===Au?this.material.defines.LINEAR_TONE_MAPPING="":this._toneMapping===Pu?this.material.defines.REINHARD_TONE_MAPPING="":this._toneMapping===Ru?this.material.defines.CINEON_TONE_MAPPING="":this._toneMapping===Lu?this.material.defines.ACES_FILMIC_TONE_MAPPING="":this._toneMapping===Du?this.material.defines.AGX_TONE_MAPPING="":this._toneMapping===Nu?this.material.defines.NEUTRAL_TONE_MAPPING="":this._toneMapping===Iu&&(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 Q3={name:"FXAAShader",uniforms:{tDiffuse:{value:null},resolution:{value:new he(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-03-04 16:40:35 +08:00
} ` },e_={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-03-05 17:43:50 +08:00
` };class t_{engine;composer;saturationPass;ssaoPass;gtaoPass;outputPass;fxaaPass;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 tl&&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 An(e,t,{minFilter:Pt,magFilter:Pt,format:vn,samples:4});this.composer=new q3(r,o),this.composer.setPixelRatio(a),this.composer.setSize(e,t);const l=new Z3(n,i);this.composer.addPass(l),this.gtaoPass=new _n(n,i,e,t),this.gtaoPass.output=_n.OUTPUT.Default,this.gtaoPass.blendIntensity=.3,this.gtaoPass.enabled=!1,this.gtaoPass.updateGtaoMaterial&&this.gtaoPass.updateGtaoMaterial({radius:1,distanceExponent:1,thickness:1,scale:1,distanceFallOff:1,screenSpaceRadius:!0}),this.composer.addPass(this.gtaoPass),this.ssaoPass=new Li(n,i,e,t),this.ssaoPass.kernelRadius=8,this.ssaoPass.minDistance=.005,this.ssaoPass.maxDistance=.1,this.ssaoPass.output=Li.OUTPUT.Default,this.ssaoPass.enabled=!1,this.composer.addPass(this.ssaoPass),this.saturationPass=new tl(e_),this.saturationPass.uniforms.saturation.value=1.3,this.saturationPass.uniforms.contrast.value=1.1,this.saturationPass.enabled=!1,this.composer.addPass(this.saturationPass),this.outputPass=new J3,this.outputPass.enabled=!1,this.composer.addPass(this.outputPass),this.fxaaPass=new tl(Q3),this.fxaaPass.material.uniforms.resolution.value.x=1/(e*a),this.fxaaPass.material.uniforms.resolution.value.y=1/(t*a),this.fxaaPass.enabled=!1,this.composer.addPass(this.fxaaPass)}}var cl=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function em(s){return s&&s.__esModule&&Object.prototype.hasOwnProperty.call(s,"default")?s.default:s}function hl(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 tm={exports:{}},nm;function n_(){return nm||(nm=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 d=typeof hl=="function"&&hl;if(!h&&d)return d(c,!0);if(o)return o(c,!0);var p=new Error("Cannot find module '"+c+"'");throw p.code="MODULE_NOT_FOUND",p}var u=i[c]={exports:{}};n[c][0].call(u.exports,function(g){var f=n[c][1][g];return a(f||g)},u,u.exports,t,n,i,r)}return i[c].exports}for(var o=typeof hl=="function"&&hl,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,d,p,u,g,f,x=[],m=0,b=l.length,v=b,y=r.getTypeOf(l)!=="string";m<l.length;)v=b-m,d=y?(c=l[m++],h=m<b?l[m++]:0,m<b?l[m++]:0):(c=l.charCodeAt(m++),h=m<b?l.charCodeAt(m++):0,m<b?l.charCodeAt(m++):0),p=c>>2,u=(3&c)<<4|h>>4,g=1<v?(15&h)<<2|d>>6:64,f=2<v?63&d:64,x.push(o.charAt(p)+o.charAt(u)+o.charAt(g)+o.charAt(f));return x.join("")},i.decode=function(l){var c,h,d,p,u,g,f=0,x=0,m="data:";if(l.substr(0,m.length)===m)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);f<l.length;)c=o.indexOf(l.charAt(f++))<<2|(p=o.indexOf(l.charAt(f++)))>>4,h=(15&p)<<4|(u=o.indexOf(l.charAt(f++)))>>2,d=(3&u)<<6|(g=o.indexOf(l.charAt(f++))),b[x++]=c,u!==64&&(b[x++]=h),g!==64&&(b[x
\ 0 ` ,pe+=r(X,2),pe+=M.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(R.length,2),pe+=r(U.length,2),{fileRecord:d.LOCAL_FILE_HEADER+pe+R+U,dirRecord:d.CENTRAL_FILE_HEADER+r(ue,2)+pe+r(I.length,2)+" \0 \0 \0 \0 "+r( $ ,4)+r(x,4)+R+U+I}}var o=t("../utils"),l=t("../stream/GenericWorker"),c=t("../utf8"),h=t("../crc32"),d=t("../signature");function p(u,g,f,x){l.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=g,this.zipPlatform=f,this.encodeFileName=x,this.streamFiles=u,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}o.inherits(p,l),p.prototype.push=function(u){var g=u.meta.percent||0,f=this.entriesCount,x=this._sources.length;this.accumulate?this.contentBuffer.push(u):(this.bytesWritten+=u.data.length,l.prototype.push.call(this,{data:u.data,meta:{currentFile:this.currentFile,percent:f?(g+100*(f-x-1))/f:100}}))},p.prototype.openedSource=function(u){this.currentSourceOffset=this.bytesWritten,this.currentFile=u.file.name;var g=this.streamFiles&&!u.file.dir;if(g){var f=a(u,g,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:f.fileRecord,meta:{percent:0}})}else this.accumulate=!0},p.prototype.closedSource=function(u){this.accumulate=!1;var g=this.streamFiles&&!u.file.dir,f=a(u,g,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(f.dirRecord),g)this.push({data:(function(x){return d.DATA_DESCRIPTOR+r(x.crc32,4)+r(x.compressedSize,4)+r(x.uncompressedSize,4)})(u),meta:{percent:100}});else for(this.push({data:f.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},p.prototype.flush=function(){for(var u=this.bytesWritten,g=0;g<this.dirRecords.length;g++)this.push({data:this.dirRecords[g],meta:{percent:100}});var f=this.bytesWritten-u,x=(function(m,b,v,y,_){var M=o.transformTo("string",_(y));return d.CENTRAL_DIRECTORY_END+" \0 \0 \0 \0 "+r(m,2)+r(m,2)+r(b,4)+r(v,4)+r(M.length,2)+M})(this.dirRecords.length,f,u,this.zipComment,this.encodeFileName);this.push({data:x,meta:{percent:100}})},p.prototype.prepareNextSource=function(){this.previous=this._sources.shift(),this.openedSource(this.previous.streamInfo),this.isPaused?this.previous.pause():this.previous.resume()},p.prototype.registerPrevious=function(u){this._sources.push(u);var g=this;return u.on("data",function(f){g.processChunk(f)}),u.on("end",function(){g.closedSource(g.previous.streamInfo),g._sources.length?g.prepareNextSource():g.end()}),u.on("error",function(f){g.error(f)}),this},p.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))},p.prototype.error=function(u){var g=this._sources;if(!l.prototype.error.call(this,u))return!1;for(var f=0;f<g.length;f++)try{g[f].error(u)}catch{}return!0},p.prototype.lock=function(){l.prototype.lock.call(this);for(var u=this._sources,g=0;g<u.length;g++)u[g].lock()},n.exports=p},{"../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),d=0;try{o.forEach(function(p,u){d++;var g=(function(b,v){var y=b||v,_=r[y];if(!_)throw new Error(y+" is not a valid compression method !");return _})(u.options.compression,l.compression),f=u.options.compressionOptions||l.compressionOptions||{},x=u.dir,m=u.date;u._compressWorker(g,f).withStreamInfo("file",{name:p,dir:x,date:m,comment:u.comment||"",unixPermissions:u.unixPermissions,dosPermissions:u.dosPermissions}).pipe(h)}),h.entriesCount=d}catch(p){h.error(p)}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]&&rM[t])&&(t==="set-cookie"?e[t]?e[t].push(n):e[t]=[n]:e[t]=e[t]?e[t]+", "+n:n)}),e},wm=Symbol("internals");function La(s){return s&&String(s).trim().toLowerCase()}function gl(s){return s===!1||s==null?s:re.isArray(s)?s.map(gl):String(s)}function oM(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 lM=s=>/^[-_a-zA-Z0-9^ ` | ~ , ! # $ % & ' * + . ] + $ / . test ( s . trim ( ) ) ; function xd ( 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 cM ( s ) { return s . trim ( ) . toLowerCase ( ) . replace ( /([a-z\d])(\w*)/g , ( e , t , n ) => t . toUpperCase ( ) + n ) } function hM ( 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 wn = class { constructor ( s ) { s && this . set ( s ) } set ( s , e , t ) { const n = this ; function i ( a , o , l ) { const c = La ( 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 ] = gl ( 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 ( ) ) && ! lM ( s ) ) r ( aM ( 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 = La ( s ) , s ) { const t = re . findKey ( this , s ) ; if ( t ) { const n = this [ t ] ; if ( ! e ) return n ; if ( e === ! 0 ) return oM ( 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 = La ( s ) , s ) { const t = re . findKey ( this , s ) ; return ! ! ( t && this [ t ] !== void 0 && ( ! e || xd ( this , this [ t ] , t , e ) ) ) } return ! 1 } delete ( s , e ) { const t = this ; let n = ! 1 ; function i ( r ) { if ( r = La ( r ) , r ) { const a = re . findKey ( t , r ) ; a && ( ! e || xd ( 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 || xd ( 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 ] = gl ( n ) , delete e [ i ] ; return } const a = s ? cM ( i ) : String ( i ) . trim ( ) ; a !== i && delete e [ i ] , e [ a ] = gl ( 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[wm]=this[wm]={accessors:{}}).accessors,t=this.prototype;function n(i){const r=La(i);e[r]||(hM(t,i),e[r]=!0)}return re.isArray(s)?s.forEach(n):n(s),this}};wn.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]),re.reduceDescriptors(wn.prototype,({value:s},e)=>{let t=e[0].toUpperCase()+e.slice(1);return{get:()=>s,set(n){this[t]=n}}}),re.freezeMethods(wn);function vd(s,e){const t=this||Ra,n=e||t,i=wn.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 Sm(s){return!!(s&&s.__CANCEL__)}function Br(s,e,t){Ke.call(this,s??"canceled",Ke.ERR_CANCELED,e,t),this.name="CanceledError"}re.inherits(Br,Ke,{__CANCEL__:!0});function Em(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 dM(s){const e=/^([-+ \w ]{1,25})(:? \/ \/ |:)/.exec(s);return e&&e[1]||""}function uM(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,d=0;for(;h!==i;)d+=t[h++],h=h%s;if(i=(i+1)%s,i===r&&(r=(r+1)%s),l-a<e)return;const p=c&&l-c;return p?Math.round(d*1e3/p):void 0}}function pM(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 xl=(s,e,t=3)=>{let n=0;const i=uM(50,250);return pM(r=>{const a=r.loaded,o=r.lengthComputable?r.total:void 0,l=a-n,c=i(l),h=a<=o;n=a;const d={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(d)},t)},Cm=(s,e)=>{const t=s!=null;return[n=>e[0]({lengthComputable:t,total:s,loaded:n}),e[1]]},Tm=s=>(...e)=>re.asap(()=>s(...e)),fM=cn.hasStandardBrowserEnv?((s,e)=>t=>(t=new URL(t,cn.origin),s.protocol===t.protocol&&s.host===t.host&&(e||s.port===t.port)))(new URL(cn.origin),cn.navigator&&/(msie|trident)/i.test(cn.navigator.userAgent)):()=>!0,mM=cn.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 gM(s){return/^([a-z][a-z \d + \- .]*:)? \/ \/ /i.test(s)}function xM(s,e){return e?s.replace(/ \/ ? \/ $ /,"")+"/"+e.replace(/^ \/ +/,""):s}function Am(s,e,t){let n=!gM(e);return s&&(n||t==!1)?xM(s,e):e}const Pm=s=>s instanceof wn?{...s}:s;function Ls(s,e){e=e||{};const t={};function n(c,h,d,p){return re.isPlainObject(c)&&re.isPlainObject(h)?re.merge.call({caseless:p},c,h):re.isPlainObject(h)?re.merge({},h):re.isArray(h)?h.slice():h}function i(c,h,d,p){if(re.isUndefined(h)){if(!re.isUndefined(c))return n(void 0,c,d,p)}else return n(c,h,d,p)}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,d){if(d in e)return n(c,h);if(d 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
2026-03-04 16:40:35 +08:00
` +a.map(Um).join( `
2026-03-05 17:43:50 +08:00
` ):" "+Um(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 Om={getAdapter:AM,adapters:bd};function yd(s){if(s.cancelToken&&s.cancelToken.throwIfRequested(),s.signal&&s.signal.aborted)throw new Br(null,s)}function zm(s){return yd(s),s.headers=wn.from(s.headers),s.data=vd.call(s,s.transformRequest),["post","put","patch"].indexOf(s.method)!==-1&&s.headers.setContentType("application/x-www-form-urlencoded",!1),Om.getAdapter(s.adapter||Ra.adapter,s)(s).then(function(e){return yd(s),e.data=vd.call(s,s.transformResponse,e),e.headers=wn.from(e.headers),e},function(e){return Sm(e)||(yd(s),e&&e.response&&(e.response.data=vd.call(s,s.transformResponse,e.response),e.response.headers=wn.from(e.response.headers))),Promise.reject(e)})}const Fm="1.13.2",bl={};["object","boolean","number","function","string","symbol"].forEach((s,e)=>{bl[s]=function(t){return typeof t===s||"a"+(e<1?"n ":" ")+s}});const Hm={};bl.transitional=function(s,e,t){function n(i,r){return"[Axios v"+Fm+"] 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&&!Hm[r]&&(Hm[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}},bl.spelling=function(s){return(e,t)=>(console.warn( ` $ { t } is likely a misspelling of $ { s } ` ),!0)};function PM(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 yl={assertOptions:PM,validators:bl},ui=yl.validators;let Is=class{constructor(s){this.defaults=s||{},this.interceptors={request:new ym,response:new ym}}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=Ls(this.defaults,e);const{transitional:t,paramsSerializer:n,headers:i}=e;t!==void 0&&yl.assertOptions(t,{silentJSONParsing:ui.transitional(ui.boolean),forcedJSONParsing:ui.transitional(ui.boolean),clarifyTimeoutError:ui.transitional(ui.boolean)},!1),n!=null&&(re.isFunction(n)?e.paramsSerializer={serialize:n}:yl.assertOptions(n,{encode:ui.function,serialize:ui.function},!0)),e.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?e.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:e.allowAbsoluteUrls=!0),yl.assertOptions(e,{baseUrl:ui.spelling("baseURL"),withXsrfToken:ui.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"],u=>{delete i[u]}),e.headers=wn.concat(r,i);const a=[];let o=!0;this.interceptors.request.forEach(function(u){typeof u.runWhen=="function"&&u.runWhen(e)===!1||(o=o&&u.synchronous,a.unshift(u.fulfilled,u.rejected))});const l=[];this.interceptors.response.forEach(function(u){l.push(u.fulfilled,u.rejected)});let c,h=0,d;if(!o){const u=[zm.bind(this),void 0];for(u.unshift(...a),u.push(...l),d=u.length,c=Promise.resolve(e);h<d;)c=c.then(u[h++],u[h++]);return c}d=a.length;let p=e;for(;h<d;){const u=a[h++],g=a[h++];try{p=u(p)}catch(f){g.call(this,f);break}}try{c=zm.call(this,p)}catch(u){return Promise.reject(u)}for(h=0,d=l.length;h<d;)c=c.then(l[h++],l[h++]);return c}getUri(s){s=Ls(this.defaults,s);const e=Am(s.baseURL,s.url,s.allowAbsoluteUrls);return bm(e,s.params,s.paramsSerializer)}};re.forEach(["delete","get","head","options"],function(s){Is.prototype[s]=function(e,t){return this.request(Ls(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(Ls(r||{},{method:s,headers:t?{"Content-Type":"multipart/form-data"}:{},url:n,data:i}))}}Is.prototype[s]=e(),Is.prototype[s+"Form"]=e(!0)});let RM=class gg{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 Br(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 gg(function(t){e=t}),cancel:e}}};function LM(s){return function(e){return s.apply(null,e)}}function IM(s){return re.isObject(s)&&s.isAxiosError===!0}const _d={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 BM(){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(d){h({draco:d})},DracoDecoderModule(s)});break;case"decode":const l=o.buffer,c=o.taskConfig;e.then(h=>{const d=h.draco,p=new d.Decoder;try{const u=t(d,p,new Int8Array(l),c),g=u.attributes.map(f=>f.array.buffer);u.index&&g.push(u.index.array.buffer),self.postMessage({type:"decode",id:o.id,geometry:u},g)}catch(u){console.error(u),self.postMessage({type:"error",id:o.id,error:u.message})}finally{d.destroy(p)}});break}};function t(a,o,l,c){const h=c.attributeIDs,d=c.attributeTypes;let p,u;const g=o.GetEncodedGeometryType(l);if(g===a.TRIANGULAR_MESH)p=new a.Mesh,u=o.DecodeArrayToMesh(l,l.byteLength,p);else if(g===a.POINT_CLOUD)p=new a.PointCloud,u=o.DecodeArrayToPointCloud(l,l.byteLength,p);else throw new Error("THREE.DRACOLoader: Unexpected geometry type.");if(!u.ok()||p.ptr===0)throw new Error("THREE.DRACOLoader: Decoding failed: "+u.error_msg());const f={index:null,attributes:[]};for(const x in h){const m=self[d[x]];let b,v;if(c.useUniqueIDs)v=h[x],b=o.GetAttributeByUniqueId(p,v);else{if(v=o.GetAttributeId(p,a[h[x]]),v===-1)continue;b=o.GetAttribute(p,v)}const y=i(a,o,p,x,m,b);x==="color"&&(y.vertexColorSpace=c.vertexColorSpace),f.attributes.push(y)}return g===a.TRIANGULAR_MESH&&(f.index=n(a,o,p)),a.destroy(p),f}function n(a,o,l){const c=l.num_faces()*3,h=c*4,d=a._malloc(h);o.GetTrianglesUInt32Array(l,h,d);const p=new Uint32Array(a.HEAPF32.buffer,d,c).slice();return a._free(d),{array:p,itemSize:1}}function i(a,o,l,c,h,d){const p=l.num_points(),u=d.num_components(),g=r(a,h),f=u*h.BYTES_PER_ELEMENT,x=Math.ceil(f/4)*4,m=x/h.BYTES_PER_ELEMENT,b=p*f,v=p*x,y=a._malloc(b);o.GetAttributeDataArrayForAllPoints(l,d,g,b,y);const _=new h(a.HEAPF32.buffer,y,b/h.BYTES_PER_ELEMENT);let M;if(f===x)M=_.slice();else{M=new h(v/h.BYTES_PER_ELEMENT);let T=0;for(let R=0,w=_.length;R<w;R++){for(let E=0;E<u;E++)M[T+E]=_[R*u+E];T+=m}}return a._free(y),{name:c,count:p,itemSize:u,array:M,stride:m}}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 ts=(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))(ts||{});function kM(s,e,t,n){let i=0,r=0,a=0,o=s.models.find(u=>u.url==t),l=e.circularMeps,c=e.rectMeps.filter(u=>u.type==="风管"),h=e.rectMeps.filter(u=>u.type==="桥架"),d=e.ellipseMep
` ))&&_<m&&v<x.byteLength;)M+=T,_+=T.length,v+=128,T+=String.fromCharCode.apply(null,new Uint16Array(x.subarray(v,v+128)));return-1<y?(x.pos+=_+y+1,M+T.slice(0,y)):!1},i=function(x){const m=/^# \? ( \S +)/,b=/^ \s *GAMMA \s *= \s *( \d +( \. \d +)?) \s * $ /,v=/^ \s *EXPOSURE \s *= \s *( \d +( \. \d +)?) \s * $ /,y=/^ \s *FORMAT=( \S +) \s * $ /,_=/^ \s * \- Y \s +( \d +) \s + \+ X \s +( \d +) \s * $ /,M={valid:0,string:"",comments:"",programtype:"RGBE",format:"",gamma:1,exposure:1,width:0,height:0};let T,R;for((x.pos>=x.byteLength||!(T=n(x)))&&t(1,"no header found"),(R=T.match(m))||t(3,"bad initial token"),M.valid|=1,M.programtype=R[1],M.string+=T+ `
` ;T=n(x),T!==!1;){if(M.string+=T+ `
` ,T.charAt(0)==="#"){M.comments+=T+ `
` ;continue}if((R=T.match(b))&&(M.gamma=parseFloat(R[1])),(R=T.match(v))&&(M.exposure=parseFloat(R[1])),(R=T.match(y))&&(M.valid|=2,M.format=R[1]),(R=T.match(_))&&(M.valid|=4,M.height=parseInt(R[1],10),M.width=parseInt(R[2],10)),M.valid&2&&M.valid&4)break}return M.valid&2||t(3,"missing format specifier"),M.valid&4||t(3,"missing image size specifier"),M},r=function(x,m,b){const v=m;if(v<8||v>32767||x[0]!==2||x[1]!==2||x[2]&128)return new Uint8Array(x);v!==(x[2]<<8|x[3])&&t(3,"wrong scanline width");const y=new Uint8Array(4*m*b);y.length||t(4,"unable to allocate buffer space");let _=0,M=0;const T=4*v,R=new Uint8Array(4),w=new Uint8Array(T);let E=b;for(;E>0&&M<x.byteLength;){M+4>x.byteLength&&t(1),R[0]=x[M++],R[1]=x[M++],R[2]=x[M++],R[3]=x[M++],(R[0]!=2||R[1]!=2||(R[2]<<8|R[3])!=v)&&t(3,"bad rgbe scanline format");let I=0,A;for(;I<T&&M<x.byteLength;){A=x[M++];const S=A>128;if(S&&(A-=128),(A===0||I+A>T)&&t(3,"bad scanline data"),S){const U=x[M++];for(let H=0;H<A;H++)w[I++]=U}else w.set(x.subarray(M,M+A),I),I+=A,M+=A}const B=v;for(let S=0;S<B;S++){let U=0;y[_]=w[S+U],U+=v,y[_+1]=w[S+U],U+=v,y[_+2]=w[S+U],U+=v,y[_+3]=w[S+U],_+=4}E--}return y},a=function(x,m,b,v){const y=x[m+3],_=Math.pow(2,y-128)/255;b[v+0]=x[m+0]*_,b[v+1]=x[m+1]*_,b[v+2]=x[m+2]*_,b[v+3]=1},o=function(x,m,b,v){const y=x[m+3],_=Math.pow(2,y-128)/255;b[v+0]=vo.toHalfFloat(Math.min(x[m+0]*_,65504)),b[v+1]=vo.toHalfFloat(Math.min(x[m+1]*_,65504)),b[v+2]=vo.toHalfFloat(Math.min(x[m+2]*_,65504)),b[v+3]=vo.toHalfFloat(1)},l=new Uint8Array(e);l.pos=0;const c=i(l),h=c.width,d=c.height,p=r(l.subarray(l.pos),h,d);let u,g,f;switch(this.type){case hn:f=p.length/4;const x=new Float32Array(f*4);for(let b=0;b<f;b++)a(p,b*4,x,b*4);u=x,g=hn;break;case dn:f=p.length/4;const m=new Uint16Array(f*4);for(let b=0;b<f;b++)o(p,b*4,m,b*4);u=m,g=dn;break;default:throw new Error("THREE.HDRLoader: Unsupported type: "+this.type)}return{width:h,height:d,data:u,header:c.string,gamma:c.gamma,exposure:c.exposure,type:g}}setDataType(e){return this.type=e,this}load(e,t,n,i){function r(a,o){switch(a.type){case hn:case dn:a.colorSpace=en,a.minFilter=Pt,a.magFilter=Pt,a.generateMipmaps=!1,a.flipY=!0;break}t&&t(a,o)}return super.load(e,r,n,i)}}function Hw(){return new wp}function Vw(s,e){s.appendChild(e.domElement)}function Gw(s,e,t){var n=new Object;n.visible=!0;let i=null,r,a,o=[];n.init=function(){r||(c(),h(),d())},n.Hide=function(){r.style.display="none",n.visible=!1},n.Show=function(){r.style.display="block",n.visible=!0},n.RenderScene=function(){n.camera.quaternion.copy(e.camera.quaternion);const g=new P(0,0,1).applyQuaternion(e.camera.quaternion);n.camera.position.copy(g.multiplyScalar(100)),n.sceneOrtho.renderer.render(n.sceneOrtho,n.camera)},n.ToggleDirectionView=function(g){var f=new P(0,0,0);g=="top"?f=new P(0,1,1e-5):g=="down"?f=new P(0,-1,1e-5):g=="front"?f=new P(0,0,1):g=="left"?f=new P(-1,0,0):g=="back"?f=new P(0,0,-1):g=="right"?f=new P(1,0,0):g=="top_front"?f=new P(1,1,0):g=="top_left"?f=new P(0,1,-1):g=="top_back"?f=new P(-1,1,0):g=="top_right"?f=new P(0,1,1):g=="down_front"?f=new P(1,-1,0):g=="down_left"?f=new P(0,-1,-1):g=="down_back"?f=new P(-1,-1,0):g=="down_right"?f=new P(0,-1,1):g=="front_right"?f=new P(1,0,1):g=="right_back"?f=new P(-1,0,1):g=="back_left"?f=new P(-1,0,-1):g=="left_front"?f=new P(1,0,-1):g=="top_left_front"?f=new P(1,1,-1):g=="top_front_right"?f=new P(1,1,1):g=="top_right_back"?f=new P(-1,1,1):g=="top_back_left"?f=new P(-1,1,-1):g=="button_left_front"?f=new P(1,-1,-1):g=="button_front_right"?f=new P(1,-1,1):g=="button_right_back"?f=new P(-1,1,1):g=="button_back_left"&&(f=new P(-1,-1,-1));var x=s.octreeBox.getBoundingBox(),m=x.min,b=x.max,v=m.clone().add(b.clone()).multiplyScalar(.5),y=v.clone().add(f.multiplyScalar(1*b.distanceTo(m)));l(e.camera.position,y,s.controls.target.clone(),v)},n.GetCameraPose=function(){var g=e.camera.quaternion,f=e.camera.position,x=s.controls.target,m={quaternion:g,position:f,target:x};return m},n.ReductionCameraPose=function(g,f=1e3,x){var m=new zn(g.quaternion._x,g.quaternion._y,g.quaternion._z,g.quaternion._w),b=new P(g.position.
2026-01-28 12:00:55 +08:00
1. 网络连接
2. API地址是否正确
2026-03-05 17:43:50 +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 d=l.split( `
` );l=d.pop()||"";for(const p of d){const u=p.trim();if(!u||!u.startsWith("data: "))continue;const g=u.slice(6);if(g!=="[DONE]")try{const f=JSON.parse(g).choices?.[0]?.delta?.content;f&&t(f,!1)}catch(f){console.warn("解析流式数据失败:",f)}}}}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 iC{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 nC(i.llmConfig);try{const r=await Promise.resolve().then(()=>dT);this.prompts.main=r.default;const a=await Promise.resolve().then(()=>uT);this.prompts.step=a.default;const o=await Promise.resolve().then(()=>pT);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-03-04 16:40:35 +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-03-04 16:40:35 +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-03-05 17:43:50 +08:00
4 ) 代码需要能在浏览器环境运行 ( 不要使用 Node 专属 API ) ` },h=await this.llmApi.chat([a,o,c]);try{return this.extractCodeFromResponse(h)}catch(d){throw new Error( ` 无法从大模型响应中提取代码 ( 修复重试阶段 ) : $ { d . 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-03-05 17:43:50 +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 sC{engine;points=[];isPlaying=!1;animationFrameId=null;playStartTime=0;playFromIndex=0;playToIndex=0;playOptions={};stayTimerId=null;playRangeToIndex=0;constructor(e){this.engine=e}init(){this.points=[],this.stop()}getCurrentPoint(){return{...this.engine.cameraModule.getCameraPose(),stayTime:0}}addPoint(e=0){const t=this.getCurrentPoint();return t.stayTime=e,this.points.push(t),this.points.length}addPoints(e){for(const t of e)this.points.push({...t});return this.points.length}savePoints(e){return this.addPoints(e)}removePoint(e){return e>=0&&e<this.points.length?(this.points.splice(e,1),!0):!1}clearPoints(){this.stop(),this.points=[]}getPoints(){return[...this.points]}getPointCount(){return this.points.length}updatePoint(e,t){return e>=0&&e<this.points.length?(this.points[e]={...t},!0):!1}jumpToPoint(e){return e>=0&&e<this.points.length?(this.stop(),this.engine.cameraModule.restoreCameraPose(this.points[e]),!0):!1}play(e={}){return this.points.length<2?(console.warn("PathRoaming: 至少需要2个点位才能播放"),!1):(this.isPlaying&&this.stop(),this.isPlaying=!0,this.playOptions={duration:3e3,loop:!1,...e},this.engine.controlModule.disActive(),this.playFromIndex=0,this.playToIndex=1,this.playRangeToIndex=this.points.length-1,this.playStartTime=performance.now(),this.animate(),!0)}playRange(e,t,n={}){return e<0||t>=this.points.length||e>=t?(console.warn("PathRoaming: 无效的索引范围"),!1):this.points.length<2?(console.warn("PathRoaming: 至少需要2个点位才能播放"),!1):(this.isPlaying&&this.stop(),this.isPlaying=!0,this.playOptions={duration:3e3,loop:!1,...n},this.engine.controlModule.disActive(),this.playFromIndex=e,this.playToIndex=e+1,this.playStartTime=performance.now(),this.playRangeToIndex=t,this.animate(),!0)}stop(){this.isPlaying=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.stayTimerId!==null&&(clearTimeout(this.stayTimerId),this.stayTimerId=null),this.engine.controlModule.active()}pause(){this.isPlaying&&(this.isPlaying=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.stayTimerId!==null&&(clearTimeout(this.stayTimerId),this.stayTimerId=null))}getIsPlaying(){return this.isPlaying}animate=()=>{if(!this.isPlaying)return;const e=performance.now()-this.playStartTime,t=this.playOptions.duration||3e3,n=Math.min(e/t,1),i=this.points[this.playFromIndex],r=this.points[this.playToIndex],a=this.interpolatePose(i,r,n);this.engine.cameraModule.restoreCameraPose(a),n>=1?this.onSegmentComplete():this.animationFrameId=requestAnimationFrame(this.animate)};onSegmentComplete(){const e=this.playToIndex;this.playOptions.onPointComplete&&this.playOptions.onPointComplete(e);const t=this.points[e];t.stayTime&&t.stayTime>0?this.stayTimerId=globalThis.setTimeout(()=>{this.stayTimerId=null,this.moveToNextSegment()},t.stayTime):this.moveToNextSegment()}moveToNextSegment(){const e=this.playToIndex>=this.playRangeToIndex,t=this.playToIndex>=this.points.length-1;e||t?this.playOptions.loop&&this.points.length>=2?(this.playFromIndex=0,this.playToIndex=1,this.playRangeToIndex=this.points.length-1,this.playStartTime=performance.now(),this.animate()):this.onPlayComplete():(this.playFromIndex=this.playToIndex,this.playToIndex=this.playToIndex+1,this.playStartTime=performance.now(),this.animate())}onPlayComplete(){this.stop(),this.playOptions.onComplete&&this.playOptions.onComplete()}interpolatePose(e,t,n){const i=this.easeInOutCubic(n),r={type:t.type,position:{x:zt.lerp(e.position.x,t.position.x,i),y:zt.lerp(e.position.y,t.position.y,i),
2026-03-04 16:40:35 +08:00
uniform float uTime ;
uniform float uWaveHeight ;
uniform float uWaveSpeed ;
varying vec2 vUv ;
varying vec3 vWorldPos ;
varying vec3 vNormal ;
void main ( ) {
vUv = uv ;
vec3 pos = position ;
float t = uTime * uWaveSpeed ;
// 多层叠加正弦波,模拟真实水面涟漪
float w1 = sin ( pos . x * 0.80 + t * 1.20 ) * uWaveHeight ;
float w2 = sin ( pos . z * 0.60 + t * 0.90 ) * uWaveHeight * 1.10 ;
float w3 = sin ( ( pos . x + pos . z ) * 0.50 + t * 1.50 ) * uWaveHeight * 0.60 ;
float w4 = sin ( pos . x * 1.40 - pos . z * 0.90 + t * 0.70 ) * uWaveHeight * 0.40 ;
pos . y += w1 + w2 + w3 + w4 ;
// 由波形偏导数近似计算法线
float dx = ( cos ( pos . x * 0.80 + t * 1.20 ) * 0.80
+ cos ( ( pos . x + pos . z ) * 0.50 + t * 1.50 ) * 0.50
+ cos ( pos . x * 1.40 - pos . z * 0.90 + t * 0.70 ) * 1.40 ) * uWaveHeight ;
float dz = ( cos ( pos . z * 0.60 + t * 0.90 ) * 0.60
+ cos ( ( pos . x + pos . z ) * 0.50 + t * 1.50 ) * 0.50
- cos ( pos . x * 1.40 - pos . z * 0.90 + t * 0.70 ) * 0.90 ) * uWaveHeight ;
vNormal = normalize ( normalMatrix * vec3 ( - dx , 1.0 , - dz ) ) ;
vec4 worldPos = modelMatrix * vec4 ( pos , 1.0 ) ;
vWorldPos = worldPos . xyz ;
gl _Position = projectionMatrix * modelViewMatrix * vec4 ( pos , 1.0 ) ;
}
2026-03-05 11:15:57 +08:00
` ,fC= `
2026-03-04 16:40:35 +08:00
uniform float uTime ;
uniform vec3 uWaterColor ;
uniform vec3 uDeepColor ;
uniform vec3 uSunColor ;
uniform vec3 uSunDir ;
uniform float uOpacity ;
varying vec2 vUv ;
varying vec3 vWorldPos ;
varying vec3 vNormal ;
void main ( ) {
vec3 N = normalize ( vNormal ) ;
vec3 V = normalize ( cameraPosition - vWorldPos ) ;
vec3 L = normalize ( uSunDir ) ;
// 高频细节法线扰动(模拟毛细波)
float rx = sin ( vUv . x * 55.0 + uTime * 3.2 ) * 0.012
+ sin ( vUv . x * 30.0 - uTime * 1.8 ) * 0.008 ;
float ry = sin ( vUv . y * 50.0 + uTime * 2.8 ) * 0.012
+ sin ( vUv . y * 25.0 - uTime * 2.2 ) * 0.008 ;
N = normalize ( N + vec3 ( rx , 0.0 , ry ) ) ;
// Fresnel( Schlick 近似):掠射角反射更强
float NdotV = clamp ( dot ( N , V ) , 0.0 , 1.0 ) ;
float fresnel = 0.02 + 0.98 * pow ( 1.0 - NdotV , 5.0 ) ;
// 漫反射
float diff = max ( dot ( N , L ) , 0.0 ) ;
// 高光( Blinn-Phong)
vec3 H = normalize ( L + V ) ;
float spec = pow ( max ( dot ( N , H ) , 0.0 ) , 160.0 ) ;
// 深浅水色混合
float depthFac = clamp ( ( N . y - 0.90 ) * 10.0 , 0.0 , 1.0 ) ;
vec3 baseCol = mix ( uDeepColor , uWaterColor , depthFac ) ;
vec3 color = baseCol * ( 0.30 + diff * 0.60 )
+ uSunColor * spec * 1.0
+ vec3 ( 0.72 , 0.88 , 1.0 ) * fresnel * 0.28 ; // 天空反射色
gl _FragColor = vec4 ( color , uOpacity ) ;
}
2026-03-05 17:43:50 +08:00
` ;class mC{options;deviceType;animationId=null;isRenderingPaused=!1;controlsEnabledBeforePause=!0;animate;onWindowResize;_fpsFrameCount=0;_fpsLastCheck=0;_fpsLastSwitch=0;_lowFpsCount=0;_highFpsCount=0;_fpsCheckInterval=100;_fpsSwitchCooldown=100;_fpsThreshold=30;_fpsUpgradeThreshold=60;_lowFpsRequired=3;_highFpsRequired=.1;isMouseDown=!1;isWheeling=!1;scene;camera;renderer;sceneModule;cameraModule;deviceModule;renderModule;controlModule;composerModule;loaderModule;engineStatus;events;lightModule;interactionModule;modelToolModule;worldToScreen;handelBehaved;octreeBox;controls;stats;catchSvg;engineModelModule;viewCube;rangeScale;setting;measure;clipping;modelTree;engineInfo;modelProperties;modelMapperBatch;modelEdge;ai;pathRoaming;hoverHighLight;minMap;grid;level;text;hdr;ground;models=[];reactBoundingClientRect={left:0,top:0};version="2.0.6";versionEl=null;container;constructor(e){if(this.options=e,this.container=document.getElementById(e.containerId),!this.container)throw new Error( ` Container $ { e . containerId } not found ` );this.engineModelModule=new Dw(this),this.engineModelModule.init(),this.ai=new iC(this),this.deviceModule=new C3(this),this.deviceType=this.deviceModule.getDeviceType(),this.cameraModule=new E3(this),this.sceneModule=new S3(this),this.scene=this.sceneModule.scene,this.renderModule=new T3(this),this.renderer=this.renderModule.createRenderer(),this.camera=this.cameraModule.orthographicCamera,this.scene.camera=this.camera,this.controlModule=new V3(this),this.controlModule.switchDefaultMode(),this.controls=this.controlModule.orbitControls,this.composerModule=new t_(this),this.composerModule.init(),this.events=new Cw,this.engineStatus=new Ew(this),this.engineStatus.init(),this.loaderModule=new Sw(this),this.lightModule=new Tw(this),this.lightModule.init(),this.viewCube=new Ww(this),this.viewCube.init(),this.options.showViewCube==!1&&this.viewCube.hide(),this.octreeBox=Xw(this),this.rangeScale=new jw(this),this.rangeScale.init(),this.clipping=new $ E(this),this.clipping.init(),this.setting=new qw(this),this.setting.init(),this.engineModelModule.init(),this.handelBehaved=cd(this),this.modelMapperBatch=new eC(this),this.measure=new nS(this),this.modelToolModule=new Pw(this),this.modelProperties=new QE(this),this.interactionModule=new Aw(this),this.interactionModule.init(),this.interactionModule.active(),this.hoverHighLight=new wl(this),this.modelEdge=new tC(this),this.modelTree=new KE(this),this.engineInfo=new JE(this),this.pathRoaming=new sC(this),this.pathRoaming.init(),this.minMap=new rC(this),this.grid=new oC(this),this.level=new cC(this),this.text=new hC(this),this.hdr=new dC(this),this.ground=new uC(this),this.ground.init(),this.worldToScreen=new yn(this.camera,this.renderer,this.scene),this.options.showStats&&(this.stats=new Uw,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.createElement("div");t.className="versionText",this.versionEl=t,this.updateVersionDisplay(),this.container.appendChild(t);let n=document.createElementNS("http://www.w3.org/2000/svg","svg");n.style.position="absolute",n.style.zIndex="1000",n.style.left="0px",n.style.top="0px",n.style.pointerEvents="none",this.container.appendChild(n),this.catchSvg=n,this.onWindowResize=()=>{this.handleWindowResize()},window.addEventListener("resize",this.onWindowResize);let i=this;this.controls.addEventListener("start",()=>{i.events.trigger(ts.EngineBusy)}),this.controls.addEventListener("end",()=>{i.events.trigger(ts.EngineFree)}),this.controls.addEventListener("change",()=>{}),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.ground.update(),this.hoverHighLight.update(),this.controlModule.update(),this.minMap.update(),this.grid.updat
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-03-05 17:43:50 +08:00
` ;for(let g=0;g<sg.length;g++){const f=sg[g],x=Xa[f],m=document.createElement("button");m.type="button",m.className="bim-measure-tool-btn",m.dataset.mode=f;const b=document.createElement("span");b.className="bim-measure-tool-icon",b.innerHTML=x.icon||i,m.appendChild(b),m.addEventListener("click",()=>{this.setActiveMode(f)}),this.toolButtons.set(f,m),n.appendChild(m)}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-03-05 17:43:50 +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),this.modeOptionsEl=this.createModeOptionsDom(),this.mainViewEl.appendChild(this.modeOptionsEl);const o=document.createElement("div");o.className="bim-measure-result";const l=document.createElement("div");l.className="bim-measure-row",this.mainValueRowEl=l;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 d=document.createElement("div");d.className="bim-measure-xyz",this.xyzBoxEl=d;const p=(g,f,x)=>{const m=document.createElement("div");m.className="bim-measure-row";const b=document.createElement("span");b.className="label",b.dataset.i18nKey=g;const v=document.createElement("span");return v.className= ` value $ { f } ` ,x(v),m.appendChild(b),m.appendChild(v),m};d.appendChild(p("measure.labels.x","bim-measure-xyz-x",g=>this.xyzXEl=g)),d.appendChild(p("measure.labels.y","bim-measure-xyz-y",g=>this.xyzYEl=g)),d.appendChild(p("measure.labels.z","bim-measure-xyz-z",g=>this.xyzZEl=g)),o.appendChild(d),this.mainViewEl.appendChild(o);const u=document.createElement("div");return u.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-03-05 17:43:50 +08:00
` ,this.settingsBtn.addEventListener("click",()=>{this.openSettings()}),u.appendChild(this.clearBtn),u.appendChild(this.settingsBtn),this.mainViewEl.appendChild(u),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}createModeOptionsDom(){const e=document.createElement("div");e.className="bim-measure-mode-options";const t=document.createElement("div");t.className="bim-measure-radio-group";const n=document.createElement("span");n.className="bim-measure-radio-label",n.dataset.i18nKey="measure.clearHeight.direction";const i=document.createElement("div");i.className="bim-measure-radio-items";const r=this.createRadioItem("measure.clearHeight.directionDown",()=>{this.setClearHeightDirection(0)}),a=this.createRadioItem("measure.clearHeight.directionUp",()=>{this.setClearHeightDirection(1)});this.directionBtns.set(0,r),this.directionBtns.set(1,a),i.appendChild(r),i.appendChild(a),t.appendChild(n),t.appendChild(i),e.appendChild(t);const o=document.createElement("div");o.className="bim-measure-radio-group";const l=document.createElement("span");l.className="bim-measure-radio-label",l.dataset.i18nKey="measure.clearHeight.selectType";const c=document.createElement("div");c.className="bim-measure-radio-items";const h=this.createRadioItem("measure.clearHeight.selectPoint",()=>{this.setClearHeightSelectType("point")}),d=this.createRadioItem("measure.clearHeight.selectElement",()=>{this.setClearHeightSelectType("element")});return this.selectTypeBtns.set("point",h),this.selectTypeBtns.set("element",d),c.appendChild(h),c.appendChild(d),o.appendChild(l),o.appendChild(c),e.appendChild(o),e}createRadioItem(e,t){const n=document.createElement("button");return n.type="button",n.className="bim-measure-radio-item",n.dataset.i18nKey=e,n.textContent=xe(e),n.addEventListener("click",t)
2026-03-04 16:40:35 +08:00
display : flex ; gap : 0 ; border - radius : 6 px ; overflow : hidden ;
border : 1 px solid $ { jr } ;
` ;const r=[{key:"simple",labelKey:"setting.modes.simple"},{key:"balance",labelKey:"setting.modes.balance"},{key:"advanced",labelKey:"setting.modes.advanced"}];for(let a=0;a<r.length;a++){const o=r[a],l=o.key===e,c=document.createElement("div");c.style.cssText= `
flex : 1 ; text - align : center ; padding : 7 px 0 ; cursor : pointer ;
font - size : 13 px ; font - weight : 500 ; transition : all 0.15 s ;
background : $ { l ? Jl : "transparent" } ;
2026-03-05 17:43:50 +08:00
color : $ { l ? FC : bu } ;
2026-03-04 16:40:35 +08:00
$ { a < r . length - 1 ? ` border-right: 1px solid ${ jr } ; ` : "" }
2026-03-05 17:43:50 +08:00
` ,c.textContent=xe(o.labelKey),c.addEventListener("mouseenter",()=>{l||(c.style.background=HC)}),c.addEventListener("mouseleave",()=>{l||(c.style.background="transparent")}),c.addEventListener("click",()=>{this.engineComponent?.setRenderMode(o.key);const h=document.getElementById(this.dialogId);h&&(this.savedPosition={x:h.offsetLeft,y:h.offsetTop}),this.hide(),this.show()}),i.appendChild(c)}return t.appendChild(i),t}createEdgeLineSection(){return this.createToggleRow(xe("setting.edgeLine"),this.edgeLineEnabled,e=>{this.edgeLineEnabled=e,e?this.engineComponent?.activeModelEdge():this.engineComponent?.disActiveModelEdge()})}createSliderSection(e,t,n,i,r){const a=document.createElement("div");a.style.cssText="margin-bottom: 4px;";const o=document.createElement("div");o.style.cssText=vu+" margin-bottom: 6px;";const l=document.createElement("span");l.style.cssText="font-size: 13px; color: var(--bim-text-secondary, #475569);",l.textContent=e,o.appendChild(l);const c=document.createElement("span");c.style.cssText=zC,c.textContent=String(t),o.appendChild(c),a.appendChild(o);const h=document.createElement("input");return h.type="range",h.min=String(n),h.max=String(i),h.value=String(t),h.className="bim-setting-slider",h.style.cssText= `
2026-03-04 16:40:35 +08:00
width : 100 % ; height : 4 px ; - webkit - appearance : none ; appearance : none ;
background : var ( -- bim - border - strong , # cbd5e1 ) ; border - radius : 2 px ;
outline : none ; cursor : pointer ;
2026-03-05 17:43:50 +08:00
` ,h.addEventListener("input",()=>{const d=Number(h.value);c.textContent=String(d),r(d)}),a.appendChild(h),a}ensureSliderStyle(){if(document.querySelector("#bim-setting-slider-style"))return;const e=document.createElement("style");e.id="bim-setting-slider-style",e.textContent= `
2026-03-04 16:40:35 +08:00
. bim - setting - slider : : - webkit - slider - thumb {
- webkit - appearance : none ; appearance : none ;
width : 16 px ; height : 16 px ; border - radius : 50 % ;
background : var ( -- bim - primary , # 3 b82f6 ) ;
cursor : pointer ;
border : 2 px solid var ( -- bim - bg - elevated , # fff ) ;
box - shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.2 ) ;
}
. bim - setting - slider : : - moz - range - thumb {
width : 16 px ; height : 16 px ; border - radius : 50 % ;
background : var ( -- bim - primary , # 3 b82f6 ) ;
cursor : pointer ;
border : 2 px solid var ( -- bim - bg - elevated , # fff ) ;
box - shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.2 ) ;
}
. bim - setting - slider : : - moz - range - track {
background : var ( -- bim - border - strong , # cbd5e1 ) ;
height : 4 px ; border - radius : 2 px ; border : none ;
}
2026-03-05 17:43:50 +08:00
` ,document.head.appendChild(e)}createEnvironmentSection(){const e=document.createElement("div"),t=document.createElement("div");t.style.cssText=xu,t.textContent=xe("setting.environment"),e.appendChild(t);const n=this.createSelect(this.environmentList.map(r=>({value:r.id,label:r.name})),this.environmentId,r=>{this.environmentId=r,this.engineComponent?.setHDRBackgroundId(r)});e.appendChild(n);const i=this.createToggleRow(xe("setting.backgroundVisible"),this.backgroundVisible,r=>{this.backgroundVisible=r,this.engineComponent?.setHDRBackgroundVisibility(r)});return i.style.marginTop="10px",e.appendChild(i),e}createGroundSection(){const e=document.createElement("div"),t=document.createElement("div");t.style.cssText=xu,t.textContent=xe("setting.ground"),e.appendChild(t);const n=this.createSelect(this.groundList.map(c=>({value:c.id,label:c.name})),this.groundId,c=>{this.groundId=c,this.engineComponent?.setGroundId(c)});e.appendChild(n);const i=document.createElement("div");i.style.cssText=vu+" margin-top: 10px;";const r=document.createElement("span");r.style.cssText="font-size: 13px; color: var(--bim-text-secondary, #475569);",r.textContent=xe("setting.groundElevation"),i.appendChild(r);const a=document.createElement("div");a.style.cssText="display: flex; align-items: center; gap: 4px;";const o=document.createElement("input");o.type="number",o.value=String(this.groundElevation),o.style.cssText= `
2026-03-05 11:15:57 +08:00
width : 72 px ; padding : 4 px 8 px ; border - radius : 4 px ;
2026-03-04 16:40:35 +08:00
border : 1 px solid $ { jr } ;
background : $ { og } ;
2026-03-05 17:43:50 +08:00
color : $ { bu } ;
2026-03-04 16:40:35 +08:00
font - size : 13 px ; outline : none ; text - align : right ;
2026-03-05 11:15:57 +08:00
` ,o.addEventListener("input",()=>{const c=Number(o.value);isNaN(c)||(this.groundElevation=c,this.engineComponent?.setGroundElevation(c))}),o.addEventListener("focus",()=>{o.style.borderColor=Jl}),o.addEventListener("blur",()=>{o.style.borderColor=jr});const l=document.createElement("span");return l.style.cssText="font-size: 13px; color: var(--bim-text-secondary, #475569);",l.textContent=xe("setting.groundElevationUnit"),a.appendChild(o),a.appendChild(l),i.appendChild(a),e.appendChild(i),e}createSelect(e,t,n){const i=document.createElement("select");i.style.cssText= `
2026-03-04 16:40:35 +08:00
width : 100 % ; padding : 7 px 10 px ; border - radius : 6 px ;
border : 1 px solid $ { jr } ;
background : $ { og } ;
2026-03-05 17:43:50 +08:00
color : $ { bu } ;
2026-03-04 16:40:35 +08:00
font - size : 13 px ; outline : none ; cursor : pointer ;
- webkit - appearance : none ; appearance : none ;
background - image : url ( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E" ) ;
background - repeat : no - repeat ;
background - position : right 10 px center ;
padding - right : 28 px ;
` ;for(const r of e){const a=document.createElement("option");a.value=r.value,a.textContent=r.label,a.style.cssText= `
background : var ( -- bim - bg - elevated , # ffffff ) ;
color : var ( -- bim - text - primary , # 0 f172a ) ;
2026-03-05 17:43:50 +08:00
` ,r.value===t&&(a.selected=!0),i.appendChild(a)}return i.addEventListener("change",()=>{n(i.value)}),i.addEventListener("focus",()=>{i.style.borderColor=Jl}),i.addEventListener("blur",()=>{i.style.borderColor=jr}),i}createToggleRow(e,t,n){const i=document.createElement("div");i.style.cssText=vu;const r=document.createElement("span");r.style.cssText="font-size: 13px; color: var(--bim-text-secondary, #475569);",r.textContent=e,i.appendChild(r);const a="var(--bim-border-strong, #cbd5e1)",o=Jl;let l=t;const c=document.createElement("div");c.style.cssText= `
2026-03-05 11:15:57 +08:00
width : 40 px ; height : 22 px ; border - radius : 11 px ; cursor : pointer ;
position : relative ; transition : background 0.2 s ;
background : $ { l ? o : a } ;
` ;const h=document.createElement("div");return h.style.cssText= `
width : 18 px ; height : 18 px ; border - radius : 50 % ;
background : # fff ; position : absolute ; top : 2 px ;
transition : left 0.2 s ;
box - shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.2 ) ;
left : $ { l ? "20px" : "2px" } ;
` ,c.appendChild(h),c.addEventListener("click",()=>{l=!l,c.style.background=l?o:a,h.style.left=l?"20px":"2px",n(l)}),i.appendChild(c),i}}class GC{element;headerEl;contentEl;contentBoxEl;arrowEl;titleEl;config;parent;constructor(e,t){this.config=e,this.parent=t,this.element=this.createDom()}createDom(){const e=document.createElement("div");if(e.className= ` bim - collapse - item $ { this . config . className || "" } ` ,this.config.disabled&&e.classList.add("is-disabled"),e.dataset.id=this.config.id,this.headerEl=document.createElement("div"),this.headerEl.className="bim-collapse-header",this.arrowEl=document.createElement("span"),this.arrowEl.className="bim-collapse-arrow",this.arrowEl.innerHTML='<svg viewBox="0 0 1024 1024"><path d="M288 192l448 320-448 320z"></path></svg>',this.headerEl.appendChild(this.arrowEl),this.config.icon){const t=document.createElement("span");t.className="bim-collapse-icon",t.innerHTML=this.config.icon,this.headerEl.appendChild(t)}if(this.titleEl=document.createElement("span"),this.titleEl.className="bim-collapse-title",this.titleEl.textContent=xe(this.config.title),this.headerEl.appendChild(this.titleEl),this.config.extra){const t=document.createElement("div");t.className="bim-collapse-extra",typeof this.config.extra=="string"?t.innerHTML=this.config.extra:t.appendChild(this.config.extra),this.headerEl.appendChild(t)}return this.headerEl.addEventListener("click",()=>{this.config.disabled||this.parent.toggleItem(this.config.id)}),e.appendChild(this.headerEl),this.contentEl=document.createElement("div"),this.contentEl.className="bim-collapse-content is-hidden",this.contentBoxEl=document.createElement("div"),this.contentBoxEl.className="bim-collapse-content-box",typeof this.config.content=="string"?this.contentBoxEl.innerHTML=this.config.content:this.contentBoxEl.appendChild(this.config.content),this.contentEl.appendChild(this.contentBoxEl),e.appendChild(this.contentEl),e}updateLocale(){this.titleEl&&(this.titleEl.textContent=xe(this.config.title))}setActive(e){e?(this.element.classList.add("is-active"),this.contentEl.classList.remove("is-hidden")):(this.element.classList.remove("is-active"),this.contentEl.classList.add("is-hidden"))}}class lg{element;options;items=new Map;activeIds=new Set;unsubscribeLocale=null;unsubscribeTheme=null;constructor(e){this.options={bordered:!0,accordion:!1,...e},this.element=document.createElement("div"),this.element.className= ` bim - collapse $ { this . options . className || "" } ` ,this.options.bordered||(this.element.style.border="none"),this.options.ghost&&this.element.classList.add("is-ghost");const t=typeof this.options.container=="string"?document.getElementById(this.options.container):this.options.container;t&&t.appendChild(this.element),this.options.activeIds&&this.options.activeIds.forEach(n=>this.activeIds.add(n)),this.init()}init(){this.options.items.forEach(e=>{const t=new GC(e,this);this.items.set(e.id,t),this.element.appendChild(t.element),this.activeIds.has(e.id)&&t.setActive(!0)}),this.unsubscribeLocale=Qt.subscribe(()=>{this.setLocales()}),this.unsubscribeTheme=ot.subscribe(e=>{this.setTheme(e)}),this.setTheme(ot.getTheme())}toggleItem(e){const t=this.activeIds.has(e);this.options.accordion?(this.activeIds.clear(),t||this.activeIds.add(e)):t?this.activeIds.delete(e):this.activeIds.add(e),this.refreshState(),this.options.onChange&&this.options.onChange(Array.from(this.activeIds))}refreshState(){this.items.forEach((e,t)=>{e.setActive(this.activeIds.has(t))})}setTheme(e){const t=this.element.style;t.setProperty("--bim-bg-elevated",e.bgElevated),t.setProperty("--bim-border-default",e.borderDefault),t.setProperty("--bim-border-subtle",e.borderSubtle),t.setProperty("--bim-border-strong",e.borderStrong),t.setProperty("--bim-text-primary",e.textPrimary),t.setProperty("--bim-text-disabled",e.textDisabled),t.setProperty("--bim-component-bg",e.componentBg),t.setProperty("--bim-component-bg-hover",e.componentBgHover),t.setProperty("--bim-component-bg-active",e.componentBgActive)}setLocales(){this.items.forEach(e=>e.updateLocale())}destroy(){this.unsubscribeLocale&&(this.unsubscrib
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-03-04 16:40:35 +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 lg({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-03-04 16:40:35 +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-03-04 16:40:35 +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-03-05 11:15:57 +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 XC{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=ot.subscribe(e=>{this.setTheme(e)}),this.unsubscribeLocale=Qt.subscribe(()=>{this.setLocales()}),this.setTheme(ot.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=xe(this.options.title));const t=this.element.querySelector(".bim-ai-textarea");t&&this.options.placeholder&&(t.placeholder=xe(this.options.placeholder));const n=this.element.querySelector(".bim-ai-helper-left");n&&(n.textContent=xe("aiChat.helper.newline"));const i=this.element.querySelector(".bim-ai-helper-right");i&&(i.textContent=xe("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-28 11:26:59 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "new" title = "${xe(" aiChat . action . new ")}" >
2026-03-05 17:43:50 +08:00
$ { rt ( "plus" ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
2026-02-28 11:26:59 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "history" title = "${xe(" aiChat . action . history ")}" >
2026-03-05 17:43:50 +08:00
$ { rt ( "history" ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
2026-02-28 11:26:59 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "settings" title = "${xe(" aiChat . action . settings ")}" >
2026-03-05 17:43:50 +08:00
$ { rt ( "settings" ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
2026-02-28 11:26:59 +08:00
< button class = "bim-ai-chat-action-btn" data - action = "close" title = "${xe(" aiChat . action . close ")}" >
2026-03-05 17:43:50 +08:00
$ { rt ( "close" ) }
2026-02-02 16:36:17 +08:00
< / 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" >
2026-03-05 17:43:50 +08:00
$ { rt ( "arrowUpBold" ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
< / d i v >
< / d i v >
2026-03-05 17:43:50 +08:00
` ,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=u=>{u.target.closest(".bim-ai-chat-action-btn")||(u.preventDefault(),u.stopPropagation(),t=u.clientX,n=u.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",d,{capture:!0}),document.addEventListener("mouseup",p,{capture:!0}))},d=u=>{u.preventDefault(),u.stopPropagation(),!this.rafId&&(this.rafId=requestAnimationFrame(()=>{const g=u.clientX-t,f=u.clientY-n;let x=i+g,m=r+f;const b=a-l,v=o-c;x=Math.max(0,Math.min(x,b)),m=Math.max(0,Math.min(m,v)),this.element.style.left= ` $ { x } px ` ,this.element.style.top= ` $ { m } px ` ,this.rafId=null}))},p=()=>{this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null),document.removeEventListener("mousemove",d,{capture:!0}),document.removeEventListener("mouseup",p,{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=> `
2026-02-02 16:36:17 +08:00
< button class = "bim-ai-quick-prompt" data - prompt - id = "${i.id}" >
2026-02-28 11:26:59 +08:00
$ { xe ( i . label ) }
2026-02-02 16:36:17 +08:00
< / b u t t o n >
2026-03-04 16:40:35 +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=xe(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}" >
2026-03-05 17:43:50 +08:00
< span class = "bim-ai-step-icon" > $ { rt ( { running : "loader" , done : "check" , error : "error" } [ e ] ) } < / s p a n >
2026-02-02 16:36:17 +08:00
< span class = "bim-ai-step-text" > $ { this . escapeHtml ( t ) } < / s p a n >
< / d i v >
` }renderThinkingMessage(){return `
< div class = "bim-ai-thinking" >
2026-03-05 17:43:50 +08:00
< span class = "bim-ai-thinking-icon" > $ { rt ( "loader" ) } < / s p a n >
2026-02-28 11:26:59 +08:00
< span class = "bim-ai-thinking-text" > $ { xe ( "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-28 11:26:59 +08:00
< span class = "bim-ai-option-text" > $ { n . isOther ? xe ( "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-28 11:26:59 +08:00
placeholder = "${xe(" 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" >
2026-03-05 17:43:50 +08:00
< div class = "bim-ai-question-icon" > $ { rt ( "bot" ) } < / d i v >
2026-02-02 16:36:17 +08:00
< 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-28 11:26:59 +08:00
< span > $ { xe ( "aiChat.submit" ) } < / s p a n >
2026-03-05 17:43:50 +08:00
$ { rt ( "send" ) }
2026-02-02 16:36:17 +08:00
< / 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-03-05 17:43:50 +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 jC{aiChat=null;registry;initialized=!1;constructor(e){this.registry=e}init(){if(this.initialized)return;const e=this.registry.wrapper;if(!e){console.warn("[AiChatManager] wrapper 不存在,无法初始化");return}this.aiChat=new XC({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 qC{events=new Map;on(e,t){return this.events.has(e)||this.events.set(e,[]),this.events.get(e).push(t),()=>this.off(e,t)}off(e,t){const n=this.events.get(e);if(!n)return;const i=n.indexOf(t);i!==-1&&n.splice(i,1)}emit(e,t){const n=this.events.get(e);n&&n.forEach(i=>{try{i(t)}catch(r){console.error( ` [ EventEmitter ] Error in listener for event "${e}" : ` ,r)}})}clear(){this.events.clear()}}class ZC{eventEmitter=new qC;container=null;wrapper=null;toolbar=null;dialog=null;engine3d=null;buttonGroup=null;rightKey=null;constructTree=null;mea
\ r
# # 角色定位 \ r
\ r
你是一位资深的 * * AI + BIM轻量化引擎架构专家 * * , 具备以下核心能力 : \ r
\ r
1. * * 深度理解BIM引擎架构 * * : 精通BIM引擎的模块化设计 、 API体系 、 数据结构和交互模式 \ r
2. * * 需求分析能力 * * : 能够准确理解用户意图 , 识别模糊需求 , 提出精准的澄清问题 \ r
3. * * 任务分解能力 * * : 将复杂需求拆解为可执行的 、 原子化的操作步骤 \ r
4. * * 技术决策能力 * * : 根据需求特点选择最优的API组合和实现路径 \ r
\ r
你的职责是通过分析用户需求 , 生成结构化的执行步骤 , 指导代码生成模块完成BIM引擎的功能实现 。 \ r
\ r
# # 工作流程 \ r
\ r
如果存在疑问 , 你就不能输出最终的步骤 , 只有当你把所有的疑问清楚后 , 你才可以输出步骤 , 如果存在疑问 , 你要以bim模型为载体 , 不能问一下和bim模型不想干的问题 , 尽量没有或减少问题 \ r
\ r
# # # 阶段一 : 需求理解与分析 \ r
\ r
当接收到用户需求时 , 你需要 : \ r
\ r
1. * * 深度分析需求 * * : \ r
- 理解用户的核心目标 \ r
- 识别涉及到的BIM引擎模块 ( 场景 、 相机 、 模型 、 测量 、 剖切等 ) \ r
- 分析数据流向和依赖关系 \ r
- 评估需求的复杂度和可行性 \ r
\ r
2. * * 识别模糊点 * * : \ r
- 检查需求中是否存在歧义 、 缺失信息或边界条件不明确的情况 \ r
- 判断是否需要用户澄清才能继续 \ r
\ r
3. * * 决策是否需要提问 * * : \ r
- * * 仅在必要时提问 * * : 如果需求足够清晰 , 直接进入步骤规划阶段 \ r
- * * 避免过度提问 * * : 不要为了提问而提问 , 不要询问可以从上下文推断的信息 \ r
- * * 精准提问 * * : 每个问题都应该针对关键决策点 , 影响后续实现路径 \ r
\ r
# # # 阶段二 : 需求澄清 ( 如需要 ) \ r
\ r
如果需要用户澄清 , 请按照以下格式输出 : \ r
\ r
* * 输出格式 * * : \ r
\ ` \` \` \r
# # question # # \ r
json内容 \ r
\ ` \` \` \r
\ r
* * JSON格式规范 * * : \ r
\ ` \` \` json \r
[ \ r
{ \ r
"id" : 0 , \ r
"question" : "您是否需要设置所有的构件?" , \ r
"answers" : [ \ r
"A. 是的,设置所有构件" , \ r
"B. 只设置1F层的构件" , \ r
"C. 根据特定条件筛选构件" \ r
] \ r
} , \ r
{ \ r
"id" : 1 , \ r
"question" : "颜色设置的优先级是什么?" , \ r
"answers" : [ \ r
"A. 按构件类型设置" , \ r
"B. 按楼层设置" , \ r
"C. 按自定义属性设置" \ r
] \ r
} \ r
] \ r
\ ` \` \` \r
\ r
* * 提问原则 * * : \ r
- 每个问题必须针对一个明确的决策点 \ r
- 答案选项应该互斥且覆盖主要场景 \ r
- 问题数量控制在3个以内 , 优先询问最关键的问题 \ r
- 问题描述清晰 、 具体 , 避免模糊表述 \ r
- 不要强行提问 , 尽量减少或不提问题 \ r
# # # 阶段三 : 步骤规划 \ r
\ r
当需求清晰后 , 你需要将用户意图拆解为一系列可执行的步骤 。 \ r
\ r
* * 输出格式 * * : \ r
\ ` \` \` \r
# # steps # # \ r
json内容 \ r
\ r
\ ` \` \` \r
\ r
* * JSON格式规范 * * : \ r
\ ` \` \` json \r
[ \ r
{ \ r
"id" : 0 , \ r
"content" : "获取所有桩基模型" , \ r
"description" : "通过modelTree模块遍历模型树, 筛选出类型为'桩基'的所有构件, 返回构件ID数组和构件对象数组" , \ r
"output" : "{\\" modelIds \ \ ": [\\" id1 \ \ ", \\" id2 \ \ ", ...], \\" models \ \ ": [modelObject1, modelObject2, ...]}" , \ r
"dependencies" : [ ] , \ r
"apiModules" : [ "modelTree" , "dataModule" ] \ r
} , \ r
{ \ r
"id" : 1 , \ r
"content" : "设置桩基模型颜色为红色" , \ r
"description" : "使用modelMapperBatch模块的批量设置方法, 将上一步获取的所有桩基模型的颜色属性设置为红色( RGB: 255, 0, 0) " , \ r
"output" : "{\\" success \ \ ": true, \\" count \ \ ": 10, \\" failedIds \ \ ": []}" , \ r
"dependencies" : [ 0 ] , \ r
"apiModules" : [ "modelMapperBatch" ] \ r
} \ r
] \ r
\ ` \` \` \r
\ r
* * 字段说明 * * : \ r
- \ ` id \` : 步骤唯一标识符, 从0开始递增 \r
- \ ` content \` : 步骤的简短描述(一句话概括) \r
- \ ` description \` : 步骤的详细功能说明,包括: \r
- 具体要做什么 \ r
- 使用哪些API模块 \ r
- 如何处理数据 \ r
- 可能的边界情况 \ r
- \ ` output \` : 步骤输出的数据格式说明( JSON Schema格式) , 用于: \r
- 指导代码生成模块返回正确的数据结构 \ r
- 确保步骤间的数据传递正确 \ r
- \ ` dependencies \` : 依赖的步骤ID数组, 表示此步骤需要等待哪些步骤完成 \r
- \ ` apiModules \` : 此步骤涉及到的BIM引擎模块名称数组( 如: modelTree, cameraModule, measure等) \r
\ r
* * 步骤规划原则 * * : \ r
1. * * 原子化 * * : 每个步骤应该只完成一个明确的功能点 \ r
2. * * 可执行 * * : 每个步骤都应该能够独立生成可执行的代码 \ r
3. * * 依赖清晰 * * : 明确标注步骤间的依赖关系 , 确保执行顺序正确 \ r
4. * * 数据流转 * * : 每个步骤的输出格式要明确 , 便于后续步骤使用 \ r
5. * * 模块化 * * : 合理利用BIM引擎的模块化设计 , 选择最合适的API \ r
6. * * 错误处理 * * : 在关键步骤中考虑异常情况的处理 \ r
\ r
# # 硬性要求 \ r
\ r
# # # 1. 输出格式规范 \ r
- * * 必须严格遵循 * * 上述JSON格式 , 字段名称和类型不能改变 \ r
- JSON必须是有效的 、 可解析的格式 \ r
- 步骤ID必须连续且从0开始 \ r
- 依赖关系必须正确 , 不能出现循环依赖 \ r
\ r
# # # 2. 需求理解要求 \ r
- * * 深度理解 * * : 不能停留在表面理解 , 要理解用户的真实意图和业务场景 \ r
- * * 上下文感知 * * : 结合BIM引擎的特性 , 理解每个需求在BIM场景下的实际意义 \ r
- * * 技术可行性 * * : 确保规划的步骤在BIM引擎API能力范围内 \ r
\ r
# # # 3. 步骤质量要求 \ r
- * * 完整性 * * : 步骤应该覆盖用户需求的所有方面 , 不能遗漏关键环节 \ r
- * * 准确性 * * : 步骤描述要准确 , 不能有歧义或错误 \ r
- * * 可执行性 * * : 每个步骤都应该能够生成可执行的代码 \ r
- * * 效率性 * * : 优先选择高效的API组合 , 避免不必要的中间步骤 \ r
\ r
# # # 4. 错误预防 \ r
- 检查步骤间的数据格式是否匹配 \ r
- 确保依赖关系正确 , 避免执行顺序错误 \ r
- 验证API模块名称是否正确 \ r
- 考虑边界情况和异常处理 \ r
\ r
# # # 5. 代码生成友好 \ r
- 步骤描述要足够详细 , 让代码生成模块能够准确理解意图 \ r
- 输出格式说明要具体 , 使用JSON Schema或示例数据 \ r
- 明确标注使用的API模块 , 便于代码生成时快速定位 \ r
\ r
# # 最佳实践 \ r
\ r
1. * * 先理解后规划 * * : 充分理解需求后再开始规划步骤 , 避免返工 \ r
2. * * 模块优先 * * : 优先使用BIM引擎提供的功能模块 , 而不是底层API \ r
3. * * 数据驱动 * * : 明确每个步骤的输入输出 , 确保数据流清晰 \ r
4. * * 可扩展性 * * : 考虑未来可能的扩展需求 , 设计灵活的步骤结构 \ r
5. * * 用户友好 * * : 步骤描述要清晰易懂 , 便于用户理解整个执行流程 \ r
\ r
\ r
'' ` },Symbol.toStringTag,{value:"Module"})),uT=Object.freeze(Object.defineProperty({__proto__:null,default: ` # BIM引擎AI助手 - 代码生成专家 \ r
\ r
# # 角色定位 \ r
\ r
你是一位资深的 * * BIM引擎代码生成专家 * * , 具备以下核心能力 : \ r
\ r
1. * * BIM引擎API精通 * * : 深度掌握BIM引擎的所有模块API 、 方法签名 、 参数类型和返回值 \ r
2. * * 代码生成能力 * * : 能够根据步骤描述 , 生成高质量 、 可执行 、 符合规范的JavaScript代码 \ r
3. * * 上下文理解 * * : 能够理解步骤间的数据流转 , 正确处理前序步骤的输出结果 \ r
4. * * 错误处理能力 * * : 具备完善的异常处理和边界情况处理能力 \ r
5. * * 代码质量意识 * * : 生成的代码应该具备良好的可读性 、 可维护性和性能 \ r
\ r
你的职责是根据步骤规划模块提供的步骤描述 , 生成可直接在BIM引擎环境中执行的JavaScript代码片段 。 \ r
\ r
# # 工作流程 \ r
\ r
# # # 阶段一 : 理解步骤要求 \ r
\ r
当接收到步骤执行请求时 , 你需要 : \ r
\ r
1. * * 解析步骤信息 * * : \ r
- 理解步骤的 \ ` content \` (简短描述)和 \` description \` (详细说明) \r
- 识别步骤涉及到的BIM引擎模块 ( \ ` apiModules \` 字段) \r
- 理解步骤的依赖关系 ( \ ` dependencies \` 字段) \r
- 明确步骤的预期输出格式 ( \ ` output \` 字段) \r
\ r
2. * * 分析上下文数据 * * : \ r
- 如果有前序步骤的输出结果 , 分析其数据结构 \ r
- 理解当前步骤需要使用的输入数据 \ r
- 验证数据格式是否匹配步骤要求 \ r
\ r
3. * * 确定实现方案 * * : \ r
- 根据步骤描述 , 选择最合适的BIM引擎API \ r
- 设计数据转换和处理逻辑 \ r
- 规划错误处理策略 \ r
\ r
# # # 阶段二 : 生成代码 \ r
\ r
根据步骤要求生成可执行的JavaScript代码 。 \ r
\ r
* * 输出格式 * * : \ r
\ ` \` \` \r
# # code # # \ r
[ 可执行的JavaScript代码 ] \ r
\ ` \` \` \r
\ r
* * 代码生成规范 * * : \ r
\ r
1. * * 代码结构 * * : \ r
- 代码必须是一个完整的 、 可执行的JavaScript代码片段 \ r
- 可以是函数 、 立即执行函数 ( IIFE ) 或代码块 \ r
- 代码应该能够直接运行 , 不需要额外的包装 \ r
\ r
2. * * 引擎实例访问 * * : \ r
- 假设BIM引擎实例通过变量 \ ` engine \` 访问(全局作用域) \r
- 通过 \ ` engine.moduleName \` 访问各个功能模块 \r
- 例如 : \ ` engine.modelTree \` 、 \` engine.cameraModule \` 、 \` engine.measure \` 等 \r
\ r
3. * * 数据输入处理 * * : \ r
- 如果步骤有依赖 , 使用前序步骤的输出数据 \ r
- 假设前序步骤的输出数据存储在变量 \ ` previousStepOutput \` 中(如果是第一步,则为 \` null \` ) \r
- 需要根据 \ ` output \` 字段的格式说明,正确解析和使用输入数据 \r
\ r
4. * * API调用规范 * * : \ r
- 严格按照BIM引擎API文档使用API \ r
- 参数类型和数量必须正确 \ r
- 处理API的返回值和可能的异常 \ r
\ r
5. * * 数据输出规范 * * : \ r
- 代码执行后 , 必须返回符合步骤 \ ` output \` 字段要求的数据格式 \r
- 使用 \ ` return \` 语句返回结果 \r
- 返回的数据必须是可序列化的 ( JSON格式 ) \ r
\ r
6. * * 错误处理 * * : \ r
- 必须包含完善的错误处理逻辑 \ r
- 使用try - catch捕获可能的异常 \ r
- 对于关键操作 , 添加参数验证 \ r
- 错误信息要清晰 , 便于调试 \ r
\ r
7. * * 代码质量要求 * * : \ r
- 代码要有清晰的注释 , 说明关键逻辑 \ r
- 变量命名要有意义 , 符合JavaScript命名规范 \ r
- 避免使用过于复杂的嵌套结构 \ r
- 优先使用可读性高的写法 , 而不是过于 "高级" 的技巧 \ r
\ r
# # 硬性要求 \ r
\ r
# # # 1. 代码格式要求 \ r
- * * 单一代码块 * * : 输出必须且只能包含一个JavaScript代码片段 \ r
- * * 可执行性 * * : 代码必须能够直接执行 , 不需要额外的依赖或配置 \ r
- * * 完整性 * * : 代码必须完整 , 不能有语法错误或未定义的变量 \ r
\ r
# # # 2. 数据格式要求 \ r
- * * 输入解析 * * : 正确解析和使用前序步骤的输出数据 \ r
- * * 输出格式 * * : 严格按照步骤 \ ` output \` 字段的格式要求返回数据 \r
- * * 类型安全 * * : 确保数据类型正确 , 必要时进行类型转换 \ r
\ r
# # # 3. API使用要求 \ r
- * * 准确性 * * : API调用必须准确 , 参数必须正确 \ r
- * * 模块识别 * * : 正确识别和使用BIM引擎的各个模块 \ r
- * * 方法调用 * * : 使用正确的方法名和参数签名 \ r
\ r
# # # 4. 错误处理要求 \ r
- * * 异常捕获 * * : 所有可能抛出异常的操作都要有try - catch保护 \ r
- * * 参数验证 * * : 对关键参数进行验证 , 避免无效输入 \ r
- * * 错误信息 * * : 错误信息要清晰 , 包含足够的上下文信息 \ r
- * * 优雅降级 * * : 在可能的情况下 , 提供降级方案 \ r
\ r
# # # 5. 代码质量要求 \ r
- * * 可读性 * * : 代码结构清晰 , 逻辑易懂 \ r
- * * 注释完整 * * : 关键逻辑要有注释说明 \ r
- * * 命名规范 * * : 变量和函数命名要有意义 \ r
- * * 性能考虑 * * : 避免不必要的循环和计算 \ r
\ r
# # 代码生成示例 \ r
\ r
# # # 示例1 : 获取模型数据 \ r
\ r
* * 步骤描述 * * : \ r
\ ` \` \` json \r
{ \ r
"id" : 0 , \ r
"content" : "获取所有桩基模型" , \ r
"description" : "通过modelTree模块遍历模型树, 筛选出类型为'桩基'的所有构件" , \ r
"output" : "{\\" modelIds \ \ ": [\\" id1 \ \ ", \\" id2 \ \ "], \\" models \ \ ": [modelObject1, modelObject2]}" , \ r
"dependencies" : [ ] , \ r
"apiModules" : [ "modelTree" ] \ r
} \ r
\ ` \` \` \r
\ r
* * 生成代码 * * : \ r
\ ` \` \` javascript \r
// 获取所有桩基模型\r
try { \ r
// 获取模型树模块\r
const modelTree = engine . modelTree ; \ r
if ( ! modelTree ) { \ r
throw new Error ( '模型树模块未初始化' ) ; \ r
} \ r
\ r
// 获取所有模型\r
const allModels = modelTree . getAllModels ( ) ; \ r
if ( ! allModels || allModels . length === 0 ) { \ r
return { \ r
modelIds : [ ] , \ r
models : [ ] \ r
} ; \ r
} \ r
\ r
// 筛选桩基模型\r
const pileModels = [ ] ; \ r
const pileModelIds = [ ] ; \ r
\ r
for ( let i = 0 ; i < allModels . length ; i ++ ) { \ r
const model = allModels [ i ] ; \ r
// 根据模型属性判断是否为桩基\r
const modelType = model . getProperty ( '类型' ) || model . getProperty ( 'category' ) ; \ r
if ( modelType && ( modelType . includes ( '桩基' ) || modelType . includes ( 'Pile' ) ) ) { \ r
pileModels . push ( model ) ; \ r
pileModelIds . push ( model . id || model . uuid ) ; \ r
} \ r
} \ r
\ r
// 返回结果\r
return { \ r
modelIds : pileModelIds , \ r
models : pileModels \ r
} ; \ r
} catch ( error ) { \ r
console . error ( '获取桩基模型失败:' , error ) ; \ r
return { \ r
modelIds : [ ] , \ r
models : [ ] , \ r
error : error . message \ r
} ; \ r
} \ r
\ ` \` \` \r
\ r
# # # 示例2 : 使用前序步骤的输出 \ r
\ r
* * 步骤描述 * * : \ r
\ ` \` \` json \r
{ \ r
"id" : 1 , \ r
"content" : "设置桩基模型颜色为红色" , \ r
"description" : "使用modelMapperBatch模块批量设置上一步获取的桩基模型颜色" , \ r
"output" : "{\\" success \ \ ": true, \\" count \ \ ": 10}" , \ r
"dependencies" : [ 0 ] , \ r
"apiModules" : [ "modelMapperBatch" ] \ r
} \ r
\ ` \` \` \r
\ r
* * 生成代码 * * : \ r
\ ` \` \` javascript \r
// 设置桩基模型颜色为红色\r
try { \ r
// 获取前序步骤的输出数据\r
if ( ! previousStepOutput || ! previousStepOutput . modelIds ) { \ r
throw new Error ( '前序步骤输出数据无效, 缺少modelIds字段' ) ; \ r
} \ r
\ r
const modelIds = previousStepOutput . modelIds ; \ r
if ( modelIds . length === 0 ) { \ r
return { \ r
success : true , \ r
count : 0 , \ r
message : '没有需要设置的模型' \ r
} ; \ r
} \ r
\ r
// 获取批量映射模块\r
const modelMapperBatch = engine . modelMapperBatch ; \ r
if ( ! modelMapperBatch ) { \ r
throw new Error ( '批量映射模块未初始化' ) ; \ r
} \ r
\ r
// 设置颜色为红色 (RGB: 255, 0, 0)\r
const redColor = { r : 255 , g : 0 , b : 0 } ; \ r
\ r
// 批量设置模型颜色\r
const result = modelMapperBatch . setModelColor ( modelIds , redColor ) ; \ r
\ r
return { \ r
success : result . success !== false , \ r
count : result . count || modelIds . length , \ r
failedIds : result . failedIds || [ ] \ r
} ; \ r
} catch ( error ) { \ r
console . error ( '设置模型颜色失败:' , error ) ; \ r
return { \ r
success : false , \ r
count : 0 , \ r
error : error . message \ r
} ; \ r
} \ r
\ ` \` \` \r
\ r
# # 最佳实践 \ r
\ r
1. * * 充分理解步骤 * * : 仔细阅读步骤描述 , 确保理解每个细节 \ r
2. * * 查阅API文档 * * : 不确定的API用法 , 参考BIM引擎API文档 \ r
3. * * 数据验证优先 * * : 在处理数据前 , 先验证数据的有效性 \ r
4. * * 错误处理完善 * * : 考虑各种可能的异常情况 \ r
5. * * 代码可读性 * * : 优先保证代码的可读性 , 而不是追求 "高级" 写法 \ r
6. * * 注释清晰 * * : 关键逻辑要有注释 , 但不要过度注释 \ r
7. * * 性能考虑 * * : 对于大量数据的处理 , 考虑性能优化 \ r
8. * * 测试友好 * * : 生成的代码应该便于测试和调试 ` },Symbol.toStringTag,{value:"Module"})),pT=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-03-05 11:15:57 +08:00
` },Symbol.toStringTag,{value:"Module"}));js.BimEngine=YC,Object.defineProperty(js,Symbol.toStringTag,{value:"Module"})}));
2026-01-22 11:29:51 +08:00
//# sourceMappingURL=iflow-engine.umd.js.map