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~1gl_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>