three.js实现模型扫光效果
预览
关键点
- 在材质的onBeforeCompile回调函数中修改模型颜色
- 在render函数中修改y(高度)
代码
<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;
let mesh;
const clock = new THREE.Clock();
init();
render();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
45,
canvasWidth / canvasHeight,
1,
10000
);
camera.position.set(400, 400, 400);
camera.lookAt(0, 0, 0);
addModel();
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 geometry = new THREE.BoxGeometry(50, 160, 50);
const material = new THREE.MeshBasicMaterial({
color: 0x00ffff,
});
mesh = new THREE.Mesh(geometry, material);
material.onBeforeCompile = function (shader) {
shader.uniforms.y = { value: 50 };
shader.vertexShader = shader.vertexShader.replace(
"void main() {",
`
varying vec3 vPosition;//顶点位置插值后的坐标
void main(){
vPosition = vec3(modelMatrix * vec4( position, 1.0 ));
// vPosition = position;//不考虑模型旋转缩放平移变换(modelMatrix) 相对模型自身
`
);
shader.fragmentShader = shader.fragmentShader.replace(
"void main() {",
`
varying vec3 vPosition;
uniform float y; //变化的y控制光带高度
float w = 10.0;//光带宽度一半
void main() {
`
);
shader.fragmentShader = shader.fragmentShader.replace(
"#include <dithering_fragment>",
`
#include <dithering_fragment>
if(vPosition.y > y && vPosition.y < y + w ){
float per = (vPosition.y-y)/w;//范围0~1
// 渐变色
gl_FragColor.rgb = mix( vec3(1.0,1.0,0.0),gl_FragColor.rgb, per);
}
if(vPosition.y <= y && vPosition.y > y - w ){
float per = (y-vPosition.y)/w;//范围0~1
gl_FragColor.rgb = mix( vec3(1.0,1.0,0.0),gl_FragColor.rgb, per);
}
`
);
console.log(shader.fragmentShader);
mesh.shader = shader;
};
mesh.position.set(0, 80, 0);
scene.add(mesh);
}
function render() {
renderer.render(scene, camera);
const deltaTime = clock.getDelta();
mesh.shader.uniforms.y.value += 30 * deltaTime;
if (mesh.shader.uniforms.y.value > 159) mesh.shader.uniforms.y.value = 0;
requestAnimationFrame(render);
}
onMounted(() => {
canvesRef.value.appendChild(renderer.domElement);
});
</script>
<style lang="scss" scoped>
.app {
position: relative;
}
</style>