轻量封装WebGPU渲染系统示例<43>- PBR材质与阴影实(源码)

原理简介:

        1. 基于rendering pass graph实现。

        2. WGSL Shader 基于文件系统和宏机制动态组装。

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/PBRShadowTest.ts

当前示例运行效果:

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

class ShadowPassGraph extends WGRPassNodeGraph {private entities: Entity3D[] = [];private mDepthMaterials: WGMaterial[];shadowDepthRTT = { uuid: "rtt-shadow-depth", rttTexture: {}, shdVarName: 'shadowData' };depAttachment: WGRPassColorAttachment = {texture: this.shadowDepthRTT,// green clear background colorclearValue: { r: 1, g: 1, b: 1, a: 1.0 },loadOp: "clear",storeOp: "store"};occVRTT = { uuid: "rtt-shadow-occV", rttTexture: {}, shdVarName: 'shadowData' };occHRTT = { uuid: "rtt-shadow-occH", rttTexture: {}, shdVarName: 'shadowData' };occVEntity: FixScreenPlaneEntity;occHEntity: FixScreenPlaneEntity;shadowBias = -0.0005;shadowRadius = 2.0;shadowMapW = 512;shadowMapH = 512;shadowViewW = 1300;shadowViewH = 1300;shadowCamera: Camera;constructor() {super();}private initMaterial(): void {const shadowDepthShdSrc = {shaderSrc: { code: shadowDepthWGSL, uuid: "shadowDepthShdSrc" }};this.mDepthMaterials = [this.createDepthMaterial(shadowDepthShdSrc)];}private createDepthMaterial(shaderSrc: WGRShderSrcType, faceCullMode = "none"): WGMaterial {let pipelineDefParam = {depthWriteEnabled: true,faceCullMode,blendModes: [] as string[]};const material = new WGMaterial({shadinguuid: "shadow-depth_material",shaderSrc,pipelineDefParam});return material;}private buildShadowCam(): void {const g = this;const cam = new Camera({eye: [600.0, 800.0, -600.0],near: 0.1,far: 1900,perspective: false,viewWidth: g.shadowViewW,viewHeight: g.shadowViewH});cam.update();g.shadowCamera = cam;}addEntity(entity: Entity3D): ShadowPassGraph {let pass = this.passes[0];let et = new Entity3D({ transform: entity.transform });et.materials = this.mDepthMaterials;et.geometry = entity.geometry;et.rstate.copyFrom(entity.rstate);this.entities.push(et);pass.addEntity(et);return this;}addEntities(entities: Entity3D[]): ShadowPassGraph {let es = entities;for (let i = 0; i < es.length; ++i) {this.addEntity(es[i]);}return this;}initialize(rc: RendererScene): ShadowPassGraph {let colorAttachments = [this.depAttachment];// create a separate rtt rendering passlet multisampleEnabled = false;let pass = rc.createRTTPass({ colorAttachments, multisampleEnabled });this.passes = [pass];rc.setPassNodeGraph(this);this.buildShadowCam();pass.node.camera = this.shadowCamera;this.initMaterial();this.initocc();return this;}private initocc(): void {let pass = this.passes[0];let extent = [-1, -1, 2, 2];let material = new ShadowOccBlurMaterial();let ppt = material.property;ppt.setShadowRadius(this.shadowRadius);ppt.setViewSize(this.shadowMapW, this.shadowMapH);material.addTextures([this.shadowDepthRTT]);this.occVEntity = new FixScreenPlaneEntity({ extent, materials: [material] });this.occVEntity.visible = false;pass.addEntity(this.occVEntity);material = new ShadowOccBlurMaterial();ppt = material.property;ppt.setShadowRadius(this.shadowRadius);ppt.setViewSize(this.shadowMapW, this.shadowMapH);ppt.toHorizonalBlur();material.addTextures([this.occVRTT]);this.occHEntity = new FixScreenPlaneEntity({ extent, materials: [material] });this.occHEntity.visible = false;pass.addEntity(this.occHEntity);}run(): void {let pass = this.passes[0];let attachment = this.depAttachment;attachment.texture = this.shadowDepthRTT;let es = this.entities;for (let i = 0; i < es.length; ++i) {es[i].visible = true;}pass.render();for (let i = 0; i < es.length; ++i) {es[i].visible = false;}attachment.texture = this.occVRTT;this.occVEntity.visible = true;pass.render();this.occVEntity.visible = false;attachment.texture = this.occHRTT;this.occHEntity.visible = true;pass.render();this.occHEntity.visible = false;}
}
export class PBRShadowTest {private mRscene = new RendererScene();private mGraph = new ShadowPassGraph();initialize(): void {this.mRscene.initialize({canvasWith: 512,canvasHeight: 512,rpassparam: { multisampleEnabled: true }});this.initShadowScene();this.initEvent();}private mEntities: Entity3D[] = [];private initShadowScene(): void {let rc = this.mRscene;let position = new Vector3(-230.0, 100.0, -200.0);let materials = this.createMaterials(position);let sph = new SphereEntity({radius: 80,transform: {position},materials});this.mEntities.push(sph);rc.addEntity(sph);position = new Vector3(160.0, 100.0, -210.0);materials = this.createMaterials(position);let box = new BoxEntity({minPos: [-30, -30, -30],maxPos: [130, 230, 80],transform: {position,rotation: [50, 130, 80]},materials});this.mEntities.push(box);rc.addEntity(box);position = new Vector3(160.0, 100.0, 210.0);materials = this.createMaterials(position);let torus = new TorusEntity({transform: {position,rotation: [50, 30, 80]},materials});this.mEntities.push(torus);rc.addEntity(torus);this.buildShadow();}private buildShadow(): void {this.initShadowPass();this.initShadowReceiveDisp(true);this.buildShadowCamFrame();}private mShadowTransMat: Matrix4;private initShadowPass(): void {let rc = this.mRscene;const graph = this.mGraph;graph.initialize(rc).addEntities(this.mEntities);let cam = graph.shadowCamera;let transMatrix = new Matrix4();transMatrix.setScaleXYZ(0.5, -0.5, 0.5);transMatrix.setTranslationXYZ(0.5, 0.5, 0.5);let shadowMat = new Matrix4();shadowMat.copyFrom(cam.viewProjMatrix);shadowMat.append(transMatrix);this.mShadowTransMat = shadowMat;let extent = [-0.95, -0.95, 0.4, 0.4];let entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: graph.shadowDepthRTT }] });rc.addEntity(entity);extent = [-0.5, -0.95, 0.4, 0.4];entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: graph.occVRTT }] });rc.addEntity(entity);extent = [-0.05, -0.95, 0.4, 0.4];entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: graph.occHRTT }] });rc.addEntity(entity);}private buildShadowCamFrame(): void {const graph = this.mGraph;const cam = graph.shadowCamera;const rsc = this.mRscene;let frameColors = [[1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 1.0]];let boxFrame = new BoundsFrameEntity({ vertices8: cam.frustum.vertices, frameColors });rsc.addEntity(boxFrame);}private initEvent(): void {const rc = this.mRscene;rc.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDown);new MouseInteraction().initialize(rc, 0, false).setAutoRunning(true);}private initShadowReceiveDisp(shadowReceived = false): void {let rc = this.mRscene;let position = new Vector3(0, -1, 0);let materials = this.createMaterials(position, shadowReceived);let plane = new PlaneEntity({axisType: 1,materials,extent:[-600,-600,1200,1200],transform: { position }});rc.addEntity(plane);}private hdrEnvtex = new SpecularEnvBrnTexture();private createBaseTextures(shadowReceived = false): WGTextureDataDescriptor[] {const albedoTex = { albedo: { url: `static/assets/pbrtex/rough_plaster_broken_diff_1k.jpg` } };const normalTex = { normal: { url: `static/assets/pbrtex/rough_plaster_broken_nor_1k.jpg` } };const armTex = { arm: { url: `static/assets/pbrtex/rough_plaster_broken_arm_1k.jpg` } };let textures = [this.hdrEnvtex,albedoTex,normalTex,armTex] as WGTextureDataDescriptor[];if(shadowReceived) {textures.push( this.mGraph.occHRTT );}return textures;}private createMaterials(position: Vector3, shadowReceived = false, uvParam?: number[]): BasePBRMaterial[] {let textures0 = this.createBaseTextures(shadowReceived);let material0 = this.createMaterial(position, textures0, ["solid"]);this.applyMaterialPPt(material0, shadowReceived);let list = [material0];if (uvParam) {for (let i = 0; i < list.length; ++i) {list[i].property.uvParam.value = uvParam;}}return list;}private applyMaterialPPt(material: BasePBRMaterial, shadowReceived = false): void {let property = material.property;property.ambient.value = [0.0, 0.2, 0.2];property.albedo.value = [0.7, 0.7, 0.3];property.arms.roughness = 0.8;property.armsBase.value = [0, 0, 0];property.param.scatterIntensity = 32;const graph = this.mGraph;let cam = graph.shadowCamera;property.shadowReceived = shadowReceived;if(shadowReceived) {property.shadowMatrix.setShadowMatrix(this.mShadowTransMat);let vsmParams = property.vsmParams;vsmParams.setShadowRadius(graph.shadowRadius);vsmParams.setShadowBias(graph.shadowBias);vsmParams.setShadowSize(graph.shadowMapW, graph.shadowMapH);vsmParams.setDirec(cam.nv);vsmParams.setIntensity(0.5);}}private mLightParams: LightShaderDataParam[] = [];private createMaterial(position: Vector3DataType, textures: WGTextureDataDescriptor[], blendModes: string[], depthCompare = 'less', lightParam?: LightShaderDataParam): BasePBRMaterial {if (!lightParam) {lightParam = createLightData(position);this.mLightParams.push(lightParam);}let pipelineDefParam = {depthWriteEnabled: true,faceCullMode: 'back',blendModes,depthCompare};let material = new BasePBRMaterial({ pipelineDefParam });material.setLightParam(lightParam);material.addTextures(textures);return material;}private mouseDown = (evt: MouseEvent): void => {};run(): void {this.mRscene.run();}
}

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

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

