|
|
@@ -19,6 +19,10 @@ import Sprite from './objects/Sprite.js'
|
|
|
let texLoader = new THREE.TextureLoader()
|
|
|
|
|
|
const raycaster = new THREE.Raycaster()
|
|
|
+const planeGeo = new THREE.PlaneGeometry(1,1)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
export class Viewer extends ViewerBase {
|
|
|
constructor( args = {}) {
|
|
|
@@ -58,7 +62,7 @@ export class Viewer extends ViewerBase {
|
|
|
})
|
|
|
this.viewports.push(this.mainViewport)
|
|
|
|
|
|
- /* let plane = new THREE.Mesh(new THREE.PlaneGeometry(10,10), new THREE.MeshBasicMaterial({transparent:false,depthTest:false,color:"#F00"}))
|
|
|
+ /* let plane = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({transparent:false,depthTest:false,color:"#F00"}))
|
|
|
this.scene.add(plane)
|
|
|
plane.renderOrder = 1 */
|
|
|
|
|
|
@@ -87,7 +91,7 @@ export class Viewer extends ViewerBase {
|
|
|
try {
|
|
|
if (e.event.ctrlKey) {
|
|
|
if (e.event.key.toLowerCase() == 'c') {
|
|
|
- let info = this.mainViewport.view.getJson()
|
|
|
+ let info = this.mainViewport.view.getJson2()
|
|
|
|
|
|
info = JSON.stringify(info)
|
|
|
;(console.log(`Copy view params: ${info}`),
|
|
|
@@ -123,7 +127,7 @@ export class Viewer extends ViewerBase {
|
|
|
light3.lookAt( new THREE.Vector3(0, 0, 0));
|
|
|
lights.add(light3)
|
|
|
|
|
|
- if(1){
|
|
|
+ if(settings.showLights){
|
|
|
let g = new THREE.SphereGeometry(1, 4, bright),
|
|
|
m = new THREE.MeshBasicMaterial({color:'#f02'})
|
|
|
|
|
|
@@ -598,56 +602,107 @@ export class Viewer extends ViewerBase {
|
|
|
})
|
|
|
} */
|
|
|
|
|
|
- closeTag(dur){
|
|
|
- let allIndex = [], i = -1
|
|
|
- while(++i < this.modelData.model.texNum){
|
|
|
- allIndex.push(i)
|
|
|
- }
|
|
|
- this.highlightTex(allIndex, 0, dur ) //hide emissive tex
|
|
|
+ closeTag(duration, defaultTarget, split){
|
|
|
+
|
|
|
+ this.highlightTex('all', 0, duration ) //hide emissive tex
|
|
|
this.mainViewport.view.cancelFlying('all', false) //stop action
|
|
|
+
|
|
|
+ if(defaultTarget){
|
|
|
+ let target = this.defaultView.target
|
|
|
+ let vec = new THREE.Vector3().subVectors(target, this.mainViewport.view.getPivot())
|
|
|
+ let position = this.mainViewport.view.position.clone().add(vec)
|
|
|
+ this.mainViewport.view.setView({
|
|
|
+ target ,
|
|
|
+ position,
|
|
|
+ duration: 1000
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if(split){
|
|
|
+ this.changeCombineState(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ this.texPlaneState && this.showPlane(0)
|
|
|
+ this.structureState && this.showStructure(0)
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- highlightTex(indexes, toPercent=0.9, duration=2000, done){
|
|
|
+ highlightTex(indexes='all', toPercent=0.8, duration=2000, done, delay=0, loopDur){
|
|
|
|
|
|
let model = viewer.objs.children[0]
|
|
|
if(!model)return console.error('模型未加载完')
|
|
|
//const duration = 2000, minAlpha = 0, maxAlpha = 0.8
|
|
|
transitions.cancelById('highlight')
|
|
|
|
|
|
- let startPercents = indexes.map(index=>model.materials_[0].emiIntensitys[index])
|
|
|
+ if(indexes == 'all') indexes = model.allTexIndex
|
|
|
+
|
|
|
+ let startPercents = indexes.map(index =>
|
|
|
+ model.materials_.find(mat=>mat.emiss_texs.includes(index)).uniforms_.emiIntensitys.value[index]
|
|
|
+ )
|
|
|
|
|
|
+ let realDur = duration * (1-delay)
|
|
|
+ duration = loopDur ? -duration : duration
|
|
|
+ let loopCount = 0
|
|
|
|
|
|
transitions.start((percent)=>{
|
|
|
|
|
|
- let currents = indexes.map((index, i)=>math.linearClamp(percent,[0,1], [startPercents[i], toPercent] ) )
|
|
|
-
|
|
|
+ let currents
|
|
|
|
|
|
- model.materials_.forEach(mat=>{
|
|
|
+ if(!loopCount){
|
|
|
+ currents = indexes.map((index, i)=>math.linearClamp(percent,[0,1], [startPercents[i], toPercent] ) )
|
|
|
+ }else{
|
|
|
+ //快-慢-快
|
|
|
+ percent = percent * 2
|
|
|
+ percent > 1 && (percent = 2 - percent )
|
|
|
+ percent = easing.easeOutCubic(percent, 0, 1, 1)
|
|
|
+ let opacity = math.linearClamp(percent,[0,1],[toPercent, 0])
|
|
|
+ currents = indexes.map(index=>opacity)
|
|
|
+ //currents = indexes.map((index, i)=>math.linearClamp(percent,[0, 0.2, 0.5, 0.8,1], [toPercent, 0.2, 0, 0.2,toPercent] ) )
|
|
|
|
|
|
- model.materials_.forEach(mat=>{
|
|
|
- indexes.forEach((index,i)=>{
|
|
|
-
|
|
|
- mat.emiIntensitys[index] = currents[i]
|
|
|
- })
|
|
|
- })
|
|
|
+ }
|
|
|
+
|
|
|
+ model.materials_.forEach(mat=>{
|
|
|
+ indexes.forEach((index,i)=>{
|
|
|
+ if(mat.emiss_texs.includes(index)){
|
|
|
+ mat.uniforms_.emiIntensitys.value[index] = currents[i]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
- })
|
|
|
+
|
|
|
viewer.dispatchEvent('content_changed')
|
|
|
}, duration, ()=>{
|
|
|
- done && done()
|
|
|
- }, 0, easing.easeInQuad, null,'highlight' )
|
|
|
+
|
|
|
+ loopCount ++;
|
|
|
+
|
|
|
+ if(loopCount == 1){
|
|
|
+ if(loopDur){
|
|
|
+ transitions.adjustSpeed("highlight", realDur / loopDur)
|
|
|
+ transitions.getById("highlight")[0].easing = easing.linearTween
|
|
|
+ }
|
|
|
+ done && done()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }, delay, easing.easeInQuad, null,'highlight' )
|
|
|
|
|
|
}
|
|
|
|
|
|
dealTagAction(id){
|
|
|
- if(id !== this.lastOpenTag) this.closeTag(0)
|
|
|
|
|
|
- this.lastOpenTag = id
|
|
|
-
|
|
|
this.mainViewport.view.cancelFlying('all', false)
|
|
|
|
|
|
let hotspot = this.modelData.hotspots.find(e=>e.id == id)
|
|
|
let targetStart = this.mainViewport.view.getPivot()
|
|
|
+ if(!hotspot)return
|
|
|
+
|
|
|
+
|
|
|
+ if(hotspot !== this.lastOpenTag){
|
|
|
+ let defaultTarget = true //如果等下没指定view,需要恢复target
|
|
|
+ let split = this.combineState && !hotspot.action?.find(e=>e.combineModel)
|
|
|
+ this.closeTag(0, defaultTarget, split, )
|
|
|
+ }
|
|
|
+ this.lastOpenTag = hotspot
|
|
|
|
|
|
if(hotspot.action){
|
|
|
let actionIndex = 0
|
|
|
@@ -670,23 +725,46 @@ export class Viewer extends ViewerBase {
|
|
|
if(action.view){
|
|
|
|
|
|
taskCount++
|
|
|
-
|
|
|
- let dis = this.mainViewport.view.position.distanceTo( action.view.position )
|
|
|
+ let endPos = action.view.position || action.view.endPos
|
|
|
+ let dis = this.mainViewport.view.position.distanceTo( endPos )
|
|
|
+ let duration = action.view.duration || math.linearClamp(dis,[0, 4, 400], [0, 500, 1500])
|
|
|
+ console.log('duration', duration);
|
|
|
this.mainViewport.view.setView({
|
|
|
- //endYaw: action.view.yaw,
|
|
|
- //endPitch: action.view.pitch,
|
|
|
+ endYaw: action.view.yaw,
|
|
|
+ endPitch: action.view.pitch,
|
|
|
position: action.view.position,
|
|
|
- //endRadius: action.view.radius,
|
|
|
+ endRadius: action.view.radius,
|
|
|
target: action.view.target,
|
|
|
- duration: math.linearClamp(dis,[0, 200], [0,1200]),
|
|
|
+ duration,
|
|
|
callback,
|
|
|
- cancelFun: callback
|
|
|
+ cancelFun: callback
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if(action.tex){
|
|
|
taskCount++
|
|
|
- this.highlightTex(action.tex, 0.9, 2000, callback )
|
|
|
+ let t = action.tex
|
|
|
+ t.show && this.highlightTex(t.show, 0.9, t.dur || 2000, callback, t.delay, t.shine)
|
|
|
+ t.hide && this.highlightTex(t.hide, 0, t.dur || 1200, callback, t.delay, t.shine )
|
|
|
+ }
|
|
|
+
|
|
|
+ if(action.combineModel){
|
|
|
+ taskCount++
|
|
|
+ this.changeCombineState(false, action.combineModel.dur || 1000, callback)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(action.structure){
|
|
|
+ taskCount++
|
|
|
+ let s = action.structure
|
|
|
+ this.showStructure(s.state, s.dir, s.rimPower, s.opacity, s.dur, callback, s.delay, s.lowOpacity)
|
|
|
+ }
|
|
|
+
|
|
|
+ if(action.planeTex){
|
|
|
+ taskCount++
|
|
|
+ let t = action.planeTex
|
|
|
+ this.showPlane(t.state, t.file, t.matrix, t.dur, t.delay, callback)
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -696,22 +774,49 @@ export class Viewer extends ViewerBase {
|
|
|
}
|
|
|
|
|
|
|
|
|
+ changeCombineState(split, duration=1000, done){ //默认是拆分的
|
|
|
+ let model = this.objs.children[0]
|
|
|
+
|
|
|
+ transitions.cancelById('splitModel')
|
|
|
+
|
|
|
+ let startMatrixs = model.splitParts.map(e=>e.matrix.clone())
|
|
|
+ let endMatrixs = model.splitParts.map(e=> split ? e.initialMatrix.clone() : e.combineMatrix.clone())
|
|
|
+ let matrix = new THREE.Matrix4
|
|
|
+ this.combineState = !split
|
|
|
+
|
|
|
+ transitions.start((percent)=>{
|
|
|
+
|
|
|
+ model.splitParts.forEach((object, i)=>{
|
|
|
+
|
|
|
+ matrix.copy(startMatrixs[i])
|
|
|
+ lerp.matrix4(matrix, endMatrixs[i])(percent)
|
|
|
+ matrix.decompose(object.position, object.quaternion, object.scale)
|
|
|
+ object.dispatchEvent('moved')
|
|
|
+ })
|
|
|
+
|
|
|
+ viewer.dispatchEvent('content_changed')
|
|
|
+ }, duration, ()=>{
|
|
|
+ done && done()
|
|
|
+ }, 0, easing.easeInOutSine, null,'splitModel' )
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- showStructure(state){
|
|
|
+ showStructure0(state, fresnelDir = [0,1,0]){
|
|
|
let meterials = viewer.objs.children[0].materials_
|
|
|
if(state){
|
|
|
meterials.forEach(mat=>{
|
|
|
- mat.defines.Fresnel = 1
|
|
|
+ mat.defines.Fresnel = 1
|
|
|
+ mat.uniforms.fresnelDir.value.fromArray(fresnelDir)
|
|
|
mat.transparent = true
|
|
|
- //mat.side = 2
|
|
|
- mat.needsUpdate = true
|
|
|
+ mat.side = 2
|
|
|
+ mat.needsUpdate = true //会触发onBeforeCompile
|
|
|
})
|
|
|
|
|
|
}else{
|
|
|
meterials.forEach(mat=>{
|
|
|
delete mat.defines.Fresnel
|
|
|
mat.transparent = false
|
|
|
- //mat.side = 0
|
|
|
+ mat.side = 0
|
|
|
mat.needsUpdate = true
|
|
|
})
|
|
|
}
|
|
|
@@ -720,7 +825,94 @@ export class Viewer extends ViewerBase {
|
|
|
}
|
|
|
|
|
|
|
|
|
+ showStructure(state, fresnelDir = [0,1,0], rimPower=1, opacity=1, duration=500, done, delay=0 ){
|
|
|
+
|
|
|
+ //if(this.structureState == state)return //直接return不好,要执行done,但要等结束才能执行
|
|
|
+ this.structureState = state
|
|
|
+ transitions.cancelById('modelStructure')
|
|
|
+ let model = viewer.objs.children[0]
|
|
|
+ let meterials = model.materials_
|
|
|
+ let startFreRatios = meterials.map(e=>e.uniforms_.fresnelRatio.value)
|
|
|
+ let startOpacitys = meterials.map(e=>e.opacity / model.structureOpacity)
|
|
|
+ let toFreRatio = state ? 1 : 0
|
|
|
+ let init
|
|
|
+
|
|
|
+ transitions.start((percent)=>{
|
|
|
+ meterials.forEach((mat,i)=>{
|
|
|
+ if(!init && percent >0 && state){
|
|
|
+ Common.addOrRemoveDefine(mat, "Fresnel", "add") //state ? "add" : "remove"
|
|
|
+ mat.uniforms_.fresnelDir.value.set(...fresnelDir );
|
|
|
+ mat.uniforms_.rimPower.value = rimPower
|
|
|
+ mat.transparent = true
|
|
|
+ //mat.opacity = model.structureOpacity || 1
|
|
|
+ mat.depthWrite = false //减轻环璧条纹, 透明度越低越不明显 用structureOpacity调节透明度
|
|
|
+ mat.side = 2
|
|
|
+ init = true
|
|
|
+ }
|
|
|
+
|
|
|
+ //mat.uniforms_.fresnelRatio.value = state ? percent : 1-percent
|
|
|
+ //mat.uniforms_.fresnelParam.value[3] = state ? percent : 1-percent
|
|
|
+ mat.uniforms_.fresnelRatio.value = math.linearClamp(percent,[0,1], [startFreRatios[i], toFreRatio] )
|
|
|
+ mat.opacity = model.structureOpacity * math.linearClamp(percent,state?[0,0.1]:[0.7,1], [startOpacitys[i], opacity * mat.initialOpacity] ) //这得大部分时间很小则过曝
|
|
|
+ //console.log('opa',mat.opacity)
|
|
|
+ })
|
|
|
+
|
|
|
+ viewer.dispatchEvent('content_changed')
|
|
|
+ }, duration, ()=>{
|
|
|
+ if(!state){
|
|
|
+ meterials.forEach((mat,i)=>{
|
|
|
+ Common.addOrRemoveDefine(mat, "Fresnel", "remove")
|
|
|
+ mat.side = 0
|
|
|
+ mat.needsUpdate = true
|
|
|
+ mat.depthWrite = true
|
|
|
+ mat.transparent = false //
|
|
|
+ })
|
|
|
+ }
|
|
|
+ done && done()
|
|
|
+ }, delay, easing.easeInOutSine, null,'modelStructure' )
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ showPlane(state=1, file, matrix, duration=1000, delay=0, done){
|
|
|
+ let model = viewer.objs.children[0]
|
|
|
+ console.log('showPlane', state)
|
|
|
+ transitions.cancelById('texPlane')
|
|
|
+ this.texPlaneState = state
|
|
|
+ if(!model.texPlane){
|
|
|
+ let url = Common.joinUrl(model.props.prefixUrl, file)
|
|
|
+ let plane = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({transparent:true, map: texLoader.load(url)}))
|
|
|
+ model.texPlane = plane
|
|
|
+ plane.opacity = 0
|
|
|
+ matrix = new THREE.Matrix4().fromArray(matrix)
|
|
|
+ matrix.decompose(plane.position, plane.quaternion, plane.scale )
|
|
|
+ this.scene.add(plane)
|
|
|
+ }
|
|
|
+
|
|
|
+ transitions.start((percent)=>{
|
|
|
+
|
|
|
+ model.texPlane.material.opacity = state ? percent : 1-percent
|
|
|
+
|
|
|
+ viewer.dispatchEvent('content_changed')
|
|
|
+ }, duration, ()=>{
|
|
|
+ done && done()
|
|
|
+ }, delay, easing.easeInSine, null,'texPlane' )
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
+ /* addPlane(){
|
|
|
+
|
|
|
+ let map = texLoader.load(url)
|
|
|
+ let plane = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({transparent:true, map}))
|
|
|
+ window.plane = plane
|
|
|
+ plane.scale.set(152,152,152)
|
|
|
+ plane.position.set(-8,-1,31)
|
|
|
+ plane.rotation.z = 3.123
|
|
|
+ this.scene.add(plane)
|
|
|
+ } */
|
|
|
}
|
|
|
|
|
|
|