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

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

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

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

javascript 复制代码
// thanks: https://esdiscuss.org/topic/float16array
const toFloat16 = (function() {
	var floatView = new Float32Array(1);
	var int32View = new Int32Array(floatView.buffer);
	/* This method is faster than the OpenEXR implementation (very often
	 * used, eg. in Ogre), with the additional benefit of rounding, inspired
	 * by James Tursa?s half-precision code. */
	return function toHalf(val: number) {
		floatView[0] = val;
		var x = int32View[0];

		var bits = (x >> 16) & 0x8000; /* Get the sign */
		var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
		var e = (x >> 23) & 0xff; /* Using int is faster here */

		/* If zero, or denormal, or exponent underflows too much for a denormal
		 * half, return signed zero. */
		if (e < 103) {
			return bits;
		}

		/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
		if (e > 142) {
			bits |= 0x7c00;
			/* If exponent was 0xff and one mantissa bit was set, it means NaN,
			 * not Inf, so make sure we set one mantissa bit too. */
			bits |= (e == 255 ? 0 : 1) && x & 0x007fffff;
			return bits;
		}

		/* If exponent underflows but not too much, return a denormal */
		if (e < 113) {
			m |= 0x0800;
			/* Extra rounding may overflow and set mantissa to 0 and exponent
			 * to 1, which is OK. */
			bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
			return bits;
		}

		bits |= ((e - 112) << 10) | (m >> 1);
		/* Extra rounding. An overflow will set mantissa to 0 and increment
		 * the exponent, which is OK. */
		bits += m & 1;
		return bits;
	};
})();

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

javascript 复制代码
private createFloat16Texture(width: number, height: number): GPUTexture {

		let data = new Uint16Array(width * height * 4);
		let scale = 1.0;
		let k = 0;
		for (let i = 0; i < height; ++i) {
			for (let j = 0; j < width; ++j) {
				k = (width * i + j) * 4;
				data[k] = toFloat16(scale * (j/width));
				data[k+1] = toFloat16(scale * (0.5 + 0.5 * Math.sin(10.0 * (1.0 - j/width))));
				data[k+2] = toFloat16(scale * (1.0 - (i * j)/(width * height)));
				data[k+3] = toFloat16(scale * 1.0);
			}
		}

		const texture = device.createTexture({
			size: { width, height },
			format: "rgba16float",
			usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
		});
        // 下面的8表示一个像素需要4个float16也就是8个字节的内存来读写
		device.queue.writeTexture({ texture }, data, {bytesPerRow: width * 8, rowsPerImage: height}, { width, height });
		return texture;
	}

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

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

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

javascript 复制代码
export class DataTextureTest {
	private mRscene = new RendererScene();

	initialize(): void {

		this.initScene();
	}
	private applyRGBAFloat16Tex(): void {
		let rc = this.mRscene;

		let width = 256;
		let height = 256;

		let dataFs32 = new Float32Array(width * height * 4);
		let scale = 10.0;
		let k = 0;
		for (let i = 0; i < height; ++i) {
			for (let j = 0; j < width; ++j) {
				k = (width * i + j) * 4;
				dataFs32[k] = scale * (j / width);
				dataFs32[k + 1] = scale * (0.5 + 0.5 * Math.sin(10.0 * (1.0 - j / width)));
				dataFs32[k + 2] = scale * (1.0 - (i * j) / (width * height));
				dataFs32[k + 3] = scale * 1.0;
			}
		}
		const tex = {
			diffuse: { uuid: "rtt0", dataTexture: { data: dataFs32, width, height }, format: "rgba16float", generateMipmaps: true }
		};

		let entity = new FixScreenPlaneEntity({ extent: [-0.8, -0.8, 0.8, 0.8], textures: [tex] });
		entity.color = [0.1, 0.1, 0.1, 0.1];
		rc.addEntity(entity);
	}

	private applyRGBA8Tex(): void {
		let rc = this.mRscene;

		let width = 256;
		let height = 256;

		let dataU8 = new Uint8Array(width * height * 4);
		let k = 0;
		for (let i = 0; i < height; ++i) {
			for (let j = 0; j < width; ++j) {
				k = (width * i + j) * 4;
				dataU8[k] = ((j / width) * 255) | 0;
				dataU8[k + 1] = ((0.5 + 0.5 * Math.sin(10.0 * (1.0 - j / width))) * 255) | 0;
				dataU8[k + 2] = ((1.0 - (i * j) / (width * height)) * 255) | 0;
				dataU8[k + 3] = 255;
			}
		}

		let tex = {
			diffuse: { uuid: "rtt1", dataTexture: { data: dataU8, width, height }, format: "rgba8unorm", generateMipmaps: true }
		};

		let entity = new FixScreenPlaneEntity({ extent: [0.0, 0.0, 0.8, 0.8], textures: [tex] });
		rc.addEntity(entity);
	}
	private initScene(): void {
		this.applyRGBAFloat16Tex();
		this.applyRGBA8Tex();
	}

	run(): void {
		this.mRscene.run();
	}
}

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

相关推荐
Death2001 小时前
Qt 3D、QtQuick、QtQuick 3D 和 QML 的关系
c语言·c++·qt·3d·c#
摇曳的树5 小时前
【3D目标检测】激光雷达和相机联合标定(二)——MATLAB联合标定工具使用
数码相机·目标检测·3d
知来者逆5 小时前
V3D——从单一图像生成 3D 物体
人工智能·计算机视觉·3d·图像生成
唐·柯里昂79816 小时前
[3D打印]拓竹切片软件Bambu Studio使用
经验分享·笔记·3d
摇曳的树20 小时前
【3D目标检测】激光雷达和相机联合标定(一)——ROS同步解包
数码相机·目标检测·3d
摩尔线程1 天前
使用MTVerseXR SDK实现VR串流
3d·xr·图形渲染·vr·摩尔线程
GIS数据转换器2 天前
城市空间设计对居民生活质量的影响:构建宜居城市的蓝图
大数据·人工智能·3d·gis·生活·智慧城市
qq_15321452642 天前
【2022工业3D异常检测文献】AST: 基于归一化流的双射性产生不对称学生-教师异常检测方法
图像处理·深度学习·神经网络·机器学习·计算机视觉·3d·视觉检测
qq_15321452642 天前
【2023工业3D异常检测文献】CPMF: 基于手工制作PCD描述符和深度学习IAD结合的AD方法
图像处理·深度学习·神经网络·机器学习·计算机视觉·3d·视觉检测
qq_15321452644 天前
【2023工业3D异常检测文献】M3DM: 基于混合融合的多模态工业异常检测方法
图像处理·深度学习·神经网络·机器学习·计算机视觉·3d·视觉检测