没有前端能抵抗住的三维效果之————个人three模版
没有前端能抵抗住的三维效果之———个人three模版
前言——使用vite + vue3 + ts+ three.js 写一个自己常用的three模版,加一点点介绍;节后陆续更新点three demo ,您们的点赞、评论是我不断向前的动力
1、创建项目
npm create vite@latest
......
2、安装three 依赖
pnpm i three
pnpm i --save-dev @types/three
pnpm i vite-plugin-glsl
依赖信息
"devDependencies": {
"@types/three": "^0.164.0",
"@vitejs/plugin-vue": "^5.0.4",
"typescript": "^5.2.2",
"vite": "^5.2.0",
"vue-tsc": "^2.0.6"
}
3、配置glsl插件,修改vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import glsl from 'vite-plugin-glsl';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
glsl({
include: [
'**/*.glsl',
'**/*.wgsl',
'**/*.vert',
'**/*.frag',
'**/*.vs',
'**/*.fs',
],
exclude: undefined,
warnDuplicatedImports: true,
defaultExtension: 'glsl',
compress: false,
root: '/',
})
],
})
4、引入依赖
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
5、声明scene
let scene = new THREE.Scene()
6、声明渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true, // 抗锯齿
})
renderer.setClearColor(0x000000)
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
7、声明渲染方法
const render = (): void => {
renderer.render(scene, camera)
}
const animate = (): void => {
requestAnimationFrame(animate)
render()
}
animate()
8、在场景中添加环境光、平行光
const createLight = () => {
// 设置环境光
const ambientLight = new THREE.AmbientLight(0xffffff) // 环境光
scene.add(ambientLight)
// 平行光
const directionalLight = new THREE.DirectionalLight(0x00ff00, 1)
// 设置光源的方向
directionalLight.position.set(50, 50, 50)
scene.add(directionalLight)
}
createLight()
9、添加一个立方体看看效果
const createMesh = () => {
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial()
return new THREE.Mesh(geometry, material)
}
const mesh = createMesh()
scene.add(mesh)
// 顺便让他旋转起来
// 在动画方法中 给立方体在x y轴上添加旋转值 每次渲染都会旋转一定值
const animate = (): void => {
requestAnimationFrame(animate)
mesh.rotation.x += 0.01 // 新增
mesh.rotation.y += 0.01 // 新增
render()
}

10、添加个两个模型进来
// 添加经典猴子头模型
// 提前设置shader材质
const material = new THREE.ShaderMaterial({
fragmentShader: fragmentShader,
vertexShader: vertexShader,
uniforms: {
uTime: { value: 0 },
},
transparent: true,
})
// 直接使用load方法加载方式
const loader = new THREE.BufferGeometryLoader()
loader.load('models/json/suzanne_buffergeometry.json', (geometry) => {
geometry.computeVertexNormals()
geometry.scale(0.5, 0.5, 0.5) // 控制模型比例——直接赋值
const mesh = new THREE.Mesh(geometry, material)
mesh.position.x = -2 // 设置模型位置——直接赋值
scene.add(mesh)
})
// 添加经典机器人
const loader2 = new GLTFLoader()
loader2.load(
'models/gltf/RobotExpressive.glb',
(gltf) => {
gltf.scene.position.set(2, -0.5, 0) // 设置模型位置——set方法
gltf.scene.scale.set(0.2, 0.2, 0.2) // 控制模型比例——set方法
scene.add(gltf.scene)
},
undefined,
(e)=> {
console.error(e)
}
)
12、引入glsl并解决引入glsl文件提示错误
import vertexShader from '../glsl/demo/main.vert'
import fragmentShader from '../glsl/demo/main.frag'
// 片元着色器
varying vec2 vUv;
uniform float uTime;
varying vec3 vNormal;
void main(){
// 使用法向量简单上个色
gl_FragColor=vec4(vec3(vNormal),1.);
#include <tonemapping_fragment>
#include <colorspace_fragment>
}
// 顶点着色器
uniform float uTime;
varying vec3 vNormal;
void main() {
vec4 mPosition = modelMatrix * vec4(position, 1.0);
mPosition.y += sin(uTime/2.)/2.; // 移动模型位置
gl_Position =projectionMatrix * viewMatrix * mPosition;
vNormal = normal;
}
// 找不到模块“../glsl/demo/main.vert”或其相应的类型声明
// 在vite-env.d.ts文件中添加如下代码
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const componnet: DefineComponent<{}, {}, any>
export default componnet
}
declare module '*.vert' {
const value: string
export default value
}
declare module '*.frag' {
const value: string
export default value
}
13、再用平面创建一个好看背景
// 使用promise 加载素材方式
const addPlaneMesh = async () => {
const loadTexture = (path: string) => {
return new Promise((resolve) => {
new THREE.TextureLoader().load(path, (texture) => {
resolve(texture)
})
})
}
let texture = await loadTexture('/img/wp2698514.png') // 刀斯林无处不在!
const geometry = new THREE.PlaneGeometry(16, 9)
const material = new THREE.MeshLambertMaterial({
// 设置纹理贴图:Texture对象作为材质map属性的属性值
map: texture as THREE.Texture
})
const planeMesh = new THREE.Mesh(geometry, material)
planeMesh.position.z = -3
scene.add(planeMesh)
}
addPlaneMesh()
// TODO: 后续再实现一个load管理器
14、配置onBeforeUnmount 刷新时避免重复添加
onBeforeUnmount(() => {
// destroyThree() // TODO: 后面再补
document.body.removeChild(renderer.domElement) // 避免热更新时创建新的canvas
})
结尾
代码地址 xzw199509/xiao-three-template (github.com) 内容如有不足之处多多提意见 ,我努力改
转载自:https://juejin.cn/post/7362547971060400166