ThreeJs新手入门不完全教学指南 快速入门篇(三)

在前两节课程中,向大家介绍了ThreeJs中一些基本的概念和一些常用的Api,今天的教程更加偏向实战,在这半个月的实战练习中反复遇到的,希望大家牢牢掌握。

还有大家在学习的过程中请务必注意当前使用的ThreeJs版本,开发与学习过程中结合官方提供的文档与案例效果最佳。

开发模块化拆分

在前两节的铺调后,相信大家已经可以在threejs中创建一些简单的几何模型。实际开发中,我们尽量将代码进行拆分,保证代码整洁方便维护。

大家跟着我一步步来操作

  1. 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 }
  1. 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 }
  1. 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 }
  1. render.ts
ts 复制代码
import { renderer, camera } from "./renderCamera";
import { scene } from "./scene";

function render() {
  renderer.render(scene, camera);
  requestAnimationFrame(render)
}

render()

export { renderer }
  1. 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属性。 在实际项目中,根据需求,选择适合你的模型对象

结语

好了,今天就先介绍到这里,下一篇会向大家介绍射线拾取来对画布中的模型添加相关事件,欢迎大家点赞收藏~

相关推荐
jump_jump10 小时前
网页 UI 终于能进游戏和 3D 场景了:HTML-in-Canvas 为什么重要
浏览器·three.js·canvas
kyriewen13 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒13 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
小林攻城狮14 小时前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦14 小时前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer14 小时前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队14 小时前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY14 小时前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
远航_15 小时前
OpenSpec 完整详细介绍
前端·后端
召钱熏15 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端