Table of contents
I. Introduction
Since the 3D model needs to render each face and edge of the model, the problem of opening the model is often very slow. So how to solve this problem, the simplest and crude method is of course to continuously optimize the model loading, but optimization is often the most difficult. On the other hand, let users accurately open the model they need, can this problem be alleviated to a certain extent? So it is necessary to realize the thumbnail of the 3D model.
2. Introduction
The main framework for implementing model thumbnails in this article is Vue3, which uses threejs to manage models. It is generally divided into three steps: 1. Prepare the threejs scene container; 2. Build the threejs scene and load the model; 3. Convert the canvas to base64 encoding and load it into the img container.
3. Simple implementation
0. Prepare
First of all, since you want to import the model, you need to prepare a model that you want to add to the scene. Here I recommend a model download site, SketchChfab , where most of the referenced models in the Threejs source code come from.
Then, you need to prepare a container for the generated canvas:
<template>
<div id="thumbnail"></div>
</template>
Create a ts file to integrate the operations that can be used in the model scene, and name it sceneCreator here:
1. Create a scene
The basic scene creation will not be repeated. If you don’t understand it, you can refer to the simple use of Three.js in Vue3 .
//引入threejs
import * as THREE from 'three'
//引入加载器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
class SceneCreator {
public scene: THREE.Scene = new THREE.Scene()
private camera: THREE.PerspectiveCamera
private renderer: THREE.Renderer
private controls: OrbitControls
constructor (fatherElement: HTMLElement) {
this.scene.background = new THREE.Color(0xaaaaaa)
// 添加光源
this.initLight()
// 创建一个透视相机
const width = window.innerWidth; const height = window.innerHeight
this.camera = new THREE.PerspectiveCamera(45, width / height, 1, 5000)
// 设置相机位置
this.camera.position.set(100, 400, 600)
// 设置相机方向
this.camera.lookAt(0, 0, 0)
// 创建辅助坐标轴
const axesHelper = new THREE.AxesHelper(100)
this.scene.add(axesHelper)
// 创建一个WebGL渲染器
this.renderer = new THREE.WebGLRenderer()
this.renderer.setSize(width, height)
this.renderer.render(this.scene, this.camera)
fatherElement.appendChild(this.renderer.domElement)
}
render () {
this.renderer.render(this.scene, this.camera)
}
/**
*灯光初始化
*/
initLight () {
const ambient = new THREE.AmbientLight(0x505050)
this.scene.add(ambient)
const pointLight1 = new THREE.PointLight(0xffffff, 0.4)
const pointLight2 = new THREE.PointLight(0xffffff, 0.4)
pointLight1.position.set(200, 300, 400)
this.scene.add(pointLight1)
pointLight2.position.set(-200, -300, -400)
this.scene.add(pointLight2)
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6)
hemiLight.color.setHSL(0.6, 1, 0.6)
hemiLight.groundColor.setHSL(0.095, 1, 0.75)
hemiLight.position.set(0, 200, 0)
this.scene.add(hemiLight)
const hemiLightHelper = new THREE.HemisphereLightHelper(hemiLight, 10)
this.scene.add(hemiLightHelper)
const dirLight = new THREE.DirectionalLight(0xffffff, 1)
dirLight.color.setHSL(0.1, 1, 0.95)
dirLight.position.set(-100, 175, 100)
dirLight.position.multiplyScalar(30)
this.scene.add(dirLight)
}
}
//暴露
export { SceneCreator }
2. Model import
Here, use the GLTFLoader in threejs to load the downloaded glb. Since making a thumbnail does not require any special operations on the model, you only need to add the loaded model to the scene.
createCar () {
const loader = new GLTFLoader()
const glbHref = new URL('../assets/glb/car/ferrari_458.glb', import.meta.url).href
loader.load(glbHref, (gltf) => {
const carModel = gltf.scene.children[0]
this.scene.add(carModel)
})
}
3. Generate Base64
<script lang='ts' setup>
import { onMounted, Ref, ref } from 'vue'
import { SceneCreator } from '../utils/sceneCreator'
let myScene: SceneCreator
const img:Ref<string> = ref('')
const createThumbnails = async () => {
const el = document.getElementById('thumbnail')
if (el) {
// 创建场景
myScene = new SceneCreator(el)
// 场景自适应,防止模型变形
myScene.resize()
// 载入模型,由于loader是异步的所以我们需要等它加载好后再生成base64,否则生成的图片是没有模型的
await myScene.createCar()
myScene.render()
// 生成base64
const canvas = el.children[0] as HTMLCanvasElement
img.value = canvas.toDataURL('img/png')
// 不需要展示canvas就移除它
// el.remove()
}
}
onMounted(() => {
createThumbnails()
})
</script>
4. Bind pictures
Create an img tag, and bind the base64 generated in step 3 to the scr of the img tag.
<template>
<div id="thumbnail"></div>
<img :src="img" alt="">
</template>