likes
comments
collection
share

webgl 1.0中一些不常用函数学习

作者站长头像
站长
· 阅读数 7

一、 关于Buffer Objects

1.1 bufferSubData

在OpenGL中,gl.bufferSubData 函数用于更新一个已经创建的缓冲区对象(Buffer Object)的子区域的数据。它允许你在不重新分配整个缓冲区的情况下,更新缓冲区中的特定范围的数据。这在动态数据更新、粒子系统、物理模拟等场景中非常有用。 函数原型:

void gl.bufferSubData(target, offset, data);
void gl.bufferSubData(target, offset)

参数说明:

  • target:指定缓冲区的类型,可以是以下值之一:

    • gl.ARRAY_BUFFER:表示顶点属性数据缓冲区。
    • gl.ELEMENT_ARRAY_BUFFER:表示顶点索引数据缓冲区。
    • 其他可能的缓冲区类型,如Uniform缓冲区等。
  • offset:指定要更新的子区域在缓冲区中的偏移位置(字节为单位)。

  • data:一个数组或一个类型化数组视图,包含了要写入到缓冲区中的数据。 使用示例:

const vertexData = new Float32Array([...]);// 要更新的数据 
const offset = 0; // 偏移位置,从缓冲区的开始处开始写入
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); // 绑定顶点缓冲区
gl.bufferSubData(gl.ARRAY_BUFFER, offset, vertexData); // 更新缓冲区的子区域

上述示例中,gl.ARRAY_BUFFER 表示顶点属性数据缓冲区。你需要先使用 gl.bindBuffer 绑定要更新的缓冲区对象,然后使用 gl.bufferSubData 更新指定偏移位置的数据。

需要注意的是,gl.bufferSubData 用于更新缓冲区的一部分数据,而不是整个缓冲区。如果要替换整个缓冲区的数据,应使用 gl.bufferData

此外,性能方面需要考虑数据更新的频率以及是否使用了合适的缓冲区用途和标志。为了获得最佳性能,可能还需要考虑使用像素缓冲对象(Pixel Buffer Objects)等更高级的技术。

二、关于Texture

2.1 gl.texSubImage2D

gl.texSubImage2D是一个用于更新纹理数据的函数。它允许你在已经创建的纹理对象中的特定区域更新像素数据,而不是重新创建整个纹理。这在动态纹理映射、视频渲染和实时图像处理等场景中非常有用。

函数原型:

void gl.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, ArrayBufferView? pixels);
void gl.texSubImage2D(target, level, xoffset, yoffset, format, type, pixels)

参数说明:

  • target: 指定纹理的类型,可以是 gl.TEXTURE_2D(二维纹理)或其他纹理类型。
  • level: 指定纹理的细节级别。0表示基本级别,较大的值表示更详细的级别。
  • xoffsetyoffset: 指定更新区域的起始像素位置。
  • widthheight: 指定更新区域的宽度和高度。
  • format: 指定像素数据的格式,例如 gl.RGB, gl.RGBA, gl.RED, 等等。
  • type: 指定像素数据的数据类型,例如 gl.UNSIGNED_BYTE, gl.FLOAT, 等等。
  • pixels: 包含待上传像素数据的数组缓冲区。可以为 null,表示只是为了分配存储空间,而不会初始化数据。

使用实例:

const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// 设置纹理参数等等
// ...

// 更新纹理的某个区域
const xoffset = 0;
const yoffset = 0;
const width = 256;
const height = 256;
const format = gl.RGBA;
const type = gl.UNSIGNED_BYTE;
const pixels = new Uint8Array(width * height * 4); // RGBA format
// 填充 pixels 数组,例如从图片加载像素数据

gl.texSubImage2D(gl.TEXTURE_2D, 0, xoffset, yoffset, width, height, format, type, pixels);

需要注意的是,texSubImage2D的调用可能会导致性能开销,特别是在频繁更新纹理数据的情况下。在某些情况下,使用gl.pixelStorei函数来调整像素打包对齐等参数,可以提高数据上传的性能。此外,一些图形API中还提供了更高效的数据更新方法,例如使用像素缓冲对象(Pixel Buffer Objects)。

2.2 copyTexImage2D

