赞
踩
效果:
先看最基本的
- function initThree(el, options) {
- options = options || {}
- const t = this
- appInstance = this
- const width = el.offsetWidth
- const height = el.offsetHeight
- const asp = width / height
-
- // scene
- const scene = new THREE.Scene()
-
- // camera
- let camera
- if (options.camera) {
- camera = options.camera
- } else {
- camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
- window.addEventListener('resize', function() {
- camera.aspect = el.offsetWidth / el.offsetHeight
- renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
- camera.updateProjectionMatrix()
- renderer.render(scene, camera)
- }, false)
- }
- camera.position.set(30, 30, 30)
-
- // renderer
- const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
- renderer.setPixelRatio(window.devicePixelRatio)
- renderer.setSize(width, height)
- el.append(renderer.domElement)
- renderer.setClearColor(options.clearColor || '#000')
-
- // 辅助
- if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
- if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线
-
- //按序渲染
- renderer.sortObjects = options.sortObjects
-
- // to the instance
- t.renderer = renderer
- t.scene = scene
- t.camera = camera
- t.el = el
- }
-
- const el = document.getElementById('box')
-
- const app = new initThree(el,{
- // gridHelper:true,//网格参考线
- // axes:true,//坐标辅助
- clearColor:'#000'//画布颜色
- })
- const camera = app.camera
- const renderer = app.renderer
- const scene = app.scene
- function initControls(scene,camera,renderer) {
- const controls = new THREE.OrbitControls( camera, renderer.domElement );
- // 如果使用animate方法时,将此函数删除
- controls.addEventListener( 'change', ()=>{
- renderer.render( scene, camera );
- });
- // // 使动画循环使用时阻尼或自转 意思是否有惯性
- // controls.enableDamping = true;
- // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
- // //controls.dampingFactor = 0.25;
- // //是否可以缩放
- // controls.enableZoom = true;
- // //是否自动旋转
- // controls.autoRotate = true;
- // controls.autoRotateSpeed = 0.5;
- // //设置相机距离原点的最远距离
- // controls.minDistance = 1;
- // //设置相机距离原点的最远距离
- // controls.maxDistance = 200;
- // //是否开启右键拖拽
- //controls.enablePan = true;
- return controls
- }
- var controls = initControls(scene,camera,renderer)
- const clock = new THREE.Clock()
-
- //add light
- const directionalLight = new THREE.DirectionalLight( '#fff' )
- directionalLight.position.set( 30, 30, 30 ).normalize()
- scene.add( directionalLight )
- const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
- scene.add(ambientLight)
- const pointList1 = [
- [20,5,10],
- [10,5,-9],
- [10,5,20],
- [-40,5,-40]
- ]
- let line1
- textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
- const material1 = new MeshLineMaterial({
- color: "green",
- map: texture1,
- useMap: true,
- lineWidth: 4,
- resolution: resolution,
- dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
- dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
- dashOffset: 0,
- transparent: true,
- sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
- side: THREE.FrontSide,
- depthTest: true,
- blending: THREE.AdditiveBlending,
- near: camera.near,
- far: camera.far,
- })
- const l = []
- pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
- let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
- const geo = new THREE.Geometry()
- geo.vertices = curve.getPoints( 50)
- console.log(geo)
- const meshLine = new MeshLine()
- meshLine.setGeometry(geo)
- console.log(meshLine.geometry)
- line1=new THREE.Mesh(meshLine.geometry, material1)
- scene.add(line1)
- })
-
- function render() {
- controls.update(clock.getDelta())
- renderer.render( scene,camera)
- requestAnimationFrame(render)
- //
- if(line1){
- line1.material.uniforms.dashOffset.value -= 0.01
- }
-
- }
- render()

