当前位置:   article > 正文

three.js流动线_threejs流动线

threejs流动线

效果:

先看最基本的

  1. function initThree(el, options) {
  2. options = options || {}
  3. const t = this
  4. appInstance = this
  5. const width = el.offsetWidth
  6. const height = el.offsetHeight
  7. const asp = width / height
  8. // scene
  9. const scene = new THREE.Scene()
  10. // camera
  11. let camera
  12. if (options.camera) {
  13. camera = options.camera
  14. } else {
  15. camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
  16. window.addEventListener('resize', function() {
  17. camera.aspect = el.offsetWidth / el.offsetHeight
  18. renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
  19. camera.updateProjectionMatrix()
  20. renderer.render(scene, camera)
  21. }, false)
  22. }
  23. camera.position.set(30, 30, 30)
  24. // renderer
  25. const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  26. renderer.setPixelRatio(window.devicePixelRatio)
  27. renderer.setSize(width, height)
  28. el.append(renderer.domElement)
  29. renderer.setClearColor(options.clearColor || '#000')
  30. // 辅助
  31. if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
  32. if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线
  33. //按序渲染
  34. renderer.sortObjects = options.sortObjects
  35. // to the instance
  36. t.renderer = renderer
  37. t.scene = scene
  38. t.camera = camera
  39. t.el = el
  40. }
  41. const el = document.getElementById('box')
  42. const app = new initThree(el,{
  43. // gridHelper:true,//网格参考线
  44. // axes:true,//坐标辅助
  45. clearColor:'#000'//画布颜色
  46. })
  47. const camera = app.camera
  48. const renderer = app.renderer
  49. const scene = app.scene
  50. function initControls(scene,camera,renderer) {
  51. const controls = new THREE.OrbitControls( camera, renderer.domElement );
  52. // 如果使用animate方法时,将此函数删除
  53. controls.addEventListener( 'change', ()=>{
  54. renderer.render( scene, camera );
  55. });
  56. // // 使动画循环使用时阻尼或自转 意思是否有惯性
  57. // controls.enableDamping = true;
  58. // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
  59. // //controls.dampingFactor = 0.25;
  60. // //是否可以缩放
  61. // controls.enableZoom = true;
  62. // //是否自动旋转
  63. // controls.autoRotate = true;
  64. // controls.autoRotateSpeed = 0.5;
  65. // //设置相机距离原点的最远距离
  66. // controls.minDistance = 1;
  67. // //设置相机距离原点的最远距离
  68. // controls.maxDistance = 200;
  69. // //是否开启右键拖拽
  70. //controls.enablePan = true;
  71. return controls
  72. }
  73. var controls = initControls(scene,camera,renderer)
  74. const clock = new THREE.Clock()
  75. //add light
  76. const directionalLight = new THREE.DirectionalLight( '#fff' )
  77. directionalLight.position.set( 30, 30, 30 ).normalize()
  78. scene.add( directionalLight )
  79. const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
  80. scene.add(ambientLight)
  81. const pointList1 = [
  82. [20,5,10],
  83. [10,5,-9],
  84. [10,5,20],
  85. [-40,5,-40]
  86. ]
  87. let line1
  88. textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
  89. const material1 = new MeshLineMaterial({
  90. color: "green",
  91. map: texture1,
  92. useMap: true,
  93. lineWidth: 4,
  94. resolution: resolution,
  95. dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
  96. dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
  97. dashOffset: 0,
  98. transparent: true,
  99. sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
  100. side: THREE.FrontSide,
  101. depthTest: true,
  102. blending: THREE.AdditiveBlending,
  103. near: camera.near,
  104. far: camera.far,
  105. })
  106. const l = []
  107. pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
  108. let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
  109. const geo = new THREE.Geometry()
  110. geo.vertices = curve.getPoints( 50)
  111. console.log(geo)
  112. const meshLine = new MeshLine()
  113. meshLine.setGeometry(geo)
  114. console.log(meshLine.geometry)
  115. line1=new THREE.Mesh(meshLine.geometry, material1)
  116. scene.add(line1)
  117. })
  118. function render() {
  119. controls.update(clock.getDelta())
  120. renderer.render( scene,camera)
  121. requestAnimationFrame(render)
  122. //
  123. if(line1){
  124. line1.material.uniforms.dashOffset.value -= 0.01
  125. }
  126. }
  127. render()

