【2】Three.js-创建3D场景

前言

入门Three.js的第一步,就是认识场景Scene相机Camera渲染器Renderer三个基本概念

想象一下,你走进了一家电影院。

  1. 场景 Scene:整个电影院就是场景 Scene。它里面有座位、屏幕、墙壁、过道,还有各种装饰品。在 Three.js 里,场景就像这个电影院,是你放置所有物体的地方,比如你想做一个 3D 动画场景,里面的角色、道具、建筑等都在这个场景中。没有场景,就好像没有电影院,那所有东西都没地方放啦。

  2. 相机 Camera:你坐在电影院座位上看电影时,眼睛就相当于相机 Camera。相机决定了你能看到场景中的哪些部分,以及从什么角度去看。在 Three.js 中,你可以设置相机的位置、方向等,就像你在电影院里选择坐在哪个位置,是前排中间,还是后排角落,不同的位置看到的画面效果是不一样的。

  3. 渲染器 Renderer:电影院的放映机就是渲染器 Renderer。它把电影胶片上的内容投射到屏幕上,让你看到精彩的画面。在 Three.js 中,渲染器的作用就是把你在场景中设置好的各种物体,按照相机的视角,绘制到网页上,让用户能够看到最终的 3D 效果。要是没有渲染器,就如同电影院没有放映机,那再精彩的电影内容你也看不到咯。

相机瞄准原点

相机瞄准物体中心点

场景Scene

三维场景Scene

ts 复制代码
// 创建3D场景对象Scene
const scene = new THREE.Scene();

物体形状:几何体Geometry

Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。

文档搜索关键词geometry你可以看到threejs提供各种几何体相关API,具体使用方法,也可以参考文档。

ts 复制代码
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(100, 100, 100); 

物体外观:材质Material

如果你想定义物体的外观效果,比如颜色,就需要通过材质Material相关的API实现。

threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质 MeshBasicMaterial (opens new window)为例给大家实现一个红色材质效果。

ts 复制代码
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
    color: 0xff0000,//0xff0000设置材质颜色为红色
}); 

物体:网格模型Mesh

实际生活中有各种各样的物体,在threejs中可以通过网格模型 Mesh (opens new window)表示一个虚拟的物体,比如一个箱子、一个鼠标。

ts 复制代码
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh

模型位置.position

实际生活中,一个物体往往是有位置的,对于threejs而言也是一样的,你可以通过位置属性.position定义网格模型Mesh在三维场景Scene中的位置。

ts 复制代码
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);

.add()方法

在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。

ts 复制代码
scene.add(mesh); 

相机 Camera

透视投影相机PerspectiveCamera

ts 复制代码
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();

相机对象Camera具有位置属性.position,通过位置属性.position可以设置相机的位置。

arduino 复制代码
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(200, 200, 200); 

相机观察目标.lookAt()

你用相机拍照你需要控制相机的拍照目标 ,具体说相机镜头对准哪个物体或说哪个坐标。对于threejs相机而言,就是设置.lookAt()方法的参数,指定一个3D坐标。

ts 复制代码
//相机观察目标指向Threejs 3D空间中某个位置
camera.lookAt(0, 0, 0); //坐标原点
ts 复制代码
camera.lookAt(0, 20, 0);  //y轴上位置20
ts 复制代码
camera.lookAt(mesh.position);//指向mesh对应的位置

拿一下网上的分享图:

咱来聊聊 Three.js 里相机和画布的事儿哈。你想啊,就跟咱平时用相机拍照似的,拍出来的照片那不得有个大小嘛。在 Three.js 里也一样,咱得给相机在网页上输出的那个 "照片",也就是 Canvas 画布,定个尺寸。尺寸这东西呢,你就按照自己的需求随便定就行,咱先给它整个随机的。

把 Three.js 虚拟相机渲染三维场景,然后在浏览器网页上呈现出来的结果,叫做 Canvas 画布。这就好比相机咔嚓一下拍出来的照片,只不过这是在网页上呈现的三维场景。

咱先给这个 "照片" 定个大小。来,咱这么搞:

javascript 复制代码
// 给相机输出的画布定个尺寸,单位是像素px
const width = 800; // 这是宽度
const height = 500; // 这是高度

再来说说透视投影相机 PerspectiveCamera,这玩意儿有个很重要的概念叫视锥体。啥是视锥体呢?你就想象成一个四棱台形状的 3D 空间,这个空间是由透视投影相机的四个参数 fov、aspect、near、far 构成的。只有在这个四棱台空间里面的物体,才会被渲染出来,跑到这个空间外面的物体,就不会显示在 Canvas 画布上,就跟相机只能拍到镜头前面一定范围内的东西一样。

咱们接着看代码:

ts 复制代码
// width和height用来设置Three.js输出的Canvas画布尺寸,单位是像素px
const width = 800; // 宽度
const height = 500; // 高度
// 30是视场角度,width / height是Canvas画布的宽高比,1是近裁截面,3000是远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

来自官网的一张图:

最后说说 PerspectiveCamera 的参数:

