p5.js 3D图形-立方体

news2024/11/20 3:19:55

本文简介

带尬猴,我嗨德育处主任


前面写了几篇 p5.js 文章 都还没涉及到3D图形,但其实 p5.js 是提供了基础的3D图形的。

本文就从最简单的立方体讲起,并做几个小demo和各位工友一起掌握立方体的用法。



立方体的基础用法

p5.js 里使用 box() 方法可以创建立方体。


基础语法说明

根据官网的说明,box() 语法如下:

box([width], [height], [depth], [detailX], [detailY])

官网给出的参数解释我觉得有点绕,以下是我的理解

  • width:立方体的宽度(选填),默认值是 50。
  • height:立方体的高度(选填)。
  • depth:立方体的深度(选填)。
  • detailX:一个用于指定立方体在x轴方向上的细分级别的数字,数值越大,立方体的表面越平滑。(选填)
  • detailY:一个用于指定立方体在y轴方向上的细分级别的数字,数值越大,立方体的表面越平滑。(选填)

首先需要了解 widthheightdepth 这3个参数,它们都是可选参数,传参时会出现以下几种情况:

  1. 3个参数都不传的情况:它们的值默认为50。
  2. 只传 width 的情况:heightdepth 都会跟着使用 width 的值。
  3. 传了 widthheight 的情况:depth 会使用 height 的值。
  4. 3个参数都有传的情况:各自使用各自的值。

动手试试

先试试创建一个基础立方体。

file

<script>
  function setup() {
    createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
    background(200) // 设置画布背景色(灰色)
    box(100) // 创建立方体
  }
</script>

这个例子使用 box() 创建出来的立方体,看上去不像立方体,只是一个平面。主要原因是我们是正对着它,所以只能看到它的一个面。

旋转一下角度就看到它是一个立方体了。

file

<script>
  function setup() {
    createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
    background(200) // 设置画布背景色(灰色)
    // 旋转角度
    rotateX(10)
    rotateY(10)
    box(100) // 创建立方体
  }
</script>

设置样式

给立方体设置样式,要把样式函数写在 box() 前!!!


填充色 fill

使用 fill() 方法可以设置填充色。

file

<script>
  function setup() {
    createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
    background(200) // 设置画布背景色(灰色)

    // 旋转角度
    rotateX(10)
    rotateY(10)

    // 填充色
    fill(255, 0, 0)

    box(100) // 创建立方体
  }
</script>

不使用填充颜色

box() 的默认填充色是白色,如果你不需要填充色,可以使用 noFill() 方法进行修改。

file

<script>
  function setup() {
    createCanvas(200, 200, WEBGL) // 创建 200 * 200 的画布
    background(200) // 设置画布背景色(灰色)

    // 旋转角度
    rotateX(10)
    rotateY(10)

    // 不使用填充颜色
    noFill()

    box(100) // 创建立方体
  }
</script>

描边颜色 stroke

使用 stroke() 方法可以设置立方体的描边颜色。

file

<script>
  function setup() {
    createCanvas(200, 200, WEBGL)
    background(200)

    noFill()
    stroke(255, 0, 0) // 设置红色边框颜色

    rotateX(10)
    rotateY(10)

    box(100)
  }
</script>

设置边框宽度

使用 strokeWeight() 方法可以设置立方体边框宽度,需要传入一个数值型数据。

file

<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 光速入门》 里有讲到,忘记这知识点的工友可以去看看。

将纹理贴到立方体上,有以下几个步骤:

  1. 加载纹理资源(图片或者视频)
  2. 设置纹理
  3. 创建立方体

file

<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() 打在立方体上。

file

<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() 里不断的改变 rotateXrotateYrotateX 就能出一个不错的效果。

file

<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() 设置纹理贴图了。

file

<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() 方法加载视频资源,然后要将视频隐藏,不然它会在页面中占位。


file

<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() 方法。

  • video.loop():循环播放。
  • video.volume():设置视频音量,取值范围是 0 ~ 1


小案例

p5.js 是一个偏艺术类的 canvas 库,我们已经掌握了 box() 基础用法创建出立方体,接下来再理解几个小案例应该就有能力自己去实现一些特效了。非常适合在掘金整活~