gl.copyTexImage2D 是一个在 OpenGL 中用于将当前帧缓冲区的像素数据复制到一个纹理对象中的函数。这样可以在之后的渲染中使用这个纹理,比如实现镜子效果、屏幕截图等。这个函数通常用于捕捉当前渲染结果并将其保存为一个纹理,方便后续的渲染操作。

函数原型:

void gl.copyTexImage2D(target, level, internalformat, x, y, width, height, border);

参数说明:

  • target: 指定纹理的类型,可以是 gl.TEXTURE_2D(二维纹理)或其他纹理类型。
  • level: 指定纹理的细节级别。0 表示基本级别,较大的值表示更详细的级别。
  • internalformat: 指定纹理的内部存储格式,例如 gl.RGBA, gl.RGB, 等等。
  • xy: 指定帧缓冲区中要复制的区域的起始像素位置。
  • widthheight: 指定要复制的区域的宽度和高度。
  • border: 边框大小,通常设置为 0。

使用示例(WebGL 上下文):

const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

// 将纹理附加到帧缓冲区
const attachmentPoint = gl.COLOR_ATTACHMENT0;
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, texture, 0);

// 绘制场景到帧缓冲区
// ...

// 复制帧缓冲区内容到纹理
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, width, height, 0);

// 之后可以使用这个纹理进行渲染

需要注意的是,使用 gl.copyTexImage2D 也可能会带来性能开销,因为它需要将当前帧缓冲区的数据复制到纹理中。在某些情况下,使用像素缓冲对象(Pixel Buffer Objects)或其他方法可以更高效地进行数据传输。此外,也要确保纹理的尺寸和格式与帧缓冲区相匹配,以确保正确的数据复制。

正如之前提到的,在具体编程时,应查阅相关的 OpenGL 文档和资源以获得最准确的信息。

2.3 copyTexSubImage2D

gl.copyTexSubImage2D 是 OpenGL 中用于将一个帧缓冲区的像素数据的子区域复制到一个已经创建的纹理对象的函数。与 gl.copyTexImage2D 不同,gl.copyTexSubImage2D 只复制一个区域的数据,而不会重新定义整个纹理对象。

函数原型:

void gl.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);

参数说明:

  • target: 指定纹理的类型,通常为 gl.TEXTURE_2D(二维纹理)。
  • level: 指定纹理的细节级别。0 表示基本级别,较大的值表示更详细的级别。
  • xoffsetyoffset: 指定纹理中的偏移位置,表示要复制的像素数据的目标起始位置。
  • xy: 指定帧缓冲区中要复制的区域的起始像素位置。
  • widthheight: 指定要复制的区域的宽度和高度。

使用示例(WebGL 上下文):

const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

// 将纹理附加到帧缓冲区
const attachmentPoint = gl.COLOR_ATTACHMENT0;
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, texture, 0);

// 绘制场景到帧缓冲区
// ...

// 复制帧缓冲区的子区域到纹理
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height);

// 之后可以使用这个纹理进行渲染

需要注意的是,gl.copyTexSubImage2D 的调用会将指定区域的像素数据从帧缓冲区复制到纹理中,不会改变纹理的大小或格式。这在一些实时渲染和镜像效果等场景中非常有用。

正如之前提到的,在具体编程时,应查阅相关的 OpenGL 文档和资源以获得最准确的信息。

2.4 compressedTexImage2D

compressedTexImage2D 是 WebGL 中的一个函数,用于将压缩的纹理数据加载到 2D 纹理目标中。它可以帮助您使用压缩格式的纹理数据来减少纹理在 GPU 内存中的占用,从而提高性能和效率。

// WebGL 1:
compressedTexImage2D(target, level, internalformat, width, height, border)
compressedTexImage2D(target, level, internalformat, width, height, border, pixels)

// Additionally available in WebGL 2:
// read from buffer bound to gl.PIXEL_UNPACK_BUFFER
compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, offset)
compressedTexImage2D(target, level, internalformat, width, height, border, srcData)
compressedTexImage2D(target, level, internalformat, width, height, border, srcData, srcOffset)
compressedTexImage2D(target, level, internalformat, width, height, border, srcData, srcOffset, srcLengthOverride)

// read from buffer bound to gl.PIXEL_UNPACK_BUFFER
compressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, offset)