参数 啥意思 默认值
fov 就是相机视锥体竖直方向的视野角度,你就想成相机竖着能看到多大范围 50
aspect 这是相机视锥体水平方向和竖直方向长度的比值,一般就设置成 Canvas 画布的宽高比 width /height 1
near 相机视锥体近裁截面离相机有多远,就像相机镜头前面多近的东西能拍到 0.1
far 相机视锥体远裁截面离相机的距离,far - near 就构成了视锥体高度方向的范围,就像相机能拍到多远的东西 2000

这么一解释,是不是感觉 Three.js 里的相机和视锥体也没那么难理解啦!

WebGL渲染器

通过WebGL渲染器WebGLRenderer (opens new window)可以实例化一个WebGL渲染器对象。

ts 复制代码
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();

设置Canvas画布尺寸.setSize()

ts 复制代码
// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)

渲染器渲染方法.render()

渲染器WebGLRenderer执行渲染方法.render()就可以生成一个Canvas画布(照片),并把三维场景Scene呈现在canvas画布上面,你可以把.render()理解为相机的拍照动作"咔"。

ts 复制代码
renderer.render(scene, camera); //执行渲染操作

渲染器Canvas画布属性.domElement

渲染器WebGLRenderer通过属性.domElement可以获得渲染方法.render()生成的Canvas画布,.domElement本质上就是一个HTML元素:Canvas画布。

ini 复制代码
document.body.appendChild(renderer.domElement);

Canvas画布插入到任意HTML元素中

html 复制代码
<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>
js 复制代码
document.getElementById('webgl').appendChild(renderer.domElement);

附上完整代码,可以试试:

ts 复制代码
import * as THREE from '../build/three.module.js';
// 浏览器控制台测试,是否引入成功
console.log(THREE.Scene);
// 创建3D场景对象Scene
const scene = new THREE.Scene();
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(100, 60, 20); 
//创建一个材质对象Material
const material = new THREE.MeshPhongMaterial({ // 基础网格材质MeshBasicMaterial (opens new window)不会受到光照影响。
    // color: 0xff0000,//0xff0000设置材质颜色为红色
    // color: 0x0000ff, //设置材质颜色
    color: 0xFFFFFF,
    shininess: 100 
});
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(100,0,0);
scene.add(mesh); //网格模型添加到场景中


// 点光源PointLight (opens new window)可以类比为一个发光点,就像生活中一个灯泡以灯泡为中心向四周发射光线。
const pointLight = new THREE.PointLight(0xffffff, 2, 10);
//点光源位置
// 设置点光源的初始位置
pointLight.position.set(2, 2, 2);
pointLight.intensity = 50000.0;//光照强度
scene.add(pointLight); //点光源添加到场景中
// 向场景中添加环境光,颜色为0x404040
scene.add(new THREE.AmbientLight(0xffffff));

// 实例化一个透视投影相机对象
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度

// const camera = new THREE.PerspectiveCamera();
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(200, 200, 200); // 相机放在x轴负半轴,目标观察点是坐标原点,这样相当于相机的视线是沿着x轴正方向
// camera.position.set(-1000, 0, 0);

//相机观察目标指向Threejs 3D空间中某个位置
// camera.lookAt(0, 0, 0); //坐标原点
camera.lookAt(mesh.position);//指向mesh对应的位置
// camera.lookAt(-1000, 0, 0);


        // AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);



// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
// 定义threejs输出画布的尺寸(单位:像素px)
const width_render = 800; //宽度
const height_render = 500; //高度
renderer.setSize(width_render, height_render); //设置three.js渲染区域的尺寸(像素px)

// renderer.render(scene, camera); //执行渲染操作
document.body.appendChild(renderer.domElement);

// 定义动画函数,用于循环渲染场景
function animate() {
    // 请求下一帧动画
    requestAnimationFrame(animate);
    // 聚光灯的X轴位置根据时间正弦变化
    // light.position.x = Math.sin(Date.now()*0.001) * 3;
    

    // 聚光灯的X轴位置根据时间正弦变化
    pointLight.position.x = Math.sin(Date.now()*0.001) * 3;
    // 聚光灯的Y轴位置根据时间余弦变化
    pointLight.position.y = Math.cos(Date.now()*0.001) * 3;

    // 使用渲染器渲染场景和相机视图
    renderer.render(scene, camera);
}
// 启动动画循环
animate();
相关推荐
程序员与背包客_CoderZ1 小时前
Node.js异步编程——Callback回调函数实现
前端·javascript·node.js·web
非凡ghost1 小时前
Pale Moon:速度优化的Firefox定制浏览器
前端·firefox
清灵xmf1 小时前
从 Set、Map 到 WeakSet、WeakMap 的进阶之旅
前端·javascript·set·map·weakset·weakmap
11054654012 小时前
11、参数化三维产品设计组件 - /设计与仿真组件/parametric-3d-product-design
前端·3d
爱笑的林羽2 小时前
Mac M系列 安装 jadx-gui
前端·macos
运维@小兵2 小时前
vue使用路由技术实现登录成功后跳转到首页
前端·javascript·vue.js
肠胃炎2 小时前
React构建组件
前端·javascript·react.js
酷爱码2 小时前
HTML5表格语法格式详解
前端·html·html5
hello_ejb32 小时前
聊聊JetCache的缓存构建
java·前端·缓存
堕落年代2 小时前
SpringSecurity当中的CSRF防范详解
前端·springboot·csrf