Simple 3D

目录

  1. 这是什么
  2. 工作原理
  3. 绘制内容
  4. 设置变换
  5. 不同步骤的执行顺序
  6. 积木块
    6.1. 清除
    6.2. 网格
    6.3. 纹理
    6.4. 文本测量
    6.5. 字体
    6.6. 视图变换
    6.7. 手动变换
    6.8. 渲染到纹理
    6.9. 着色和雾
    6.10. 分辨率更改
  7. 与其他扩展的集成
    7.1. 增强现实扩展

这是什么

Simple 3D 是由 Vadik1 制作的扩展,旨在让用户能够创建 GPU 加速的 3D 项目。它并非为制作图形复杂的 3D 项目而设计(如需此类功能,请参阅 Pen+ v7 和 WebGL2 扩展,两者都支持可编程着色器),而是将主要重心放在让用户能够轻松快捷地创建 3D 项目上。尽管如此,尽管缺少可编程着色器,它仍然相当强大。它涵盖了广泛的使用场景,从像用不到 20 个积木块制作一个不到 20 个积木块的 AR 项目并从 OBJ 文件加载模型这样的高层次应用,到像在 CPU 上进行所有计算并每帧流式传输变换后的多边形(如 Pen+)这样的低层次应用。当然,也涵盖了两者之间的各种情况。

由于它能够通过实例化渲染大量相似对象(例如粒子),构造由三角形组成的 2D 网格,渲染到纹理以实现多通道渲染和比 Clipping & Blending 扩展更高级的裁剪,因此它对于制作某些类型的 2D 项目也很有用。它可用于 2D 图像处理,之后可以通过 Skins 扩展用作造型。它支持的顶点权重和索引可用于 2D 角色的骨骼动画,使身体部位变形而非使用刚性图像,甚至可用于平滑扩展 UI 元素。

工作原理

Scratch 有背景层、视频层、画笔层和角色层。此扩展增加了另一个层——simple3D,位于视频层和画笔层之间。高质量画笔模式也会影响它。

此扩展的关键概念是网格和变换。

网格存储 3D 模型数据,并可以被绘制。它们有点类似于基于图章的项目中的造型。也就是说,如果你想制作一个项目,使用图章在不同位置绘制某个造型的许多副本,你只会有一个造型,将所有位置以任何你认为合适的格式存储在列表中,然后每一帧你都会清除屏幕,并根据列表中的所有位置重新盖上该造型的图章。

使用此扩展也是同样的道理。如果你有 10 个相同的 3D 盒子,你只会创建一个网格。然后每一帧,首先清除屏幕,之后遍历列表,为每个盒子设置正确的变换并绘制那一个网格。

简而言之,此扩展没有任何形式的场景、对象、摄像机等,你必须自己跟踪这些。


3D 模型由顶点组成,这些顶点共同构成图元(点、线、三角形)。每个顶点都有用 2 个或 3 个数字分别描述的 2D(XY)或 3D(XYZ)位置。在绘制网格之前,你通常会设置变换,它告诉如何将这些初始位置转换到 2D 屏幕上的正确位置。通常的做法是将多个简单的变换链接在一起。简单变换可以是平移(偏移)、旋转、缩放、镜像、倾斜等。

绘制内容

Tip

如需更完整的教程,请参见此处(外部链接)。

现在让我们先不担心变换,直接按原样绘制一些东西。
第一步是清除屏幕:

设置清除颜色 R: (0.5) G: (0.5) B: (0.5) A: (1) :: sensing 清除 [颜色和深度 v] :: sensing

运行后屏幕应该变成灰色。
现在让我们绘制 2 个三角形,组成一个矩形。首先创建一个网格:

创建网格 [my mesh] :: sensing

然后创建 2 个列表 posX 和 posY。
用以下内容填充 posX:

-0.9
0.9
-0.9
-0.9
0.9
0.9

用以下内容填充 posY:

-0.9
-0.9
0.9
0.9
-0.9
0.9

然后设置网格的位置:

设置 [my mesh] 位置 XY [posX v] [posY v] :: sensing

最后绘制它:

绘制网格 [my mesh] :: sensing

结果应该看起来像这样:
灰色背景上的白色矩形
此扩展使用的屏幕坐标系不是 Scratch 典型的 480x360(X 从 -240 到 240,Y 从 -180 到 180),而是 2x2(两个轴都从 -1 到 1)。这与 WebGL 和 OpenGL 中相同。
这里我们创建的三角形顶点坐标在 -0.9 和 0.9 处,虽然没有完全到达屏幕边界,但已经很接近了。

另外,这里我们指定了 6 个顶点。每个三角形有 3 个顶点,所以它被当作 6/3=2 个三角形处理。
但每个三角形指定 3 个顶点并不是唯一的方式。当某些顶点被多个三角形共用时,有办法只指定它们一次然后重复使用,而不是复制数据。主要有 2 种方式:

索引列表

使用这种方式,可以创建另一个列表来引用以何种顺序使用哪些顶点。将其添加到我们的示例中:
用以下内容填充 posX:

-0.9
0.9
-0.9
0.9

用以下内容填充 posY:

-0.9
-0.9
0.9
0.9

创建另一个列表 indices 并填充:

1
2
3
3
2
4

现在重新上传 XY 位置并将索引列表上传到网格,清除屏幕并再次绘制网格。结果应该看起来一样。

设置清除颜色 R: (0.5) G: (0.5) B: (0.5) A: (1) :: sensing 清除 [颜色和深度 v] :: sensing 创建网格 [my mesh] :: sensing 设置 [my mesh] 位置 XY [posX v] [posY v] :: sensing 设置 [my mesh] 顶点索引 [indices v] :: sensing 绘制网格 [my mesh] :: sensing

链式图元类型

