带尬猴,我嗨德育处主任
前面写了几篇 p5.js 文章 都还没涉及到3D图形,但其实 p5.js 是提供了基础的3D图形的。
本文就从最简单的立方体讲起,并做几个小demo和各位工友一起掌握立方体的用法。
在 p5.js 里使用 box() 方法可以创建立方体。
基础语法说明根据官网的说明,box() 语法如下:
box([width], [height], [depth], [detailX], [detailY])
官网给出的参数解释我觉得有点绕,以下是我的理解
首先需要了解 width、height 和 depth 这3个参数,它们都是可选参数,传参时会出现以下几种情况:
先试试创建一个基础立方体。
<script>
function setup() {
createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
background(200) // 设置画布背景色(灰色)
box(100) // 创建立方体
}
</script>
这个例子使用 box() 创建出来的立方体,看上去不像立方体,只是一个平面。主要原因是我们是正对着它,所以只能看到它的一个面。
旋转一下角度就看到它是一个立方体了。
<script>
function setup() {
createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
background(200) // 设置画布背景色(灰色)
// 旋转角度
rotateX(10)
rotateY(10)
box(100) // 创建立方体
}
</script>
设置样式
给立方体设置样式,要把样式函数写在 box() 前!!!
填充色 fill使用 fill() 方法可以设置填充色。
<script>
function setup() {
createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
background(200) // 设置画布背景色(灰色)
// 旋转角度
rotateX(10)
rotateY(10)
// 填充色
fill(255, 0, 0)
box(100) // 创建立方体
}
</script>
不使用填充颜色
box() 的默认填充色是白色,如果你不需要填充色,可以使用 noFill() 方法进行修改。
<script>
function setup() {
createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
background(200) // 设置画布背景色(灰色)
// 旋转角度
rotateX(10)
rotateY(10)
// 不使用填充颜色
noFill()
box(100) // 创建立方体
}
</script>
描边颜色 stroke
使用 stroke() 方法可以设置立方体的描边颜色。
<script>
function setup() {
createCanvas(200, 200, WEBGL)
background(200)
noFill()
stroke(255, 0, 0) // 设置红色边框颜色
rotateX(10)
rotateY(10)
box(100)
}
</script>
设置边框宽度
使用 strokeWeight() 方法可以设置立方体边框宽度,需要传入一个数值型数据。
<script>
function setup() {
createCanvas(200, 200, WEBGL)
background(200)
noFill()
stroke(255, 0, 0) // 设置红色边框颜色
strokeWeight(4) // 设置边框宽度
rotateX(10)
rotateY(10)
box(100)
}
</script>
纹理
除了基础的填充和描边外,立方体还可以设置纹理。
纹理可以是图片,也可以是视频。我先用图片资源举例。
加载资源需要在 preload() 这个生命周期里处理,我在 《p5.js 光速入门》 里有讲到,忘记这知识点的工友可以去看看。
将纹理贴到立方体上,有以下几个步骤:
<script>
let myTexture = null
function preload() {
myTexture = loadImage('texture.gif') // 加载纹理
}
function setup() {
createCanvas(200, 200, WEBGL)
background(200)
rotateX(0.5)
rotateY(0.5)
texture(myTexture) // 设置纹理
box(100) // 创建立方体
}
</script>
在这个例子中,我加载了一个 gif 纹理,但这个纹理贴到立方体上是不会动的,因为立方体是在 setup() 里创建的,如果需要它会动,我们需要在 draw() 声明周期里设置纹理和创建立方体。这部分我会放到后面“动画”章节讲。
光照效果你没看错,p5.js 也有提供了光照效果的,我在前面的文章没讲过光照效果,本文也不会讲这部分(我要留到下一篇水文里讲),但工友们也可以先了解一下这部分内容。
我使用了 环境光 ambientLight() 和 定向光 directionalLight() 打在立方体上。
<script>
function setup() {
createCanvas(200, 200, WEBGL)
background(200)
rotateX(10)
rotateY(10)
ambientLight(255) // 设置环境光照
directionalLight(255, 255, 255, 0, 0, -1) // 设置定向光照
box(100)
}
</script>
可以看出,不同面的颜色是有点不一样的。
动画要做动画非常简单,只需要在 draw() 生命周期里改变立方体的属性即可。
除此之外,我们还要了解 frameCount,这是 p5.js 提供的一个全局系统变量,它记录了 p5.js 运行了多少帧。在 setup() 时,frameCount 的值是0,之后每执行一次 draw() 都会给 frameCount 加1。
还不清楚 draw() 这个生命周期的工友一定要看看 《p5.js 光速入门》的“drap”章节。
旋转动画比如想做旋转动画,只要在 draw() 里不断的改变 rotateX 、 rotateY 或 rotateX 就能出一个不错的效果。
<script>
function setup() {
createCanvas(200, 200, WEBGL)
}
function draw() {
// 每次刷新都要重新填充画布颜色,不然会留下上一次绘制的立方体
background(200)
// 旋转
rotateX(frameCount * 0.01)
rotateY(frameCount * 0.01)
rotateZ(frameCount * 0.01)
// 绘制立方体
box(100)
}
</script>
gif 贴图
在前面的纹理例子中我们已经知道怎么贴图了,如果你贴的是gif动图,又希望这个图是真的能在运行时动起来,就需要在 draw() 设置纹理贴图了。
<script>
let myTexture = null
function preload() {
myTexture = loadImage('texture.gif') // 加载gif
}
function setup() {
createCanvas(200, 200, WEBGL)
}
function draw() {
background(200)
rotateX(frameCount * 0.01)
rotateY(frameCount * 0.01)
rotateZ(frameCount * 0.01)
// 设置纹理贴图
texture(myTexture)
box(100)
}
</script>
视频纹理
设置视频纹理其实和设置图片纹理差不多,只是加载的资源类型不同。
使用 createVideo() 方法加载视频资源,然后要将视频隐藏,不然它会在页面中占位。
<script>
let video = null
function preload() {
video = createVideo('video.mp4') // 加载 mp4
video.hide() // 隐藏视频元素
}
function setup() {
createCanvas(640, 480, WEBGL)
video.loop() // 循环播放
video.volume(0) // 设置音量
}
function draw() {
background(200)
rotateX(frameCount * 0.01)
rotateY(frameCount * 0.01)
// 设置视频纹理
texture(video)
box(200)
}
</script>
上面的代码还是用了 video.loop() 和 video.volume() 方法。
p5.js 是一个偏艺术类的 canvas 库,我们已经掌握了 box() 基础用法创建出立方体,接下来再理解几个小案例应该就有能力自己去实现一些特效了。非常适合在掘金整活~
案例1:Rotate Push Pop第一个案例叫《Rotate Push Pop》,是 processing 的一个例子,我把他的代码转成使用 p5.js 编写。
先提一嘴 processing 和 p5.js 的关系:processing 是用 Java 编写的,而 p5.js 是 processing 的 JS 版。
想了解 processing 可以找 『南方者哥哥』,他写过 Processing 相关的文章。
先看看本例效果和代码
<script>
let a = 0
let offset = Math.PI / 24
let num = 12
function setup() {
createCanvas(440, 460, WEBGL)
noStroke()
}
function draw() {
lights()
background(200, 200, 200)
for(let i = 0; i < num; i ) {
// map 映射
let gray = map(i, 0, num - 1, 0, 255)
push()
fill(gray)
rotateY(a offset * i)
rotateX(a / 2 offset * i)
box(200)
pop()
}
a = 0.01
}
</script>
这个例子用到 《p5.js 状态管理》 和 《p5.js map映射》 的知识,工友们可以先自行理解,如果不明白的话我再在评论区留下该例子的注解。
案例2:运动的立方体们<script>
function setup() {
createCanvas(400, 400, WEBGL)
}
let letter = [
[0, 0, 0],
[0, 0, 50],
[25, 0, 25],
[0, 50, 0],
[0, 50, 50],
[25, 25, 25],
[50, 0, 0],
[50, 0, 50],
[50, 50, 0],
[50, 50, 50]
]
function draw() {
background(200)
rotateX(frameCount * 0.01)
rotateY(frameCount * 0.01)
for (let i = 0; i < letter.length; i ) {
push()
translate(letter[i][0], letter[i][1], letter[i][2])
box(10)
pop()
}
}
</script>
这个例子我结合了 《p5.js 变换操作》 和 《p5.js 状态管理》 里讲到的知识。
letter 创建了一堆坐标点,他们记录了立方体们的位置。在 draw() 里不断的改变他们的位置。
为了让立方体们在 translate() 时不会相互影像,需要使用 push() 和 pop() 让它们“相互隔离开”。
案例3:排列立方体<script>
function setup() {
createCanvas(400, 400, WEBGL)
}
function draw() {
background(200);
rotateX(frameCount * 0.01);
rotateY(frameCount * 0.01);
for (let x = -50; x <= 50; x = 10) {
for (let y = -50; y <= 50; y = 10) {
for (let z = -50; z <= 50; z = 10) {
push();
translate(x, y, z);
box(5);
pop();
}
}
}
}
</script>
如果你理解了“案例2”,那么“案例3”这个例子相对起来会简单很多,它有点像我们刚学 JS 时做的 “九九乘法表” 的练习。
案例4:还是立方体,我不知道怎么起名了再编一个立方体案例吧,尽力了。。。
<script>
function setup() {
createCanvas(400, 400, WEBGL)
}
function fractalBox(size, level) {
box(size)
if (level > 1) {
level--
push()
translate(-size/2, -size/2, -size/2)
fractalBox(size/2, level)
pop()
push()
translate(-size/2, -size/2, size/2)
fractalBox(size/2, level)
pop()
push()
translate(-size/2, size/2, -size/2)
fractalBox(size/2, level)
pop()
push()
translate(-size/2, size/2, size/2)
fractalBox(size/2, level)
pop()
push()
translate(size/2, -size/2, -size/2)
fractalBox(size/2, level)
pop()
push()
translate(size/2, -size/2, size/2)
fractalBox(size/2, level)
pop()
push()
translate(size/2, size/2, -size/2)
fractalBox(size/2, level)
pop()
push()
translate(size/2, size/2, size/2)
fractalBox(size/2, level)
pop()
}
}
function draw() {
background(200)
rotateX(frameCount * 0.01)
rotateY(frameCount * 0.01)
fractalBox(200, 3)
}
</script>
还是使用了前面例子中的方法,瞎改了一下。
我实在是没有艺术感
《p5.js 光速入门》
《p5.js 状态管理》
《p5.js 使用npm安装p5.js后如何使用?》
《p5.js map映射》
《p5.js 变换操作》
点赞 关注 收藏 = 学会了
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved