diff --git a/src/jlmap3d/lesson3d/lesson3dplayer.js b/src/jlmap3d/lesson3d/lesson3dplayer.js new file mode 100644 index 000000000..5273dd56d --- /dev/null +++ b/src/jlmap3d/lesson3d/lesson3dplayer.js @@ -0,0 +1,88 @@ +import store from '@/store/index'; +// import { Loading } from 'element-ui'; +import {Stats} from '@/jlmap3d/main/lib/stats.min.js'; +//静态资源文件路径 +import { JL3D_LOCAL_STATIC } from '@/api/jlmap3d/assets3d.js'; +//loader +import { FBXLoader } from '@/jlmap3d/main/loaders/FBXLoader'; +//轨道视角控制 +import { OrbitControls } from '@/jlmap3d/main/control/OrbitControls'; +//骨骼动画模型辅助工具 +import { SkeletonUtils } from '@/jlmap3d/main/utils/SkeletonUtils.js'; + +import { AssetModelManager } from '@/jlmap3d/lesson3d/manager/assetmodelmanager.js'; + +import { ControlManager } from '@/jlmap3d/lesson3d/manager/controlmanager.js'; + +// import { AnimationManager } from '@/jlmap3d/lesson3d/manager/assetmodelmanager.js'; + + +//动画播放相关 +let clock = new THREE.Clock(); +let delta; + +let scene; + +export function Lesson3dPlayer(dom,lessonData,lessonIndex) { + + // let stats = new Stats(); + // dom.appendChild( stats.dom ); + + let scope = this; + this.dom = dom; + + //定义相机 + + + //定义场景(渲染容器) + scene = new THREE.Scene(); + scene.background = new THREE.Color(0xa0a0a0); + + //定义全局光 + let ambientLight = new THREE.AmbientLight(0xffffff, 1.3); + scene.add(ambientLight); + var light = new THREE.HemisphereLight( 0xffffff, 0x444444 ); + light.position.set( 0, 4000, 0 ); + scene.add( light ); + + let controlManager = new ControlManager( dom,scene,lessonData,lessonIndex); + + let assetModelManager = new AssetModelManager(scene,controlManager); + assetModelManager.lessonAssetsLoader(lessonData.assetList,lessonData.modelList).then((result) => { + controlManager.initOctree(assetModelManager.loadAsset['default1'].mesh); + + animate(); + console.log(lessonData.lessonProgress[lessonIndex]); + if(lessonData.lessonProgress[lessonIndex].action.length>0){ + controlManager.initNewEvent(lessonData.lessonProgress[lessonIndex].action,assetModelManager.lessonTriggerList); + } + resolve("loadeend"); //['成功了', 'success'] + }).catch((error) => { + //console.log(error); + });; + + + + this.actionRemove = function(actionModel){ + assetModelManager.otherModel.remove(actionModel); + } + + + + //循环渲染函数 + function animate() { + + if(controlManager.controlMode == "free"){ + controlManager.updateOrbitControl(); + } + if(controlManager.controlMode == "fps"){ + controlManager.updateFpsControl(); + } + // delta = clock.getDelta(); + requestAnimationFrame(animate); + + } + + this.attachModel = function(selectModel){ + } +} diff --git a/src/jlmap3d/lesson3d/manager/assetmodelmanager.js b/src/jlmap3d/lesson3d/manager/assetmodelmanager.js new file mode 100644 index 000000000..81012032f --- /dev/null +++ b/src/jlmap3d/lesson3d/manager/assetmodelmanager.js @@ -0,0 +1,160 @@ +import { BASE_ASSET_API } from '@/api/jlmap3d/assets3d.js'; + +export function AssetModelManager(scene) { + let scope = this; + + + this.assetList = []; + + this.otherModel = new THREE.Group(); + + scene.add(this.otherModel); + + this.loadAsset = []; + + this.loadAsset['default1'] = { + modelId:'default1', + packageName:"车站", + url:"/MODEL/2021-04-06/1381-54584.FBX", + mesh:"", + assetType:'default', + isUse:true, + resourceType:"三维课程", + }; + + //场景中可触发事件模型 + this.lessonTriggerList = []; + + //加载课程资源 + this.lessonAssetsLoader = function(assetList,modelList){ + let initlist = []; + if(assetList){ + for(let i = 0;i { + + initTriggerList(); + for(let i=0;i { + //console.log(error); + }); + + }); + resolve("loaderassets"); + + } + + + + // + // + // + // + // + //FT 扶梯 + //FTAN 扶梯按钮(急停) + //FTD 扶梯灯 + //FTKG 扶梯开关(钥匙孔) + //FTTJ 扶梯台阶 + function initTriggerList(){ + + scope.loadAsset['default1'].mesh.getObjectByName("FTAN").showType = "default"; + scope.loadAsset['default1'].mesh.getObjectByName("FTAN").label = "扶梯急停按钮"; + scope.lessonTriggerList.push(scope.loadAsset['default1'].mesh.getObjectByName("FTAN")); + + scope.loadAsset['default1'].mesh.getObjectByName("FTKG").showType = "default"; + scope.loadAsset['default1'].mesh.getObjectByName("FTKG").label = "扶梯钥匙孔"; + scope.lessonTriggerList.push(scope.loadAsset['default1'].mesh.getObjectByName("FTKG")); + + + // console.log(scope.loadAsset['default1'].mesh.getObjectByName("FTKG")); + } + + //动态加载资源 + this.lessonAssetsNewLoader = function(assetData,pos){ + let isLoaded = false; + + if(scope.loadAsset[assetData.id]){ + let newModelTrigger = scope.loadAsset[assetData.id].mesh.clone(true); + newModelTrigger.modelId = assetData.id; + newModelTrigger.showType = "loadModel"; + newModelTrigger.label = assetData.packageName; + newModelTrigger.position.copy(pos); + scope.otherModel.add(newModelTrigger); + scope.lessonTriggerList.push(newModelTrigger); + updateTriggerList(scope.lessonTriggerList); + }else{ + scope.loadAsset[assetData.id] = { + modelId:assetData.id, + packageName:assetData.packageName, + url:assetData.url, + mesh:"", + assetType:'loadModel', + isUse:true, + resourceType:"三维课程", + }; + + fbxpromise(scope.loadAsset[assetData.id]).then(function(object){ + + let newModelTrigger = scope.loadAsset[assetData.id].mesh.clone(true); + newModelTrigger.showType = "loadModel"; + newModelTrigger.modelId = assetData.id; + newModelTrigger.label = assetData.packageName; + newModelTrigger.position.copy(pos); + scope.otherModel.add(newModelTrigger); + scope.lessonTriggerList.push(newModelTrigger); + + updateTriggerList(scope.lessonTriggerList); + // resolve("loadednew"); + }); + } + } + + + //fbx模型加载 + function fbxpromise(asset){ + return new Promise(function(resolve, reject){ + var loader = new THREE.FBXLoader(); + loader.load( BASE_ASSET_API+asset.url, function ( object ) { + + if(asset.assetType == "default"){ + scene.add(object); + }else if(asset.assetType == 'loadModel'){ + + } + object.label = asset.packageName; + asset.mesh = object; + resolve(); + } ); + + }); + } + +} diff --git a/src/jlmap3d/lesson3d/manager/controlmanager.js b/src/jlmap3d/lesson3d/manager/controlmanager.js new file mode 100644 index 000000000..e306df16b --- /dev/null +++ b/src/jlmap3d/lesson3d/manager/controlmanager.js @@ -0,0 +1,403 @@ + +import { Capsule } from '@/jlmap3d/lesson3d/math/Capsule.js'; + +import { Octree } from '@/jlmap3d/lesson3d/math/Octree.js'; + +export function ControlManager(dom,scene,lessonData,lessonIndex) { + + let scope = this; + this.controlMode = ""; + this.controls = {}; + this.nowCamera = null; + this.eventHitMode = false; + + let eventBoxs = []; + + + + let renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setClearColor(new THREE.Color(0x000000)); + renderer.setViewport( 0, 0, dom.offsetWidth, dom.offsetHeight); + renderer.setScissor( 0, 0, dom.offsetWidth, dom.offsetHeight); + renderer.setScissorTest( false ); + renderer.setSize(dom.offsetWidth, dom.offsetHeight); + renderer.sortObjects = true; + dom.appendChild(renderer.domElement); + + let orbitCamera = new THREE.PerspectiveCamera(70, dom.offsetWidth / dom.offsetHeight, 0.01, 1000); + orbitCamera.position.set(0, 80, 40); + orbitCamera.aspect = dom.offsetWidth / dom.offsetHeight; + orbitCamera.updateProjectionMatrix(); + + let oribitControl = new THREE.OrbitControls(orbitCamera,dom); + oribitControl.maxPolarAngle = Math.PI / 2; + oribitControl.minPolarangle = Math.PI / 5; + oribitControl.maxDistance = 800; + oribitControl.screenSpacePanning = true; + oribitControl.update(); + + + let fpsCamera = new THREE.PerspectiveCamera( 75,dom.offsetWidth / dom.offsetHeight, 0.1, 1000 ); + fpsCamera.aspect = dom.offsetWidth / dom.offsetHeight; + fpsCamera.rotation.order = 'YXZ'; + + let attachBox = new THREE.Mesh( + new THREE.BoxGeometry(1, 5, 1), + new THREE.MeshBasicMaterial({color: 0xff00000})//RED box + ); + let hitBox = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3()); + hitBox.setFromObject(attachBox); + scene.add(attachBox); + + //fps control + const GRAVITY = 30; + + const NUM_SPHERES = 20; + const SPHERE_RADIUS = 0.2; + + const sphereGeometry = new THREE.SphereGeometry( SPHERE_RADIUS, 32, 32 ); + const sphereMaterial = new THREE.MeshStandardMaterial( { color: 0x888855, roughness: 0.8, metalness: 0.5 } ); + + const spheres = []; + let sphereIdx = 0; + + for ( let i = 0; i < NUM_SPHERES; i ++ ) { + + const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial ); + + + scene.add( sphere ); + + spheres.push( { mesh: sphere, collider: new THREE.Sphere( new THREE.Vector3( 0, - 100, 0 ), SPHERE_RADIUS ), velocity: new THREE.Vector3() } ); + + } + + scope.controlMode = lessonData.lessonProgress[lessonIndex].controlMode; + // scope.controls = oribitControl; + if(scope.controlMode == "free"){ + scope.nowCamera = orbitCamera; + scope.controls.enabled = true; + }else if(scope.controlMode == "fps"){ + scope.nowCamera = fpsCamera; + scope.controls.enabled = false; + } + + + + const worldOctree = new Octree(); + + const playerCollider = new Capsule( new THREE.Vector3( 0, 10, 0 ), new THREE.Vector3( 0, 11.9, 0 ), 1 ); + playerCollider.set( + new THREE.Vector3( + lessonData.lessonProgress[lessonIndex].cameraPosition.x, + lessonData.lessonProgress[lessonIndex].cameraPosition.y, + lessonData.lessonProgress[lessonIndex].cameraPosition.z), + new THREE.Vector3( + lessonData.lessonProgress[lessonIndex].cameraPosition.x, + lessonData.lessonProgress[lessonIndex].cameraPosition.y+1.5, + lessonData.lessonProgress[lessonIndex].cameraPosition.z ), 1); + attachBox.position.x = lessonData.lessonProgress[lessonIndex].cameraPosition.x; + attachBox.position.y = lessonData.lessonProgress[lessonIndex].cameraPosition.y ; + attachBox.position.z = lessonData.lessonProgress[lessonIndex].cameraPosition.z; + + + + + const playerVelocity = new THREE.Vector3(); + const playerDirection = new THREE.Vector3(); + + let playerOnFloor = false; + + const keyStates = {}; + let clock = new THREE.Clock(); + + this.updateOrbitControl = function(){ + oribitControl.update(); + }; + + this.updateFpsControl = function(){ + const deltaTime = Math.min( 0.1, clock.getDelta() ); + + controls( deltaTime ); + + updatePlayer( deltaTime ); + + updateSpheres( deltaTime ); + + if(scope.eventHitMode == true){ + if(eventBoxs.length>0){ + + attachBox.position.copy(fpsCamera.position); + for(let i=0;i { + + keyStates[ event.code ] = true; + + } ); + + document.addEventListener( 'keyup', ( event ) => { + + keyStates[ event.code ] = false; + + } ); + let fpsMouseStatus = false; + document.addEventListener( 'mousedown', () => { + fpsMouseStatus = true; + // document.body.requestPointerLock(); + } ); + + document.body.addEventListener( 'mousemove', ( event ) => { + if(fpsMouseStatus == true){ + fpsCamera.rotation.y -= event.movementX / 500; + fpsCamera.rotation.x -= event.movementY / 500; + } + // if ( document.pointerLockElement === document.body ) { + // } + } ); + + document.addEventListener( 'mouseup', () => { + fpsMouseStatus = false; + } ); + + + function playerCollitions() { + + const result = worldOctree.capsuleIntersect( playerCollider ); + + playerOnFloor = false; + + if ( result ) { + + playerOnFloor = result.normal.y > 0; + + if ( ! playerOnFloor ) { + + playerVelocity.addScaledVector( result.normal, - result.normal.dot( playerVelocity ) ); + + } + + playerCollider.translate( result.normal.multiplyScalar( result.depth ) ); + + } + + } + + function updatePlayer( deltaTime ) { + + if ( playerOnFloor ) { + + const damping = Math.exp( - 3 * deltaTime ) - 1; + playerVelocity.addScaledVector( playerVelocity, damping ); + + } else { + + playerVelocity.y -= GRAVITY * deltaTime; + + } + + const deltaPosition = playerVelocity.clone().multiplyScalar( deltaTime ); + playerCollider.translate( deltaPosition ); + + playerCollitions(); + + fpsCamera.position.copy( playerCollider.end ); + + } + + function spheresCollisions() { + + for ( let i = 0; i < spheres.length; i ++ ) { + + const s1 = spheres[ i ]; + + for ( let j = i + 1; j < spheres.length; j ++ ) { + + const s2 = spheres[ j ]; + + const d2 = s1.collider.center.distanceToSquared( s2.collider.center ); + const r = s1.collider.radius + s2.collider.radius; + const r2 = r * r; + + if ( d2 < r2 ) { + + const normal = s1.collider.clone().center.sub( s2.collider.center ).normalize(); + const v1 = normal.clone().multiplyScalar( normal.dot( s1.velocity ) ); + const v2 = normal.clone().multiplyScalar( normal.dot( s2.velocity ) ); + s1.velocity.add( v2 ).sub( v1 ); + s2.velocity.add( v1 ).sub( v2 ); + + const d = ( r - Math.sqrt( d2 ) ) / 2; + + s1.collider.center.addScaledVector( normal, d ); + s2.collider.center.addScaledVector( normal, - d ); + + } + + } + + } + + } + + function updateSpheres( deltaTime ) { + + spheres.forEach( sphere =>{ + + sphere.collider.center.addScaledVector( sphere.velocity, deltaTime ); + + const result = worldOctree.sphereIntersect( sphere.collider ); + + if ( result ) { + + sphere.velocity.addScaledVector( result.normal, - result.normal.dot( sphere.velocity ) * 1.5 ); + sphere.collider.center.add( result.normal.multiplyScalar( result.depth ) ); + + } else { + + sphere.velocity.y -= GRAVITY * deltaTime; + + } + + const damping = Math.exp( - 1.5 * deltaTime ) - 1; + sphere.velocity.addScaledVector( sphere.velocity, damping ); + + spheresCollisions(); + + sphere.mesh.position.copy( sphere.collider.center ); + + } ); + + } + + function getForwardVector() { + + fpsCamera.getWorldDirection( playerDirection ); + playerDirection.y = 0; + playerDirection.normalize(); + + return playerDirection; + + } + + function getSideVector() { + + fpsCamera.getWorldDirection( playerDirection ); + playerDirection.y = 0; + playerDirection.normalize(); + playerDirection.cross( fpsCamera.up ); + + return playerDirection; + + } + + function controls( deltaTime ) { + + const speed = 25; + + if ( playerOnFloor ) { + + if ( keyStates[ 'KeyW' ] ) { + + playerVelocity.add( getForwardVector().multiplyScalar( speed * deltaTime ) ); + + } + + if ( keyStates[ 'KeyS' ] ) { + + playerVelocity.add( getForwardVector().multiplyScalar( - speed * deltaTime ) ); + + } + + if ( keyStates[ 'KeyA' ] ) { + + playerVelocity.add( getSideVector().multiplyScalar( - speed * deltaTime ) ); + + } + + if ( keyStates[ 'KeyD' ] ) { + + playerVelocity.add( getSideVector().multiplyScalar( speed * deltaTime ) ); + + } + + + + } + + } + + function render(){ + + if(scope.nowCamera){ + renderer.render( scene, scope.nowCamera ); + } + } + window.onresize = function () { + renderer.setSize(dom.offsetWidth,dom.offsetHeight); + } + + this.initNewEvent = function(actions,lessonTriggerList){ + console.log(actions); + console.log(lessonTriggerList); + eventBoxs = []; + for(let i=0;i 8 && level < 16 ) { + + subTrees[ i ].split( level + 1 ); + + } + + if ( len != 0 ) { + + this.subTrees.push( subTrees[ i ] ); + + } + + } + + return this; + + }, + + build: function () { + + this.calcBox(); + this.split( 0 ); + + return this; + + }, + + getRayTriangles: function ( ray, triangles ) { + + for ( var i = 0; i < this.subTrees.length; i ++ ) { + + var subTree = this.subTrees[ i ]; + if ( ! ray.intersectsBox( subTree.box ) ) continue; + + if ( subTree.triangles.length > 0 ) { + + for ( var j = 0; j < subTree.triangles.length; j ++ ) { + + if ( triangles.indexOf( subTree.triangles[ j ] ) === - 1 ) triangles.push( subTree.triangles[ j ] ); + + } + + } else { + + subTree.getRayTriangles( ray, triangles ); + + } + + } + + return triangles; + + }, + + triangleCapsuleIntersect: function ( capsule, triangle ) { + + var point1, point2, line1, line2; + + triangle.getPlane( _plane ); + + var d1 = _plane.distanceToPoint( capsule.start ) - capsule.radius; + var d2 = _plane.distanceToPoint( capsule.end ) - capsule.radius; + + if ( ( d1 > 0 && d2 > 0 ) || ( d1 < - capsule.radius && d2 < - capsule.radius ) ) { + + return false; + + } + + var delta = Math.abs( d1 / ( Math.abs( d1 ) + Math.abs( d2 ) ) ); + var intersectPoint = _v1.copy( capsule.start ).lerp( capsule.end, delta ); + + if ( triangle.containsPoint( intersectPoint ) ) { + + return { normal: _plane.normal.clone(), point: intersectPoint.clone(), depth: Math.abs( Math.min( d1, d2 ) ) }; + + } + + var r2 = capsule.radius * capsule.radius; + + line1 = _line1.set( capsule.start, capsule.end ); + + var lines = [ + [ triangle.a, triangle.b ], + [ triangle.b, triangle.c ], + [ triangle.c, triangle.a ] + ]; + + for ( var i = 0; i < lines.length; i ++ ) { + + line2 = _line2.set( lines[ i ][ 0 ], lines[ i ][ 1 ] ); + + [ point1, point2 ] = capsule.lineLineMinimumPoints( line1, line2 ); + + if ( point1.distanceToSquared( point2 ) < r2 ) { + + return { normal: point1.clone().sub( point2 ).normalize(), point: point2.clone(), depth: capsule.radius - point1.distanceTo( point2 ) }; + + } + + } + + return false; + + }, + + triangleSphereIntersect: function ( sphere, triangle ) { + + triangle.getPlane( _plane ); + + if ( ! sphere.intersectsPlane( _plane ) ) return false; + + var depth = Math.abs( _plane.distanceToSphere( sphere ) ); + var r2 = sphere.radius * sphere.radius - depth * depth; + + var plainPoint = _plane.projectPoint( sphere.center, _v1 ); + + if ( triangle.containsPoint( sphere.center ) ) { + + return { normal: _plane.normal.clone(), point: plainPoint.clone(), depth: Math.abs( _plane.distanceToSphere( sphere ) ) }; + + } + + var lines = [ + [ triangle.a, triangle.b ], + [ triangle.b, triangle.c ], + [ triangle.c, triangle.a ] + ]; + + for ( var i = 0; i < lines.length; i ++ ) { + + _line1.set( lines[ i ][ 0 ], lines[ i ][ 1 ] ); + _line1.closestPointToPoint( plainPoint, true, _v2 ); + + var d = _v2.distanceToSquared( sphere.center ); + + if ( d < r2 ) { + + return { normal: sphere.center.clone().sub( _v2 ).normalize(), point: _v2.clone(), depth: sphere.radius - Math.sqrt( d ) }; + + } + + } + + return false; + + }, + + getSphereTriangles: function ( sphere, triangles ) { + + for ( var i = 0; i < this.subTrees.length; i ++ ) { + + var subTree = this.subTrees[ i ]; + + if ( ! sphere.intersectsBox( subTree.box ) ) continue; + + if ( subTree.triangles.length > 0 ) { + + for ( var j = 0; j < subTree.triangles.length; j ++ ) { + + if ( triangles.indexOf( subTree.triangles[ j ] ) === - 1 ) triangles.push( subTree.triangles[ j ] ); + + } + + } else { + + subTree.getSphereTriangles( sphere, triangles ); + + } + + } + + }, + + getCapsuleTriangles: function ( capsule, triangles ) { + + for ( var i = 0; i < this.subTrees.length; i ++ ) { + + var subTree = this.subTrees[ i ]; + + if ( ! capsule.intersectsBox( subTree.box ) ) continue; + + if ( subTree.triangles.length > 0 ) { + + for ( var j = 0; j < subTree.triangles.length; j ++ ) { + + if ( triangles.indexOf( subTree.triangles[ j ] ) === - 1 ) triangles.push( subTree.triangles[ j ] ); + + } + + } else { + + subTree.getCapsuleTriangles( capsule, triangles ); + + } + + } + + }, + + sphereIntersect( sphere ) { + + _sphere.copy( sphere ); + + var triangles = [], result, hit = false; + + this.getSphereTriangles( sphere, triangles ); + + for ( var i = 0; i < triangles.length; i ++ ) { + + if ( result = this.triangleSphereIntersect( _sphere, triangles[ i ] ) ) { + + hit = true; + + _sphere.center.add( result.normal.multiplyScalar( result.depth ) ); + + } + + } + + if ( hit ) { + + var collisionVector = _sphere.center.clone().sub( sphere.center ); + var depth = collisionVector.length(); + + return { normal: collisionVector.normalize(), depth: depth }; + + } + + return false; + + }, + + capsuleIntersect: function ( capsule ) { + + _capsule.copy( capsule ); + + var triangles = [], result, hit = false; + + this.getCapsuleTriangles( _capsule, triangles ); + + for ( var i = 0; i < triangles.length; i ++ ) { + + if ( result = this.triangleCapsuleIntersect( _capsule, triangles[ i ] ) ) { + + hit = true; + + _capsule.translate( result.normal.multiplyScalar( result.depth ) ); + + } + + } + + if ( hit ) { + + var collisionVector = _capsule.getCenter( new THREE.Vector3() ).sub( capsule.getCenter( _v1 ) ); + var depth = collisionVector.length(); + + return { normal: collisionVector.normalize(), depth: depth }; + + } + + return false; + + }, + + rayIntersect: function ( ray ) { + + if ( ray.direction.length() === 0 ) return; + + var triangles = [], triangle, position, + distance = 1e100, + result; + + this.getRayTriangles( ray, triangles ); + + for ( var i = 0; i < triangles.length; i ++ ) { + + result = ray.intersectTriangle( triangles[ i ].a, triangles[ i ].b, triangles[ i ].c, true, _v1 ); + + if ( result ) { + + var newdistance = result.sub( ray.origin ).length(); + + if ( distance > newdistance ) { + + position = result.clone().add( ray.origin ); + distance = newdistance; + triangle = triangles[ i ]; + + } + + } + + } + + return distance < 1e100 ? { distance: distance, triangle: triangle, position: position } : false; + + }, + + fromGraphNode: function ( group ) { + + group.traverse( ( obj ) => { + + if ( obj.type === 'Mesh' ) { + + obj.updateMatrix(); + obj.updateWorldMatrix(); + + var geometry, isTemp = false; + + if ( obj.geometry.index ) { + + isTemp = true; + geometry = obj.geometry.clone().toNonIndexed(); + + } else { + + geometry = obj.geometry; + + } + + var positions = geometry.attributes.position.array; + var transform = obj.matrixWorld; + + for ( var i = 0; i < positions.length; i += 9 ) { + + var v1 = new THREE.Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); + var v2 = new THREE.Vector3( positions[ i + 3 ], positions[ i + 4 ], positions[ i + 5 ] ); + var v3 = new THREE.Vector3( positions[ i + 6 ], positions[ i + 7 ], positions[ i + 8 ] ); + + v1.applyMatrix4( transform ); + v2.applyMatrix4( transform ); + v3.applyMatrix4( transform ); + + this.addTriangle( new THREE.Triangle( v1, v2, v3 ) ); + + } + + if ( isTemp ) { + + geometry.dispose(); + + } + + } + + } ); + + this.build(); + + return this; + + } + + } ); + + return Octree; + +} )(); + +export { Octree }; diff --git a/src/jlmap3d/lesson3d/model/lessondata.js b/src/jlmap3d/lesson3d/model/lessondata.js new file mode 100644 index 000000000..96cc06a5b --- /dev/null +++ b/src/jlmap3d/lesson3d/model/lessondata.js @@ -0,0 +1,177 @@ + +export function LessonData() { + let scope = this; + + this.lessonId = ""; + this.lessonName = ""; + this.lessonType = ""; + this.lessonStatus = ""; + this.lessonData = { + //资源列表 + assetList:[], + //场景交互物体列表 + modelList:[], + //课程组件启用状态 + lessonTools:[], + dataType:"", + toolJobPane:[], + //课程内容 + lessonProgress:[ + + ] + }; + + this.initLessonProgress = function(){ + let newLessonProgress = { + id:generateUUID(), + progressName:"命名", + roleName:"", + roleUse:true, + + progressScene:"", + nextCode:"", + nextNode:"", + triggerType:"", + triggerMode:"", + triggerTime:"", + triggerModel:"", + controlMode:"", + cameraMode:"", + changeCamera:false, + cameraPosition:{ + x:0, + y:0, + z:0 + }, + cameraTarget:{ + x:0, + y:0, + z:0 + }, + assetId:scope.lessonData.lessonProgress.length, + assetPos:"", + assetRot:"", + assetType:"", + index:"", + stepTipsData:{ + tittle:"标题", + text:"内容", + }, + explainPane:{ + tittle:"标题", + picurl:"url", + text:"内容", + }, + action:[], + }; + + scope.lessonData.lessonProgress.push(newLessonProgress); + + } + + this.loadLessonProgress = function(loadData){ + console.log(loadData); + for(let i=0;i
-
{{element.assetId}}
+
{{element.progressName}}
X
-
+
@@ -33,6 +35,7 @@ import localStore from 'storejs'; import draggable from 'vuedraggable'; + import { JL3D_LOCAL_STATIC } from '@/api/jlmap3d/assets3d.js'; export default { name: 'LessonProgress', @@ -42,6 +45,7 @@ }, data() { return { + localstatic:JL3D_LOCAL_STATIC, activeName: 'progresslist', progressList:[ @@ -89,7 +93,7 @@ deleteModel(selectedModel){ this.$emit('deleteModel',selectedModel); }, - + }, @@ -122,6 +126,7 @@ margin: 20px; float:left; border:solid 2px #000; + background-size: 100%; } .changeprogressdiv{ diff --git a/src/views/jlmap3d/lesson3dedit/component/property.vue b/src/views/jlmap3d/lesson3dedit/component/property.vue index 241450d19..0f4c85944 100644 --- a/src/views/jlmap3d/lesson3dedit/component/property.vue +++ b/src/views/jlmap3d/lesson3dedit/component/property.vue @@ -4,53 +4,83 @@ + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + 重置镜头位置 - 记录初始镜头位置 + 记录初始镜头位置 + + + + + + + + + + + + @@ -59,7 +89,9 @@
{{actionitem.actionName}}
-
添加
+
@@ -69,12 +101,12 @@ - - - + + + @@ -82,7 +114,7 @@ - + @@ -91,6 +123,7 @@ + @@ -98,17 +131,19 @@ - + + 删除事件 +
@@ -118,6 +153,12 @@ + + + + + + @@ -131,19 +172,21 @@ + + - - 保存修改 + 删除联控信息 + @@ -156,6 +199,7 @@ + @@ -184,6 +228,8 @@ import Vue from 'vue'; import localStore from 'storejs'; + import { JobPaneData } from '@/jlmap3d/lesson3dedit/toolsmodel/jobpanedata.js'; + import { JL3D_LOCAL_STATIC } from '@/api/jlmap3d/assets3d.js'; export default { name: 'ProPerty', @@ -193,6 +239,7 @@ }, data() { return { + localstatic:JL3D_LOCAL_STATIC, activeName: 'cameraproperty', selectLesson3dControl:"", selected:"", @@ -204,6 +251,7 @@ actionType:"事件操作类型", actionMode:"触发事件类型", }, + revisionList:[], selectType:"", cameraMode:[ { @@ -217,6 +265,29 @@ label: '自由视角控制' } ], + sceneDataList:[ + { + label:"车站", + value:"standstation", + }, + { + label:"停车场", + value:"stopstation", + }, + { + label:"单体设备", + value:"device", + }, + { + label:"线路", + value:"xl", + }, + { + label:"道岔", + value:"dc", + }, + ], + jobDataList:[], value:'', } }, @@ -230,6 +301,9 @@ window.lesson3dUpdateControl = this.lesson3dUpdateControl; window.lesson3dSelect = this.lesson3dSelect; window.lesson3dUpdatePicurl = this.lesson3dUpdatePicurl; + + let jobList = new JobPaneData(); + this.jobDataList = jobList.dataList; }, beforeDestroy() { @@ -247,7 +321,7 @@ console.log("reset"); this.activeName = 'cameraproperty'; }, - lesson3dSelect(mode,type,obj){ + lesson3dSelect(mode,type,obj,revisionlist){ this.activeName = mode; this.selectType = type; // console.log(this.lessonData.lessonData.lessonProgress[this.lessonEditIndex].stepTipsData); @@ -263,6 +337,7 @@ if(type == "jobpane"){ this.selected = obj; + this.revisionList = revisionlist; } if(type == "modelproperty"){ @@ -274,11 +349,46 @@ updateData(){ // this.lessonData.lessonData.lessonProgress[this.lessonEditIndex].stepTipsData; }, + deleteJobItem(selectedJob){ + console.log(selectedJob); + for(let i=0;i diff --git a/src/views/jlmap3d/lesson3dedit/tools/jobpane.vue b/src/views/jlmap3d/lesson3dedit/tools/jobpane.vue index 11c0375e3..cb0ee8957 100644 --- a/src/views/jlmap3d/lesson3dedit/tools/jobpane.vue +++ b/src/views/jlmap3d/lesson3dedit/tools/jobpane.vue @@ -13,8 +13,12 @@
-
{{itemin.text}}
-
添加
+
+ {{itemin.text}} +
+
@@ -39,6 +43,7 @@ }, data() { return { + localstatic:JL3D_LOCAL_STATIC, jobList:[], showJobList:false, showJob:false, @@ -79,17 +84,30 @@ }, addjob(index){ this.selectedJob.controlList[index].data.push({ - cname:"1", + cname:this.generateUUID(), text:"123", + explainRole:"角色", nextNode:"null", sceneId:this.lessonData.lessonData.lessonProgress[this.lessonEditIndex].id, type:"", }); }, - selsectJobTool(selectTool){ - lesson3dSelect('toolproperty','jobpane',selectTool); + selsectJobTool(selectTool,jobList){ + lesson3dSelect('toolproperty','jobpane',selectTool,jobList); console.log(selectTool); }, + generateUUID() { + var d = new Date().getTime(); + if (window.performance && typeof window.performance.now === "function") { + d += performance.now(); //use high-precision timer if available + } + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + return uuid; + }, }, } @@ -195,12 +213,16 @@ border:solid 2px #000; } + .addjobdiv{ width:98%; - height:50px; + height:64px; margin: 1%; border:solid 2px #000; + background-repeat: no-repeat; } + + diff --git a/src/views/jlmap3d/lesson3dedit/tools/toolbar.vue b/src/views/jlmap3d/lesson3dedit/tools/toolbar.vue index 0ca06a3d0..9ea25ca9d 100644 --- a/src/views/jlmap3d/lesson3dedit/tools/toolbar.vue +++ b/src/views/jlmap3d/lesson3dedit/tools/toolbar.vue @@ -135,7 +135,7 @@ bottom:0; border-radius:10px; border:solid 2px #000; - background-color: #fff; + // background-color: #fff; z-index:1; } diff --git a/src/views/jlmap3d/lesson3dplayer/lesson3dplayer.vue b/src/views/jlmap3d/lesson3dplayer/lesson3dplayer.vue index 8d60af054..aa1c5dce7 100644 --- a/src/views/jlmap3d/lesson3dplayer/lesson3dplayer.vue +++ b/src/views/jlmap3d/lesson3dplayer/lesson3dplayer.vue @@ -5,29 +5,29 @@
+ :lessonPlayIndex='lessonPlayIndex' + v-show="lessonTools[0].isShow && lessonData.lessonData.lessonProgress[lessonPlayIndex].progressScene == 'standstation'"> + v-show="lessonTools[1].isShow && lessonData.lessonData.lessonProgress[lessonPlayIndex].progressScene == 'standstation'"> + :lessonPlayIndex='lessonPlayIndex' + v-show="lessonTools[2].isShow && lessonData.lessonData.lessonProgress[lessonPlayIndex].progressScene == 'standstation'"> + v-show="lessonTools[3].isShow && lessonData.lessonData.lessonProgress[lessonPlayIndex].progressScene == 'standstation'"> - +
@@ -50,10 +50,10 @@ import ToolBar from '@/views/jlmap3d/lesson3dplayer/tools/toolbar'; - import { Lesson3dEditor } from '@/jlmap3d/lesson3dedit/lesson3deditor.js'; + import { Lesson3dPlayer } from '@/jlmap3d/lesson3d/lesson3dplayer.js'; - import { LessonData } from '@/jlmap3d/lesson3dedit/model/lessondata.js'; - import { JobPaneData } from '@/jlmap3d/lesson3dedit/toolsmodel/jobpanedata.js'; + import { LessonData } from '@/jlmap3d/lesson3d/model/lessondata.js'; + import { JobPaneData } from '@/jlmap3d/lesson3d/toolsmodel/jobpanedata.js'; import { getLesson3dData,updateLesson3dData } from '@/api/jmap/lesson3d'; export default { @@ -85,7 +85,7 @@ } }, jobPaneData:{}, - lessonEditIndex:0, + lessonPlayIndex:0, lessonTools:[ { name:"步骤组件", @@ -118,7 +118,8 @@ }, mounted() { window.updateTriggerList = this.updateTriggerList; - + window.jumpEvent = this.jumpEvent; + window.actionEvent = this.actionEvent; this.init(this.$route.query.lessonId); }, beforeDestroy() { @@ -138,7 +139,6 @@ let loadData; if(data.data.data){ loadData = JSON.parse(data.data.data); - console.log(loadData); this.jobPaneData.dataList = loadData.toolJobPane; this.$refs.jobpane.initJobList(this.jobPaneData.dataList); @@ -151,7 +151,7 @@ } console.log("loaddata----------------"); console.log(loadData); - this.jl3d = new Lesson3dEditor(dom,loadData); + this.jl3d = new Lesson3dPlayer(dom,loadData,this.lessonPlayIndex); }).catch(() => { }); }, @@ -173,7 +173,19 @@ }); }, - + jumpEvent(type,action){ + if(type == "action"){ + this.lessonPlayIndex = action.jumpNode; + } + if(type == "tools"){ + this.lessonPlayIndex = action.nextNode; + } + }, + actionEvent(type,action,mesh){ + if(type == "remove"){ + this.jl3d.actionRemove(mesh); + } + }, updateTriggerList(newTriggerList){ this.triggerList = newTriggerList; console.log(this.triggerList); diff --git a/src/views/jlmap3d/lesson3dplayer/tools/explainpane.vue b/src/views/jlmap3d/lesson3dplayer/tools/explainpane.vue index e24bb0413..16a517781 100644 --- a/src/views/jlmap3d/lesson3dplayer/tools/explainpane.vue +++ b/src/views/jlmap3d/lesson3dplayer/tools/explainpane.vue @@ -1,13 +1,16 @@ @@ -19,13 +22,14 @@ export default { name: 'ExplainPane', - props:['lessonData','lessonEditIndex'], + props:['lessonData','lessonPlayIndex'], components: { }, data() { return { localStatic:BASE_ASSET_API, + lessonbg:JL3D_LOCAL_STATIC+"/lesson3d/lessonbg.png", } }, computed: { @@ -60,7 +64,7 @@ top:0; border-radius:10px; border:solid 2px #000; - background-color: #fff; + color:#fff; z-index:1; } .explainpanetittle{ @@ -70,12 +74,18 @@ } .explainpanepic{ + position:relative; + width:90%; + left:5%; height:65%; border:solid 2px #000; background-size: 100%; } .explainpanetext{ + position:relative; + left:5%; + width:90%; font-size: 14px; // height:20%; } diff --git a/src/views/jlmap3d/lesson3dplayer/tools/jobpane.vue b/src/views/jlmap3d/lesson3dplayer/tools/jobpane.vue index 11c0375e3..a06bf00a2 100644 --- a/src/views/jlmap3d/lesson3dplayer/tools/jobpane.vue +++ b/src/views/jlmap3d/lesson3dplayer/tools/jobpane.vue @@ -1,20 +1,36 @@