另一种方法是将网格从仅使用"三角形"切换为使用"三角形带"或"三角形扇"。
使用三角形带时,前 2 个顶点正常处理,然后每个后续顶点与前 2 个顶点组合成一个三角形。
使用三角形扇时,前 2 个顶点正常处理,然后每个后续顶点与前一个顶点和第一个顶点组合成一个三角形。

设置清除颜色 R: (0.5) G: (0.5) B: (0.5) A: (1) :: sensing 清除 [颜色和深度 v] :: sensing 创建网格 [my mesh] :: sensing 设置 [my mesh] 位置 XY [posX v] [posY v] :: sensing 设置 [my mesh] 图元 [三角形带 v] :: sensing 绘制网格 [my mesh] :: sensing

结果应该再次看起来一样。

图元重启索引

"三角形带"和"三角形扇"很高效,但使用它们时你只能得到 1 个连续的长三角形网格,这意味着要绘制许多"带"或"扇",你必须多次调用"绘制网格",这使其效率降低。

解决方案是将"三角形带"和"三角形扇"与索引列表一起使用。如果指定索引 0 或以下,它将中断前一个三角形链并重新开始一个新的。

这同样适用于"线带"和"线环"。

设置变换

3D 项目的典型简单变换序列如下:
你首先有一个处于自身坐标系(模型空间)中的 3D 模型,所有顶点位置都相对于其原点存储。此后的第一步是将其变换到世界坐标系。如果对象有自己的旋转,则将其每个顶点绕其原点 (0,0,0) 旋转正确的度数。如果它被缩放了,则缩放它们。完成后,将每个顶点按对象的世界位置偏移。现在所有顶点的位置都在世界坐标系(世界空间)中。

下一步是将它们变换到相对于观察者的坐标系,其中观察者位于 X:0, Y:0, Z:0,并且始终面向负 Z 方向。在普通("原版")Scratch 的 3D 项目中,观察者通常面向正 Z 方向,Z 越大,在观察者前方的距离越远。而在此扩展中——以及 Scratch 之外的大多数软件中——Z 越小,在观察者前方的距离越远。要进行此变换,首先从每个顶点的位置中减去摄像机位置。这会将摄像机置于世界的原点,并将所有内容相对于它定位,但旋转仍未考虑。要使用它,请将每个点按取反/逆摄像机旋转进行旋转。

现在你拥有的是相对于摄像机的 3D 位置。但你的屏幕是 2D 的,所以最后一步是进行投影。其大致要点是将所有 X 和 Y 除以 Z,这样越远的东西越小,越靠近屏幕中心。同时,裁剪掉所有超出屏幕或太近以及在你身后的东西。

但实际上这要复杂一些。
你首先将 X、Y、Z 变换为裁剪空间的 X、Y、Z 和 W,然后 GPU 自动将 X、Y 和 Z 裁剪到 -W 到 W 的范围,然后
将 X、Y、Z 除以 W,使 X、Y、Z 最终落在 -1 到 1 的范围内。其中 W 是实际深度,而 Z 是转换为正确范围的深度,用于深度缓冲区(低于 -1 和高于 1 的部分会被裁剪)(太远和太近)。

如果这听起来很复杂,别担心,Simple3D 扩展大部分会为你处理。

所以让我们回顾一下:

给定模型空间中的顶点坐标 x, y, z 时:

按对象缩放进行缩放
按对象方向进行旋转
按对象位置进行平移

按负摄像机位置进行平移
按负摄像机方向进行旋转

转换为裁剪空间

将 X,Y,Z 除以深度 W(由 GPU 完成,无法控制)
在 X,Y 处绘制到屏幕。使用 Z 进行深度检查。

现在是时候编写一些实际的 Simple3D 代码了。
在 Simple3D 中,这些变换被合并为 1 个大的变换,所有步骤都必须以相反的顺序指定。

以透视投影开始 FOV: (90) 近: (0.1) 远: (1000) :: sensing 绕 [X v] 轴旋转 ((0) - (camRotX)) 度 :: sensing 绕 [Y v] 轴旋转 ((0) - (camRotY)) 度 :: sensing 移动 X ((0) - (camX)) Y ((0) - (camY)) Z ((0) - (camZ)) :: sensing 移动 X (objectX) Y (objectY) Z (objectZ) :: sensing 绕 [Y v] 轴旋转 (objectRotY) 度 :: sensing 绕 [X v] 轴旋转 (objectRotX) 度 :: sensing 缩放 X (objectSizeX) Y (objectSizeY) Z (objectSizeZ) :: sensing 绘制网格 [my mesh] :: sensing

为每个要绘制的网格再次执行所有这些步骤是低效的。这就是以相反顺序执行步骤变得有用的地方。包装器积木块在进入时会保存变换,并在退出时恢复它。使用这个,可以做到以下事情:

以透视投影开始 FOV: (90) 近: (0.1) 远: (1000) :: sensing 绕 [X v] 轴旋转 ((0) - (camRotX)) 度 :: sensing 绕 [Y v] 轴旋转 ((0) - (camRotY)) 度 :: sensing 移动 X ((0) - (camX)) Y ((0) - (camY)) Z ((0) - (camZ)) :: sensing 重复 (10) 包装器 { ... 移动 X (objectX) Y (objectY) Z (objectZ) :: sensing 绕 [Y v] 轴旋转 (objectRotY) 度 :: sensing 绕 [X v] 轴旋转 (objectRotX) 度 :: sensing 缩放 X (objectSizeX) Y (objectSizeY) Z (objectSizeZ) :: sensing 绘制网格 [my mesh] :: sensing } :: sensing end

这会起作用,而且很高效,但是此扩展还提供了高级功能(如雾、实例化和公告板),这些功能需要在某些中间步骤中进行干预。
这意味着当你自己创建一个大的变换时,它无法做到这一点。这就是为什么目前设置变换的正确方式是这样的:

配置 [从视图空间到投影 v] 变换 :: sensing 以透视投影开始 FOV: (90) 近: (0.1) 远: (1000) :: sensing 配置 [从世界空间到视图空间 v] 变换 :: sensing 以无变换开始 :: sensing 绕 [X v] 轴旋转 ((0) - (camRotX)) 度 :: sensing 绕 [Y v] 轴旋转 ((0) - (camRotY)) 度 :: sensing 移动 X ((0) - (camX)) Y ((0) - (camY)) Z ((0) - (camZ)) :: sensing 重复 (10) ... 配置 [从模型空间到世界空间 v] 变换 :: sensing 以无变换开始 :: sensing 移动 X (objectX) Y (objectY) Z (objectZ) :: sensing 绕 [Y v] 轴旋转 (objectRotY) 度 :: sensing 绕 [X v] 轴旋转 (objectRotX) 度 :: sensing 缩放 X (objectSizeX) Y (objectSizeY) Z (objectSizeZ) :: sensing 绘制网格 [my mesh] :: sensing end

此扩展允许你将大的变换拆分为 3 个独立的变换,它们将按顺序应用,允许某些功能在中间起作用。
它还允许你使用以下积木块轻松地在不同坐标系之间工作:

变换 X (0) Y (0) Z (0) 从 [世界空间 v] 到 [模型空间 v] :: sensing 变换方向 X (0) Y (0) Z (0) 从 [世界空间 v] 到 [模型空间 v] :: sensing

不同步骤的执行顺序

顶点位置

对于每个顶点,最终位置的计算如下:

  1. 读取顶点位置
  2. 应用蒙皮
  3. 从模型空间变换到世界空间
  4. 由实例变换进行变换
  5. 从世界空间变换到视图空间
  6. 从视图空间变换到裁剪空间
  7. XYZ 除以 W(由 GPU 自动执行)

当启用公告板时:

  1. 读取顶点位置
  2. 应用蒙皮
  3. 从模型空间变换到世界空间
  4. 位置被复制到别处,而原始位置被替换为 (0,0,0)
  5. 由实例变换进行变换
  6. 从世界空间变换到视图空间
  7. 保存的位置被添加到当前位置
  8. 从视图空间变换到裁剪空间
  9. XYZ 除以 W(由 GPU 自动执行)

顶点颜色

  1. 读取顶点颜色,如果未提供则为白色
  2. 乘以实例颜色

顶点 UV

对于每个顶点,其上的 UV 纹理坐标计算如下:

  1. 读取顶点 UV
  2. 按实例 UV 缩放(第 3 和第 4 个分量)进行缩放
  3. 加上实例 UV 偏移(第 1 和第 2 个分量)
  4. 应用网格 UV 偏移

像素颜色

对于每个像素,最终颜色计算如下:

  1. 读取纹理,如果未提供纹理则为白色
  2. 乘以插值的顶点颜色 RGBA
  3. 执行 alpha 阈值检查
  4. 应用"设为不透明"
  5. 乘以全局颜色乘数
  6. 加上全局颜色加数
  7. 应用雾

积木块

清除

重置所有内容 :: sensing

将所有内容重置为初始状态,如同扩展刚加载一样。它还会删除网格和着色器缓存。


清除 [颜色和深度 v] :: sensing

清除所选渲染目标的颜色和/或深度。


设置清除颜色 R: (0.5) G: (0.5) B: (0.5) A: (1) :: sensing

将清除颜色设置为指定的红、绿、蓝和 Alpha(不透明度)值,范围从 0 到 1。
清除颜色是一个全局值。


深度测试 [更近 v] 写入 [开 v] :: sensing

在新像素被绘制之前,它的深度会与已绘制在该位置上的像素进行比较。
如果它根据此积木块第一个参数中的检查通过,则被绘制。如果失败,新像素被丢弃,原来在那里的内容保持不变。
第二个参数控制当检查通过时,是只更新颜色还是同时更新颜色和深度值。将其关闭对于绘制透明物体很有用,这些物体应对已绘制的不透明物体做出反应,同时不修改深度以免相互干扰。
深度测试和写入是为每个渲染目标单独保存的值。
尽管立方体纹理的全部 6 个面是不同的渲染目标,但它们仍然共享这些值。

对于舞台,默认值为"更近"和"开"。但是,对于用作渲染目标的纹理,默认值为"全部"和"关"。 在深度写入设置为"开"之前,甚至不会分配用于存储深度的内存。

网格

(所有网格 :: sensing)

列出所有网格名称,用逗号分隔。主要用于手动调试目的。


创建网格 [my mesh] :: sensing

创建一个具有指定名称的空网格。如果已存在同名网格,它将被替换。

名称两端的空白字符和任何逗号都会被移除以兼容"使网格继承"积木块。


删除网格 [my mesh] :: sensing

删除具有指定名称的网格。


使 [my mesh 3] 继承自网格 [my mesh 1,my mesh 2] :: sensing

设置第一个网格从多个其他网格继承任何列表或属性。
如果多个其他网格具有相同的属性,最后一个优先。
如果任何指定的要继承的网格形成循环依赖,整个操作将失败。
名称以逗号分隔列表提供。网格名称两端会被去除空格。因此 my mesh 1,my mesh 2、my mesh 1, my mesh 2 和 my mesh 1 , my mesh 2 的行为都相同。

这是一个关键特性,旨在避免数据重复。使用它时,任何可能昂贵的内容都不会被复制。
使用它而不是将相同的列表或纹理上传到多个不同的网格。
你甚至可以在项目运行时快速更改继承的网格。


(网格 [my mesh] [继承自 v] :: sensing)

用于获取网格的属性。


设置 [my mesh] 顶点索引 [list v] :: sensing

一个可选的网格列表,用于提供读取顶点并用于构造图元的顺序。
从 1 开始。指定值 0 或以下可用于将"三角形带"、"三角形扇"、"线带"和"线环"分解为多个。


设置 [my mesh] 位置 XY [listX v] [listY v] :: sensing 设置 [my mesh] 位置 XYZ [listX v] [listY v] [listZ v] :: sensing