由上文可以看到,其实核心就是基于meshline作者提供的插件来完成的。
完成代码如下:
- <script src="../../plugins/threeLibrary/three.min.js"></script>
- <script src="../../plugins/threeLibrary/js/controls/OrbitControls.js"></script>
- <script src="../../plugins/threeLibrary/js/lines/MeshLine.js"></script>
-
- <script>
-
- function initThree(el, options) {
- options = options || {}
- const t = this
- appInstance = this
- const width = el.offsetWidth
- const height = el.offsetHeight
- const asp = width / height
-
- // scene
- const scene = new THREE.Scene()
-
- // camera
- let camera
- if (options.camera) {
- camera = options.camera
- } else {
- camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
- window.addEventListener('resize', function() {
- camera.aspect = el.offsetWidth / el.offsetHeight
- renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
- camera.updateProjectionMatrix()
- renderer.render(scene, camera)
- }, false)
- }
- camera.position.set(30, 30, 30)
-
- // renderer
- const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
- renderer.setPixelRatio(window.devicePixelRatio)
- renderer.setSize(width, height)
- el.append(renderer.domElement)
- renderer.setClearColor(options.clearColor || '#000')
-
- // 辅助
- if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
- if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线
-
- //按序渲染
- renderer.sortObjects = options.sortObjects
-
- // to the instance
- t.renderer = renderer
- t.scene = scene
- t.camera = camera
- t.el = el
- }
-
- const el = document.getElementById('box')
-
- const app = new initThree(el,{
- // gridHelper:true,//网格参考线
- // axes:true,//坐标辅助
- clearColor:'#000'//画布颜色
- })
- const camera = app.camera
- const renderer = app.renderer
- const scene = app.scene
- function initControls(scene,camera,renderer) {
- const controls = new THREE.OrbitControls( camera, renderer.domElement );
- // 如果使用animate方法时,将此函数删除
- controls.addEventListener( 'change', ()=>{
- renderer.render( scene, camera );
- });
- // // 使动画循环使用时阻尼或自转 意思是否有惯性
- // controls.enableDamping = true;
- // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
- // //controls.dampingFactor = 0.25;
- // //是否可以缩放
- // controls.enableZoom = true;
- // //是否自动旋转
- // controls.autoRotate = true;
- // controls.autoRotateSpeed = 0.5;
- // //设置相机距离原点的最远距离
- // controls.minDistance = 1;
- // //设置相机距离原点的最远距离
- // controls.maxDistance = 200;
- // //是否开启右键拖拽
- //controls.enablePan = true;
- return controls
- }
- var controls = initControls(scene,camera,renderer)
- const clock = new THREE.Clock()
-
- //add light
- const directionalLight = new THREE.DirectionalLight( '#fff' )
- directionalLight.position.set( 30, 30, 30 ).normalize()
- scene.add( directionalLight )
- const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
- scene.add(ambientLight)
-
-
- camera.position.set(100,100,100)
- const resolution = new THREE.Vector2( el.offsetWidth, el.offsetHeight );
- const textureLoader = new THREE.TextureLoader()
-
-
- function getSphereHeightPoints (v0, v3, n1, n2, p0) {
- // 夹角
- const angle = (v0.angleTo(v3) * 180) / Math.PI / 10 // 0 ~ Math.PI
- const aLen = angle * (n1 || 10)
- const hLen = angle * angle * (n2 || 120)
- p0 = p0 || new THREE.Vector3(0, 0, 0) // 默认以 坐标原点为参考对象
- // 法线向量
- const rayLine = new THREE.Ray(p0, v0.clone().add(v3.clone()).divideScalar(2))
- // 顶点坐标
- const vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0))
- // 计算制高点
- const getLenVector = (v1, v2, len) => v1.lerp(v2, len / v1.distanceTo(v2))
- // 控制点坐标
- return [getLenVector(v0.clone(), vtop, aLen), getLenVector(v3.clone(), vtop, aLen)]
- }
-
- /* **** **** **** ****/
- function createAnimateLine (option) {
- let curve
- if (option.kind === 'sphere') { // 由两点之间连线成贝塞尔曲线
- const sphereHeightPointsArgs = option.sphereHeightPointsArgs
- const pointList = this.getSphereHeightPoints(...sphereHeightPointsArgs) // v0,v3,n1,n2,p0
- curve = new THREE.CubicBezierCurve3(sphereHeightPointsArgs[0], pointList[0], pointList[1], sphereHeightPointsArgs[1])
- } else { // 由多个点数组构成的曲线 通常用于道路
- const l = []
- option.pointList.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
- curve = new THREE.CatmullRomCurve3(l) // 曲线路径
- }
- if (option.type === 'pipe') { // 使用管道线
- // 管道体
- const tubeGeometry = new THREE.TubeGeometry(curve, option.number || 50, option.radius || 1, option.radialSegments)
- return new THREE.Mesh(tubeGeometry, option.material)
- } else { // 使用 meshLine
- if (!MeshLine || !MeshLineMaterial) console.error('you need import MeshLine & MeshLineMaterial!')
- else {
- const geo = new THREE.Geometry()
- geo.vertices = curve.getPoints(option.number || 50)
- const meshLine = new MeshLine()
- meshLine.setGeometry(geo)
- return new THREE.Mesh(meshLine.geometry, option.material)
- }
- }
- }
-
- const pointList1 = [
- [20,5,10],
- [10,5,-9],
- [10,5,20],
- [-40,5,-40]
- ]
- let line1
- textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
- const material1 = new MeshLineMaterial({
- color: "green",
- map: texture1,
- useMap: true,
- lineWidth: 4,
- resolution: resolution,
- dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
- dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
- dashOffset: 0,
- transparent: true,
- sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
- side: THREE.FrontSide,
- depthTest: true,
- blending: THREE.AdditiveBlending,
- near: camera.near,
- far: camera.far,
- })
- const l = []
- pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
- let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
- const geo = new THREE.Geometry()
- geo.vertices = curve.getPoints( 50)
- console.log(geo)
- const meshLine = new MeshLine()
- meshLine.setGeometry(geo)
- console.log(meshLine.geometry)
- line1=new THREE.Mesh(meshLine.geometry, material1)
- scene.add(line1)
- })
-
- /** 2:绘制普通pipeLine**/
-
- const pointList2 = [
- [-20,5,-10],
- [30,5,-15],
- [10,5,20],
- [40,5,40]
- ]
- const texture2 = textureLoader.load("../../images/ysThree/red_line.png")
- texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping; //每个都重复
- texture2.repeat.set(1, 1)
- const material2 = new THREE.MeshBasicMaterial({map:texture2,side:THREE.BackSide,transparent:true})
- texture2.needsUpdate = true
- const line2 = createAnimateLine({
- // kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
- type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
- pointList: pointList2,
- material: material2,
- number: 100
- })
- scene.add(line2)
-
- /** 1:在球面上绘制meshLine**/
- const v0 = new THREE.Vector3( -80, 10, 0 )
- const v3 = new THREE.Vector3( 80, 10, 0 )
-
- let line3
- textureLoader.load( '../../images/ysThree/green_line.png', function (texture3) {
- const material3 = new MeshLineMaterial({
- color: "green",
- map: texture3,
- useMap: true,
- lineWidth: 4,
- resolution: resolution,
- dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
- dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
- dashOffset: 0,
- transparent: true,
- sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
- side: THREE.FrontSide,
- depthTest: true,
- blending: THREE.AdditiveBlending,
- near: camera.near,
- far: camera.far,
- })
- line3 = createAnimateLine({
- kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
- // type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
- sphereHeightPointsArgs: [v0,v3],
- material: material3
- })
- scene.add(line3)
- })
-
- /** 1:在球面上绘制pipeLine**/
-
- const v0_1 = new THREE.Vector3( -60, 10, 0 )
- const v3_1 = new THREE.Vector3( 60, 10, 0 )
-
- const texture4 = textureLoader.load("../../images/ysThree/red_line.png")
- texture4.wrapS = texture4.wrapT = THREE.RepeatWrapping; //每个都重复
- texture4.repeat.set(1, 1)
- const materia4 = new THREE.MeshBasicMaterial({map:texture4,side:THREE.BackSide,transparent:true})
- texture4.needsUpdate = true
- const line4 = createAnimateLine({
- kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
- type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
- sphereHeightPointsArgs: [v0_1,v3_1],
- material: materia4,
- number: 100,
- radius: 1 // 默认
- })
- scene.add(line4)
-
- /* **** **** **** ****/
- function render() {
- controls.update(clock.getDelta())
- renderer.render( scene,camera)
- requestAnimationFrame(render)
- //
- if(line1){
- line1.material.uniforms.dashOffset.value -= 0.01
- }
-
- //
- texture2.offset.x -= 0.01
-
- //
- if(line3){
- line3.material.uniforms.dashOffset.value -= 0.01
- }
-
- texture4.offset.x -= 0.01
- }
- render()
- </script>

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。