在前两节课程中,向大家介绍了ThreeJs中一些基本的概念和一些常用的Api,今天的教程更加偏向实战,在这半个月的实战练习中反复遇到的,希望大家牢牢掌握。
还有大家在学习的过程中请务必注意当前使用的ThreeJs版本,开发与学习过程中结合官方提供的文档与案例效果最佳。
开发模块化拆分
在前两节的铺调后,相信大家已经可以在threejs中创建一些简单的几何模型。实际开发中,我们尽量将代码进行拆分,保证代码整洁方便维护。
大家跟着我一步步来操作
model.ts
ts
import * as THREE from 'three';
const geometry = new THREE.BoxGeometry(50, 50, 50);
const material = new THREE.MeshLambertMaterial({
color: 0xcccccc
})
const mesh = new THREE.Mesh(geometry, material);
const model = new THREE.Group()
model.add(mesh)
export { model }
scene.ts
ts
import * as THREE from 'three';
import { model } from './model'
const scene = new THREE.Scene();
scene.add(model)
const amibient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(amibient);
const dirLight1 = new THREE.DirectionalLight(0xffffff, 1);
dirLight1.position.set(400, 400, 400);
scene.add(dirLight1);
const dirLight2 = new THREE.DirectionalLight(0xffffff, 1);
dirLight2.position.set(-400, -400, -400);
scene.add(dirLight2);
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
export { scene }
renderCamera.ts
ts
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(45, width / height, 0.25, 2000);
camera.position.set(200, 200, 200);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio);
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
const controls = new OrbitControls(camera, renderer.domElement);
controls.update()
export { renderer, camera }
render.ts
ts
import { renderer, camera } from "./renderCamera";
import { scene } from "./scene";
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render)
}
render()
export { renderer }
index.vue
ts
<script lang="ts" setup>
import { renderer } from './render';
const initRender = () => {
document.body.appendChild(renderer.domElement);
};
onMounted(() => {
initRender();
});
</script>
经过以上操作,我们在画布中间创建了一个方形模型,并且有着清晰的代码结构。后面我们可以根据需求添加模型文件,引入到scene文件add添加即可。
场景信息标注
实际开发中,经常会有这样一个需求,在产品模型上标注产品的名称、价格等一系列信息,这时就需要将我们前端常用的HTML代码与ThreeJs结合来实现。
CSS2DObject、CSS2DRenderer
首先我们来添加2D模型查看效果 创建css2D.ts
js
const create2DObject = () => {
const div = document.createElement("div")
div.classList.add("flex", "justify-around",
"py-2", "w-40", "border", "border-yellow-300", "absolute", "text-light-50")
div.innerHTML = ` <span>花西子</span>
<span>79</span>`
const tag = new CSS2DObject(div)
tag.position.y += 40
return tag
}
export { create2DObject }
这里用了windicss,没有使用的根据语义添加css属性即可
在model.ts
中引入
ts
import { create2DObject } from './css2D'
const tag = create2DObject()
model.add(tag)
renderCamera.ts
添加
ts
const css2Renderer = new CSS2DRenderer();
css2Renderer.setSize(window.innerWidth, window.innerHeight);
css2Renderer.domElement.style.position = 'absolute';
css2Renderer.domElement.style.top = '0';
css2Renderer.domElement.style.left = '0';
css2Renderer.domElement.style.pointerEvents = 'none';
导出css2Renderer
在render.ts
引入 render函数内添加
js
css3Renderer.render(scene, camera);
在index.vue
js
const initRender = () => {
document.body.appendChild(renderer.domElement);
document.body.appendChild(css2Renderer.domElement);
};
效果如图,并且旋转视角时,标签内容始终平铺在画布上
CSS3DObject、CSS3DRenderer
操作其实与2D类似,大家把相应的CSS2DObject换成CSS3DObject CSS2DRenderer换成CSS3DRenderer即可 这里贴下关键代码
ts
import { CSS3DObject } from "three/examples/jsm/renderers/CSS3DRenderer.js"
const create3DObject = () => {
const div = document.createElement("div")
div.classList.add("flex", "justify-around",
"py-2", "w-40", "border", "border-yellow-300", "absolute", "text-light-50")
div.innerHTML = ` <span>花西子</span>
<span>79</span>`
const tag = new CSS3DObject(div)
tag.position.y += 40
return tag
}
export { create3DObject }
ts
const css3Renderer = new CSS3DRenderer();
css3Renderer.setSize(window.innerWidth, window.innerHeight);
css3Renderer.domElement.style.position = 'absolute';
css3Renderer.domElement.style.top = '0';
css3Renderer.domElement.style.left = '0';
css3Renderer.domElement.style.pointerEvents = 'none';
其余方法都是一样的
这时候转动视角,会发现标签会随着视角发生变化,具有了3D属性。 在实际项目中,根据需求,选择适合你的模型对象
结语
好了,今天就先介绍到这里,下一篇会向大家介绍射线拾取来对画布中的模型添加相关事件,欢迎大家点赞收藏~