three.js实现电子围栏效果(纹理贴图)
实现步骤
围栏的坐标 坐标转换为几何体顶点,uv顶点坐标 加载贴图,移动
图例
代码
< template>
< div class = "app" >
< div ref= "canvesRef" class = "canvas-wrap" > < / div>
< / div>
< / template>
< script setup>
import { ref, onMounted } from "vue" ;
import * as THREE from "three" ;
import { OrbitControls } from "three/addons/controls/OrbitControls.js" ;
const canvesRef = ref ( null ) ;
const canvasWidth = window. innerWidth;
const canvasHeight = window. innerHeight;
let scene;
let camera;
let renderer;
let axesHelper;
let cameraControls;
init ( ) ;
render ( ) ;
function init ( ) {
scene = new THREE. Scene ( ) ;
addModel ( ) ;
camera = new THREE. PerspectiveCamera (
75 ,
canvasWidth / canvasHeight,
0.1 ,
3000
) ;
camera. position. set ( 300 , 300 , 300 ) ;
axesHelper = new THREE. AxesHelper ( 200 ) ;
scene. add ( axesHelper) ;
renderer = new THREE. WebGLRenderer ( ) ;
renderer. setSize ( canvasWidth, canvasHeight) ;
cameraControls = new OrbitControls ( camera, renderer. domElement) ;
}
function addModel ( ) {
const points = [
[ 0 , 0 , 0 ] ,
[ 0 , 0 , 200 ] ,
[ 200 , 0 , 200 ] ,
[ 200 , 0 , 0 ] ,
[ 0 , 0 , 0 ] ,
] ;
const height = 30 ;
const color1 = "#ff00ff" ;
const pointDistance = [ ] ;
const distance = points. reduce ( ( totalDistance, point, index ) => {
let segmentDistance = 0 ;
if ( index > 0 ) {
let lastPoint = new THREE. Vector3 ( ... points[ index - 1 ] ) ;
let currPoint = new THREE. Vector3 ( ... point) ;
segmentDistance = lastPoint. distanceTo ( currPoint) ;
}
totalDistance += segmentDistance;
pointDistance. push ( totalDistance) ;
return totalDistance;
} , 0 ) ;
const geometry = new THREE. BufferGeometry ( ) ;
const posArr = [ ] ;
const uvArr = [ ] ;
points. forEach ( ( point, index ) => {
if ( index == 0 ) return ;
const lastPoint = points[ index - 1 ] ;
posArr. push ( ... lastPoint) ;
uvArr. push ( pointDistance[ index - 1 ] / distance, 0 ) ;
posArr. push ( ... point) ;
uvArr. push ( pointDistance[ index] / distance, 0 ) ;
posArr. push ( lastPoint[ 0 ] , lastPoint[ 1 ] + height, lastPoint[ 2 ] ) ;
uvArr. push ( pointDistance[ index - 1 ] / distance, 1 ) ;
posArr. push ( ... point) ;
uvArr. push ( pointDistance[ index] / distance, 0 ) ;
posArr. push ( point[ 0 ] , point[ 1 ] + height, point[ 2 ] ) ;
uvArr. push ( pointDistance[ index] / distance, 1 ) ;
posArr. push ( lastPoint[ 0 ] , lastPoint[ 1 ] + height, lastPoint[ 2 ] ) ;
uvArr. push ( pointDistance[ index - 1 ] / distance, 1 ) ;
} ) ;
console. log ( posArr, uvArr) ;
geometry. setAttribute (
"position" ,
new THREE. BufferAttribute ( new Float32Array ( posArr) , 3 )
) ;
geometry. setAttribute (
"uv" ,
new THREE. BufferAttribute ( new Float32Array ( uvArr) , 2 )
) ;
const texture = new THREE. TextureLoader ( ) . load ( "../src/assets/img/icon.png" ) ;
texture. wrapS = THREE . RepeatWrapping;
texture. wrapT = THREE . RepeatWrapping;
const material = new THREE. MeshBasicMaterial ( {
map : texture,
transparent : true ,
opacity : 1 ,
depthWrite : false ,
side : THREE . DoubleSide,
} ) ;
const mesh = new THREE. Mesh ( geometry, material) ;
scene. add ( mesh) ;
texture. repeat. set ( 10 , 1 ) ;
textrue_offset ( texture, "top" , 5 ) ;
}
function textrue_offset ( texture, direction = "right" , speed = 0.5 ) {
const start = Date. now ( ) ;
const h = ( ) => {
requestAnimationFrame ( h) ;
const now = Date. now ( ) ;
const offset = ( ( now - start) / 1000 ) * speed;
switch ( direction) {
case "left" :
texture. offset = new THREE. Vector2 ( offset, 0 ) ;
break ;
case "right" :
texture. offset = new THREE. Vector2 ( - offset, 0 ) ;
break ;
case "top" :
texture. offset = new THREE. Vector2 ( 0 , - offset) ;
break ;
case "left" :
texture. offset = new THREE. Vector2 ( 0 , offset) ;
break ;
}
} ;
h ( ) ;
}
function render ( ) {
renderer. render ( scene, camera) ;
requestAnimationFrame ( render) ;
}
onMounted ( ( ) => {
canvesRef. value. appendChild ( renderer. domElement) ;
} ) ;
< / script>
< style lang= "scss" scoped>
. app {
position : relative;
}
< / style>