import * as THREE from "../../../../libs/three.js/build/three.module.js";
const initDir = new THREE.Vector3(0,1,0)//指南针模型的北方向 向屏幕里
class Compass extends THREE.EventDispatcher{
constructor(dom, viewport){
super()
this.angle = 0;
this.show = false;
if(dom){
this.dom = $(dom);
}
this.viewport = viewport
this.init()
}
init(){
var width = 100, height = 100
if(!this.dom){
this.dom = $('
')
$(viewer.renderArea).append(this.dom)
}
this.dom.css({ display:"none", position:"absolute",right:"1%",top: "60px",width:width+"px",height:height+"px", "z-index":100,"pointer-events":"none" })
let child = $(""+/* (config.lang=='zh'? */'北'/* :'N') */+"
")
this.dom.append(child)
this.dom.find(".dirText").css({textAlign:"center","font-size":"10px","position":"absolute",
width: "100%",
height: "25px",
"line-height": "25px"})
this.dom.find(".north").css({"color":"#02a0e9","top":"0"})
this.dom.find(".south").css({"color":"#ff1414","bottom":"0"})
this.dom.find(".center").css({
//"background":`url(${config.getStaticResource('img')}/dire.png)`,
width: width/2+"px",
height: height/2+"px",
"background-size": "contain",
"background-position": "center",
left: "50%",
top: "50%",
transform: "translate(-50%,-50%)",
position: "absolute"
})
this.dom.find(".dirText").css({
"text-align": "center",
"font-size": "10px",
"color": "rgb(255, 255, 255)",
"position": "absolute",
"top": "50%",
"left": "50%",
"width": "45%",
"height": "0px",
"transform-origin": "left center",
})
this.dom.find(".dirText span").css({
display: "block",
position: "absolute",
right: "5px",
top: "0",
width: "20px",
height: "20px",
"line-height": "20px",
// "font-size": ".75rem ",
"margin-top": "-10px",
})
try {
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha:true })//许钟文 添加个抗锯齿,否则添加的线条锯齿严重,
this.renderer.autoClear = !0
this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1)
this.renderer.domElement.setAttribute('name','compass')
this.renderer.setClearAlpha(0.0)
//xst修改
//this.renderer.setSize(width/2, height/2, false, window.devicePixelRatio ? window.devicePixelRatio : 1);
//xst修改
//this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
//this.renderer.setSize(width/2, height/2);
//xst修改
this.renderer.setDrawingBufferSize( width/2, height/2, window.devicePixelRatio ? window.devicePixelRatio : 1 )
//this.emit(SceneRendererEvents.ContextCreated)
} catch (e) {
viewer.dispatchEvent('webglError', {msg:e})
}
this.dom.find(".center")[0].appendChild(this.renderer.domElement);
this.renderer.domElement.style.width = this.renderer.domElement.style.height = '100%'
this.camera = new THREE.PerspectiveCamera;
this.camera.fov = 50;
this.camera.updateProjectionMatrix()
this.scene = new THREE.Scene,
this.scene.add(this.camera)
this.createCompass()
viewer.addEventListener('camera_changed', e => {
if (e.viewport == this.viewport && (e.changeInfo.quaternionChanged /* || e.changeInfo.quaternionChanged */)) {
this.update()
}
})
this.setDomPos()
if(this.viewport)this.setDisplay(true)
}
createCompass(){
//ConeBufferGeometry(radius : Float, height : Float, radialSegments : Integer, heightSegments : Integer, openEnded : Boolean, thetaStart : Float, thetaLength : Float)
const height = 2;
const geometry1 = new THREE.ConeBufferGeometry( 0.7, height, 4, true );
const geometry2 = new THREE.ConeBufferGeometry( 0.7, height, 4, true );
const material = new THREE.MeshBasicMaterial({
vertexColors :true
})
//指南针由两个四棱锥拼成,为了渐变颜色,采用指定vertexColor的方式。
var setColor = function(geometry, color1,color2){
const colors = [];
for ( let i = 0, n = geometry.attributes.position.count; i < n; ++ i ) {
colors.push( 1, 1, 1 );
}
var set = function(index, color){//设置第index个点的颜色
colors[index*3+0] = color[0]
colors[index*3+1] = color[1]
colors[index*3+2] = color[2]
}
var mid = [(color1[0]+color2[0])/2, (color1[1]+color2[1])/2, (color1[2]+color2[2])/2 ]
set(1,color1); set(5,color1);set(6,color1);
set(2,mid); set(3,mid);set(7,mid);
set(4,color2); set(8,color2);set(9,color2);
geometry.setAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3))
}
var blue1 = [1/255,238/255,245/255] //逐渐变深
var blue2 = [20/255,146/255,170/255]
var blue3 = [40/255,60/255,103/255]
setColor(geometry1, blue1,blue2)
setColor(geometry2, blue2,blue3)
/* 朝箭头方向看点构成如下 虽然geometry.attributes.position.count = 19 只有1-9设置的颜色是有效的 另外为什么7决定了上下两边的颜色呢…… 5、9可将其分成上下两个颜色
6
/|\
/ | \
7 /_2|1_\ 5
\ 3|4 / 9
\ | /
\|/
8
*/
const cone = new THREE.Mesh( geometry1, material );
cone.position.setY(height/2)
geometry1.computeVertexNormals()//computeFaceNormals
geometry2.computeVertexNormals()
const cones = new THREE.Object3D();
cones.add(cone)
let cone2 = new THREE.Mesh( geometry2, material );
cone2.rotation.x = Math.PI;
cone2.position.setY(-height/2)
cones.add(cone2)
//cones.rotation.x = Math.PI / 2;//转向initDir的方向
//cones.rotation.z = Math.PI / 2;
cones.rotation.z = Math.PI ;//转向initDir的方向
cones.scale.set(0.7,0.7,0.7)
this.scene.add(cones)
this.cones = cones
}
setNorth(){ //设置北方向,这决定了指南针自身的朝向。
const floors = store.getters['scene/houstFloor'].floors
if(!floors || !floors.length){
return
}
const floor = floors[0]
const metadata = app.store.getters['scene/metadata'] || {}
this.angle = (floor && floor.dire || 0) + THREE.Math.radToDeg(parseFloat(metadata.floorPlanAngle || 0)) //基础朝向
this.cones.rotation.y = Math.PI / 2 - THREE.Math.degToRad(this.angle)
//console.log("dir:"+floor.dire+", floorPlanAngle:"+metadata.floorPlanAngle)
this.update()
}
update(quaternion){
if(!this.show)return;
if(!quaternion) quaternion = this.viewport.camera.quaternion.clone();
this.updateCamera(quaternion)
this.updateLabel(quaternion)
this.render()
}
/*updateLabel(quaternion){//更新北标签
var dir = viewer.mainViewport.view.direction;
var oriDir = initDir.clone() //指南针最初始时的北方向
var extraQua
if(objects.player.mode == "transitioning"){//当transitioning时,相机的quaternion不是用control的lookAt算出来,而是直接由一个quaternion过渡到另一个,这样相机将会是歪的,投影面也就不会是原先的水平面。
var tempCamera = new THREE.Camera(); //借用camera的lookAt算出如果正视同样的target, quaternion会是什么值。 将它乘以当前相机quaternion,得到的就是相机歪的旋转值。
tempCamera.position.copy(this.camera.position);
tempCamera.lookAt(tempCamera.position.clone().add(dir))
var q = tempCamera.quaternion.inverse()
extraQua = q.premultiply(quaternion) //歪掉的额外旋转值
}
//北标签的方向为指南针轮盘方向,也就是要将camera的方向投影到水平面上。 但是如果相机歪了,看到的世界都会歪一定角度,投影面也要歪一定角度。
var up = new THREE.Vector3(0,0,1) //投影水平面的法线,也是相机的摆正的up方向
extraQua && up.applyQuaternion(extraQua)
dir.projectOnPlane(up) //将方向投影到水平面上; 如果相机不是正视(extraQua不为0001),就要将水平面也转动
oriDir.projectOnPlane(up)//为什么initDir投影了和没有投影angle结果一样
var angle = dir.angleTo(oriDir)
if(dir.cross(oriDir).y > 0)angle = -angle
var deg = this.angle - 90 + THREE.Math.radToDeg(angle) //因为css写的样式初始是指向右方,和initDir差了90°,所以减去。
this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" )
this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)")
} */
updateLabel(quaternion){//更新北标签
let deg = THREE.Math.radToDeg(this.viewport.view.yaw) - 90
this.dom.find(".dirText").css( "transform","rotate("+deg+"deg)" )
this.dom.find(".dirText span").css("transform","rotate("+(-deg)+"deg)")
}
updateCamera(quaternion){ //更新canvas中的指南针表现,也就是更新相机,和场景中的相机朝向一致。
const radius = 5; //相机距离
this.camera.quaternion.copy(quaternion);
var dir = this.viewport.view.direction; //相机朝向
this.camera.position.copy(dir.multiplyScalar(radius).negate()) //相机绕着指南针中心(000)转动
}
changeViewport(viewport){
this.viewport = viewport;
this.update(); //因相机更新了
}
render(){
this.renderer.render(this.scene, this.camera)
}
setDisplay(state){
this.show = !!state;
if(this.show){
this.update()
this.dom.fadeIn(100)
}else{
this.dom.fadeOut(100)
}
}
autoJudgeDisplay(){
}
setDomPos(){
if(!this.viewport)return
let right = this.viewport.left + this.viewport.width
this.dom.css({'right':((1-right)*100 + 1) + '%'})
}
}
export default Compass;