相关文章

Ribbon-IRule 修改负载均衡的规则

1、负载均衡规则描述 &#xff08;1&#xff09;整体关系 &#xff08;2&#xff09;规则描述 内置负载均衡规则类规则描述RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。AvailabilityFilteringRule对以下两种服务器进行忽略: (1)在默认情况下&…

1-4、调试汇编程序

语雀原文链接 文章目录 1、执行过程第一步&#xff1a;源程序第二步&#xff1a;编译连接第三步&#xff1a;执行 2、DOSBox运行程序第1步 进入EDIT.EXE第2步 编写源程序第3步 编译第4步 连接第5步 执行完整过程 3、DEBUG跟踪执行过程加载程序到内存执行程序debug和源程序数字…

软件平台架构设计与技术管理之道笔记

软件平台架构设计与技术管理之道笔记 认知 领导软件平台各方面的工作&#xff0c;对技术底蕴、思维模式、决策能力、工作风格、文化铸造等方面都有极高的要求&#xff0c;可以称之为“领域智慧”。认知盲区的代价是巨大的&#xff0c;“不知”比“不会”的后果更严重&#xf…

探讨Unity中的动画融合技术(BlendTree)

动画在游戏和虚拟现实应用中扮演着关键的角色&#xff0c;而动画融合技术则是使角色动作更加流畅和逼真的核心。在Unity引擎中&#xff0c;我们可以使用动画混合树&#xff08;Blend Trees&#xff09;来实现这一目标。本篇技术博客将深入讨论动画融合技术的实现原理、在Unity中…