用于将顶点位置上传到网格。
网格变得可绘制唯一必需的列表。


设置 [my mesh] 颜色 RGB [listR v] [listG v] [listB v] :: sensing 设置 [my mesh] 颜色 RGBA [listR v] [listG v] [listB v] [listA v] :: sensing

用于将顶点颜色(作为红、绿、蓝和 alpha)上传到网格。
值必须是 0 到 255 范围内的整数。


设置 [my mesh] 纹理坐标 UV [listU v] [listV v] :: sensing 设置 [my mesh] 纹理坐标 UVW [listU v] [listV v] [listW v] :: sensing

用于将纹理坐标上传到网格。
具有 2 个分量的积木块用于 2D 纹理。指定纹理上的 2D 坐标,范围从 0 到 1。但超出这些范围的值也是有效且有用的。
具有 3 个分量的积木块用于立方体纹理(cubemap)。指定从中心出发的 3D 方向,该方向将与围绕它的立方体相交。
如果指定了纹理坐标但没有纹理,则使用默认纹理。


设置 [my mesh] 纹理 () [钳制到边缘 v] [像素化 v] :: sensing 设置 [my mesh] 立方体纹理 (X+ v) () [钳制到边缘 v] [像素化 v] :: sensing

用于将纹理上传到网格。
根据使用的纹理类型,调用此积木块要么立即上传纹理(例如 empty 或 text),要么安排纹理在未来的某个时间上传到网格(例如从 url 或从造型加载)。
因此,例如,如果你从造型上传纹理并立即尝试绘制此网格一次,你将看不到它。加载需要一些时间!

使用下面的积木块检查纹理是否已完成加载。

(网格 [my mesh] [纹理加载中 v] :: sensing)

第 2(3)个参数控制当 UV 坐标超出 0..1 范围时会发生什么:

第 3(4)个参数控制每个像素如何从纹理获取颜色:

立方体纹理中的第 1 个参数控制纹理应上传到 6 个面中的哪一个。它必须是正方形,且与其他所有面大小相同。
上传不匹配的大小将导致所有其他面清除自身。
上传非正方形大小的纹理将失败且不执行任何操作。

网格将拥有的纹理类型只能设置一次。如果网格有立方体纹理,尝试用 2D 纹理替换将失败。如果网格有 2D 纹理,尝试用立方体纹理替换也将失败。


设置 [my mesh] 纹理 Mip 映射 [关 v] :: sensing

用于启用和禁用 mipmapping。
启用时,重新生成 mipmap。
当启用 mipmapping 时,上传纹理也会重新生成 mipmap。

Mipmapping 是一种让纹理具有多种不同分辨率(mipmap)的技术,当物体距离较远或以陡峭角度观看时,切换到使用较低分辨率的纹理版本。
它有助于消除像素闪烁,在高分辨率下还可以提高性能(低分辨率版本的纹理可以放入 GPU 缓存,使远处的几何体能够非常快速地绘制)。

网格默认为"关"。


设置 [my mesh] 纹理各向异性过滤 (16 v) :: sensing

用于设置各向异性过滤。
1 表示不进行各向异性过滤。
16 是最大值。
并非所有 GPU 都支持!最大值也因 GPU 而异。
始终将其设置为 16,无论是否支持或支持哪些值,仍然完全没问题。不过在支持它的低性能设备上性能会受到影响。因此添加一个开关是个好主意。

网格默认为 1。


设置 [my mesh] 骨骼索引 [listIndices v] 权重 [listWeights v] 每顶点数量 (3) :: sensing

用于设置骨骼索引和权重。
每个顶点的数量必须在 1 到 4 之间。
索引从 1 开始。
当每个顶点的数量为 1 时,不使用权重。
提供的索引和权重列表的长度必须匹配,并且能被"每个顶点的数量"整除。


设置 [my mesh] [原始 v] 变换 [listTransforms v] :: sensing 设置 [my mesh] [当前 v] 变换 [listTransforms v] :: sensing

用于设置每个骨骼的原始和当前变换。
将计算从原始到当前的变换,并根据顶点的骨骼索引和权重应用于顶点。
提供的变换列表长度必须能被 16 整除。如果不能,操作失败。
设置原始变换是可选的。缺少的原始变换被视为空变换。


设置 [my mesh] 交错 [XY 位置 v] [list v] :: sensing

用于设置顶点数据。与以下积木块作用相同:

设置 [my mesh] 位置 XY [listX v] [listY v] :: sensing 设置 [my mesh] 位置 XYZ [listX v] [listY v] [listZ v] :: sensing 设置 [my mesh] 颜色 RGB [listR v] [listG v] [listB v] :: sensing 设置 [my mesh] 颜色 RGBA [listR v] [listG v] [listB v] [listA v] :: sensing 设置 [my mesh] 纹理坐标 UV [listU v] [listV v] :: sensing 设置 [my mesh] 纹理坐标 UVW [listU v] [listV v] [listW v] :: sensing

但是从单个列表中以交错方式包含所有分量。


设置 [my mesh] 实例 [变换 v] [list v] :: sensing

用于设置实例化数据:在多个位置绘制同一网格多次(可以超过一百万次)。

以下 3 个类别中每个类别只允许一个。设置另一个会替换旧的。

定位:

颜色:

纹理坐标:

实例化需要设置定位才能激活。

所有已定义的类别必须具有相同数量实例的数据。如果从这些列表的长度推断出的实例数量不匹配,则网格无效,无法绘制。


设置 [my mesh] 列表更新偏移 (1) :: sensing

允许部分更新网格数据而不是完全重新上传。

从 1 开始。
将其设置为 1 或以上启用部分更新模式。
将其设置为 0 或以下禁用部分更新模式,使列表完全更新。
在部分更新模式下,你只能更新现有数据。如果你的新数据太长,超出了网格已设置的范围,操作将失败。
如果你不小心启用了它并想禁用它,请将其设置为 0,而不是 1!
这是因为虽然两者都从开头更新列表,但当它设置为 1 时,部分更新模式已启用,你无法调整数据大小。如果你尝试上传更多,它将失败。如果你尝试上传更少,末尾将保持不变。

