threejs教程-几何体

简介

本系列教程需要具备threejs的基础入门知识,了场景、几何体、相机等基础概念。

学习本教程之前,建议学习【纹理贴图与环境贴图】的基础知识

几何体简介

通过前置知识,我们已经对几何体有了初步的认识。

比如最基本的立方体BoxGeometry

js 复制代码
// 2、创建几何体Geometry模型
const geometry = new THREE.BoxGeometry(20, 20, 20);

还有球形几何体SphereGeometry

js 复制代码
// 2、创建球体模型
const sphere = new THREE.SphereGeometry(20);

从官方示例图中我们可以看出,几何体都是由面组成的,所以想要深入了解几何体,我们就需要从最基本的开始。

平面几何体PlaneGeometry

Api:threejs.org/docs/#api/z...

PlaneGeometry一个用于生成平面几何体的类。其语法示例

js 复制代码
PlaneGeometry(width , height, widthSegments, heightSegments)
  • width --- 平面沿着 X 轴的宽度。默认值是 1。
  • height --- 平面沿着 Y 轴的高度。默认值是 1。
  • widthSegments --- (可选)平面的宽度分段数,默认值是 1。
  • heightSegments --- (可选)平面的高度分段数,默认值是 1。

代码示例

js 复制代码
const geometry = new THREE.PlaneGeometry(40, 40);
const material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
// 设置模型mesh的xyz坐标
mesh.position.set(0, 40, 0);
scene.add(mesh);

side: THREE.DoubleSide 是用来设定材质的哪一面应该被渲染。THREE.DoubleSide 意味着两面都会被渲染。

几何体的模型数据

我们在数据层面看看这个最基本的几何体的结构长什么样

可以看到,一个几何体的对象包含了非常多的数据

在Three.js中,geometry 对象的 attributes 属性包含了许多用于定义几何体形状和外观的信息。其中,normal、position 和 uv 是最常用的几种。

  1. normal: 法线(Normal)是三维图形中用来表示表面向外方向的一个矢量。在渲染过程中,光线会根据表面的法线方向来确定如何照亮表面。通过改变法线的方向,可以改变表面受光的方向和形状的阴影效果。
  2. position: 位置(Position)属性定义了每个顶点在三维空间中的坐标。这些坐标被用来确定顶点如何连接以及它们如何形成形状。每个顶点的位置都是相对于原点的,原点(0,0,0)通常在形状的中心。
  3. uv: UV坐标(也称为U、V、V1、V2等)定义了纹理映射的位置和方向。纹理映射是一种将二维图像(纹理)映射到三维形状表面的技术。UV坐标是用来确定纹理如何映射到形状的顶点上的。它们通常被用来实现复杂的表面细节和外观,例如通过将纹理映射到物体的表面上。

这些属性一起定义了物体的形状、外观和光照效果。

上图中,我们可以看到geometry的原型链指向BufferGeometry构造函数,这意味着它具备BufferGeometry的所有属性和方法。

BufferGeometry

我先看看官网是如何定义它的:

简单来说,它是所有不同几何体的基类,使用它可以创造出所有的几何体,比如立方体BoxGeometry、球体SphereGeometry等等。

使用BufferGeometry创建平面几何体

我们参考官方代码示例,创建一个平面几何体

js 复制代码
const geometry = new THREE.BufferGeometry();
// 创建一个简单的矩形. 在这里我们左上和右下顶点被复制了两次。
// 因为在两个三角面片里,这两个顶点都需要被用到。
const vertices = new Float32Array( [
	-1.0, -1.0,  1.0,
	 1.0, -1.0,  1.0,
	 1.0,  1.0,  1.0,

	 1.0,  1.0,  1.0,
	-1.0,  1.0,  1.0,
	-1.0, -1.0,  1.0
] );

// itemSize = 3 因为每个顶点都是一个三元组。
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const mesh = new THREE.Mesh( geometry, material );

