700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > three.js全景搭建 锚点标注添加 OrbitControls 轨道方向控制 场景切换

three.js全景搭建 锚点标注添加 OrbitControls 轨道方向控制 场景切换

时间:2020-04-03 23:52:47

相关推荐

three.js全景搭建  锚点标注添加  OrbitControls 轨道方向控制   场景切换

背景: 公司产品预演全景参访

实现: 场景查看 锚点标注

关键点: 二维点击转换三维坐标轴、 锚点绘制、场景切换、数据格式设计

未实现: 标注点添加gif 图片

添加视屏未实践 文档中有 添加视频的材质 可以尝试一下

场景查看

一、 创建一个场景

为了真正能够让你的场景借助three.js来进行显示,我们需要以下几个对象:场景、相机和渲染器,这样我们就能透过摄像机渲染出场景。

直接看官网文档 贼详细 three.js

实操

场景创建

// 场景const scene = new THREE.Scene();// 透视相机const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );/*** 透视相机四个参数 :视野角度*长宽比*近截面*远截面**/// 渲染器const renderer = new THREE.WebGLRenderer();// 渲染大小renderer.setSize( window.innerWidth, window.innerHeight );document.body.appendChild( renderer.domElement );// 几何体 --------const geometry = new THREE.BoxGeometry();// 球体 ----// SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)// - radius:球体半径// - widthSegments,// - heightSegments:水平方向和垂直方向上分段数。widthSegments最小值为3,默认值为8。heightSegments最小值为2,默认值为6。// - phiStart:水平方向上的起始角,默认值0// - phiLenght:水平方向上球体曲面覆盖的弧度,默认Math.PI * 2// - thetaStart : 垂直方向上的起始角, 默认0// - thetaLength: 垂直方向是球体曲面覆盖的弧度,默认值为Math.PIconst geometry = new THREE.SphereGeometry(500, 60, 40)// -------------const material = new THREE.MeshBasicMaterial( {color: 0x00ff00 } );const cube = new THREE.Mesh( geometry, material );scene.add( cube );/**默认情况下,当我们调用scene.add()的时候,物体将会被添加到(0,0,0)坐标。但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。*/camera.position.z = 5;const animate = function () {requestAnimationFrame( animate );cube.rotation.x += 0.01;cube.rotation.y += 0.01;renderer.render( scene, camera );};animate();

图片加载- 加载图片 贴到纹理图 然后add 创建网格 添加到场景- 引用图片有两种方式(第二种方式 引入图片不清晰 应该是canvas 绘图的原因)

let demo = new THREE.TextureLoader().load(vrImgurl)

// 方法一//防止跨域用canvas作为纹理let canvas = document.createElement("canvas");canvas.style.backgroundColor = "rgba(255,255,255,0)";let context = canvas.getContext("2d");let img = new Image();img.src = imgurl// img.src='';//绘制全景图img.onload = function () {canvas.width = this.width;canvas.height = this.height;context.drawImage(img, 0, 0, this.width, this.height);let texture = new THREE.Texture();texture.image = canvas;texture.needsUpdate = true;//开启纹理更新texture.minFilter = THREE.LinearFilter;//minFilter属性:指定纹理如何缩小let material = new THREE.MeshBasicMaterial({map: texture,transparent: false});mesh = new THREE.Mesh(geometry, material);scene.add(mesh);};

// 方法二、let demo = new THREE.TextureLoader().load(vrImgurl)let material = new THREE.MeshBasicMaterial({map: demo, // 此处使用 demo 的参数 图片更为清晰transparent: false,})mesh = new THREE.Mesh(geometry, material)// 几何体 材料(渲染图)scene.add(mesh)}

场景切换

1、先获取挂载元素的子节点2、由于mesh 和scene 是全局定义 所以需要清除 mesh && scene.remove(mesh)3、重新实例化即可

// 初始化先删除子节点let container = document.getElementById('container')if (container.childNodes.length) {container.removeChild(container.childNodes[0])}

轨道控制

`在轨道控制中 全景图方向与鼠标拖拽方向一致 如果需要翻转 则在源码找到`function rotateLeft( angle ) {sphericalDelta.theta -= angle;}function rotateUp( angle ) {sphericalDelta.phi -= angle;}// ---- 修改为 即可修正方向function rotateLeft( angle ) {sphericalDelta.theta += angle;}function rotateUp( angle ) {sphericalDelta.phi += angle;}

import OrbitControls from 'three-orbitcontrols'// 在场景初始化完成后 初始化控制器// 初始化控制器const initcontrols = () => {controls = new OrbitControls(camera, renderer.domElement)console.log(controls,'--controls')//是否可以缩放controls.enableZoom = false//是否自动旋转controls.autoRotate = autoRotate // 动态控制是否制动旋转、// 使动画循环使用时阻尼或自转 意思是否有惯性controls.enableDamping = true;}