compressedTexImage3D(target, level, internalformat, width, height, depth, border, srcData)
compressedTexImage3D(target, level, internalformat, width, height, depth, border, srcData, srcOffset)
compressedTexImage3D(target, level, internalformat, width, height, depth, border, srcData, srcOffset, srcLengthOverride)

以下是 compressedTexImage2D 函数的参数说明:

  1. target: 表示纹理目标,通常是 gl.TEXTURE_2D

  2. level: 表示纹理级别,通常为 0,表示基本级别。

  3. internalformat: 表示压缩的纹理内部格式,例如 gl.COMPRESSED_RGB_S3TC_DXT1_EXT

  4. width: 表示纹理的宽度。

  5. height: 表示纹理的高度。

  6. border: 表示边框的大小,通常为 0。

  7. data: 表示包含压缩纹理数据的 ArrayBufferView 或者是 null。

这个函数的使用场景通常是当您有压缩格式的纹理数据时,您可以使用此函数将其加载到纹理目标中。压缩纹理数据通常是通过外部工具生成的,并且它们在 GPU 上的解压缩过程通常由硬件执行,因此可以减少内存占用和纹理加载时间。

需要注意的是,不同的硬件和浏览器支持不同的压缩格式,因此在使用特定的压缩格式之前,最好查阅 WebGL 和硬件的文档以了解支持的压缩格式。

以下是一个示例用法:

var target = gl.TEXTURE_2D;
var level = 0;
var internalformat = gl.COMPRESSED_RGB_S3TC_DXT1_EXT;
var width = 512;
var height = 512;
var border = 0;
var data = // ArrayBufferView containing compressed texture data

gl.compressedTexImage2D(target, level, internalformat, width, height, border, data);

请注意,示例中的 internalformatdata 值需要根据您实际的纹理数据格式和硬件支持进行调整。

2.5 compressedTexSubImage2D

compressedTexSubImage2D 是 WebGL 中的一个函数,用于将压缩的纹理子图像加载到已存在的 2D 纹理目标中的特定级别。这个函数允许您更新现有纹理的特定区域,而不是重新加载整个纹理。

// WebGL 1:
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, srcData)

// Additionally available in WebGL 2:
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, offset)
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, srcData)
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, srcData, srcOffset)
compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, srcData, srcOffset, srcLengthOverride)

以下是 compressedTexSubImage2D 函数的参数说明:

  1. target: 表示纹理目标,通常是 gl.TEXTURE_2D

  2. level: 表示要更新的纹理级别。

  3. xoffsetyoffset: 表示要更新的纹理区域的起始像素坐标。

  4. widthheight: 表示要更新的纹理区域的宽度和高度。

  5. format: 表示压缩纹理数据的格式。

  6. data: 表示包含压缩纹理子图像数据的 ArrayBufferView 或者是 null。

这个函数的使用方式类似于 gl.compressedTexImage2D,但是它用于更新已存在纹理的特定区域。您可以使用它来实现动态的纹理更新,而不必重新加载整个纹理。同样地,在使用 compressedTexSubImage2D 之前,您需要确保浏览器和设备支持相应的压缩纹理格式。

以下是一个示例用法:

// Update a portion of an existing compressed texture
const target = gl.TEXTURE_2D;
const level = 0;
const xoffset = 100; // Starting x coordinate of the update area
const yoffset = 100; // Starting y coordinate of the update area
const width = 256;   // Width of the update area
const height = 256;  // Height of the update area
const format = COMPRESSED_RGB_S3TC_DXT1_EXT; // Replace with actual format
const data = // ArrayBufferView containing compressed texture subimage data

gl.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, data);

这个示例演示了如何使用 compressedTexSubImage2D 函数更新现有的压缩纹理的一部分。在实际应用中,您可以根据需要使用此函数来更新纹理,以实现动态的图像变化。

三. 特殊函数

3.1 hint

在OpenGL中,gl.hint函数用于设置渲染的提示。这个函数可以告诉OpenGL某些操作的性能或质量偏好,以便OpenGL在进行渲染时可以根据这些提示进行优化或选择合适的方案。

函数原型:

void gl.hint(target, mode);

