轻量封装WebGPU渲染系统示例<48>- 多种光源的多种组合(源码)

news2024/11/24 2:06:34

实现方式:

1. 全局的灯光和阴影。

2. 球体和矩形平面使用了相同的材质对象。

3. 通过材质自动关联和组装对应的渲染材质功能节点。

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MultiLightsShading2.ts

当前示例运行效果:

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

export class MultiLightsShading2 {
	private mRscene = new RendererScene();
	initialize(): void {
		this.loadImg();
	}
	initSys(): void {

		this.mRscene.initialize({
			canvasWith: 512,
			canvasHeight: 512,
			mtplEnabled: true,
			rpassparam:
			{
				multisampled: true
			}
		});
		this.initScene();
		this.initEvent();
	}
	private mPixels: Uint8ClampedArray;
	private mPixelsW = 128;
	private mPixelsH = 128;
	getRandomColor(s?: number): ColorDataType {
		if (s === undefined) {
			s = 1.0;
		}
		let i = 5;
		let j = Math.floor(Math.random() * this.mPixelsW);
		let k = i * this.mPixelsW + j;
		let vs = this.mPixels;
		k *= 4;
		let cs = [s * vs[k] / 255.0, s * vs[k + 1] / 255.0, s * vs[k + 2] / 255.0];
		return cs;
	}
	private loadImg(): void {
		let img = new Image();
		img.onload = evt => {
			this.mPixelsW = img.width;
			this.mPixelsH = img.height;
			let canvas = document.createElement("canvas");
			canvas.width = img.width;
			canvas.height = img.height;
			let ctx = canvas.getContext('2d');
			ctx.drawImage(img, 0, 0);
			this.mPixels = ctx.getImageData(0, 0, img.width, img.height).data;
			this.initSys();
		}
		img.src = 'static/assets/colorPalette.jpg';
	}
	private mLightData: MtLightDataDescriptor;
	private createLightData(): MtLightDataDescriptor {
		let ld = { pointLights: [], directionLights: [], spotLights: [] } as MtLightDataDescriptor;

		let total = 5;
		let scale = 3;
		for (let i = 0; i < total; ++i) {
			let fi = i / (total - 1);
			for (let j = 0; j < total; ++j) {
				let fj = j / (total - 1);
				fi = 1;
				fj = 1;
				let position = [-500 + 250 * j, 50 + Math.random() * 30, -500 + 250 * i];
				position[0] += Math.random() * 60 - 30;
				position[2] += Math.random() * 60 - 30;
				let color = this.getRandomColor(scale);
				let factor1 = 0.00001;
				let factor2 = 0.00002;
				let pLight = new PointLight({ color, position, factor1, factor2 });
				ld.pointLights.push(pLight);
				if (Math.random() > 0.5) {
					position = [-500 + 250 * j, 50 + Math.random() * 30, -500 + 250 * i];
					position[0] += Math.random() * 70 - 35;
					position[2] += Math.random() * 70 - 35;
					color = this.getRandomColor(scale);
					let direction = [(Math.random() - 0.5) * 8, -1, (Math.random() - 0.5) * 8];
					let degree = Math.random() * 10 + 5;
					let spLight = new SpotLight({ position, color, direction, degree, factor1, factor2 });
					ld.spotLights.push(spLight);
				}
			}
		}
		let dLight = new DirectionLight({ color: [0.5, 0.5, 0.5], direction: [-1, -1, 0] });
		ld.directionLights.push(dLight);
		return ld;
	}
	private createBillboard(pv: Vector3DataType, c: ColorDataType, type: number): void {
		let rc = this.mRscene;
		let diffuseTex0 = { diffuse: { url: "static/assets/flare_core_03.jpg" } };
		if (type > 1) {
			diffuseTex0 = { diffuse: { url: "static/assets/circleWave_disp.png" } };
		}
		let billboard = new BillboardEntity({ size: 10, textures: [diffuseTex0] });
		billboard.color = c;
		billboard.alpha = 1.0;
		billboard.transform.setPosition(pv);
		rc.addEntity(billboard);
	}
	private createBillboards(): void {
		let lightData = this.mLightData;
		let pls = lightData.pointLights;
		for (let i = 0; i < pls.length; i++) {
			let lp = pls[i];
			this.createBillboard(lp.position, lp.color, 1);
		}
		let spls = lightData.spotLights;
		for (let i = 0; i < spls.length; i++) {
			let lp = spls[i];
			this.createBillboard(lp.position, lp.color, 2);
		}
	}
	private initScene(): void {

		let rc = this.mRscene;

		let mtpl = rc.renderer.mtpl;

		this.mLightData = this.createLightData();

		mtpl.light.lightData = this.mLightData;
		mtpl.shadow.param.intensity = 0.4;
		mtpl.shadow.param.radius = 4;

		let position = [-30, 220, -50];
		let materials = this.createMaterials(true);

		let sphere: SphereEntity;
		let total = 6;
		let py = -10;
		let k = 0;
		for (let i = 0; i < total; ++i) {
			for (let j = 0; j < total; ++j) {
				if (total > 2) {
					position = [-350 + 150 * j, py, -350 + 150 * i];
				} else {
					position = [0, py, 0];
				}
				if (sphere) {
					let sph = new SphereEntity(
						{
							geometry: sphere.geometry,
							materials,
							transform: { position }
						}
					);
					rc.addEntity(sph);
				} else {
					sphere = new SphereEntity(
						{
							radius: 35.0,
							materials,
							transform: { position }
						}
					);
					rc.addEntity(sphere);
				}
			}
		}

		position = [0, -50, 0];
		materials = this.createMaterials(true, false, 'back', [3, 3]);
		let plane = new PlaneEntity({
			axisType: 1,
			materials,
			extent: [-600, -600, 1200, 1200],
			transform: { position }
		});
		rc.addEntity(plane);

		this.createBillboards();

	}
	private createMaterials(shadowReceived = false, shadow = true, faceCullMode = 'back', uvParam?: number[]): BaseMaterial[] {

		let material0 = this.createMaterial( ["solid"], 'less', faceCullMode);
		this.applyMaterialPPt(material0, shadowReceived, shadow);
		let list = [material0];
		if (uvParam) {
			for (let i = 0; i < list.length; ++i) {
				list[i].property.uvParam.value = uvParam;
			}
		}
		return list;
	}