锚点添加 关键点 二维视图获取三维场景中的点击坐标 (THREE.Raycaster)

1、获取点击时的坐标位置1-1、 创建场景时绑定 点击事件1-2、在当前相机所正视的世界方向建立 三维向量vector31-3、 根据页面展示大小 设置该向量的x、y 和 z 分量。1-4、(重点)使用 光线投射Raycaster 计算鼠标在三维坐标中点击的坐标位置1-5、传入鼠标点击点击坐标在三维坐标中的中位置信息 2、绘制需要标注的精灵 Sprite在下面代码中可以 有具体添加步骤3、将绘制的精灵添加到 场景 全局 scene

// 鼠標点击添加一个 确定点击位置 -- 锚点 ---待配置 热点图片const onDocumentMouseDown = event => {/*** 1、 camera.target 当前相机所正视的世界空间方向 赋值给 vector* 2、根据配置页面 展示的宽高值 设置XYZ 轴* 3、 vector.unproject(camera) 在投影中使用的摄像机。* 4、 使用 光线投射Raycaster 计算鼠标在三维坐标中点击的坐标位置*这将创建一个新的raycaster对象。* let raycaster = new THREE.Raycaster(* camera.position,* vector.sub(camera.position).normalize() //初始化* )*Raycaster( origin : Vector3, direction : Vector3, near : Float, far : Float ) {origin —— 光线投射的原点向量。direction —— 向射线提供方向的方向向量,应当被标准化。near —— 返回的所有结果比near远。near不能为负值,其默认值为0。far —— 返回的所有结果都比far近。far不能小于near,其默认值为Infinity(正无穷。)* */isUserInteracting = trueif (forType === 'Equirectangular') {event.preventDefault()// let vector = new THREE.Vector3() //三维坐标对象let vector = camera.targetconsole.log(vector, 'vector预计是坐标轴的位置')vector.set(((event.clientX - 248) / (window.innerWidth - 248)) * 2 - 1,-((event.clientY - 32) / (window.innerHeight - 32)) * 2 + 1,0.5)// 在投影中使用的摄像机。vector.unproject(camera)// 这将创建一个新的raycaster对象。let raycaster = new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize() //初始化 光线投射的原点向量)raycaster.camera = camera// 得到 点击的坐标 或 点击的标注点 // intersects 每项中的object 的type 可以分辨 点击的是标注还是 场景图let intersects = raycaster.intersectObjects(scene.children)//如果绘制热点属于激活状态// 此处需要判断 是否有两个坐标为0let isOnShaft = []Object.keys(intersects[0].point).forEach(v => {if (intersects[0].point[v] === 0) {isOnShaft.push(1)}})//---------------------------添加標注-----------------------------------------// 打开添加热点 true 坐标轴中是否存在两坐标为0 打开删除热点开关 为fasleif (refIsHotspot.current && isOnShaft.length < 2 && !refIsDelete.current) {// 绘制热点 //绘制图片有两种方式//一种直接引入 new img//一种使用 canvas /**let canvas = document.createElement('canvas')canvas.style.backgroundColor = 'rgba(255,255,255,0)'let context = canvas.getContext('2d')canvas.width = 128canvas.height = 128context.drawImage(img, 0, 0, 128, 128)*/let img = new Image()img.src = hotspot //( 标注使用的图片) 也可以使用canvas 绘制文字 img.onload = function () {let texture = new THREE.Texture(img)texture.needsUpdate = truetexture.minFilter = THREE.LinearFiltervar spriteMaterial = new THREE.SpriteMaterial({map: texture,transparent: false,})// 创建一个 sprite 物体var sprite = new THREE.Sprite(spriteMaterial)sprite.scale.set(30, 30, 30)let rate = 0.8var endV = new THREE.Vector3(intersects[0].point.x * rate,intersects[0].point.y * rate,intersects[0].point.z * rate)sprite.position.copy(endV)scene.add(sprite)// addHotspot(intersects[0].point) //同步到全局数据}//移除热点} else {if (!refIsDelete.current) returnif (intersects.length > 0) {const target = intersects[0]console.log(!refIsHotspot.current, refIsDelete.current, '删除打印结果')try {if (target.object && target.object.type.length > 0) {if (target.object.type.toLowerCase() === 'sprite') {scene.remove(target.object)}}} catch (e) {console.log(e)}}}}}

初始化 绘制热点

