代码
<template>
<div>
<div id="my-three">
</div>
</div>
</template>
<script setup>
import * as THREE from 'three'
import { BackSide } from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { onMounted,watch } from 'vue'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer.js';
import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js';
import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js';
import {OutlinePass} from 'three/examples/jsm/postprocessing/OutlinePass.js';
import {FXAAShader} from 'three/examples/jsm/shaders/FXAAShader.js';
import Stats from 'three/addons/libs/stats.module.js';
import gsap from 'gsap'
import { TweenMax, Power0 } from "gsap";
import * as dat from "dat.gui"
import nipplejs from 'nipplejs';
let stats = new Stats();
let mixer;
let lastTime = 0;
let composer, effectFXAA, outlinePass,outlineColor=['#fff','#c40000'],selectedObjects,mesh;
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let meshes = [],
clonemeshes = [];
const clock = new THREE.Clock();
//创建一个三维场景
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xbfd1e5 );
const vertices1 = [];//model1的点位
const vertices2 = [];//model2的点位
const ambientLight = new THREE.AmbientLight( 0xbbbbbb );
scene.add( ambientLight );
const light = new THREE.DirectionalLight( 0xffffff, 5 );
light.position.set( 10, 10, 5 );
light.castShadow = true;
const d = 10;
light.shadow.camera.left = - d;
light.shadow.camera.right = d;
light.shadow.camera.top = d;
light.shadow.camera.bottom = - d;
light.shadow.camera.near = 2;
light.shadow.camera.far = 50;
light.shadow.mapSize.x = 1024;
light.shadow.mapSize.y = 1024;
scene.add( light );
//创建一个透视相机,窗口宽度,窗口高度
const width = window.innerWidth, height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(45, width/height, 1, 1000);
//设置相机位置
camera.position.set(5,1,6)
//设置相机方向
//camera.lookAt(0,0,0);
//创建辅助坐标轴
const axesHelper = new THREE.AxesHelper(200);//参数200标示坐标系大小,可以根据场景大小去设置
//scene.add(axesHelper);
//创建一个WebGL渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(width,height)//设置渲染区尺寸
renderer.shadowMap.enabled = true;
renderer.render(scene,camera)//执行渲染操作、指定场景、相机作为参数
const axis = new THREE.Vector3(1,1,1);//向量axis
//mesh.rotateOnAxis(axis,Math.PI/8);//绕axis轴旋转π/8
const gridHelper = new THREE.GridHelper(10, 100, 0x004444, 0x004444);
scene.add(gridHelper);
const controls = new OrbitControls(camera, renderer.domElement)//创建控件对象
controls.addEventListener('change',()=>{
renderer.render(scene, camera)//监听鼠标,键盘事件
})
// 添加高亮效果
renderer.domElement.addEventListener( 'pointermove', onPointerMove );
const size = renderer.getSize(new THREE.Vector2());
const _pixelRatio = renderer.getPixelRatio();
const _width = size.width;
const _height = size.height;
const renderTarget = new THREE.WebGLRenderTarget(
_width * _pixelRatio,
_height * _pixelRatio,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
encoding: THREE.sRGBEncoding
}
);
renderTarget.texture.name = "EffectComposer.rt1";
composer = new EffectComposer(renderer, renderTarget);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera);
composer.addPass(outlinePass);
effectFXAA = new ShaderPass(FXAAShader);
effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
composer.addPass(effectFXAA);
outlinePass.visibleEdgeColor.set(outlineColor[0]); // 边缘可见部分发颜色 sColor[0].color
outlinePass.hiddenEdgeColor.set(outlineColor[1]); // 边缘遮挡部分发光颜色 sColor[1].color
outlinePass.edgeStrength = Number(10.0); //边框的亮度
outlinePass.edgeGlow = Number(1); //光晕[0,1]
outlinePass.edgeThickness = Number(1.0); //边缘浓度
outlinePass.pulsePeriod = Number(1.8); //呼吸闪烁的速度 闪烁频率 ,默认0 ,值越大频率越低
outlinePass.usePatternTexture = false; //是否使用父级的材质
outlinePass.downSampleRatio = 2; // 边框弯曲度
outlinePass.clear = true;
controls.minDistance = 1.5
controls.maxDistance = 50;
onMounted(()=>{
document.getElementById('my-three')?.appendChild( stats.dom );
document.getElementById('my-three')?.appendChild(renderer.domElement)
// shownipple()
})
controls.enablePan = true
controls.enableDamping = true
animate()
function animate(currentTime){
//mesh.rotateOnAxis(axis.normalize(),0.1);//绕axis轴旋转π/8
const deltaTime = (currentTime - lastTime) / 1000;
lastTime = currentTime;
if (mixer) {
mixer.update(deltaTime); // deltaTime is the time since the last frame
}
controls.update();
stats.update();
renders()
requestAnimationFrame(animate);
renderer.render(scene,camera)
}
let model
let pointCloud,pointCloud2,pointCloudGeometry,pointCloudGeometry2,pointCloudMaterial
let modelOpacity = 0;
addmodel()
function addmodel(){
new RGBELoader()
.setPath( './model/hdr/' )
.load( '33.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
renderer.render( scene, camera )
const loader = new GLTFLoader();
// 加载地图模型
loader.load('./model/robot/sicrun.glb', function(gltf){
//将模型添加至场景
// 将模型添加至场景
model = gltf.scene//.children[0];
scene.add( model )
model.traverse((child) => {
if (child instanceof THREE.Mesh) {
const geometry = child.geometry;
//设置透明度 设置为透明
child.material.transparent = true;
child.material.opacity = modelOpacity;
if (geometry instanceof THREE.BufferGeometry) {
const position = geometry.attributes.position.array;
for (let i = 0; i < position.length; i += 3) {
vertices1.push(new THREE.Vector3( position[i], position[i + 1], position[i + 2]));
}
}
}
});
// 创建点云对象
pointCloudGeometry = new THREE.BufferGeometry().setFromPoints(vertices1);
pointCloudMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.03 }); // 调整点的大小和颜色
pointCloud = new THREE.Points(pointCloudGeometry, pointCloudMaterial);
// 将点云添加到场景中
scene.add(pointCloud);
let mxposition = pointCloudGeometry.attributes.position
createMesh( mxposition, scene, 4.05, - 500, - 350, 600, 0xff7744 );
})
} );
}
function checkIntersection() {
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObject( scene, true );
if ( intersects.length > 0 ) {
const selectedObject = intersects[ 0 ].object;
addSelectedObject( selectedObject );
outlinePass.selectedObjects = selectedObjects;
} else {
// outlinePass.selectedObjects = [];
}
}
function addSelectedObject( object ) {
selectedObjects = [];
selectedObjects.push( object );
}
function onPointerMove( event ) {
if ( event.isPrimary === false ) return;
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
checkIntersection();
}
function createMesh( positions, scene, scale, x, y, z, color ) {
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', positions.clone() );
geometry.setAttribute( 'initialPosition', positions.clone() );
geometry.attributes.position.setUsage( THREE.DynamicDrawUsage );
const clones = [
[ 0, 0, 0 ]
];
for ( let i = 0; i < clones.length; i ++ ) {
const c = ( i < clones.length - 1 ) ? 0x252525 : color;
mesh = new THREE.Points( geometry, new THREE.PointsMaterial( { size: 30, color: c } ) );
mesh.scale.x = mesh.scale.y = mesh.scale.z = scale;
mesh.position.x = x + clones[ i ][ 0 ];
mesh.position.y = y + clones[ i ][ 1 ];
mesh.position.z = z + clones[ i ][ 2 ];
clonemeshes.push( { mesh: mesh, speed: 0.5 + Math.random() } );
}
meshes.push( {
mesh: mesh,
verticesDown: 0,
verticesUp: 0,
direction: 0,
speed: 15,
delay: Math.floor( 200 + 200 * Math.random() ),
start: Math.floor( 100 + 200 * Math.random() ),
} );
}
function renders(){
let delta = 10 * clock.getDelta();
delta = delta < 2 ? delta : 2;
for ( let j = 0; j < meshes.length; j ++ ) {
const data = meshes[ j ];
const positions = data.mesh.geometry.attributes.position;
const initialPositions = data.mesh.geometry.attributes.initialPosition;
const count = positions.count;
if ( data.start > 0 ) {
data.start -= 1;
} else {
if ( data.direction === 0 ) {
data.direction = - 1;
}
}
for ( let i = 0; i < count; i ++ ) {
const px = positions.getX( i );
const py = positions.getY( i );
const pz = positions.getZ( i );
// falling down
if ( data.direction < 0 ) {
if ( py > 0 ) {
debugger
positions.setXYZ(
i,
px + 1.5 * ( 0.50 - Math.random() ) * data.speed * delta,
py + 3.0 * ( 0.25 - Math.random() ) * data.speed * delta,
pz + 1.5 * ( 0.50 - Math.random() ) * data.speed * delta
);
} else {
data.verticesDown += 1;
}
}
}
console.log(positions)
positions.needsUpdate = true;
}
}
</script>
<style lang='less'>
body{
margin: 0;
padding: 0;
}
.my-three{
}
.buttons{
position: fixed;
right: 10px;
top: 10px;
}
</style>