做一个类似万师傅家政小程序需要有哪些功能?

现如今人们生活节奏不断加快&#xff0c;自然很少有时间去处理生活中的琐事&#xff0c;恰好家政维修保洁小程序开发则能给线下用户提供方便。 家政保洁小程序应该具备哪些功能&#xff1f; 1、提供家政行业资讯&#xff0c;方便用户在选择家政保洁前了解行业动态。 2、分类搜…

Android wifi Enable之后扫描流程

流程框架图 通常我们在设备开启wifi之后&#xff0c;等会会自动扫描出周围的热点。 下面看下自动扫描周围热点的流程 代码流程 1. ClientModeManager.ClientModeStateMachine ClientModeStateMachine 由CMD_START 转换到StartedStateStartedState 状态机&#xff0c;在更新…

让代码变得优雅简洁的神器:Java8 Stream流式编程

原创/朱季谦 本文主要基于实际项目常用的Stream Api流式处理总结。 因笔者主要从事风控反欺诈相关工作&#xff0c;故而此文使用比较熟悉的三要素之一的【手机号】黑名单作代码案例说明。 我在项目当中&#xff0c;很早就开始使用Java 8的流特性进行开发了&#xff0c;但是一直…

流媒体方案之FFmpeg——实现物联网视频监控项目

目录 前言 一、FFmpeg介绍 二、FFmpeg简易理解 三、FFmpeg的重要概念 四、软硬件准备 五、移植、运行FFmpeg 六、运行FFmpeg 前言 最近想做一个安防相关的项目&#xff0c;所以跟着韦东山老师的视频来学习视频监控方案的相关知识&#xff0c;韦东山老师讲的课非常好&…

