Load PLY format model
1.demo effect
As shown in the figure above, the demo loads the PLY format model through PLYLoader, and presents the car model on the page
2. Implementation points
2.1 PLY model placement path
When loading files in vue, the default path is public, so the files that need to be loaded are placed in this path, and the variable publicPath is created in the data attribute of vue. The value of this variable is the environment variable process.env.BASE_URL in vue
data() {
return {
publicPath: process.env.BASE_URL
}
}
2.2 Load PLY model
Here we import the model through PLYLoader, but here we need to pay attention to the import path, splicing the publicpath variable we created to the file path, and the related processing can be carried out in the imported callback function as follows:
const loader = new PLYLoader()
loader.load(`${
THIS.publicPath}models/test.ply`, model => {
//对导入模型进行相关处理
...
})
2.3 Create particle material texture
//生成纹理
generateSprite() {
const canvas = document.createElement('canvas')
canvas.width = 16
canvas.height = 16
const context = canvas.getContext('2d')
const gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
)
gradient.addColorStop(0, 'rgba(255,255,255,1)')
gradient.addColorStop(0.2, 'rgba(0,255,255,1)')
gradient.addColorStop(0.4, 'rgba(0,0,64,1)')
gradient.addColorStop(1, 'rgba(0,0,0,1)')
context.fillStyle = gradient
context.fillRect(0, 0, canvas.width, canvas.height)
const texture = new THREE.Texture(canvas)
texture.needsUpdate = true
return texture
}
2.4 Format as a particle system
// 创建粒子材质
const material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.4,
opacity: 0.6,
transparent: true,
blending: THREE.AdditiveBlending,
map: this.generateSprite()
})
// 创建粒子系统
this.mesh = new THREE.Points(geometry, material)
// 添加到场景
this.scene.add(this.mesh)
3.demo code
<template>
<div>
<div id="container"></div>
</div>
</template>
<script>
import * as THREE from 'three'
import {
OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import {
PLYLoader } from 'three/examples/jsm/loaders/PLYLoader.js'
export default {
data() {
return {
publicPath: process.env.BASE_URL,
mesh: null,
camera: null,
scene: null,
renderer: null,
controls: null
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.createScene() // 创建场景
this.loadPLY() // 加载PLY模型
this.createLight() // 创建光源
this.createCamera() // 创建相机
this.createRender() // 创建渲染器
this.createControls() // 创建控件对象
this.render() // 渲染
},
// 创建场景
createScene() {
this.scene = new THREE.Scene()
},
// 加载PLY模型
loadPLY() {
const THIS = this
const loader = new PLYLoader()
loader.load(`${
THIS.publicPath}models/test.ply`, geometry => {
// 创建粒子材质
const material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.4,
opacity: 0.6,
transparent: true,
blending: THREE.AdditiveBlending,
map: this.generateSprite()
})
// 创建粒子系统
this.mesh = new THREE.Points(geometry, material)
// 添加到场景
this.scene.add(this.mesh)
})
},
//生成纹理
generateSprite() {
const canvas = document.createElement('canvas')
canvas.width = 16
canvas.height = 16
const context = canvas.getContext('2d')
const gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
)
gradient.addColorStop(0, 'rgba(255,255,255,1)')
gradient.addColorStop(0.2, 'rgba(0,255,255,1)')
gradient.addColorStop(0.4, 'rgba(0,0,64,1)')
gradient.addColorStop(1, 'rgba(0,0,0,1)')
context.fillStyle = gradient
context.fillRect(0, 0, canvas.width, canvas.height)
const texture = new THREE.Texture(canvas)
texture.needsUpdate = true
return texture
},
// 创建光源
createLight() {
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) // 创建环境光
this.scene.add(ambientLight) // 将环境光添加到场景
const spotLight = new THREE.SpotLight(0xffffff) // 创建聚光灯
spotLight.position.set(50, 50, 50)
spotLight.castShadow = true
this.scene.add(spotLight)
},
// 创建相机
createCamera() {
const element = document.getElementById('container')
const width = element.clientWidth // 窗口宽度
const height = element.clientHeight // 窗口高度
const k = width / height // 窗口宽高比
// PerspectiveCamera( fov, aspect, near, far )
this.camera = new THREE.PerspectiveCamera(35, k, 0.1, 1000)
this.camera.position.set(20, 20, 20) // 设置相机位置
this.camera.lookAt(new THREE.Vector3(10, 40, 0)) // 设置相机方向
this.scene.add(this.camera)
},
// 创建渲染器
createRender() {
const element = document.getElementById('container')
this.renderer = new THREE.WebGLRenderer({
antialias: true, alpha: true })
this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
this.renderer.shadowMap.enabled = true // 显示阴影
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
element.appendChild(this.renderer.domElement)
},
render() {
if (this.mesh) {
this.mesh.rotation.y += 0.006
}
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this.render)
},
// 创建控件对象
createControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
}
}
}
</script>
<style>
#container {
position: absolute;
width: 100%;
height: 100%;
}
</style>