Threejs-管道流光效果

管道流光效果

管道流光效果

贴图素材:
管道流光效果

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>流光</title>
 <style>
  body{
      overflow: hidden;
      margin: 0px;
  }
</style>
</head>
<body>
 
 <script type="importmap">
  {
    "imports": {
      "three": "../three.js-r148/build/three.module.js",
      "three/addons/": "../three.js-r148/examples/jsm/",
      "@tweenjs/tween.js": "../tween.esm.js"
    }
  }
</script>
<script src="./index.js" type="module">  </script>
</body>
</html>

创建场景、相机、渲染器

创建文件index.js

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import model from './drawline.js'

//场景
const scene = new THREE.Scene();
scene.add(model)

//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(300);
scene.add(axesHelper);


//环境光
const ambient = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambient);

//渲染器和相机
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(0, 300, 600);
camera.lookAt(0, 0, 0);

const renderer = new THREE.WebGLRenderer({
    logarithmicDepthBuffer: true,// 设置对数深度缓冲区,优化深度冲突问题
    antialias:true//执行抗锯齿
});
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);



// 渲染循环
function render() {
 renderer.render(scene, camera);
 requestAnimationFrame(render);
}
render();

// 画布跟随窗口变化
window.onresize = function () {
 renderer.setSize(window.innerWidth, window.innerHeight);
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
};

创建顶点、贴图、管道、样条曲线

创建文件drawline.js
1、创建道路顶点数组

let points1 = [
 new THREE.Vector3(100, 100, -100),
 new THREE.Vector3(-100, 100, -100),
 new THREE.Vector3(-100, -100, -100),
 new THREE.Vector3(100, -100, -100)
]
let points2 = [
 new THREE.Vector3(100, 100, 0),
 new THREE.Vector3(-100, 100, 0),
 new THREE.Vector3(-100, -100, 0),
 new THREE.Vector3(100, -100, 0)
]

2、使用CatmullRomCurve3生成曲线

let curve = new THREE.CatmullRomCurve3(lines[i],true) // 曲线路径

3、使用TubeGeometry创建管道

 let tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.1)

4、创建材质并在动画函数中使用贴图位移

  let texture = new THREE.TextureLoader().load("../imgs/路面流光.png")
  // 设置阵列模式为 RepeatWrapping
  texture.wrapS = THREE.RepeatWrapping
  texture.wrapT = THREE.RepeatWrapping
  texture.repeat.x = 20;// x方向阵列
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复

  let material = new THREE.MeshLambertMaterial({
    color: 0x00ffff, //颜色
    map:texture,
    transparent:true,
    depthTest:false,
    map: texture,
    side: THREE.DoubleSide
  })

5、创建mesh

  let meshTube = new THREE.Mesh(tubeGeometry, material);
  meshTube.rotateX(Math.PI/2)
  model.add(meshTube)

完整代码

import * as THREE from 'three';

var loader = new THREE.FileLoader();
loader.setResponseType('json');

let texture = new THREE.TextureLoader().load("../imgs/路面流光.png")
// 设置阵列模式为 RepeatWrapping
texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
texture.repeat.x = 20;// x方向阵列
texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复

let material = new THREE.MeshLambertMaterial({
 color: 0x00ffff, //颜色
  map:texture,
  transparent:true,
  depthTest:false,
  map: texture,
  side: THREE.DoubleSide
})
let colors = [0x00ffff,0xffd700]

// 创建顶点数组

let points1 = [
 new THREE.Vector3(100, 100, -100),
 new THREE.Vector3(-100, 100, -100),
 new THREE.Vector3(-100, -100, -100),
 new THREE.Vector3(100, -100, -100)
]
let points2 = [
 new THREE.Vector3(100, 100, 0),
 new THREE.Vector3(-100, 100, 0),
 new THREE.Vector3(-100, -100, 0),
 new THREE.Vector3(100, -100, 0)
]

const lines = [points1, points2]

const model = new THREE.Group()

async function init(){
 // CatmullRomCurve3创建一条平滑的三维样条曲线
 for(let i =0; i < lines.length; i++){
  let curve = new THREE.CatmullRomCurve3(lines[i],true) // 曲线路径
  // 创建管道
  let tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.1)

  let meshTube = new THREE.Mesh(tubeGeometry, material);
  meshTube.rotateX(Math.PI/2)
  meshTube.material = new THREE.MeshLambertMaterial({
    map:texture,
    transparent:true,
    depthTest:false,
    map: texture,
    side: THREE.DoubleSide
  })
  meshTube.material.color.set(colors[i]);
  model.add(meshTube)
 }
 
}
init()


function animate() {
 if(texture) texture.offset.x -= 0.01
 requestAnimationFrame(animate)
}

animate()

export default model

  目录