由上文可以看到,其实核心就是基于meshline作者提供的插件来完成的。

完成代码如下:

  1. <script src="../../plugins/threeLibrary/three.min.js"></script>
  2. <script src="../../plugins/threeLibrary/js/controls/OrbitControls.js"></script>
  3. <script src="../../plugins/threeLibrary/js/lines/MeshLine.js"></script>
  4. <script>
  5. function initThree(el, options) {
  6. options = options || {}
  7. const t = this
  8. appInstance = this
  9. const width = el.offsetWidth
  10. const height = el.offsetHeight
  11. const asp = width / height
  12. // scene
  13. const scene = new THREE.Scene()
  14. // camera
  15. let camera
  16. if (options.camera) {
  17. camera = options.camera
  18. } else {
  19. camera = new THREE.PerspectiveCamera(45, asp, 1, 100000)
  20. window.addEventListener('resize', function() {
  21. camera.aspect = el.offsetWidth / el.offsetHeight
  22. renderer.setSize(el.offsetWidth, el.offsetHeight) // 重新获取
  23. camera.updateProjectionMatrix()
  24. renderer.render(scene, camera)
  25. }, false)
  26. }
  27. camera.position.set(30, 30, 30)
  28. // renderer
  29. const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  30. renderer.setPixelRatio(window.devicePixelRatio)
  31. renderer.setSize(width, height)
  32. el.append(renderer.domElement)
  33. renderer.setClearColor(options.clearColor || '#000')
  34. // 辅助
  35. if (options.axes) scene.add(new THREE.AxesHelper(10))// 坐标轴辅助红x 绿y 蓝z
  36. if (options.gridHelper) scene.add(new THREE.GridHelper(100, 100))// 网格参考线
  37. //按序渲染
  38. renderer.sortObjects = options.sortObjects
  39. // to the instance
  40. t.renderer = renderer
  41. t.scene = scene
  42. t.camera = camera
  43. t.el = el
  44. }
  45. const el = document.getElementById('box')
  46. const app = new initThree(el,{
  47. // gridHelper:true,//网格参考线
  48. // axes:true,//坐标辅助
  49. clearColor:'#000'//画布颜色
  50. })
  51. const camera = app.camera
  52. const renderer = app.renderer
  53. const scene = app.scene
  54. function initControls(scene,camera,renderer) {
  55. const controls = new THREE.OrbitControls( camera, renderer.domElement );
  56. // 如果使用animate方法时,将此函数删除
  57. controls.addEventListener( 'change', ()=>{
  58. renderer.render( scene, camera );
  59. });
  60. // // 使动画循环使用时阻尼或自转 意思是否有惯性
  61. // controls.enableDamping = true;
  62. // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
  63. // //controls.dampingFactor = 0.25;
  64. // //是否可以缩放
  65. // controls.enableZoom = true;
  66. // //是否自动旋转
  67. // controls.autoRotate = true;
  68. // controls.autoRotateSpeed = 0.5;
  69. // //设置相机距离原点的最远距离
  70. // controls.minDistance = 1;
  71. // //设置相机距离原点的最远距离
  72. // controls.maxDistance = 200;
  73. // //是否开启右键拖拽
  74. //controls.enablePan = true;
  75. return controls
  76. }
  77. var controls = initControls(scene,camera,renderer)
  78. const clock = new THREE.Clock()
  79. //add light
  80. const directionalLight = new THREE.DirectionalLight( '#fff' )
  81. directionalLight.position.set( 30, 30, 30 ).normalize()
  82. scene.add( directionalLight )
  83. const ambientLight = new THREE.AmbientLight('#fff',0.3) // obj 唯一 id
  84. scene.add(ambientLight)
  85. camera.position.set(100,100,100)
  86. const resolution = new THREE.Vector2( el.offsetWidth, el.offsetHeight );
  87. const textureLoader = new THREE.TextureLoader()
  88. function getSphereHeightPoints (v0, v3, n1, n2, p0) {
  89. // 夹角
  90. const angle = (v0.angleTo(v3) * 180) / Math.PI / 10 // 0 ~ Math.PI
  91. const aLen = angle * (n1 || 10)
  92. const hLen = angle * angle * (n2 || 120)
  93. p0 = p0 || new THREE.Vector3(0, 0, 0) // 默认以 坐标原点为参考对象
  94. // 法线向量
  95. const rayLine = new THREE.Ray(p0, v0.clone().add(v3.clone()).divideScalar(2))
  96. // 顶点坐标
  97. const vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0))
  98. // 计算制高点
  99. const getLenVector = (v1, v2, len) => v1.lerp(v2, len / v1.distanceTo(v2))
  100. // 控制点坐标
  101. return [getLenVector(v0.clone(), vtop, aLen), getLenVector(v3.clone(), vtop, aLen)]
  102. }
  103. /* **** **** **** ****/
  104. function createAnimateLine (option) {
  105. let curve
  106. if (option.kind === 'sphere') { // 由两点之间连线成贝塞尔曲线
  107. const sphereHeightPointsArgs = option.sphereHeightPointsArgs
  108. const pointList = this.getSphereHeightPoints(...sphereHeightPointsArgs) // v0,v3,n1,n2,p0
  109. curve = new THREE.CubicBezierCurve3(sphereHeightPointsArgs[0], pointList[0], pointList[1], sphereHeightPointsArgs[1])
  110. } else { // 由多个点数组构成的曲线 通常用于道路
  111. const l = []
  112. option.pointList.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
  113. curve = new THREE.CatmullRomCurve3(l) // 曲线路径
  114. }
  115. if (option.type === 'pipe') { // 使用管道线
  116. // 管道体
  117. const tubeGeometry = new THREE.TubeGeometry(curve, option.number || 50, option.radius || 1, option.radialSegments)
  118. return new THREE.Mesh(tubeGeometry, option.material)
  119. } else { // 使用 meshLine
  120. if (!MeshLine || !MeshLineMaterial) console.error('you need import MeshLine & MeshLineMaterial!')
  121. else {
  122. const geo = new THREE.Geometry()
  123. geo.vertices = curve.getPoints(option.number || 50)
  124. const meshLine = new MeshLine()
  125. meshLine.setGeometry(geo)
  126. return new THREE.Mesh(meshLine.geometry, option.material)
  127. }
  128. }
  129. }
  130. const pointList1 = [
  131. [20,5,10],
  132. [10,5,-9],
  133. [10,5,20],
  134. [-40,5,-40]
  135. ]
  136. let line1
  137. textureLoader.load( '../../images/ysThree/green_line.png', function (texture1) {
  138. const material1 = new MeshLineMaterial({
  139. color: "green",
  140. map: texture1,
  141. useMap: true,
  142. lineWidth: 4,
  143. resolution: resolution,
  144. dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
  145. dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
  146. dashOffset: 0,
  147. transparent: true,
  148. sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
  149. side: THREE.FrontSide,
  150. depthTest: true,
  151. blending: THREE.AdditiveBlending,
  152. near: camera.near,
  153. far: camera.far,
  154. })
  155. const l = []
  156. pointList1.forEach(e => l.push(new THREE.Vector3(e[0], e[1], e[2])))
  157. let curve = new THREE.CatmullRomCurve3(l) // 曲线路径
  158. const geo = new THREE.Geometry()
  159. geo.vertices = curve.getPoints( 50)
  160. console.log(geo)
  161. const meshLine = new MeshLine()
  162. meshLine.setGeometry(geo)
  163. console.log(meshLine.geometry)
  164. line1=new THREE.Mesh(meshLine.geometry, material1)
  165. scene.add(line1)
  166. })
  167. /** 2:绘制普通pipeLine**/
  168. const pointList2 = [
  169. [-20,5,-10],
  170. [30,5,-15],
  171. [10,5,20],
  172. [40,5,40]
  173. ]
  174. const texture2 = textureLoader.load("../../images/ysThree/red_line.png")
  175. texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping; //每个都重复
  176. texture2.repeat.set(1, 1)
  177. const material2 = new THREE.MeshBasicMaterial({map:texture2,side:THREE.BackSide,transparent:true})
  178. texture2.needsUpdate = true
  179. const line2 = createAnimateLine({
  180. // kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
  181. type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
  182. pointList: pointList2,
  183. material: material2,
  184. number: 100
  185. })
  186. scene.add(line2)
  187. /** 1:在球面上绘制meshLine**/
  188. const v0 = new THREE.Vector3( -80, 10, 0 )
  189. const v3 = new THREE.Vector3( 80, 10, 0 )
  190. let line3
  191. textureLoader.load( '../../images/ysThree/green_line.png', function (texture3) {
  192. const material3 = new MeshLineMaterial({
  193. color: "green",
  194. map: texture3,
  195. useMap: true,
  196. lineWidth: 4,
  197. resolution: resolution,
  198. dashArray: 0.8, // 破折号之间的长度和间距。(0 -无破折号)
  199. dashRatio: 0.5, // 定义可见和不可见之间的比率(0 -更可见,1 -更不可见)。
  200. dashOffset: 0,
  201. transparent: true,
  202. sizeAttenuation: 1, //使线宽不变,不管距离(1个单位是屏幕上的1px)(0 -衰减,1 -不衰减)
  203. side: THREE.FrontSide,
  204. depthTest: true,
  205. blending: THREE.AdditiveBlending,
  206. near: camera.near,
  207. far: camera.far,
  208. })
  209. line3 = createAnimateLine({
  210. kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
  211. // type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
  212. sphereHeightPointsArgs: [v0,v3],
  213. material: material3
  214. })
  215. scene.add(line3)
  216. })
  217. /** 1:在球面上绘制pipeLine**/
  218. const v0_1 = new THREE.Vector3( -60, 10, 0 )
  219. const v3_1 = new THREE.Vector3( 60, 10, 0 )
  220. const texture4 = textureLoader.load("../../images/ysThree/red_line.png")
  221. texture4.wrapS = texture4.wrapT = THREE.RepeatWrapping; //每个都重复
  222. texture4.repeat.set(1, 1)
  223. const materia4 = new THREE.MeshBasicMaterial({map:texture4,side:THREE.BackSide,transparent:true})
  224. texture4.needsUpdate = true
  225. const line4 = createAnimateLine({
  226. kind: 'sphere',//默认不填 为普通 ; 如为sphere,则表示球面建点
  227. type: 'pipe',//默认不填 为MeshLine ; 如为pipe,则表示管道线
  228. sphereHeightPointsArgs: [v0_1,v3_1],
  229. material: materia4,
  230. number: 100,
  231. radius: 1 // 默认
  232. })
  233. scene.add(line4)
  234. /* **** **** **** ****/
  235. function render() {
  236. controls.update(clock.getDelta())
  237. renderer.render( scene,camera)
  238. requestAnimationFrame(render)
  239. //
  240. if(line1){
  241. line1.material.uniforms.dashOffset.value -= 0.01
  242. }
  243. //
  244. texture2.offset.x -= 0.01
  245. //
  246. if(line3){
  247. line3.material.uniforms.dashOffset.value -= 0.01
  248. }
  249. texture4.offset.x -= 0.01
  250. }
  251. render()
  252. </script>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/536716
推荐阅读
相关标签
  

闽ICP备14008679号