LaTex入门简明教程

文章目录 写在前面安装Texlive的安装TeXstudio 的安装 LaTex 的使用节指令图指令表指令公式指令参考文献指令引用指令TeXstudio 编译 LaTex 的 \label{} 写法建议最后 写在前面 这篇文章面向没有任何 LaTex 基础的小白&#xff0c;主要讲解了 LaTex 的安装和使用。读完文章之后…

android https 证书过期

有的时候 我们android https 证书过期 &#xff0c;或者使用明文等方式去访问服务器 可能会碰到类似的 问题 &#xff1a; javax.net.ssl.SSLHandshakeException: Chain validation failed java.security.cert.CertPathValidatorException: Response is unreliable: its validi…

通讯录管理系统(基于C语言)

模块设计 本通讯录管理系统功能模块共包括9个部分&#xff1a;1.输入数据、2.显示数据、 3.插入数据、4.删除数据、5.查看数据、6.修改数据、7.保存数据、 8.返回主菜单、9.退出系统. 一&#xff0e;总体设计 通讯录的每一条信息包括&#xff1a;姓名、性别、住址、联系电话…

西南科技大学模拟电子技术实验七(集成运算放大器的非线性应用)预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 预习计算内容根据运放的非线…

【Linux下如何生成coredump文件】

一&#xff0c;什么是coredump 我们经常听到大家说到程序core掉了&#xff0c;需要定位解决&#xff0c;这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止&#xff0c;并且在满足一定条件下&#xff08;这里为什么说需要满足一定的条件呢&#…

QT使用SQLite(打开db数据库以及对数据库进行增删改查)

QTSQLite 在QT中使用sqlite数据库&#xff0c;有多种使用方法&#xff0c;在这里我只提供几种简单&#xff0c;代码简短的方法&#xff0c;包括一些特殊字符处理。 用SQlite建立一个简单学生管理数据库 数据库中有两个表一个是class和student。 class表结构 student表结果…

非标设计之气缸类型

空压机&#xff1a; 空压机又称空气压缩机&#xff0c;简单来说就是将机械能转化为压力能来进行工作的&#xff0c;空压机在电力行业应用比较多&#xff0c;除了在电力行业应用较多外&#xff0c;其实空压机还有一个比较常见的用途就是用来制冷和分离气体&#xff0c;输送气体…

【web安全】RCE漏洞原理

前言 菜某的笔记总结&#xff0c;如有错误请指正。 RCE漏洞介绍 简而言之&#xff0c;就是代码中使用了可以把字符串当做代码执行的函数&#xff0c;但是又没有对用户的输入内容做到充分的过滤&#xff0c;导致可以被远程执行一些命令。 RCE漏洞的分类 RCE漏洞分为代码执行…

RT-Thread 三步实现利用DMA进行串口发送

应某些网友需求&#xff0c;说网上根本找不到基于Rt-Thread DMA串口发送代码&#xff0c;只有官方开源的串口DMA接收。 其实这些东西并不难&#xff0c;只要你细心去看哪些闲置的驱动文件且都是包装好的&#xff0c;通过关键字去查询或点开源文件查看&#xff0c;花不了几分钟…

【C/PTA —— 14.结构体1(课内实践)】

C/PTA —— 14.结构体1&#xff08;课内实践&#xff09; 6-1 计算两个复数之积6-2 结构体数组中查找指定编号人员6-3 综合成绩6-4 结构体数组按总分排序 6-1 计算两个复数之积 struct complex multiply(struct complex x, struct complex y) {struct complex product;product.…

Selenium 自动化高级操作与解决疑难杂症,如无法连接、使用代理等

解决 Selenium 自动化中的常见疑难杂症 这里记录一些关于 Selenium的常用操作和疑难杂症。 有一些细节的知识点就不重复介绍了&#xff0c;因为之前的文章中都有&#xff01; 如果对本文中的知识点有疑问的&#xff0c;可以先阅读我以前分享的文章&#xff01; 知识点&…

PyQt实战 创建一个PyQt5项目

前后端分离 参考链接 PyQt5实战&#xff08;二&#xff09;&#xff1a;创建一个PyQt5项目_pyqt5实战项目_笨鸟未必先飞的博客-CSDN博客 项目目录 创建一个QT项目 调用pyuic工具将dialog.ui文件编译为Python程序文件ui_dialog.py。 # -*- coding: utf-8 -*-# Form implemen…