这是 2 个不被继承的属性之一。 这出于性能原因和减少误用机会。

如果你需要完全更新数据,不要使用偏移 1 的部分更新模式来"节省内存"。它只会让事情变得更糟。 仅当你需要只更新相对较小部分的数据时才使用它。

网格默认为 0。


设置 [my mesh] 优化下次上传列表为 [很少 v] 更新 :: sensing

用于向 GPU 驱动程序提示数据应如何准备。不同的 GPU 驱动程序会以不同方式处理。

通常你创建网格,设置静态数据一次,然后将此切换为频繁模式之一,并开始更新一些频繁数据。
如果你突然需要再次更新静态数据,别忘了在设置该数据之前临时将其切换为"很少"。

这仅影响与顶点相关的数据。它不影响从列表上传纹理像素数据。

这是 2 个不被继承的属性之一。 这出于性能原因和减少误用机会。

网格默认为"很少"。


从 [obj mtl v] [list v] 设置 [my mesh] :: sensing 从 [off v] [list v] 设置 [my mesh] :: sensing

解码 3D 模型文件并将其上传到网格。积木块立即继续,但模型加载在单独的线程中执行,并会延迟完成。目前只使用一个线程,因此所有内容排队并逐个处理。将来可能会使用多个线程。

Important

此积木块设计为更多是用于快速测试的快捷方式,而不是加载 3D 模型的主要方式。对于任何更复杂的情况,请制作自己的 3D 模型解析器。

文件格式:

配置 [从文件导入 v] 变换 :: sensing

设置 [my mesh] 图元 [点 v] :: sensing

用于更改顶点组装成图元的方式。

使用顶点索引时,指定顶点索引 0 或以下可用于将"三角形带"、"三角形扇"、"线带"和"线环"分解为多个。

网格默认为"三角形"。


设置 [my mesh] 图元大小 (1) :: sensing

使用点图元时,更改点大小。
使用线、线带或线环图元时,更改线宽。

Warning

此功能不应依赖,因为支持的最小值和最大值因 GPU 而异。许多 GPU 不支持大于 1 的值。你可以在 https://webglreport.com/ 查看关于你的 GPU 的信息。

网格默认为 1。


设置 [my mesh] 混合模式 [默认 v] :: sensing

用于设置网格将如何与已绘制的内容混合。

如果你的网格完全不透明,请使用"覆盖颜色(不透明最快)"。如果你的网格是透明的,你可以使用它在已不透明的图像中绘制透明孔洞。
使用不可见绘制到深度缓冲区。
其他所有选项都是不言自明的,与 Clipping & Blending 扩展中相同。

网格默认为"默认"。


设置 [my mesh] 剔除 [背面 v] :: sensing

用于启用/禁用背面/正面剔除。基本上使三角形仅从一侧可见,具体取决于它们的顶点在屏幕上出现的顺序是顺时针还是逆时针。

网格默认为"无"。


设置 [my mesh] 丢弃不透明度低于 (0.5) 的像素,通过的像素 [设为不透明 v] :: sensing

用于丢弃低于特定不透明度阈值的像素,并可选择使所有内容不透明。

对于绘制文本或树叶纹理很有用,其中纹理本身应该是完全不透明或完全透明,纹理 alpha 用于确定清晰的截止边缘应该在哪里。

网格默认为阈值:0 保持不透明度。


设置 [my mesh] 公告板 [开 v] :: sensing

用于启用和禁用公告板。
当启用公告板时,网格始终面向与你的观察方向相反的方向(在你身后)。
注意这与转向你的位置不同。

网格默认为"关"。


设置 [my mesh] 精确插值 [开 v] :: sensing

(已弃用)
用于启用更准确的插值方法,该方法没有纹理坐标在三角形边缘上外推到指定范围之外的问题,从而避免难看的接缝。它计算成本更高,仅当这是一个问题时才应使用。
启用 mipmapping 和/或各向异性过滤可能会阻止其工作并重新引入接缝。

网格默认为"关"。


设置 [my mesh] 计算颜色 [在像素中心一次 v] :: sensing

替代已弃用的"精确插值"积木块。

更改启用 MSAA 抗锯齿时每个像素颜色的计算方式。

有时让渲染的 3D 图形边缘平滑而不是像素颜色急剧过渡对视觉效果有益。这就是不同的抗锯齿技术试图解决的问题。目前,在 Simple3D 扩展中,MSAA 抗锯齿始终为主 Simple3D 层启用,渲染到纹理时始终禁用。

最简单的抗锯齿方法称为超采样,包括以高于所需的分辨率渲染图像,然后通过平均颜色将其缩小到较低分辨率。它有效,但相当慢。

超采样的更便宜的替代方案是一种称为多重采样抗锯齿 (MSAA) 的技术。它仍然包括通过给每个像素多个子像素来以更高分辨率渲染图像,但是,所有子像素的颜色只计算一次,通常基于像素中心的位置。最后,所有子像素的颜色被平均,结果是边缘平滑的渲染图像。子像素通常被称为样本。

与超采样不同,MSAA 只平滑图元边缘,而不平滑图元本身上的尖锐像素化过渡(例如纹理)。

注意,启用 mipmapping 和/或各向异性过滤可能会重新引入接缝,无论使用此积木块选择了什么。

使用 为每个样本单独 并回退到 在覆盖样本中点一次 可以通过调用积木块两次来实现。在不支持时选择 为每个样本单独 将不执行任何操作并保留先前的值。

网格默认为"在像素中心一次"。


设置 [my mesh] 顶点绘制范围从 (1) 到 (6) :: sensing

用于通过仅绘制部分顶点范围来部分绘制网格。

