three.js学习之立体圆环及立体扭结圆环

今天我们学习初级阶段能学到的最后两个图元,圆环和扭结圆环。还是和之前一样,将three.js学习之类球多面体的html代码复制出来新建一个文件,删除有关多面体的代码,保留公共部分。

three.js之立体圆环TorusGeometry

直接上构造用的参数:

  • radius 环面的半径,从环面的中心到管道横截面的中心。默认值是1。这个半径是从圆环的中心到圆环管道中心的距离。所以这个半径乘以2不是整个圆环的大小。
  • tube 管道的半径;radius + tube后再乘以2,我们就能得到实际圆环的大小了。
  • radialSegments 管道自身的分段数,默认值为8,最小是2,当成为2时,就是一个平面。分段越少,管道越扁,分段越多,管道越圆。
  • tubularSegments 圆环的分段数,默认值为6,最小值为2,2时圆环成一条直线。
  • arc — 圆环的圆心角(单位是弧度),默认值为Math.PI * 2。

说完了基本参数,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
// 创建圆环示例代码
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 20
const arc = getSearchObj('arc') || 2

const torusGeometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc * Math.PI)
const torus = new THREE.Mesh(torusGeometry, material)

const torusLineGeometry = new THREE.WireframeGeometry(torusGeometry)
const torusLine = new THREE.LineSegments(torusLineGeometry, lineMaterial)
torus.position.x = -2
torus.position.y = -2
torusLine.position.y = -2
if (search.includes('torus') || !search) {
group.add(torus, torusLine)
}

}

上面的代码中,我将用到的参数都配置成了可以在URL中调整的,大家可以复制或者点击这个链接https://www.91yqz.com/learnThree/learnThreeTorusAndturusKnot.html?show=[torus]&arc=2&radialSegments=6&tubularSegments=10调整不同的参数去看看在不同情况下的变化。下面的案例是我不传参数默认情况下的demo。

下面这个关于圆环TorusGeometry的示例中,我将tubularSegments设置为3,圆环变成了三角环。希望有缘人多多尝试不同数字,看看不同的效果。

下面这个关于圆环TorusGeometry的示例中,我将arc设置为0.8,圆环变成了小扇形。

这里我们可以去尝试,也可以思考,同时改变分段,圆心等参数,会有什么不同呢?

three.js TorusKnotGeometry 圆形扭结几何体

  • radius 圆环的半径,默认值为1。这个不太好理解,其实就是扭结中心到最边上的距离。
  • tube 管道的半径,默认值为0.4。
  • radialSegments 管道自身的分段数,默认值为8,最小是2,当成为2时,就是一个平面。分段越少,管道越扁,分段越多,管道越圆。
  • tubularSegments 圆环的分段数,默认值为64,最小值为2,2时圆环成一条直线。
  • p 管道自身旋转扭结的次数,默认值是2.
  • q 管道扭结次数,默认值是3

演示代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
// 圆环扭结集合体
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 100
const p = getSearchObj('p') || 3
const q = getSearchObj('q') || 4
const torusKnotGeometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
const tirusKnot = new THREE.Mesh(torusKnotGeometry, material)
tirusKnot.position.y = 3
const torusKnotLineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
const torusKnotLine = new THREE.Line(torusKnotLineGeometry, lineMaterial)
tirusKnot.position.x = -2
torusKnotLine.position.x = 2
torusKnotLine.position.y = 3
if (search.includes('tirusKnot') || !search) {
group.add(tirusKnot, torusKnotLine)
}
}

上面的代码中,我将用到的参数都配置成了可以在URL中调整的,大家可以复制或者点击这个链接https://www.91yqz.com/learnThree/learnThreeTorusAndturusKnot.html?show=[tirusKnot]&radialSegments=6&tubularSegments=10调整不同的参数去看看在不同情况下的变化。下面的案例是我不传参数默认情况下的demo。

three.js TorusKnotGeometry 圆形扭结几何体不调整参数示例

three.js TorusKnotGeometry 圆形扭结几何体调整radialSegments为2示例

three.js TorusKnotGeometry 圆形扭结几何体调整tubularSegments为4示例

