常见几何体
Three.js中提供了很多几何体API,其中几种常见几何体如下所示
长方体:BoxGeometry
球体:SphereGeometry
圆柱体:CylinderGeometry
矩形平面:PlaneGeometry
圆形平面:CircleGeometry
更多几何体API参考官网:https://threejs.org/docs/index.html#api/en/geometries/BoxGeometry
让我们在之前构建的3D场景中试一下这些几何体的效果
创建几何体
//创建正方体(参数为长、宽、高)
const cuboid = new THREE.BoxGeometry(50, 50, 50)
//创建球体(参数为球体半径)
const sphere = new THREE.SphereGeometry(25)
//创建圆柱体(参数为底面半径、顶面半径、高)
const cylinder = new THREE.CylinderGeometry(25, 25, 100)
//创建矩形平面(参数为长、宽)
const rectPlane = new THREE.PlaneGeometry(50, 50)
//创建圆形平面(参数为半径)
const circPlane = new THREE.CircleGeometry(25)
创建材质
//创建一个材质
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,
side: THREE.DoubleSide, //设置为双面可见
})
创建模型并添加到场景中
// 创建正方体模型,设置位置位于x轴负半轴
const cuboidMesh = new THREE.Mesh(cuboid, material)
cuboidMesh.position.set(-140, 0, 0)
// 创建球体模型,设置位置位于x轴负半轴
const sphereMesh = new THREE.Mesh(sphere, material)
sphereMesh.position.set(-70, 0, 0)
// 创建圆柱体模型,设置位置位于原点
const cylinderMesh = new THREE.Mesh(cylinder, material)
cylinderMesh.position.set(0, 0, 0)
// 创建矩形平面模型,设置位置位于x轴正半轴
const rectPlaneMesh = new THREE.Mesh(rectPlane, material)
rectPlaneMesh.position.set(70, 0, 0)
// 创建圆形平面模型,设置位置位于x轴正半轴
const circPlaneMesh = new THREE.Mesh(circPlane, material)
circPlaneMesh.position.set(140, 0, 0)
// 将模型添加到场景中
scene.add(cuboidMesh)
scene.add(sphereMesh)
scene.add(cylinderMesh)
scene.add(rectPlaneMesh)
scene.add(circPlaneMesh)
通过创建几何体、创建材质、使用几何体和材质创建模型、将模型添加到场景中之后就可以在页面上看到我们添加的模型了。设置模型位置很重要,如果不设置位置的话,模型将全部默认叠放到坐标原点,结果就是什么都看不清。我们可以借助辅助观察坐标系(AxesHelper)来更直观的观察模型所在的位置,只需加入下面的代码即可。
// 创建辅助观察的坐标系(参数为每个轴的长度)
const axesHelper = new THREE.AxesHelper(150)
// 将坐标系添加到场景中
scene.add(axesHelper)
最后得到的效果应如下图所示。
常见材质
在Three.js中,材质是非常常见且重要的概念,试想一下如果一个球体只有形状,没有材质,那我们并不能认出它是什么东西。但如果一个球体加了材质,那我们就可以分辨出这是一个足球还是篮球或者是地球这类具体的事物。下面让我们来看一下Three.js给我们提供的几种常见的网格材质。
基础材质:MeshBasicMaterial
漫反射材质:MeshLambertMaterial
高光材质:MeshPhongMaterial
物理材质:MeshStandardMaterial、MeshPhysicalMaterial
这些材质的详细解释内容比较多具体可以参考官网,简单来说就是基础材质是一种不受光照影响的材质;漫反射材质能受光照影响,但是不能模拟出高光效果;高光材质可以模拟出高光的效果;物理材质可以模拟出更好的物理效果。接下来让我们简单的试一下这些效果。
创建不同材质
//创建一个基础材质
const basicMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
})
//创建一个漫反射材质
const lambertMaterial = new THREE.MeshLambertMaterial({
color: 0xffff00,
})
// 创建一个高光材质
const phongMaterial = new THREE.MeshPhongMaterial({
color: 0x00ffc3,
shininess: 20,
})
// 创建一个Standard材质
const standardMaterial = new THREE.MeshStandardMaterial({
color: 0x00b0f0,
metalness: 0, //金属度
roughness: 0.5, //粗糙度
})
// 创建一个Physical材质
const physicalMaterial = new THREE.MeshPhysicalMaterial({
color: 0x00ff00,
metalness: 0, //金属度
roughness: 0.5, //粗糙度
clearCoat: 0, //清漆层
clearCoatRoughness: 0, //清漆层粗糙度
ior: 1.5, //非金属材质折射率
})
配置模型材质
// 创建正方体模型,设置位置位于x轴负半轴
const cuboidMesh = new THREE.Mesh(cuboid, basicMaterial)
cuboidMesh.position.set(-140, 0, 0)
// 创建球体模型,设置位置位于x轴负半轴
const sphereMesh = new THREE.Mesh(sphere, phongMaterial)
sphereMesh.position.set(-70, 0, 0)
// 创建圆柱体模型,设置位置位于原点
const cylinderMesh = new THREE.Mesh(cylinder, lambertMaterial)
cylinderMesh.position.set(0, 0, 0)
// 创建矩形平面模型,设置位置位于x轴正半轴
const rectPlaneMesh = new THREE.Mesh(rectPlane, standardMaterial)
rectPlaneMesh.position.set(70, 0, 0)
// 创建圆形平面模型,设置位置位于x轴正半轴
const circPlaneMesh = new THREE.Mesh(circPlane, physicalMaterial)
circPlaneMesh.position.set(140, 0, 0)
此时上面创建的模型已经有了材质,但在页面上看到的效果会比较诡异,模型黑不溜秋的。这是因为环境中没有添加光照,所以并不能看起模型的样子,就像晚上不开灯也没有月光的时候一样。让我们赶紧来把光照加入到场景中吧
// 创建环境光(参数为光照颜色、光照强度)
const ambient = new THREE.AmbientLight(0xffffff, 0.4)
// 将环境光添加到场景中
scene.add(ambient)
// 创建点光源(参数为光照颜色,光照强度,最大照射距离:0为无限远、衰退量)
const pointLight = new THREE.PointLight(0xffffff, 3000, 0, 1)
// 设置点光源位置
pointLight.position.set(0, 150, 100)
// 将点光源添加到场景中
scene.add(pointLight)
// 创建点光源辅助观察对象(参数为点光源、尺寸)
const pointLightHelper = new THREE.PointLightHelper(pointLight, 2)
// 将点光源辅助观察对象添加到场景中
scene.add(pointLightHelper)
上面我们给场景添加了环境光和点光源,顺便加了一个点光源辅助观察对象,用于直观的感受点光源所在的位置。现在来我们就可以在页面上看到添加光源后的效果了(如下图所示)。其中白色的点就是点光源目前所处的位置。使用鼠标转动角度可以更加清楚的观察到光线对于物体表面的影响。
常见光源
见证了光源对物体的影响后,接下来我们看一下Three.js中几种常见的光源。
环境光:AmbientLight
点光源:PointLight
聚光灯光源:SpotLight
平行光:DirectionalLight
图片来自于http://www.webgl3d.cn/pages/343ae9/
简而言之,环境光是最基础的一种光照,会均匀的照亮场景中的所有物体,并且没有位置和方向;点光源就像是电灯泡一样,以一个点为中心,向四周散发光芒;聚光灯光源就像是舞台的聚光灯一样,从一个点射出,光线呈类似圆锥的形状;平行光就是一束光沿特定的方向射出。
创建光源
在上面材质的例子中我们已经使用过了环境光与点光源,这里就不再赘述。
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
// 设置光源的位置
directionalLight.position.set(0, -150, -100)
// 平行光指向的对象
directionalLight.target = sphereMesh
scene.add(directionalLight)
// 创建平行光辅助观察对象
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000)
// 将平行光辅助观察对象添加到场景中
scene.add(dirLightHelper)
// 创建聚光灯光源
const spotLight = new THREE.SpotLight(0xffffff, 1.0)
// 设置聚光灯光源位置
spotLight.position.set(-140, 100, 0)
// 设置聚光灯光源照射的目标对象
spotLight.target = cylinderMesh
// 设置聚光灯光源发散角度
spotLight.angle = Math.PI / 6
// 将聚光灯光源添加到场景中
scene.add(spotLight) //光源添加到场景中
// 创建聚光灯光源辅助观察对象
const spotLightHelper = new THREE.SpotLightHelper(spotLight, 0xffffff)
// 将聚光灯光源辅助观察对象添加到场景中
scene.add(spotLightHelper)
在上面的代码中,我们创建了平行光与聚光灯光源并设置了相应的参数。并且还引入了对应的辅助观察对象,用于观察其在场景中的位置。效果如图所示(其中白色的点为点光源,红色的线为平行光,白色的椎体为聚光灯光源)
到此为止我们大概了解了常见Three.js中常见的几何体、材质与光源,这系列帖子随缘更新,感兴趣的小伙伴可以去官网进行更深入的学习。
完整代码
<template>
<div id="threeBox"></div>
</template>
<script setup>
import { onMounted } from 'vue'
// 引入Three.js
import * as THREE from 'three'
// 引入轨道控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 定义宽度和高度
const width = innerWidth
const height = innerHeight
// 创建场景
const scene = new THREE.Scene()
// 创建相机
const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 3000)
// 设置相机位置
camera.position.set(0, 0, 500)
// 设置相机朝向
camera.lookAt(0, 0, 0)
// 创建渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染器尺寸
renderer.setSize(width, height)
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150)
scene.add(axesHelper)
//创建正方体(参数为长、宽、高)
const cuboid = new THREE.BoxGeometry(50, 50, 50)
//创建球体(参数为球体半径)
const sphere = new THREE.SphereGeometry(25)
//创建圆柱体(参数为底面半径、顶面半径、高)
const cylinder = new THREE.CylinderGeometry(25, 25, 100)
//创建矩形平面(参数为长、宽)
const rectPlane = new THREE.PlaneGeometry(50, 50)
//创建圆形平面(参数为半径)
const circPlane = new THREE.CircleGeometry(25)
//创建一个基础材质
const basicMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
})
//创建一个漫反射材质
const lambertMaterial = new THREE.MeshLambertMaterial({
color: 0xffff00,
})
// 创建一个高光材质
const phongMaterial = new THREE.MeshPhongMaterial({
color: 0x00ffc3,
shininess: 20,
})
// 创建一个Standard材质
const standardMaterial = new THREE.MeshStandardMaterial({
color: 0x00b0f0,
metalness: 0, //金属度
roughness: 0.5, //粗糙度
})
// 创建一个Physical材质
const physicalMaterial = new THREE.MeshPhysicalMaterial({
color: 0x00ff00,
metalness: 0, //金属度
roughness: 0.5, //粗糙度
clearCoat: 0, //清漆层
clearCoatRoughness: 0, //清漆层粗糙度
ior: 1.5, //非金属材质折射率
})
// 创建正方体模型,设置位置位于x轴负半轴
const cuboidMesh = new THREE.Mesh(cuboid, basicMaterial)
cuboidMesh.position.set(-140, 0, 0)
// 创建球体模型,设置位置位于x轴负半轴
const sphereMesh = new THREE.Mesh(sphere, phongMaterial)
sphereMesh.position.set(-70, 0, 0)
// 创建圆柱体模型,设置位置位于原点
const cylinderMesh = new THREE.Mesh(cylinder, lambertMaterial)
cylinderMesh.position.set(0, 0, 0)
// 创建矩形平面模型,设置位置位于x轴正半轴
const rectPlaneMesh = new THREE.Mesh(rectPlane, standardMaterial)
rectPlaneMesh.position.set(70, 0, 0)
// 创建圆形平面模型,设置位置位于x轴正半轴
const circPlaneMesh = new THREE.Mesh(circPlane, physicalMaterial)
circPlaneMesh.position.set(140, 0, 0)
// 将模型添加到场景中
scene.add(cuboidMesh)
scene.add(sphereMesh)
scene.add(cylinderMesh)
scene.add(rectPlaneMesh)
scene.add(circPlaneMesh)
// 创建环境光(参数为光照颜色、光照强度)
const ambient = new THREE.AmbientLight(0xffffff, 0.4)
// 将环境光添加到场景中
scene.add(ambient)
// 创建点光源(参数为光照颜色,光照强度,最大照射距离:0为无限远、衰退量)
const pointLight = new THREE.PointLight(0xffffff, 3000, 0, 1)
// 设置点光源位置
pointLight.position.set(0, 150, 100)
// 将点光源添加到场景中
scene.add(pointLight)
// 创建点光源辅助观察对象(参数为点光源、尺寸)
const pointLightHelper = new THREE.PointLightHelper(pointLight, 2)
// 将点光源辅助观察对象添加到场景中
scene.add(pointLightHelper)
// 创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
// 设置光源的位置
directionalLight.position.set(0, -150, -100)
// 平行光指向的对象
directionalLight.target = sphereMesh
scene.add(directionalLight)
// 创建平行光辅助观察对象
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000)
// 将平行光辅助观察对象添加到场景中
scene.add(dirLightHelper)
// 创建聚光灯光源
const spotLight = new THREE.SpotLight(0xffffff, 1.0)
// 设置聚光灯光源位置
spotLight.position.set(-140, 100, 0)
// 设置聚光灯光源照射的目标对象
spotLight.target = cylinderMesh
// 设置聚光灯光源发散角度
spotLight.angle = Math.PI / 6
// 将聚光灯光源添加到场景中
scene.add(spotLight) //光源添加到场景中
// 创建聚光灯光源辅助观察对象
const spotLightHelper = new THREE.SpotLightHelper(spotLight, 0xffffff)
// 将聚光灯光源辅助观察对象添加到场景中
scene.add(spotLightHelper)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 监听轨道控制器的改变,并在改变后重新渲染
controls.addEventListener('change', (e) => {
renderer.render(scene, camera)
})
// 渲染Canvas画布,将场景和相机作为参数传入
renderer.render(scene, camera)
// 页面挂载完毕后将domElement插入到页面元素内
onMounted(() => {
document.getElementById('threeBox').appendChild(renderer.domElement)
})
</script>
<style scoped>
#threeBox {
width: 100%;
height: 100%;
}
</style>