• 轻量封装WebGPU渲染系统示例<33>- 单精度浮点纹理(源码)


    在WebGPU中创建纹理使用纹理很方便,只是JavaScript中只有Float32Array而没有原生只是的Float16Array类型,所以略微费点事。不过网上的大神多的是,摇摇小手就能获得解决方案。

    废话多了容易挨胖揍,看代码。

    js中float16单精度float数值转换:

    1. // thanks: https://esdiscuss.org/topic/float16array
    2. const toFloat16 = (function() {
    3. var floatView = new Float32Array(1);
    4. var int32View = new Int32Array(floatView.buffer);
    5. /* This method is faster than the OpenEXR implementation (very often
    6. * used, eg. in Ogre), with the additional benefit of rounding, inspired
    7. * by James Tursa?s half-precision code. */
    8. return function toHalf(val: number) {
    9. floatView[0] = val;
    10. var x = int32View[0];
    11. var bits = (x >> 16) & 0x8000; /* Get the sign */
    12. var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
    13. var e = (x >> 23) & 0xff; /* Using int is faster here */
    14. /* If zero, or denormal, or exponent underflows too much for a denormal
    15. * half, return signed zero. */
    16. if (e < 103) {
    17. return bits;
    18. }
    19. /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
    20. if (e > 142) {
    21. bits |= 0x7c00;
    22. /* If exponent was 0xff and one mantissa bit was set, it means NaN,
    23. * not Inf, so make sure we set one mantissa bit too. */
    24. bits |= (e == 255 ? 0 : 1) && x & 0x007fffff;
    25. return bits;
    26. }
    27. /* If exponent underflows but not too much, return a denormal */
    28. if (e < 113) {
    29. m |= 0x0800;
    30. /* Extra rounding may overflow and set mantissa to 0 and exponent
    31. * to 1, which is OK. */
    32. bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
    33. return bits;
    34. }
    35. bits |= ((e - 112) << 10) | (m >> 1);
    36. /* Extra rounding. An overflow will set mantissa to 0 and increment
    37. * the exponent, which is OK. */
    38. bits += m & 1;
    39. return bits;
    40. };
    41. })();

    基于上述数值转换,实现单精度浮点数纹理(rgba16float格式纹理):

    1. private createFloat16Texture(width: number, height: number): GPUTexture {
    2. let data = new Uint16Array(width * height * 4);
    3. let scale = 1.0;
    4. let k = 0;
    5. for (let i = 0; i < height; ++i) {
    6. for (let j = 0; j < width; ++j) {
    7. k = (width * i + j) * 4;
    8. data[k] = toFloat16(scale * (j/width));
    9. data[k+1] = toFloat16(scale * (0.5 + 0.5 * Math.sin(10.0 * (1.0 - j/width))));
    10. data[k+2] = toFloat16(scale * (1.0 - (i * j)/(width * height)));
    11. data[k+3] = toFloat16(scale * 1.0);
    12. }
    13. }
    14. const texture = device.createTexture({
    15. size: { width, height },
    16. format: "rgba16float",
    17. usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
    18. });
    19. // 下面的8表示一个像素需要4个float16也就是8个字节的内存来读写
    20. device.queue.writeTexture({ texture }, data, {bytesPerRow: width * 8, rowsPerImage: height}, { width, height });
    21. return texture;
    22. }

    上述代码呈现的纹理效果:

    此引擎系统当前示例RGBA8纹理和Float16纹理运行效果:

    此示例基于此渲染系统实现,当前示例TypeScript源码如下:

    1. export class DataTextureTest {
    2. private mRscene = new RendererScene();
    3. initialize(): void {
    4. this.initScene();
    5. }
    6. private applyRGBAFloat16Tex(): void {
    7. let rc = this.mRscene;
    8. let width = 256;
    9. let height = 256;
    10. let dataFs32 = new Float32Array(width * height * 4);
    11. let scale = 10.0;
    12. let k = 0;
    13. for (let i = 0; i < height; ++i) {
    14. for (let j = 0; j < width; ++j) {
    15. k = (width * i + j) * 4;
    16. dataFs32[k] = scale * (j / width);
    17. dataFs32[k + 1] = scale * (0.5 + 0.5 * Math.sin(10.0 * (1.0 - j / width)));
    18. dataFs32[k + 2] = scale * (1.0 - (i * j) / (width * height));
    19. dataFs32[k + 3] = scale * 1.0;
    20. }
    21. }
    22. const tex = {
    23. diffuse: { uuid: "tex0", dataTexture: { data: dataFs32, width, height }, format: "rgba16float", generateMipmaps: true }
    24. };
    25. let entity = new FixScreenPlaneEntity({ extent: [-0.8, -0.8, 0.8, 0.8], textures: [tex] });
    26. entity.color = [0.1, 0.1, 0.1, 0.1];
    27. rc.addEntity(entity);
    28. }
    29. private applyRGBA8Tex(): void {
    30. let rc = this.mRscene;
    31. let width = 256;
    32. let height = 256;
    33. let dataU8 = new Uint8Array(width * height * 4);
    34. let k = 0;
    35. for (let i = 0; i < height; ++i) {
    36. for (let j = 0; j < width; ++j) {
    37. k = (width * i + j) * 4;
    38. dataU8[k] = ((j / width) * 255) | 0;
    39. dataU8[k + 1] = ((0.5 + 0.5 * Math.sin(10.0 * (1.0 - j / width))) * 255) | 0;
    40. dataU8[k + 2] = ((1.0 - (i * j) / (width * height)) * 255) | 0;
    41. dataU8[k + 3] = 255;
    42. }
    43. }
    44. let tex = {
    45. diffuse: { uuid: "tex1", dataTexture: { data: dataU8, width, height }, format: "rgba8unorm", generateMipmaps: true }
    46. };
    47. let entity = new FixScreenPlaneEntity({ extent: [0.0, 0.0, 0.8, 0.8], textures: [tex] });
    48. rc.addEntity(entity);
    49. }
    50. private initScene(): void {
    51. this.applyRGBAFloat16Tex();
    52. this.applyRGBA8Tex();
    53. }
    54. run(): void {
    55. this.mRscene.run();
    56. }
    57. }

    注: 这里的纹理应用基于系统的对应功能的封装实现。

  • 相关阅读:
    一到汇报思绪乱? 学会这4个模型,高效表达无废话
    元年专利解析|元数据管理系统和使用其对模型对象进行建模的方法
    计算机网络常识通览
    Node.js |(六)express框架 | 尚硅谷2023版Node.js零基础视频教程
    项目管理之Scrum
    猿创征文|瑞吉外卖——移动端_购物车
    【论文阅读笔记】XLINK:淘宝短视频传输的多径QUIC协议
    设计模式之职责链模式应用例题
    元宇宙的气味体验有哪些可能?#共创招募
    54、Neural 3D Video Synthesis from Multi-view Video
  • 原文地址:https://blog.csdn.net/vily_lei/article/details/134433388