在网格不断变化(包括顶点和图元数量)的情况下可能很有用。
对于这种情况,提前准备大量虚拟顶点数据。然后只填充并开始绘制其开头部分。
使用部分更新在正在绘制的范围之后添加任何额外多边形,然后扩展范围以包括它们。
要删除多边形,将要删除的位置上的多边形从绘制范围的末尾移动到该位置,然后在末尾收缩绘制范围。

网格默认为未设置。一旦设置,无法撤销。


设置 [my mesh] 顶点绘制范围从 [starts list v] 到 [ends list v] :: sensing

与 顶点绘制范围 积木块相同,但一次用于多个范围。

对于实现剔除很有用,因为它允许切换网格不同部分的可见性,而无需多次绘制调用的成本。


设置 [my mesh] 实例绘制上限 (10) :: sensing

通常,绘制多少实例由提供的列表长度决定。
此积木块可用于将绘制的实例数量限制为更低的数字。
这对于与部分列表更新一起使用以动态更改绘制的实例数量而无需重新上传整个列表很有用。也就是说,提前为一定数量的实例预分配空间,但绘制更少。当需要添加新实例时,使用部分更新更新下一个未使用实例的实例数据,然后将限制增加 1。要删除实例,可以将最后一个实例移到它的位置,然后将限制减少 1。

设置为任何低于 1 的值等同于设置为 Infinity。

网格默认为 Infinity。


设置 [my mesh] 纹理坐标偏移 UV (0) (0) :: sensing

用于偏移纹理 UV。
与"重复"模式的纹理和计时器积木块结合使用,这可以非常容易地创建具有滚动纹理的网格。

网格默认为 0,0。


绘制网格 [my mesh] :: sensing

绘制指定的网格一次或多次(实例化),但仅当它有效时。

网格无效且无法绘制,如果:

此积木块在首次绘制某物时可能导致卡顿,因为它需要生成和编译着色器。

纹理