	private applyMaterialPPt(material: BaseMaterial, shadowReceived = false, shadow = true): void {
		let ppt = material.property;
		ppt.ambient.value = [0.1, 0.1, 0.1];
		ppt.albedo.value = [0.8, 0.8, 0.8];
		ppt.arms.roughness = 0.25;
		ppt.arms.metallic = 0.2;
		ppt.armsBase.value = [0, 0, 0];
		ppt.specularFactor.value = [0.1, 0.1, 0.1];

		ppt.shadow = shadow;
		ppt.lighting = true;

		ppt.shadowReceived = shadowReceived;
	}
	private createMaterial(blendModes: string[], depthCompare = 'less', faceCullMode = 'back'): BaseMaterial {

		let pipelineDefParam = {
			depthWriteEnabled: true,
			faceCullMode,
			blendModes,
			depthCompare
		};
		let material = new BaseMaterial({ pipelineDefParam });
		material.addTextures([{ specularEnv: {} }]);
		return material;
	}
	private initEvent(): void {
		const rc = this.mRscene;
		rc.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDown);
		new MouseInteraction().initialize(rc, 0, false).setAutoRunning(true);
	}
	private mouseDown = (evt: MouseEvent): void => { };
	run(): void {
		this.mRscene.run();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1316934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python 连接SQL server 请用pymssql连接,千万别用pyodbc

pymssql官方介绍文档 python 使用 pymssql连接 SQL server 代码示例&#xff1a; 安装pymssql包&#xff1a; pip install pymssql代码&#xff1a; import pymssqldef conn_sqlserver_demo():# 连接字符串示例&#xff08;根据您的配置进行修改&#xff09;conn Nonetry:co…

【C++】 C++11 新特性探索:decltype 和 auto

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ decltype推导变量类型推导函数返回类型 2️⃣ auto自动推导变量类型迭代器和范围循环 3️⃣ decltype 和 auto 同时使用&#x1f6ec; 结论&#x1f4d6; 参考资料 &#x1f6eb; 问题 描述 C11 引入了一些强大的新特性&#xff…

探索 HBase GUI 工具,助您轻松驾驭大数据世界!

你是否曾为 HBase 数据管理而苦恼&#xff1f;别担心&#xff0c;这一款超级好用的 HBase GUI &#xff08;HBase Assistant&#xff09;工具&#xff0c;让您在大数据世界中游刃有余。不再需要繁琐的命令行操作&#xff0c;也不再为复杂的配置感到头疼。 主要功能 直观和设计…

AttributeError: module ‘edge_tts‘ has no attribute ‘Communicate‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

插入排序:直接插入排序 希尔排序

插入排序&#xff1a; 假设红竖线前的元素全部排好序&#xff0c;红线后面的数即为要插入的数据&#xff0c;红线依次往后移&#xff0c;假设end为排好序的最后一个数字&#xff0c;end1即为要插入的数字&#xff0c;一次插入时&#xff0c;end与要插入的数字依次比较&#xf…

自定义时间选择器

自定义时间选择器 文章目录 自定义时间选择器第一章 效果演示第01节 效果图第02节 主要文件 第二章 案例代码第01节 核心文件 WheelPicker第02节 实体类 WheelBean第03节 接口类 IWheelPicker第04节 原子时间类 DateTimePickerView第05节 原子时间类 PickerYear第06节 原子时间…

比特币价格创新高:加密货币的崛起与未来

一、引言 近年来&#xff0c;比特币的价格一路上涨&#xff0c;引起了全球投资者和市场的广泛关注。作为最早一批区块链技术应用案例之一&#xff0c;比特币的成功带动了整个加密货币市场的兴起。本文将探讨比特币价格创新高的原因、加密货币的崛起以及未来发展趋势。 二、比特…

CV炼丹心得总结

1&#xff0c;ResNet的思想 yF(x)x 这个经验可帮助模型更快的收敛 class Block(nn.Module): # Encoder Blockdef __init__(self,dim, # 每个token的维度drop_rate0.1,switch_flagFalse,num_heads8):super(Block, self).__init__()self.switch_flag switch_flagself.…

驾龄不足三年如何注册网约车?刘师傅的反击之途!

刘师傅是个勤奋的司机。他想注册成为一名网约车司机&#xff0c;但由于驾龄不够三年&#xff0c;他一直被平台回绝。在多次尝试注册失败后&#xff0c;刘师傅慢慢四处求助。他咨询了多个渠道&#xff0c;但都没有得到有效的解决方案。当他在准备放弃的时候&#xff0c;他得知了…

从0创建并部署一个网页到服务器

创建一个页面 1 下载node.js 下载VScode 2 在Windows下找一个路径新建一个文件夹 例如&#xff1a;D:\study_project\PersonalWeb 3 VSCodee中打开文件夹 4 Windows下 管理员身份打开命令提示符&#xff0c;执行npm install -g vue/cli 5 VSCode下打开终端&#xff0c;执…

使用Audition录制电脑内部声音

在电脑上播放的媒体文件&#xff0c;包括视频和声音&#xff0c;很多是可以播放却无法保存的。例如一些网页播放的视频&#xff0c;或者在线播放的音乐。 视频的话&#xff0c;可以使用工具来截图&#xff0c;抓取GIF或录屏。 声音的话&#xff0c;也可以使用工具进行录制。这里…

【️Java是值传递还是引用传递?】

✅Java是值传递还是引用传递&#xff1f; ✅Java是值传递还是引用传递&#xff1f;✅典型理解 ✅增加知识仓✅Java的求值策略✅Java中的对象传递✅值传递和共享对象传递的现象冲突吗? ✅总结 ✅Java是值传递还是引用传递&#xff1f; ✅典型理解 编程语言中需要进行方法间的…

实战演示 H5 性能分析

W3C标准是浏览器标准&#xff0c;一般浏览器都支持W3C标准&#xff0c;它规定使用者可以通过api查询性能信息&#xff0c;可借用W3C协议完成自动化H5性能测试。 W3C官网&#xff1a;www.w3.org/TR/navigati… 使用chrome浏览器对webview进行手工查看&#xff0c;伴随着业务增多…

ChatGPT4 Excel 高级组合函数用法index+match完成实际需求

在Excel 函数用法中有一对组合函数使用是非常多的,那就是Index+match组合函数。 接下来我们用一个实际的需求让ChatGPT来帮我们实现一下。 我们给ChatGPT4发送一个prompt:有一个表格A2至A14为业务员B列至H列为1月至7月的销售额,请根据J2单元格的业务员与K2单元格的月份查找出…

【python】Debian安装miniconda、spyder、tushare

1. miniconda 安装 — 动手学深度学习 2.0.0 documentation中有安装Miniconda的一些说明。 Miniconda — miniconda documentation是Miniconda网站&#xff0c;里面也有安装说明。 Debian安装按照linux安装即可&#xff1a; mkdir -p ~/miniconda3 wget https://repo.anaco…

NoSQL 数据库有哪些典型应用?

前面的内容介绍了数据库读写分离和分库分表相关知识&#xff0c;都是针对关系型数据库的&#xff0c;即通常说的 RDBMS。除了关系型数据库&#xff0c;NoSQL 在项目开发中也有着越来越重要的作用&#xff0c;与此同时&#xff0c;NoSQL 相关的内容也是面试的常客。今天我们一起…

OSG中几何体的绘制(二)

5. 几何体操作 在本章的前言中就讲到&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体,简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能存在多种降低场景渲染效率的原因…

基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里

【JDK安装】 1.首先下载一个JDK版本 官网地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载1.8版本&#xff0c;用红框标注出来了&#xff1a; 也许有的同学看到没有1.8版本&#xff0c;你可以随便下载一个linux的…

最强Pose模型RTMO开源 | 基于YOLO架构再设计,9MB+9ms性能完爆YOLO-Pose

实时多人在图像中的姿态估计面临着在速度和精度之间实现平衡的重大挑战。尽管两阶段的上下文方法在图像中人数增加时会减慢速度&#xff0c;但现有的单阶段方法往往无法同时实现高精度和实时性能。 本文介绍了RTMO&#xff0c;这是一个单阶段姿态估计框架&#xff0c;通过在YOL…

【十】我们都是面向spring注解开发的

spring 注解驱动开发 简介&#xff1a; 前面有写过spring框架的演进历程&#xff0c;得出一个结论就是我们都是面向spring编程的&#xff0c;这里讲另一个结论&#xff1a;我们都是面向spring注解开发的。spring框架的核心设计理念是简化java开发&#xff0c;而这一路的发展越…