参数说明:

  • target:表示提示的目标,可以是以下值之一:
    • gl.GENERATE_MIPMAP_HINT:提示OpenGL生成多级渐远纹理的方式。
    • gl.FRAGMENT_SHADER_DERIVATIVE_HINT:提示OpenGL如何计算片段着色器的导数。
  • mode:表示期望的提示模式,可以是以下值之一:
    • gl.FASTEST:提示OpenGL优先选择最快速度,可能会降低质量。
    • gl.NICEST:提示OpenGL优先选择最高质量,可能会降低速度。
    • gl.DONT_CARE:表示不关心性能或质量,由OpenGL自行决定。

示例:

// 设置生成多级渐远纹理的提示
gl.hint(gl.GENERATE_MIPMAP_HINT, gl.NICEST);

// 设置片段着色器导数计算的提示
gl.hint(gl.FRAGMENT_SHADER_DERIVATIVE_HINT, gl.FASTEST);

这些提示通常用于帮助OpenGL在某些情况下做出更好的决策,但并不保证一定会产生预期的效果。根据OpenGL的具体实现和硬件支持,提示的效果可能会有所不同。

需要注意的是,gl.hint是一个辅助性质的函数,不会直接影响渲染结果,而是影响OpenGL的内部策略和优化。在实际使用中,你可以根据应用程序的性能和质量需求进行相应的设置。

3.2 depthRange

在OpenGL中,gl.depthRange函数用于设置深度值的范围,即将从深度缓冲区中读取的深度值映射到的范围。深度值通常在近平面和远平面之间线性变化。这个函数可以用来控制深度测试的行为,以及在特定情况下实现不同的效果,比如阴影映射。

函数原型:

void gl.depthRange(nearVal, farVal);

参数说明:

  • nearVal:指定深度范围的近平面值,通常在0.0到1.0之间。
  • farVal:指定深度范围的远平面值,通常在0.0到1.0之间。

这两个参数定义了深度值映射的范围,具体而言,它们决定了从深度缓冲区读取的深度值如何映射到实际的深度坐标。

示例:

// 将深度值范围设置为默认的0.0到1.0
gl.depthRange(0.0, 1.0);

// 将深度值范围设置为自定义范围
gl.depthRange(0.2, 0.8);

通常情况下,深度值范围默认为0.0到1.0,即近平面对应深度值0.0,远平面对应深度值1.0。通过修改深度值范围,你可以调整深度测试和深度写入的行为,例如将深度值范围设置为不同的值,可以用于实现阴影贴图中的深度偏差,以减少自阴影的产生。

需要注意的是,gl.depthRange的范围参数通常是标准化的深度值范围,即在0.0到1.0之间。实际上,它们会映射到视口的深度坐标范围,视口中的深度坐标范围可以由 gl.viewport 函数设置。

四.状态掩码相关

4.1 colorMask

在OpenGL中,gl.colorMask 函数用于控制颜色缓冲区的写入掩码。颜色缓冲区是用于存储绘制的像素颜色值的缓冲区,通过设置写入掩码,你可以选择性地禁用对颜色缓冲区的某些分量的写入,以实现一些特定的渲染效果。

函数原型:

void gl.colorMask(red, green, blue, alpha);

参数说明:

  • red:指定是否允许对红色分量进行写入。可以为 true(允许写入)或 false(禁止写入)。
  • green:指定是否允许对绿色分量进行写入。
  • blue:指定是否允许对蓝色分量进行写入。
  • alpha:指定是否允许对 alpha 分量进行写入。

示例:

// 允许对所有颜色分量进行写入
gl.colorMask(true, true, true, true);

// 只允许对红色分量进行写入
gl.colorMask(true, false, false, false);

上述示例中,gl.colorMask 函数用于控制是否允许对各个颜色分量进行写入。如果某个分量的写入被禁止,那么在绘制时相应的分量值将不会被写入颜色缓冲区。

这种技术可以用于各种效果,例如创建颜色遮罩、轮廓渲染、后期处理等。通过控制颜色写入掩码,你可以实现很多有趣的视觉效果。

需要注意的是,gl.colorMask 对颜色缓冲区的写入操作具有全局影响,即所有渲染命令都会受到写入掩码的影响。在修改写入掩码后,记得在不需要的时候将其恢复到默认值,以免影响后续的渲染操作。

4.2 depthMask

