123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
-
- 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 = $('<div name="compass"></div>')
- $(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 = $("<div class='dirText north'><span>"+/* (config.lang=='zh'? */'北'/* :'N') */+"</span></div><div class='center'></div>")
- 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.positionChanged || 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;
|