three.js TorusKnotGeometry 圆形扭结几何体调整q为10, p为50示例

习惯了在2d空间写网页,突然到了3d空间,发现参数的每一次变化,都蕴含着惊喜,希望看到的人能够多多尝试。关于基础图元的部分,我们就到这里。

本篇完整源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!DOCTYPE html>
<html>
<head>
<title>three.js学习之圆环缓冲几何体和圆环扭结集合体学习</title>
<meta name="keywords" content="">
<meta name="description" content="">
<meta charset="utf8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r99/three.min.js"></script>
<!-- <script src="./js/three.min.js"></script> -->
<style>
html,body{
height: 100%;
margin: 0;
}
#three{
display: block;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="three"></canvas>
<script>
function getSearchObj (key) {
const search = window.location.search.replace('?', '')
const list = search.split('&')
const obj = {}
for (let i = 0; i < list.length; i++) {
const eachList = list[i].split('=')
obj[eachList[0]] = eachList[1]
}
return obj[key]
}
function main () {
const search = location.search
const canvas = document.querySelector('#three')
const renderer = new THREE.WebGLRenderer({canvas})
const fov = 75;
const aspect = 2;
const near = 0.1;
const far = 200;

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)

const group = new THREE.Group()
group.position.z = -10
const material = new THREE.MeshPhongMaterial({ color: 0x00F5FF })
const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5,linecap:'round' })


{
// 创建圆环示例代码
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 20
const arc = getSearchObj('arc') || 2

const torusGeometry = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc * Math.PI)
const torus = new THREE.Mesh(torusGeometry, material)

const torusLineGeometry = new THREE.WireframeGeometry(torusGeometry)
const torusLine = new THREE.LineSegments(torusLineGeometry, lineMaterial)
torus.position.x = -2
torus.position.y = -2
torusLine.position.y = -2
if (search.includes('torus') || !search) {
group.add(torus, torusLine)
}

}

{
// 圆环扭结集合体
const radius = 2;
const tube = 0.3;
const radialSegments = getSearchObj('radialSegments') || 10;
const tubularSegments = getSearchObj('tubularSegments') || 100
const p = getSearchObj('p') || 5
const q = getSearchObj('q') || 4
const torusKnotGeometry = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
const tirusKnot = new THREE.Mesh(torusKnotGeometry, material)
tirusKnot.position.y = 3
const torusKnotLineGeometry = new THREE.WireframeGeometry(torusKnotGeometry)
const torusKnotLine = new THREE.Line(torusKnotLineGeometry, lineMaterial)
tirusKnot.position.x = -2
torusKnotLine.position.x = 2
torusKnotLine.position.y = 3
if (search.includes('tirusKnot') || !search) {
console.log(1)
group.add(tirusKnot, torusKnotLine)
}
}


const scene = new THREE.Scene()
{
const lightColor = 0xffffff; // 灯光颜色
const intensity = 1; // 灯光强度
const light = new THREE.DirectionalLight(lightColor, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
scene.add(group)

function resizeRenderSizeToDisplaySize () {
const pixelRatio = window.devicePixelRatio;
const displayWidth = canvas.clientWidth * pixelRatio
const displayHeight = canvas.clientHeight * pixelRatio
const renderWidth = canvas.width;
const renderHeight = canvas.height;
const needResize = displayWidth !== renderWidth || displayHeight !== renderHeight
return needResize
}
function render (time) {
if (resizeRenderSizeToDisplaySize()) {
const pixelRatio = window.devicePixelRatio;
const width = canvas.clientWidth * pixelRatio
const height = canvas.clientHeight * pixelRatio
renderer.setSize(width, height, false)
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}

time *= 0.001
group['children'].forEach((each, index) => {
if (each.position.y === 0) {
each.rotation.y = -time
} else {
each.rotation.y = -time
}
// if (index % 2 === 0) {
// each.rotation.z = -time
// } else {
// each.rotation.z = time
// }
})

// group.position.y = time
// group.position.x = time
renderer.render(scene, camera)
requestAnimationFrame(render)
}
requestAnimationFrame(render)
// render()
}
main()
</script>
</body>
</html>