Web编程技术营地
研究、演示、创新

TEXTURE_3D

撰写时间:2026-05-16

修订时间:2026-05-16

TEXTURE_3D (3D纹理)在图形编程中主要用于需要在三维空间内访问体数据 (volumn data) 的场合,其典型应用场合诸如体积渲染、流体烟雾模拟、动画变形及蒙皮等纹理插值,等等。

这些应用都依赖于TEXTURE_3D的两大特性:随机访问任意空间位置和GPU硬件三线性插值,使得体数据处理高效且代码简洁。

因此,TEXTURE_3D典型应用已经超出纹理贴图的常规范畴。本章中,我们将实现最基本的TEXTURE_3D应用。

着色器

顶点着色器

源代码

aTexCoords的数据类型为vec3。即对于每个顶点的纹理坐标值,我们将传入诸如:

的数据。

关于纹理坐标系的字母缩写

在早期的图形学中,纹理坐标常用(u, v)来表示。其中u代表纹理坐标系中的X轴v代表纹理坐标系中的Y轴

后面为支持3维纹理坐标系,又使用(u, v, w)来表示纹理坐标值。至今一些应用软件的界面中仍可看到这种表示方式。

齐次坐标系中的顶点坐标一般使用(x, y, z, w)来表示其坐标值。可以看出,w在两种坐标系中都出现了,容易引起混淆。

为避免混淆,OpenGL, WebGL均在纹理坐标系中引入了(s, t, r, q)的表示方法。故此,在下面,我们将看到如下代码:

即分别设置纹理坐标系S轴, T轴R轴的重复贴图方式。

片断着色器

源代码

代码解析

代码:

对于类型为sampler3D的通用顶点属性,我们必须显式地指定其精度,否则将编译出错。

也可以统一设置:

之前我们在片断着色器中判断是否使用纹理坐标的代码为:

而代码:

可将相应代码浓缩为一行。GLSLmix常用于生成中间的线性插值。若uIsUseTexture的值为false,则float(uIsUseTexture)的值为0.0,则mix函数返回vColor;否则,mix函数返回texture函数的采样值。

调试技巧

要让一个纹理应用程序正确地运行起来,主要涉及两大方面,一是纹理图像内容的正确设置,二是纹理坐标的正确设置。两者必须同时准确无误才行。而3D纹理应用的调试又比2D纹理应用增加了额外的难度。

我们可以采用分而治之的策略。例如,下面的片断着色器的代码先使用一个固定的纹理坐标值:

这样可将重心放在纹理图像内容的正确设置上面。而当应用程序运行起来,确认纹理图像内容已没有任何问题后,再恢复为:

从而将重心转向纹理坐标的设置上面。

客户端主程序

其主要代码如下所示。

对于vertices的每一个顶点,都向它们分别指定一组三维的纹理坐标值。

为易于理解,我们可将三维纹理图像视为具有多层的二维纹理图像。上面tex3DCoords每个纹理坐标值(s, t, r)分量中,r的分量均为0.0,表示这是第0层的二维纹理图像的纹理坐标值。而一个2维纹理坐标系如下所示:

tex3DCoords代码中的每个纹理坐标位置从上到下,分别映射至四边形的左上角、左下角、右下角及右上角。

运行应用

因为只有一层的二维纹理图像,因此其效果与前面的二维纹理贴图完全一样。

而不同的是,这次我们的代码是完全基于TEXTURE_3D的纹理应用程序。我们将其降级为二维纹理贴图,先让应用程序跑起来,从而掌握其基本规律及原理后,下面我们再实现多层的三维纹理贴图。

这其中的理念类似于如何理解现实世界中的四维世界。对于已经牢牢被三维世界所束缚的我们,很难一下子理解何为四维世界。但我们可以先降级为一维坐标系,找出一维坐标系如何升格为二维坐标系的规律;再找出二维坐标系如何升格为三维坐标系的规律。最后应用类似的规律将三维坐标系升格为四维坐标系。

Texture3DMesh的实现

构造器

Texture3DMesh继承于SoleColorMesh,先将其抽象为一个单色的Mesh,而又能充分利用应用框架对Mesh类的各种支持。

initTexVAO方法

WebGLUtils-v12.js中增加了对TEXTURE_3D的纹理支持:

并且loadShader函数中可自动感知sampler3D的采样器:

initTexture方法

gltexImage3D方法是WebGL 2.0才新增的方法,用于为三维纹理图像填充内容。它有多个版本,这里使用类型化数组的版本,并且最后一个参数srcOffset可用以灵活、自由地指定类型化数组中的起始位置。从而让我们更充分地理解texImage3D各参数的具体含义。

例如,对于srcData

这是一个具有4个颜色值的类型数组,每4个数组元素代表一个颜色值。

如果我们希望将纹理图像的内容初始化为1 × 1 × 1的内容时,无需改动srcData的值:

上面使用了C0颜色值作为仅有的像素颜色值。同理,将pixelIndex的值改为(0, 3)之间的任意值,可使用其它对应的颜色值。

而原来的代码为:

则要求使用2行、2列(只有1层)的纹理图像,此时必须完全使用srcData的所有数据,因此此时pixelIndex的值必须为0,否则将抛出:

的异常,意为,srcData的容量不够大。

以后当需要使用2层的纹理图像数据时:

通过这种方式,可以增加代码的灵活性与多样性。

renderTexture方法

激活第0个纹理单元,将该纹理单元内的TEXTURE_3D绑定至上节所创建的纹理对象,渲染图像。

运行应用

参考资源

  1. WebGL 1.0 Specification
  2. WebGL 2.0 Specification
  3. WebGL Texture Units
  4. OpenGL ES 3.0 Reference Pages
  5. The OpenGL ES® Shading Language V3.0