//绘制多个跳转热点const drawJumpHotSpots = (variable, newsrc) => {console.log(variable, '锚点坐标轴数据 参数')variable.forEach(item => {let position = item.point// TextureLoader 异步记载图片var texture = new THREE.TextureLoader().load(gif)// SpriteMaterial 材质var spriteMaterial = new THREE.SpriteMaterial({map: texture,transparent: true,})// 物体 Spritevar sprite = new THREE.Sprite(spriteMaterial)sprite.scale.set(30, 30, 30)/*** 此处添加自定义属性 不能跟原有属性重复避免报错* name: 添加锚点名称* ids: 唯一ID* iconUrl: 图标*/sprite.name = item.namesprite.ids = item.idsprite.iconUrl = ''let rate = 0.8var endV = new THREE.Vector3(position.x * rate, position.y * rate, position.z * rate)sprite.position.copy(endV)scene.add(sprite)})}

操作

纹理图引入图片( 材质 加载图片)

// 方案一、let texture = new THREE.TextureLoader().load(img)// // TextureLoader 异步记载图片var texture = new THREE.TextureLoader().load(gif)// SpriteMaterial 材质var spriteMaterial = new THREE.SpriteMaterial({map: texture,transparent: true,}) // 方案二、let texture = new THREE.Texture(img)texture.needsUpdate = truetexture.minFilter = THREE.LinearFiltervar spriteMaterial = new THREE.SpriteMaterial({map: texture,transparent: false,})// 创建一个 sprite 物体var sprite = new THREE.Sprite(spriteMaterial)

鼠标点击二维坐标 转换三维坐标轴 信息 绘制标注点( Raycaster)

// 我其实也没太理解里面的 API的具体参数// camera.target 全局声明的 透视相机//(event.clientX - 248) / (window.innerWidth - 248)) * 2 - 1// 页面布局 全景图距离左方 248px // (event.clientY - 32) / (window.innerHeight - 32)) * 2 + 1// 页面布局 全景图距离左方32pX// scene.children >>> scene 为全局声明 let scene = new THREE.Scene()let vector = camera.targetconsole.log(vector, 'vector预计是坐标轴的位置')vector.set(((event.clientX - 248) / (window.innerWidth - 248)) * 2 - 1,-((event.clientY - 32) / (window.innerHeight - 32)) * 2 + 1,0.5)// 在投影中使用的摄像机。vector.unproject(camera)// 这将创建一个新的raycaster对象。let raycaster = new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize() //初始化 光线投射的原点向量)raycaster.camera = camera// 得到 点击的坐标 或 点击的标注点 // intersects 每项中的object 的type 可以分辨 点击的是标注还是 场景图点击的坐标点上的 物体let intersects = raycaster.intersectObjects(scene.children)//如果绘制热点属于激活状态// 此处需要判断 是否有两个坐标为0 两个为0 时 添加的锚点会很大let isOnShaft = [] // 是否在坐标轴上Object.keys(intersects[0].point).forEach(v => {if (intersects[0].point[v] === 0) {isOnShaft.push('靓仔')}})

坐标轴展示 开发实用(AxesHelper)

// 三维坐标轴 坐标轴长度var axesHelper = new THREE.AxesHelper(150);scene.add(axesHelpe r);

数据格式设计

panoramicData: [{name: '会所',id: '2102271653',url: 'huisuo',active: true,// 锚点信息anchorPoint: [{point: {x: 180.01349809670057,y: 15.79023683858044,z: 465.07418151652786,},id: '2102091411',name: '海边',iconUrl: 'haibian',},{point: {x: 247.4793362659326,y: -189.1800093391692,z: 390.2798175065487,},id: '02181619',name: '客厅',iconUrl: 'keting',},],},{name: '海边',id: '2102091411',url: 'haibian',active: false,autoRotate: false,// 锚点信息anchorPoint: [{point: {x: 374.5454984418328,y: -5.458415157221607,z: 330.55353704327746,},id: '02181621',name: '豪宅',iconUrl: 'haozhai',},{point: {x: 140.18787952741366,y: -97.9969695393665,z: 468.933553788003,},id: '02181619',name: '客厅',iconUrl: 'keting',},],},{name: '客厅',id: '02181619',url: 'keting',active: false,autoRotate: false,// 锚点信息anchorPoint: [{point: {x: 481.8527362463277,y: -24.6389543862957,z: 127.17004633132723,},id: '2102271653',name: '会所',iconUrl: 'huisuo',},{point: {x: 347.09301641855546,y: -109.56249057173801,z: 341.54549425701236,},id: '2102091411',name: '海边',iconUrl: 'haibian',},],},{name: '豪宅',id: '02181621',url: 'haozhai',active: false,autoRotate: false,// 锚点信息anchorPoint: [{point: {x: 85.2120582814672,y: -0.4428222360704279,z: 492.0249309249495,},id: '2102271653',name: '会所',iconUrl: 'huisuo',},{point: {x: 441.06070438164795,y: -157.51582618415583,z: 173.01486267642798,},id: '2102091411',name: '海边',iconUrl: 'haibian',},],},],

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。