(从 URL 创建纹理 [https://extensions.turbowarp.org/dango.png] :: sensing)

从指定 URL 的图像创建纹理。
如果 URL 未获批准,将显示提示。
如果图像加载失败,你通常可以打开浏览器控制台并查看错误是什么(F12 或 Ctrl+Shift+I)。

Warning

网站不能访问任何其他网站的任何数据,除非那些其他网站明确允许。正确的术语是 CORS(跨源资源共享)。你可以使用一些 CORS 代理来绕过它。

🐢 纹理会延迟加载。


(从造型创建纹理 [costume1 v] :: sensing)

从造型创建纹理。
🐢 纹理会延迟加载。在进行图像处理时,不要尝试加载并立即绘制。它不会显示出来!

别忘了:位图造型有 2x2 子像素,这里被计为像素。 所以当你看似 8x8 的造型变成 16x16 纹理时不要惊讶。

使用 TurboWarp Packager 时,你需要禁用"Remove raw asset data after loading to save RAM"(加载后删除原始资源数据以节省 RAM)才能使此积木块工作。


(从文本创建纹理 [Hello World!] 字体 [italic bold 32px sans-serif] 颜色 (#ffff00) :: sensing) (从文本创建纹理 [Hello World!] 字体 [italic bold 32px sans-serif] 颜色 (#ffff00) 边框 (5) (#000000) :: sensing)

创建具有指定文本的纹理。
⚡ 纹理立即加载。
边框在所有 4 个方向上将纹理扩展其值的像素数。
有关字体参数语法的更多信息,请参见 CSS 规范。


(从列表 [list v] 第 (1) 项创建大小 (16) (16) 的纹理 :: sensing)

从列表中的 RGBA 数据创建纹理。每个像素用列表 4 个元素表示,每个元素在 0 到 255 之间。元素是:红、绿、蓝、alpha。
注意这不是 Scratch 上许多画笔项目使用的 alpha、红、绿、蓝。
⚡ 纹理立即加载。


(大小 (16) (16) 的纹理 :: sensing)

创建给定大小的黑色纹理。
⚡ 纹理立即加载。


(从视频创建纹理 [my video] :: sensing)

从视频的当前帧创建纹理。要使视频移动,需要每帧调用。
⚡ 纹理立即加载。

文本测量

测量文本 [Hello World!] 字体 [italic bold 32px sans-serif] :: sensing (测量的 [上 v] 大小 :: sensing)

用于测量文本纹理是如何生成或将要生成的。
输出 5 个尺寸。尺寸可以为负。

字体

(大小 [32] 的字体 [Sans Serif] :: sensing)

用于获取默认和自定义字体的内部名称。不是必须使用。

视图变换

配置 [从视图空间到投影 v] 变换 :: sensing

用于在少数几个变换之间切换当前正在编辑的是哪一个。
变换 从模型空间到世界空间、从世界空间到视图空间、从视图空间到投影 是 3 个用于绘制的顺序变换,在本页顶部有解释。
变换 从文件导入 影响以下积木块的工作方式:

从 [.obj .mtl v] [list v] 设置 [my mesh] :: sensing

变换 自定义 不影响任何内容。用于你自己的计算。


以透视投影开始 FOV: (90) 近: (0.1) 远: (1000) :: sensing

用透视投影的视图空间到裁剪空间转换变换覆盖当前活动变换。
假设摄像机面向负 Z 方向。
FOV 是垂直视场角,以度为单位。
任何比"近"更近或比"远"更远的内容将被裁剪。

需要记住的是深度缓冲区精度有限。
"近"和"远"之间的整个范围被映射到深度缓冲区的整个范围。
因此,将近和远设置得彼此接近可以使深度更精确。
将近和远设置得差异很大将导致因精度不足而产生的 Z-fighting 问题。

另一个需要记住的是此积木块需要宽高比。 为了不麻烦用户,决定让它采用当前活动渲染目标的宽高比。大多数项目在运行时不会更改宽高比,但如果你计划支持这一点,请在获取以下内容后重新计算:

当分辨率改变时 :: sensing hat

以正交投影开始 近: (0.1) 远: (1000) :: sensing

用正交投影的视图空间到裁剪空间转换变换覆盖当前活动变换。
假设摄像机面向负 Z 方向。
关于"近"、"远"和宽高比与上述积木块相同。


以无变换开始 :: sensing

用不做任何事并保持一切的变换覆盖当前活动变换。


以 [外部源 v] 开始 :: sensing

用从外部源获取的变换覆盖当前活动变换。默认隐藏。外部源可以由其他扩展提供。


以保存在 [list v] 第 (1) 项开始 :: sensing

用列表中的变换覆盖当前活动变换。从第二个参数指定的索引开始读取 16 个值。


移动 X: (0) Y: (0) Z: (0) :: sensing 绕 [X v] 轴旋转 (0) 度 :: sensing 缩放 X: (1) Y: (1) Z: (1) :: sensing 沿 [X v] 倾斜 (1) [X v] :: sensing

对当前选中的变换应用更改。


包装器 { } :: sensing

在进入时保存所有 5 个变换(不仅是当前选中的),在退出时恢复。由于技术原因,如果内部脚本调用了以下内容,目前不会恢复:

停止 [这个脚本 v]

另外退出时有 1 帧延迟,因为它在技术上被视为循环。与循环类似,你可以使用 运行时不刷新屏幕 自定义积木块来消除延迟。


保存到 [list v] 第 (1) 项 :: sensing

从指定项开始覆盖列表中的 16 个元素,用代表当前选中变换的数字。


重置变换的 [偏移 v] :: sensing

重置变换的偏移或旋转。

无偏移的旋转可用于变换方向或绘制天空盒。
无旋转的偏移可用于在长变换链的末尾定位某物,但之后相对于世界独立旋转它。

手动变换

变换 X: (0) Y: (0) Z: (0) :: sensing

使用当前选中的变换变换点。这是变换坐标的最快方式,特别是在有很多坐标的情况下。


变换 X: (0) Y: (0) Z: (0) 从 [世界空间 v] 到 [模型空间 v] :: sensing 变换方向 X: (0) Y: (0) Z: (0) 从 [世界空间 v] 到 [模型空间 v] :: sensing

将点从指定的坐标系变换到另一个。方便但较慢。
变换方向仅应用旋转,不应用偏移。

"投影"是除法前的裁剪空间坐标。
"投影(Scratch 单位)"进行除以 W 并缩放到当前舞台大小(例如 480x360)。它可用于确定某个点在当前变换下将最终出现在屏幕上的位置,以便将角色定位在其上方或用画笔绘制某些内容。

渲染到纹理

渲染到画布 :: sensing

选择 simple3D 层作为活动渲染目标。


渲染到 [my mesh] 的纹理 :: sensing

选择指定网格的 2D 纹理作为活动渲染目标。
如果没有纹理或纹理不是 2D 则失败。


渲染到 [my mesh] 的立方体纹理 (X+ v) :: sensing

选择指定网格的立方体纹理的面作为活动渲染目标。
如果没有纹理、纹理不是立方体或面无效则失败。


将当前渲染目标读入 [list v] :: sensing

将当前渲染目标的像素数据读入列表。
每个像素有 4 个值:红、绿、蓝、alpha。
值应在 0 到 255 之间。

内部扩展使用预乘 alpha 存储所有内容。读取时,它除以 alpha 以恢复直接表示的颜色。


(渲染目标 [宽度 v] :: sensing)

允许读取当前渲染目标的属性。


设置 [视口框 v] 为 X1: (0) Y1: (0) X2: (100) Y2: (100) :: sensing 设置 [裁剪框 v] 为 X1: (0) Y1: (0) X2: (100) Y2: (100) :: sensing 设置 [回读框 v] 为 X1: (0) Y1: (0) X2: (100) Y2: (100) :: sensing

为当前活动渲染目标的不同用途配置自定义矩形区域。
视口框指定渲染图像将从其正常 -1 到 1 范围拉伸覆盖的区域。
裁剪框指定允许修改像素的区域。
回读框指定读取到列表和读取到 data URI 积木块将从中读取像素的区域。

Note

坐标以实际像素指定,从左下角开始,不是 Scratch 单位。你可以从以下任一获取 Simple3D 层的像素大小:

(舞台宽度 :: sensing) (舞台高度 :: sensing) (渲染目标 [宽度 v] :: sensing) (渲染目标 [高度 v] :: sensing)

虽然在高品质画笔禁用时它可能与 Scratch 单位匹配,但当高品质画笔开启时,分辨率通常会更高。你的项目需要考虑这一点。

Note

这些自定义区域可以设置或不设置。未设置时,它们使用 X1:0 Y1:0 X2:渲染目标宽度 Y2:渲染目标高度 并随分辨率更改自动更新。如果你将它们设置为自定义值,则需要手动处理重新缩放。


清除 [视口框 v] :: sensing 清除 [裁剪框 v] :: sensing 清除 [回读框 v] :: sensing

移除上述积木块配置的自定义矩形区域。

着色和雾

设置全局颜色 [乘数 v] 为 R: (1) G: (1) B: (1) A: (1) :: sensing 设置全局颜色 [加数 v] 为 R: (0) G: (0) B: (0) A: (0) :: sensing

允许设置对颜色的线性变换。
输入颜色 RGBA 乘以"乘数",然后加上"加数"值。
这里 0 是完全暗,1 是全亮。高于 1 或低于 0 的值将被钳制。
这是一个全局值。每帧更改多次是可以的。

默认乘数是 R:1 G:1 B:1 A:1。
默认加数是 R:0 G:0 B:0 A:0。


雾 [开 v] :: sensing

用于打开或关闭雾。接受布尔参数(true 或 false)。
这是一个全局值。每帧更改多次是可以的。
默认为关闭。


设置雾颜色 R: (1) G: (1) B: (1) :: sensing

设置雾颜色。
默认为 R:1 G:1 B:1。


设置雾距离 近: (10) 远: (100) :: sensing

设置雾距离。
近 设置网格开始过渡到雾颜色的距离。
远 设置网格完全完成过渡到雾颜色的距离。

将 近 设置为大于 远 的值会导致雾从近处开始,并随距离衰减。
将两个参数设置为相同值会导致除以 0 并导致未定义结果,因此避免这样做。

默认为 近:10 远:100。


设置雾 [视图空间 v] 原点为 X: (0) Y: (0) Z: (0) :: sensing

指定将围绕其绘制雾的中心点。
默认是视图空间中的 X:0 Y:0 Z:0。

分辨率更改

这里"canvas"指的是 Simple3D 渲染其所有图形的皮肤。
默认情况下,canvas 显示在 Simple3D 层上。
默认情况下,canvas 以 Scratch 单位表示的大小与舞台以 Scratch 单位表示的大小匹配,因此它覆盖整个舞台。
默认情况下,canvas 的分辨率模仿画笔层的行为:

Canvas 也可以显示在角色上。Simple3D 层可以关闭。
Canvas 的分辨率和显示大小可以更改。它被拉伸的方式(模糊或像素化)也可以更改。


当舞台分辨率改变时 :: sensing hat (水平舞台分辨率 :: sensing) (垂直舞台分辨率 :: sensing)

报告积木块返回舞台以实际屏幕像素渲染的分辨率。
当该分辨率更改时,帽子积木块触发。


(舞台宽度 :: sensing) (舞台高度 :: sensing)

返回舞台以 Scratch 单位表示的大小。(例如 480x360 或 640x360)


<高品质画笔已启用? :: sensing>

返回高品质画笔是否启用。


设置画布 [大小 v] 为 X: (100) Y: (100) :: sensing 设置画布 [分辨率 v] 为 X: (100) Y: (100) :: sensing 清除画布 [大小 v] :: sensing 清除画布 [分辨率 v] :: sensing

分辨率 - 更改 simple3D 层渲染的分辨率。
大小 - 更改 simple3D 层在舞台上显示的以 Scratch 单位表示的大小。


使缩放画布看起来 [像素化 v] :: sensing 使缩放画布看起来 [模糊 v] :: sensing

更改缩放 canvas 的外观。

默认为"像素化"。


当画布分辨率改变时 :: sensing hat (画布宽度 :: sensing) (画布高度 :: sensing)

报告积木块返回 canvas 的分辨率,而不是其显示的大小。
当该分辨率更改时,帽子积木块触发。


在我自己上显示画布 :: sensing hat 恢复我的外观 :: sensing

将 Simple3D canvas 作为皮肤显示在当前角色上的积木块。工作方式类似于 Skins 扩展。


设置 Simple3D 层可见性为 [可见 v] :: sensing

显示或隐藏 simple3D 层。
隐藏 Simple3D 层主要在 canvas 显示在另一个角色上时有用。
接受布尔值 true 和 false,而不是字符串"可见"和"隐藏"。


重置所有内容并设置抗锯齿 [开 v] :: sensing

与"重置所有内容"积木块相同,但可以控制抗锯齿。
接受布尔值 true 和 false,而不是字符串"开"和"关"。

Note

WebGL 不提供任何在 WebGL 上下文已创建后切换抗锯齿的方法,并且没有简单的方法在 WebGL 上下文之间传输资源。

与其他扩展的集成

Simple 3D 可以与其他扩展集成。如果你是扩展开发者,请参阅 Scratch.vm.runtime.ext_xeltallivSimple3Dapi。

增强现实扩展

虽然可以将增强现实扩展提供的矩阵中的所有 16 个分量上传到此扩展的变换中,

配置 [从视图空间到投影 v] 变换 :: sensing 将 [i v] 设为 (0) 重复 (16) 将 [i v] 增加 (1) 替换 [list v] 的第 (i) 项为 (projection 矩阵的第 (i) 项 :: #d10000) end 以保存在 [list v] 第 (0) 项开始 :: sensing

为了使此过程更容易,添加了一个额外功能。

当 Simple 3D 扩展和增强现实扩展同时存在于项目中时,用户可以使用以下额外积木块:

以 (AR: 组合 v) 开始 :: sensing 以 (AR: 视图到投影 v) 开始 :: sensing 以 (AR: 视图到世界 v) 开始 :: sensing 以 (AR: 世界到视图 v) 开始 :: sensing

这些积木块与上面的重复循环示例完全相同地从 AR 扩展复制值,但在 1 个积木块中完成。
一个同时使用两个扩展的简单 3D 项目示例如下:

当绿旗被点击 进入 AR 模式 :: #d10000 创建网格 [my mesh] :: sensing 从 [obj mtl v] [my 3D model v] 设置 [my mesh] :: sensing forever 配置 [从视图空间到投影 v] 变换 :: sensing 以 (AR: 视图到投影 v) 开始 :: sensing 配置 [从世界空间到视图空间 v] 变换 :: sensing 以 (AR: 世界到视图 v) 开始 :: sensing 清除 [颜色和深度 v] :: sensing 绘制网格 [my mesh] :: sensing end 当舞台被点击 将所有内容移动 x: (hit position [x v] :: #d10000) y: (hit position [y v] :: #d10000) z: (hit position [z v] :: #d10000) :: #d10000

Lily/Video 扩展

Simple3D 提供了一个专用积木块来将视频的当前帧读取到纹理中。

从 URL 加载视频 [https://extensions.turbowarp.org/dango.mp4] 为 [my video] :: #557882 将 [my video] 设为 [循环 v] :: #557882 在 (我自己 v) 上开始视频 [my video] :: #557882 forever 设置 [my mesh v] 纹理 (从视频创建纹理 [my video] :: sensing) [钳制到边缘 v] [像素化 v] :: sensing end