创建胶囊体和甜圈圈(three.js实战8)
Posted 点燃火柴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建胶囊体和甜圈圈(three.js实战8)相关的知识,希望对你有一定的参考价值。
1. demo效果
2. 实现过程
2.1 实现原理
完全对称的几何体可以通过一条样条曲线,扫描360度创建几何体。three.js提供的LatheGeometry类,只需要提供样条曲线的点集,就可以创建出demo中的几何体。
2.2 绘制胶囊体
上图为绘制胶囊体原理图
绘制胶囊体的样条曲线分为三部分,上半部分四分之一圆弧,中间一条直线,下半部分四分之一圆,接下来看看绘制过程
// 创建胶囊体
function createCapsule() {
const radius = 4;
const height = 18;
// 存放样条曲线的点集
const points = []
//上半部分四分之一圆弧
for (let i = Math.PI / 2; i > 0; i -= 0.1) {
points.push(
new THREE.Vector3(
Math.cos(i) * radius,
Math.sin(i) * radius + height / 2,
0
)
)
}
//中间直线
for (let i = height / 2; i > -height / 2; i -= 0.1) {
points.push(
new THREE.Vector3(
radius,
i,
0
)
)
}
//下半部分四分之一圆弧
for (let i = 0; i <= Math.PI / 2; i += 0.1) {
points.push(
new THREE.Vector3(
Math.cos(i) * radius,
-Math.sin(i) * radius - height / 2,
0
)
)
}
// 补充一个点,去掉底部的小洞洞
points.push(
new THREE.Vector3(
0,
-radius - height / 2,
0
)
)
// 根据样条曲线创建扫描几何体
const geom = new THREE.LatheGeometry(
points,
200,
0,
Math.PI * 2
)
// 创建材质
const meshMaterial = new THREE.MeshPhongMaterial({
side: THREE.DoubleSide,
color: 0xfff000
})
const mesh = new THREE.Mesh(geom, meshMaterial)
// 网格对象添加到场景中
scene.add(mesh)
}
2.3 绘制甜圈圈
上图为绘制甜圈圈原理图
绘制甜圈圈的样条曲线就是一个圆,然后环绕Y轴旋转一周就可以绘制出几何体,具体如下
function createDoughnut() {
const Radius = 10;
const radius = 4;
const height = 12;
//绘制一个圆
const curve = new THREE.EllipseCurve(
0, 0, // ax, aY
radius, radius, // xRadius, yRadius
0, Math.PI * 2, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
const innerCirclePoints = curve.getPoints(100)
// 存放样条曲线的点集
const points = []
innerCirclePoints.forEach(point => {
point.x = point.x + Radius
points.push(point)
})
//根据样条曲线创建扫描几何体
const geom = new THREE.LatheGeometry(
points,
200,
0,
Math.PI * 2
)
// 创建材质
const meshMaterial = new THREE.MeshPhongMaterial({
color: 0x318eff,
side: THREE.DoubleSide
})
const mesh = new THREE.Mesh(geom, meshMaterial)
mesh.position.x = 30
//添加到场景中
scene.add(mesh)
}
3 demo代码
<!DOCTYPE html>
<html>
<head>
<title>Example latheGeometry</title>
<script type="text/javascript" src="../three/build/three.js"></script>
<script type="text/javascript" src="../three/examples/js/controls/OrbitControls.js"></script>
<script type="text/javascript" src="../three/examples/js/libs/stats.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="Stats-output"></div>
<div id="WebGL-output"></div>
<script type="text/javascript">
let stats, controls;
let camera, scene, renderer;
function initScene() {
scene = new THREE.Scene();
//用一张图加载为纹理作为场景背景
scene.background = new THREE.TextureLoader().load("../assets/textures/starry-deep-outer-space-galaxy.jpg")
}
function initCamera() {
camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 1, 20000);
camera.position.set(20, 50, 100);
}
function initLight() {
//添加环境光
var ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(25, 30, 50);
spotLight.castShadow = true;
scene.add(spotLight);
}
function initModel() {
createCapsule();
createDoughnut();
}
// 创建胶囊体
function createCapsule() {
const radius = 4;
const height = 18;
// 存放样条曲线的点集
const points = []
//上半部分四分之一圆弧
for (let i = Math.PI / 2; i > 0; i -= 0.1) {
points.push(
new THREE.Vector3(
Math.cos(i) * radius,
Math.sin(i) * radius + height / 2,
0
)
)
}
//中间直线
for (let i = height / 2; i > -height / 2; i -= 0.1) {
points.push(
new THREE.Vector3(
radius,
i,
0
)
)
}
//下半部分四分之一圆弧
for (let i = 0; i <= Math.PI / 2; i += 0.1) {
points.push(
new THREE.Vector3(
Math.cos(i) * radius,
-Math.sin(i) * radius - height / 2,
0
)
)
}
// 补充一个点,去掉底部的小洞洞
points.push(
new THREE.Vector3(
0,
-radius - height / 2,
0
)
)
// 根据样条曲线创建扫描几何体
const geom = new THREE.LatheGeometry(
points,
200,
0,
Math.PI * 2
)
// 创建材质
const meshMaterial = new THREE.MeshPhongMaterial({
side: THREE.DoubleSide,
color: 0xfff000
})
const mesh = new THREE.Mesh(geom, meshMaterial)
// 网格对象添加到场景中
scene.add(mesh)
}
function createDoughnut() {
const Radius = 10;
const radius = 4;
const height = 12;
//绘制一个圆
const curve = new THREE.EllipseCurve(
0, 0, // ax, aY
radius, radius, // xRadius, yRadius
0, Math.PI * 2, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
);
const innerCirclePoints = curve.getPoints(100)
// 存放样条曲线的点集
const points = []
innerCirclePoints.forEach(point => {
point.x = point.x + Radius
points.push(point)
})
//根据样条曲线创建扫描几何体
const geom = new THREE.LatheGeometry(
points,
200,
0,
Math.PI * 2
)
// 创建材质
const meshMaterial = new THREE.MeshPhongMaterial({
color: 0x318eff,
side: THREE.DoubleSide
})
const mesh = new THREE.Mesh(geom, meshMaterial)
mesh.position.x = 30
//添加到场景中
scene.add(mesh)
}
function initRender() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
})
//renderer.shadowMap.enabled = true // 显示阴影
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x0f2d48); //设置背景色
renderer.toneMapping = THREE.ACESFilmicToneMapping;
document.getElementById("WebGL-output").appendChild(renderer.domElement);
}
//初始化轨道控制器
function initControls() {
clock = new THREE.Clock() // 创建THREE.Clock对象,用于计算上次调用经过的时间
controls = new THREE.OrbitControls(camera, renderer.domElement)
//controls.autoRotate = true // 是否自动旋转
}
function initStats() {
stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
document.getElementById("Stats-output").appendChild(stats.domElement);
}
function render() {
updateFun()
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function updateFun() {
stats.update();
const delta = clock.getDelta() // 获取自上次调用的时间差
controls.update(delta) // 相机更新
}
//初始化
function init() {
initScene();
initCamera();
initLight();
initRender();
initStats();
initControls();
initModel();
render();
}
window.onload = init;
</script>
</body>
</html>
以上是关于创建胶囊体和甜圈圈(three.js实战8)的主要内容,如果未能解决你的问题,请参考以下文章
绘制不断变色的台体,BufferGeometry和ShaderMaterial的黄金组合(three.js实战5)
使用shader着色器程序创建扩散光圈效果(three.js实战10)