案例1:Rotate Push Pop

第一个案例叫《Rotate Push Pop》,是 processing 的一个例子,我把他的代码转成使用 p5.js 编写。

先提一嘴 processingp5.js 的关系:processing 是用 Java 编写的,而 p5.jsprocessingJS 版。

想了解 processing 可以找 『南方者哥哥』,他写过 Processing 相关的文章。


先看看本例效果和代码

file

<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:运动的立方体们

file

<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:排列立方体

file

<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:还是立方体,我不知道怎么起名了

再编一个立方体案例吧,尽力了。。。

file

<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映射》


点赞 + 关注 + 收藏 = 学会了 代码仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1137945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧矿山AI算法助力煤矿安全:人员越界识别精准迅速

煤矿作为一种危险性较高的工业领域&#xff0c;安全管理一直是煤矿企业的重要任务。传统煤矿安全管理主要依靠人工巡逻及视频监控等手段&#xff0c;但这些方法往往存在人力不足、盲区多等问题&#xff0c;无法实时监控和预警&#xff0c;难以有效避免事故的发生。随着人工智能…

如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载

如何在linux服务器上安装Anaconda与pytorch&#xff0c;以及pytorch卸载 1&#xff0c;安装anaconda1.1 下载anaconda安装包1.2 安装anaconda1.3 设计环境变量1.4 安装完成验证 2 Anaconda安装pytorch2.1 创建虚拟环境2.2 查看现存环境2.3 激活环境2.4 选择合适的pytorch版本下…

FL Studio水果2023体验版如何破解?

FL Studio是一款非常专业的水果工具&#xff0c;软件功能齐全&#xff0c;拥有编曲、剪辑、录音、混音等功能&#xff0c;可以满足用户的各种音乐制作需求。软件已经成功破解&#xff0c;全中文的软件界面&#xff0c;去除了试用时间限制&#xff0c;有需要的快来下载吧&#x…

《动手学深度学习 Pytorch版》 10.6 自注意力和位置编码

在注意力机制中&#xff0c;每个查询都会关注所有的键&#xff0d;值对并生成一个注意力输出。由于查询、键和值来自同一组输入&#xff0c;因此被称为 自注意力&#xff08;self-attention&#xff09;&#xff0c;也被称为内部注意力&#xff08;intra-attention&#xff09;…

react-typescript-demo

1.使用 Context 来存储数据

rabbitMQ入门指南:管理页面全面指南及实战操作

文章目录 1. 引言2. RabbitMQ 管理页面的概览3. 探索 RabbitMQ 管理页面的主要功能3.1 连接3.2 通道3.3 交换机3.4 队列3.5 生产者3.6 消费者 4. RabbitMQ 的实战例子4.1 创建虚拟机4.2 连接和通道4.3 建立交换机4.3.1 交换机类型4.3.2 创建一个交换机 4.4 创建队列4.4.1 队列类…

海外广告投放保姆级教程,如何使用Quora广告开拓新流量市场?

虽然在Quora 上学习广告相对容易&#xff0c;但需要大量的试验和错误才能找出最有效的方法。一些广告技巧可以让您的工作更有效率。这篇文章将介绍如何有效进行quora广告投放与有价值的 Quora 广告要点&#xff0c;这将为您节省数万美元的广告支出和工作时间&#xff01;往下看…

五大绩效指标,为企业新媒体矩阵管理注入新动力

⭐关注矩阵通服务号&#xff0c;探索企业新媒体矩阵搭建与营销策略 新媒体矩阵的建设运营是为了能实现企业确定的业务目标。 那如何才能让推动最后业务目标的实现&#xff1f; 对于企业来说&#xff0c;可以将业务目标拆解为短期绩效目标&#xff0c;通过适当调整短期指标来保证…

【Java 进阶篇】Java HTTP 请求消息详解

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于传输超文本的应用层协议&#xff0c;广泛用于构建互联网应用。在Java中&#xff0c;我们经常需要发送HTTP请求来与远程服务器进行通信。本文将详细介绍Java中HTTP请求消息的各个部分&#xff0c;包括请求行、…

