p5.js 3D图形-立方体

本文简介

带尬猴,我嗨德育处主任


前面写了几篇 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映射》


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 内核降级到指定版本

reference https://www.cnblogs.com/leebri/p/16786685.html 前往此网站&#xff0c;找到所需的内核 https://kernel.ubuntu.com/~kernel-ppa/mainline/ 查看系统架构 dpkg --print-architecture 二、下载安装包 注意&#xff1a;下载除lowlatency以外的deb包 三、安装内核 3…

基于图像识别的跌倒检测算法 计算机竞赛

前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于图像识别的跌倒检测算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/…

FreeRTOS 事件标志组 详解

目录 什么是事件标志组&#xff1f; 事件标志位 事件标志组 事件标志组相关 API 函数 1. 创建事件标志组 2. 设置事件标志位 3. 清除事件标志位 4. 等待事件标志位 事件标志组实操 什么是事件标志组&#xff1f; 事件标志位 表明某个事件是否发生&#xff0c;联想&am…

优咔科技创新连接方案助力高质量5G车联服务

上海优咔网络科技有限公司 CEO 闫楠 【摘要】本文就智能网联汽车对高质量5G车联服务的需求背景和行业趋势进行了分析&#xff0c;主要介绍采用5G双SIM卡的创新连接方案&#xff0c;重点讲述双SIM卡联网的端到端体系架构和技术方案&#xff0c;并就优咔科技全方位支撑行业领先车…

设计模式—创建型模式之单例模式

设计模式—创建型模式之单例模式 介绍 单例模式说明&#xff1a;一个单一的类&#xff0c;负责创建自己的对象&#xff0c;同时确保系统中只有单个对象被创建。 单例模式特点&#xff1a; 某个类只能有一个实例&#xff1b;&#xff08;构造器私有&#xff09;它必须自行创…

【抓包分析】通过ChatGPT解密还原某软件登录算法实现绕过手机验证码登录

文章目录 &#x1f34b;前言实现效果成品广告抓包分析一、定位加密文件二、编辑JS启用本地替换 利用Chatgpt进行代码转换获取计划任务id模拟数据请求最后 &#x1f34b;前言 由于C站版权太多&#xff0c;所有的爬虫相关均为记录&#xff0c;不做深入&#xff01; 今天发现gith…

读图数据库实战笔记01_初识图

1. 图论 1.1. 起源于莱昂哈德欧拉在1736年发表的一篇关于“哥尼斯堡七桥问题”的论文 1.2. 要解决这个问题&#xff0c;该图需要零个或两个具有奇数连接的节点 1.3. 任何满足这一条件的图都被称为欧拉图 1.4. 如果路径只访问每条边一次&#xff0c;则该图具有欧拉路径 1.5…

【华为路由器】配置企业通过5G链路接入Internet示例

场景介绍 5G Cellular接口是路由器用来实现5G技术的物理接口&#xff0c;它为用户提供了企业级的无线广域网接入服务&#xff0c;主要用于eMBB场景。与LTE相比&#xff0c;5G系统可以为企业用户提供更大带宽的无线广域接入服务。 路由器的5G功能&#xff0c;可以实现企业分支…

贪心算法学习——单调递增的数字

一&#xff0c;单调递增的数字 1.题目 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 示例 1: 输入: n 10 输出: 9示例 2: 输入…

智能问答技术在百度搜索中的应用

作者 | Xiaodong 导读 本文主要介绍了智能问答技术在百度搜索中的应用。包括机器问答的发展历程、生成式问答、百度搜索智能问答应用。欢迎大家加入百度搜索团队&#xff0c;共同探索智能问答技术的发展方向&#xff0c;文末有简历投递方式。 全文6474字&#xff0c;预计阅读时…

8.稳定性专题

1. anr https://code84.com/303466.html 一句话&#xff0c;规定的时间没有干完要干的事&#xff0c;就会发生anrsystem_anr场景 input 5sservice 前台20s 后台60scontentprivider超市 比较少见 原因 主线程耗时 复杂layout iobinder对端block子线程同步锁blockbinder被占满导…

vr虚拟现实技术融入司法办案实操培训中的优势

模拟法院诉讼一直室各大法学院法律实践性教学的重要方式和内容&#xff0c;通过让学员在模拟环境中实操一遍诉讼流程及相关资料&#xff0c;达到上岗就业的教学目标。 学生可以选择法官席、律师席、证人席等不同角色进行体验&#xff0c;在VR模拟法庭中进行案件审判和辩论&…

Linux - firewall-cmd 命令添加端口规则不生效排查

文章目录 linux 防火墙 firewall-cmd 命令详解问题排查 linux 防火墙 firewall-cmd 命令详解 基本语法 firewall-cmd --zonezone-name --add-serviceservice-name --permanent命令参数 --zone&#xff1a;指定要添加服务的区域名称。 --add-service&#xff1a;指定要添加的…

Android环境变量macOS环境变量配置

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览macOS基础知识 三、设置环境变量3.1 终…

【C++系列】STL容器——vector类的例题应用(12)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01;本章主要内容面向接触过C的老铁&#xff0c;下面是收纳的一些例题与解析~ 主要内容含&#xff1a; 目录 【例1] 只出现一次的数字i&#xff08;范围for与模等&#xff08;^&#xff09;)【例2]…

【计算机网络笔记】Web应用之HTTP协议(涉及HTTP连接类型和HTTP消息格式)

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

Node编写用户登录接口

目录 前言 服务器 编写登录接口API 使用sql语句查询数据库中是否有该用户 判断密码是否正确 生成JWT的Token字符串 配置解析token的中间件 配置捕获错误中间件 完整的登录接口代码 前言 本文介绍如何使用node编写登录接口以及解密生成token&#xff0c;如何编写注册接…

【VUE】ElementPlus之动态主题色调切换(Vue3 + Element Plus+Scss + Pinia)

前言 关于ElementPlus的基础主题色自定义可以参阅《【VUE】ElementPlus之自定义主题样式和命名空间》 有了上面基础的了解&#xff0c;我们知道ElementPlus的主题色调是基于CSS3变量特性进行全局控制的&#xff0c; 那么接下来我们也基于CSS3变量来实现主题色调的动态切换效果&…

ChinaSoft 论坛巡礼 | 开源软件生态健康度量论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

Python字典-dict “ “ ---记一次查缺补漏“ “

文章目录 0x0 前言0x1 字典 &#xff08;Dictionary&#xff09;0x01 访问字典里的值0x02 修改字典0x03 删除字典元素0x04 判断字典是否包含指定key&#xff0c;用in或not in 运算符 0x2 字典键的特性0x010x2 0x3 字典内置函数&方法0x4 使用格式化字符串 0x0 前言 python没…