我们对核心代码也做出一点点调整,方便更好的演示效果

js 复制代码
<template>
  <div class="wrap" ref="threeContainer"></div>
</template>

<script setup>
import * as THREE from "three";
import { onMounted, ref } from "vue";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

const threeContainer = ref(null);

// 1、创建3D场景对象Scene
const scene = new THREE.Scene();
// 添加背景颜色
const cubeTexture = new THREE.CubeTextureLoader().setPath("/sky/").load(["posx.jpg", "negx.jpg", "posy.jpg", "negy.jpg", "posz.jpg", "negz.jpg"]);
scene.background = cubeTexture;

// 添加网格地面
const gridHelper = new THREE.GridHelper(200, 10);
scene.add(gridHelper);

// 添加三维坐标轴
const axesHelper = new THREE.AxesHelper(8);
scene.add(axesHelper);

// 2.使用BufferGeometry创建模型
const geometry = new THREE.BufferGeometry();
// 创建一个简单的矩形. 在这里我们左上和右下顶点被复制了两次。
// 因为在两个三角面片里,这两个顶点都需要被用到。
const vertices = new Float32Array([
  -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0,

  1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
]);

// itemSize = 3 因为每个顶点都是一个三元组。
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// 3、使用虚拟相机观察模型
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 15);
camera.lookAt(0, 0, 0); //坐标原点

// 4、渲染3D场景到DOM上
const width = 800; //宽度
const height = 500; //高度
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.setAnimationLoop(animation);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 添加阻尼
controls.enableDamping = true;
controls.dampingFactor = 0.01;

function animation() {
  controls.update();
  renderer.render(scene, camera);
}

onMounted(() => {
  threeContainer.value.appendChild(renderer.domElement);
});
</script>

<style scoped></style>

我们也许会很好奇,为什么当移动到图形北面时,看不到物体了?其实很简单,和side: THREE.DoubleSide配置有关。

渲染面side设置

API:threejs.org/docs/#api/z...

语法结构:

sql 复制代码
.side : Integer

定义将要渲染哪一面 - 正面,背面或两者。 默认为THREE.FrontSide。其他选项有THREE.BackSideTHREE.DoubleSide

php 复制代码
// 双面渲染
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });

渲染线框wireframe

之前的章节中,我们做过线框设置

我们在代码中体现一下

php 复制代码
const material = new THREE.MeshBasicMaterial(
  { 
    color: 0xff0000, 
    side: THREE.DoubleSide, 
  + wireframe: true 
  }
);

小节

本节课,我们对几何体进行了一些较为深入的了解,知道了所有几何体继承自BufferGeometry基类,通过BufferGeometry我们也可以创建各种各样形状的几何体。因为正常开发中,一个复杂的模型几乎不会使用这种方式创建,而是直接导出其他软件开发好的模型,所以我们不做深入了解。

相关推荐
豆包MarsCode3 分钟前
我用豆包MarsCode IDE 做了一个 CSS 权重小组件
开发语言·前端·javascript·css·ide·html
22x艾克斯13 分钟前
Web Notifications API-让网页也能像QQ一样实现消息通知
前端
想你的风吹到了瑞士20 分钟前
变量提升&函数提升
前端·javascript·vue.js
生椰拿铁You32 分钟前
12 —— Webpack中向前端注入环境变量
前端
Huazzi.1 小时前
免费好用的静态网页托管平台全面对比介绍
前端·网络·github·web
吃土少女古拉拉1 小时前
前端和后端
前端·学习笔记
寒雒2 小时前
【Python】实战:实现GUI登录界面
开发语言·前端·python
独上归州2 小时前
Vue与React的Suspense组件对比
前端·vue.js·react.js·suspense
Komorebi⁼2 小时前
Vue核心特性解析(内含实践项目:设置购物车)
前端·javascript·vue.js·html·html5
明月清风徐徐2 小时前
Vue实训---0-完成Vue开发环境的搭建
前端·javascript·vue.js