spring-初识spring

初识spring Spring简介 初识spring一、Spring 特性二、IOC容器(反转控制)1、IOC容器1.1、IOC思想1.2、IOC容器在Spring中的实现 2、基于XML管理bean2.1入门案例2.2获取bean2.3依赖注入(DI)2.3.1set方法注入2.3.1构造器注入 2.4 为类类型属性赋值2.4.1 引用外部已声明bean2.4.2 …

一键同步,无处不在的书签体验:探索多电脑Chrome书签同步插件

说在前面 平时大家都是怎么管理自己的浏览器书签数据的呢&#xff1f;有没有过公司和家里的电脑浏览器书签不同步的情况&#xff1f;有没有过电脑突然坏了但书签数据没有导出&#xff0c;导致书签数据丢失了&#xff1f;解决这些问题的方法有很多&#xff0c;我选择自己写个chr…

数据结构与算法基础(青岛大学-王卓)(9)

终于迎来了最后一部分(排序)了&#xff0c;整个王卓老师的数据结构就算是一刷完成了&#xff0c;但是也才是数据结构的开始而已&#xff0c;以后继续与诸位共勉 &#x1f603; (PS.记得继续守护家人们的健康当然还有你自己的)。用三根美味的烤香肠开始吧。。。 文章目录 排序基…

高级深入--day41

用Pymongo保存数据 爬取豆瓣电影top250movie.douban.com/top250的电影数据&#xff0c;并保存在MongoDB中。 items.py class DoubanspiderItem(scrapy.Item):# 电影标题title scrapy.Field()# 电影评分score scrapy.Field()# 电影信息content scrapy.Field()# 简介info …

基于SSM的OA办公系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

nginx浏览器缓存和上流缓存expires指令_nginx配置HTTPS

1.nginx控制浏览器缓存是针对于静态资源[js,css,图片等] 1.1 expires指令 location /static {alias/home/imooc;#设置浏览器缓存10s过期expires 10s;#设置浏览器缓存时间晚上22:30分过期expires @22h30m;#设置浏览器缓存1小时候过期expires -1h;#设置浏览器不缓存expires …

【JavaEE初阶】 线程安全的集合类

文章目录 &#x1f340;前言&#x1f332;多线程环境使用 ArrayList&#x1f6a9;自己使用同步机制 (synchronized 或者 ReentrantLock)&#x1f6a9;Collections.synchronizedList(new ArrayList);&#x1f6a9;使用 CopyOnWriteArrayList &#x1f38d;多线程环境使用队列&am…

通过jdk自制https证书并配置到nginx并配置http2

生成证书 这里使用自己生成的免费证书。在${JAVA_HOME}/bin 下可以看到keytool.exe,在改目录打开cmd然后输入&#xff1a; keytool -genkey -v -alias lgq.com -keyalg RSA -keystore d:/zj/ssl/fastfly.com.keystore -validity 3650生成证书过程中&#xff1a;【你的名字】对…

美国海运专线冬季通航情况

随着全球经济一体化的推进&#xff0c;海运业务的重要性日益凸显。特别是在美国&#xff0c;作为世界上最大的经济体之一&#xff0c;其海运业务的发展对全球物流供应链有着重要影响。而在冬季&#xff0c;美国海运专线又会面临怎样的通航情况呢?下面就让我们一起来探讨一下。…

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第二套区块链系统部署与运维

第二套区块链系统部署与运维题目 环境 : ubuntu20 fisco : 2.8.0 docker: 20.10.21 webase-deploy : 1.5.5 mysql: 8.0.34 子任务1-2-1: 搭建区块链系统并验证(4分) 使用build_chain.sh 脚本文件进行搭建区块链 ,要求: 四节点,默认配置,单机,docker root@192-168-19…

【推荐】如何使用drawio的编辑器,看本文就够

学会使用drawio的编辑器 drawio是免费的开源的图表应用&#xff0c;你可以通过app.diagrams.net使用在线版本或者下载离线安装版在桌面端使用。 对于团队来讲&#xff0c; 把数据存储作为安全第一的图表应用&#xff0c; 你可以选择存储数据到不同的介质。例如Atlassian Conf…