在OpenGL中,gl.depthMask 函数用于控制深度缓冲区的写入操作。深度缓冲区用于存储每个像素的深度值,控制着在深度测试时是否允许更新深度缓冲区的值。通过设置深度写入掩码,你可以选择性地禁止或允许对深度缓冲区的写入,从而实现一些特定的渲染效果。

函数原型:

void gl.depthMask(flag);

参数说明:

  • flag:指定是否允许对深度缓冲区进行写入。可以为 true(允许写入)或 false(禁止写入)。

示例:

// 允许对深度缓冲区进行写入
gl.depthMask(true);

// 禁止对深度缓冲区进行写入
gl.depthMask(false);

上述示例中,gl.depthMask 函数用于控制是否允许对深度缓冲区进行写入。如果被禁止写入,那么在绘制时深度测试的结果不会影响深度缓冲区的值。

这种技术可以用于一些特殊的渲染效果,比如绘制透明物体时,你可能需要先绘制不透明物体来更新深度缓冲区,然后再绘制透明物体,但不更新深度缓冲区,以确保透明物体正确地进行深度测试和排序。

需要注意的是,gl.depthMask 对深度缓冲区的写入操作具有全局影响,即所有渲染命令都会受到深度写入掩码的影响。在修改深度写入掩码后,记得在不需要的时候将其恢复到默认值,以免影响后续的渲染操作。

4.3 stencilMask

在OpenGL中,gl.stencilMask 函数用于设置模板缓冲区的写入掩码。模板缓冲区(Stencil Buffer)用于存储每个像素的模板值,这些值可以用于实现各种图案剪切、特殊效果和掩码测试等功能。通过设置模板写入掩码,你可以选择性地允许或禁止对模板缓冲区的写入。

函数原型:

void gl.stencilMask(mask);

参数说明:

  • mask:一个整数,表示要设置的模板写入掩码。

示例:

// 允许对模板缓冲区进行写入
gl.stencilMask(0xFF);

// 禁止对模板缓冲区进行写入
gl.stencilMask(0x00);

上述示例中,gl.stencilMask 函数用于设置模板写入掩码。通过指定掩码,可以选择性地对模板缓冲区的某些位进行写入或禁止写入。

模板缓冲区的主要应用之一是在特定的渲染过程中,使用模板测试和模板写入来控制绘制的部分区域。这可以用于绘制剪切区域、生成阴影、镜像等复杂的效果。

需要注意的是,gl.stencilMask 的参数是一个整数,通常用二进制位来表示要写入或禁止写入的模板缓冲区位。在具体使用中,你需要根据需要进行位运算或位操作来设置掩码。

与其他写入掩码函数类似,gl.stencilMask 对模板缓冲区的写入具有全局影响,所以在修改模板写入掩码后,记得在不需要的时候将其恢复到默认值,以免影响后续的渲染操作。

4.4 scissor

在OpenGL中,gl.scissor 函数用于定义一个裁剪矩形,该矩形用于限制渲染的区域。只有在裁剪矩形内的像素才会被绘制到帧缓冲区中,超出矩形的像素将被裁剪掉。这个函数通常用于实现视口(Viewport)内的局部渲染或剪切。

函数原型:

void gl.scissor(x, y, width, height);

参数说明:

  • xy:裁剪矩形左下角的坐标。
  • widthheight:裁剪矩形的宽度和高度。

示例:

// 设置裁剪矩形,仅允许在 (100, 100) 到 (300, 300) 区域内渲染
gl.scissor(100, 100, 200, 200);

上述示例中,gl.scissor 函数定义了一个裁剪矩形,只有在该矩形区域内的像素才会被绘制。超出该矩形的像素将被忽略。

需要注意的是,gl.scissor 的设置只有在启用裁剪测试(glEnable(GL_SCISSOR_TEST))的情况下才会生效。此外,gl.scissor 的坐标和大小是基于窗口坐标的,而不是标准化设备坐标。通常情况下,窗口坐标和标准化设备坐标的原点都在左下角,但在不同的框架和平台上,坐标系的方向可能会有不同的约定。

使用 gl.scissor 可以实现一些有趣的效果,比如在屏幕上放大特定区域、实现镜子效果等。在每次绘制之前,确保正确设置裁剪矩形和启用裁剪测试,以便获得预期的渲染结果。