轻量封装WebGPU渲染系统示例<11>- WebGPU简单PBR效果(源码)

2023-11-02 12:28

本文主要是介绍轻量封装WebGPU渲染系统示例<11>- WebGPU简单PBR效果(源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/SimplePBRTest.ts

此示例渲染系统实现的特性:

1. 用户态与系统态隔离。

         细节请见:引擎系统设计思路 - 用户态与系统态隔离-CSDN博客

2. 高频调用与低频调用隔离。

3. 面向用户的易用性封装。

4. 渲染数据和渲染机制分离。

5. 用户操作和渲染系统调度并行机制。

当前示例运行效果:

顶点shader:


@group(0) @binding(0) var<uniform> objMat : mat4x4<f32>;
@group(0) @binding(1) var<uniform> viewMat : mat4x4<f32>;
@group(0) @binding(2) var<uniform> projMat : mat4x4<f32>;struct VertexOutput {@builtin(position) Position : vec4<f32>,@location(0) pos: vec4<f32>,@location(1) uv : vec2<f32>,@location(2) normal : vec3<f32>,@location(3) camPos : vec3<f32>
}fn inverseM33(m: mat3x3<f32>)-> mat3x3<f32> {let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2];let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2];let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2];let b01 = a22 * a11 - a12 * a21;let b11 = -a22 * a10 + a12 * a20;let b21 = a21 * a10 - a11 * a20;let det = a00 * b01 + a01 * b11 + a02 * b21;return mat3x3<f32>(vec3<f32>(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11)) / det,vec3<f32>(b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10)) / det,vec3<f32>(b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det);
}
fn m44ToM33(m: mat4x4<f32>) -> mat3x3<f32> {return mat3x3(m[0].xyz, m[1].xyz, m[2].xyz);
}fn inverseM44(m: mat4x4<f32>)-> mat4x4<f32> {let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2]; let a03 = m[0][3];let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2]; let a13 = m[1][3];let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2]; let a23 = m[2][3];let a30 = m[3][0]; let a31 = m[3][1]; let a32 = m[3][2]; let a33 = m[3][3];let b00 = a00 * a11 - a01 * a10;let b01 = a00 * a12 - a02 * a10;let b02 = a00 * a13 - a03 * a10;let b03 = a01 * a12 - a02 * a11;let b04 = a01 * a13 - a03 * a11;let b05 = a02 * a13 - a03 * a12;let b06 = a20 * a31 - a21 * a30;let b07 = a20 * a32 - a22 * a30;let b08 = a20 * a33 - a23 * a30;let b09 = a21 * a32 - a22 * a31;let b10 = a21 * a33 - a23 * a31;let b11 = a22 * a33 - a23 * a32;let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;return mat4x4<f32>(vec4<f32>(a11 * b11 - a12 * b10 + a13 * b09,a02 * b10 - a01 * b11 - a03 * b09,a31 * b05 - a32 * b04 + a33 * b03,a22 * b04 - a21 * b05 - a23 * b03) / det,vec4<f32>(a12 * b08 - a10 * b11 - a13 * b07,a00 * b11 - a02 * b08 + a03 * b07,a32 * b02 - a30 * b05 - a33 * b01,a20 * b05 - a22 * b02 + a23 * b01) / det,vec4<f32>(a10 * b10 - a11 * b08 + a13 * b06,a01 * b08 - a00 * b10 - a03 * b06,a30 * b04 - a31 * b02 + a33 * b00,a21 * b02 - a20 * b04 - a23 * b00) / det,vec4<f32>(a11 * b07 - a10 * b09 - a12 * b06,a00 * b09 - a01 * b07 + a02 * b06,a31 * b01 - a30 * b03 - a32 * b00,a20 * b03 - a21 * b01 + a22 * b00) / det);
}
@vertex
fn main(@location(0) position : vec3<f32>,@location(1) uv : vec2<f32>,@location(2) normal : vec3<f32>
) -> VertexOutput {let wpos = objMat * vec4(position.xyz, 1.0);var output : VertexOutput;output.Position = projMat * viewMat * wpos;output.uv = uv;let invMat33 = inverseM33( m44ToM33( objMat ) );output.normal = normalize( normal * invMat33 );output.camPos = (inverseM44(viewMat) * vec4<f32>(0.0,0.0,0.0, 1.0)).xyz;output.pos = wpos;return output;
}

片段shader:

@group(0) @binding(3) var<storage> albedo: vec4f;
@group(0) @binding(4) var<storage> param: vec4f;const PI = 3.141592653589793;
const PI2 = 6.283185307179586;
const PI_HALF = 1.5707963267948966;
const RECIPROCAL_PI = 0.3183098861837907;
const RECIPROCAL_PI2 = 0.15915494309189535;
const EPSILON = 1e-6;fn approximationSRGBToLinear(srgbColor: vec3<f32>) -> vec3<f32> {return pow(srgbColor, vec3<f32>(2.2));
}
fn approximationLinearToSRCB(linearColor: vec3<f32>) -> vec3<f32> {return pow(linearColor, vec3(1.0/2.2));
}fn accurateSRGBToLinear(srgbColor: vec3<f32>) -> vec3<f32> {let linearRGBLo = srgbColor / 12.92;let linearRGBHi = pow((srgbColor + vec3(0.055)) / vec3(1.055), vec3(2.4));if( all( srgbColor <= vec3(0.04045) ) ) {return linearRGBLo;}return linearRGBHi;
}
fn accurateLinearToSRGB(linearColor: vec3<f32>) -> vec3<f32> {let srgbLo = linearColor * 12.92;let srgbHi = (pow(abs(linearColor), vec3(1.0 / 2.4)) * 1.055) - 0.055;if(all(linearColor <= vec3(0.0031308))) {return srgbLo;}return srgbHi;
}// Trowbridge-Reitz(Generalized-Trowbridge-Reitz,GTR)
fn DistributionGTR1(NdotH: f32, roughness: f32) -> f32 {if (roughness >= 1.0) {return 1.0/PI;}let a2 = roughness * roughness;let t = 1.0 + (a2 - 1.0)*NdotH*NdotH;return (a2 - 1.0) / (PI * log(a2) *t);
}
fn DistributionGTR2(NdotH: f32, roughness: f32) -> f32 {let a2 = roughness * roughness;let t = 1.0 + (a2 - 1.0) * NdotH * NdotH;return a2 / (PI * t * t);
}fn DistributionGGX(N: vec3<f32>, H: vec3<f32>, roughness: f32) -> f32 {let a = roughness*roughness;let a2 = a*a;let NdotH = max(dot(N, H), 0.0);let NdotH2 = NdotH*NdotH;let nom   = a2;var denom = (NdotH2 * (a2 - 1.0) + 1.0);denom = PI * denom * denom;return nom / max(denom, 0.0000001); // prevent divide by zero for roughness=0.0 and NdotH=1.0
}fn GeometryImplicit(NdotV: f32, NdotL: f32) -> f32 {return NdotL * NdotV;
}// ----------------------------------------------------------------------------
fn GeometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {let r = (roughness + 1.0);let k = (r*r) / 8.0;let nom   = NdotV;let denom = NdotV * (1.0 - k) + k;return nom / denom;
}
// ----------------------------------------------------------------------------
fn GeometrySmith(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, roughness: f32) -> f32 {let NdotV = max(dot(N, V), 0.0);let NdotL = max(dot(N, L), 0.0);let ggx2 = GeometrySchlickGGX(NdotV, roughness);let ggx1 = GeometrySchlickGGX(NdotL, roughness);return ggx1 * ggx2;
}// @param cosTheta is clamp(dot(H, V), 0.0, 1.0)
fn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
}
fn fresnelSchlick2(specularColor: vec3<f32>, L: vec3<f32>, H: vec3<f32>) -> vec3<f32> {return specularColor + (1.0 - specularColor) * pow(1.0 - saturate(dot(L, H)), 5.0);
}
//fresnelSchlick2(specularColor, L, H) * ((SpecularPower + 2) / 8 ) * pow(saturate(dot(N, H)), SpecularPower) * dotNL;const OneOnLN2_x6 = 8.656171;// == 1/ln(2) * 6 (6 is SpecularPower of 5 + 1)
// dot -> dot(N,V) or
fn fresnelSchlick3(specularColor: vec3<f32>, dot: f32, glossiness: f32) -> vec3<f32> {return specularColor + (max(vec3(glossiness), specularColor) - specularColor) * exp2(-OneOnLN2_x6 * dot);
}
fn fresnelSchlickWithRoughness(specularColor: vec3<f32>, L: vec3<f32>, N: vec3<f32>, gloss: f32) -> vec3<f32> {return specularColor + (max(vec3(gloss), specularColor) - specularColor) * pow(1.0 - saturate(dot(L, N)), 5.0);
}const A = 2.51f;
const B = 0.03f;
const C = 2.43f;
const D = 0.59f;
const E = 0.14f;
fn ACESToneMapping(color: vec3<f32>, adapted_lum: f32) -> vec3<f32> {let c = color * adapted_lum;return (c * (A * c + B)) / (c * (C * c + D) + E);
}//color = color / (color + vec3(1.0));
fn reinhard(v: vec3<f32>) -> vec3<f32> {return v / (vec3<f32>(1.0) + v);
}
fn reinhard_extended(v: vec3<f32>, max_white: f32) -> vec3<f32> {let numerator = v * (1.0f + (v / vec3(max_white * max_white)));return numerator / (1.0f + v);
}
fn luminance(v: vec3<f32>) -> f32 {return dot(v, vec3<f32>(0.2126f, 0.7152f, 0.0722f));
}fn change_luminance(c_in: vec3<f32>, l_out: f32) -> vec3<f32> {let l_in = luminance(c_in);return c_in * (l_out / l_in);
}
fn reinhard_extended_luminance(v: vec3<f32>, max_white_l: f32) -> vec3<f32> {let l_old = luminance(v);let numerator = l_old * (1.0f + (l_old / (max_white_l * max_white_l)));let l_new = numerator / (1.0f + l_old);return change_luminance(v, l_new);
}
fn ReinhardToneMapping( color: vec3<f32>, toneMappingExposure: f32 ) -> vec3<f32> {let c = color * toneMappingExposure;return saturate( c / ( vec3( 1.0 ) + c ) );}
// expects values in the range of [0,1]x[0,1], returns values in the [0,1] range.
// do not collapse into a single function per: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
const highp_a = 12.9898;
const highp_b = 78.233;
const highp_c = 43758.5453;
fn rand( uv: vec2<f32> ) -> f32 {let dt = dot( uv.xy, vec2<f32>( highp_a, highp_b ) );let sn = modf( dt / PI ).fract;return fract(sin(sn) * highp_c);
}
// // based on https://www.shadertoy.com/view/MslGR8
fn dithering( color: vec3<f32>, fragCoord: vec2<f32> ) -> vec3<f32> {//Calculate grid positionlet grid_position = rand( fragCoord );//Shift the individual colors differently, thus making it even harder to see the dithering patternvar dither_shift_RGB = vec3<f32>( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );//modify shift acording to grid position.dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );//shift the color by dither_shiftreturn color + dither_shift_RGB;
}const dis = 700.0;
const disZ = 400.0;
const u_lightPositions = array<vec3<f32>, 4>(vec3<f32>(-dis, dis, disZ),vec3<f32>(dis, dis, disZ),vec3<f32>(-dis, -dis, disZ),vec3<f32>(dis, -dis, disZ)
);
const colorValue = 300.0;
const u_lightColors = array<vec3<f32>, 4>(vec3<f32>(colorValue, colorValue, colorValue),vec3<f32>(colorValue, colorValue, colorValue),vec3<f32>(colorValue, colorValue, colorValue),vec3<f32>(colorValue, colorValue, colorValue),
);fn calcPBRColor3(Normal: vec3<f32>, WorldPos: vec3<f32>, camPos: vec3<f32>) -> vec3<f32> {var color = vec3<f32>(0.0);var ao = param.x;var roughness = param.y;var metallic = param.z;var N = normalize(Normal);var V = normalize(camPos.xyz - WorldPos);var dotNV = clamp(dot(N, V), 0.0, 1.0);// calculate reflectance at normal incidence; if dia-electric (like plastic) use F0// of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)var F0 = vec3(0.04);F0 = mix(F0, albedo.xyz, metallic);// reflectance equationvar Lo = vec3(0.0);for (var i: i32 = 0; i < 4; i++) {// calculate per-light radiancelet L = normalize(u_lightPositions[i].xyz - WorldPos);let H = normalize(V + L);let distance = length(u_lightPositions[i].xyz - WorldPos);let attenuation = 1.0 / (1.0 + 0.001 * distance + 0.0003 * distance * distance);let radiance = u_lightColors[i].xyz * attenuation;// Cook-Torrance BRDFlet NDF = DistributionGGX(N, H, roughness);let G   = GeometrySmith(N, V, L, roughness);//vec3 F    = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);let F    = fresnelSchlick3(F0,clamp(dot(H, V), 0.0, 1.0), 0.9);//vec3 F    = fresnelSchlick3(F0,dotNV, 0.9);let nominator    = NDF * G * F;let denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);let specular = nominator / max(denominator, 0.001); // prevent divide by zero for NdotV=0.0 or NdotL=0.0// kS is equal to Fresnellet kS = F;// for energy conservation, the diffuse and specular light can't// be above 1.0 (unless the surface emits light); to preserve this// relationship the diffuse component (kD) should equal 1.0 - kS.var kD = vec3<f32>(1.0) - kS;// multiply kD by the inverse metalness such that only non-metals// have diffuse lighting, or a linear blend if partly metal (pure metals// have no diffuse light).kD *= 1.0 - metallic;// scale light by NdotLlet NdotL = max(dot(N, L), 0.0);// add to outgoing radiance Lo// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS againLo += (kD * albedo.xyz / PI + specular) * radiance * NdotL;}// ambient lighting (note that the next IBL tutorial will replace// this ambient lighting with environment lighting).let ambient = vec3<f32>(0.03) * albedo.xyz * ao;color = ambient + Lo;// HDR tonemappingcolor = reinhard( color );// gamma correctcolor = pow(color, vec3<f32>(1.0/2.2));return color;
}@fragment
fn main(@location(0) pos: vec4<f32>,@location(1) uv: vec2<f32>,@location(2) normal: vec3<f32>,@location(3) camPos: vec3<f32>
) -> @location(0) vec4<f32> {var color4 = vec4(calcPBRColor3(normal, pos.xyz, camPos), 1.0);return color4;
}

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

export class SimplePBRTest {private mRscene = new RendererScene();geomData = new GeomDataBuilder();initialize(): void {console.log("SimplePBRTest::initialize() ...");const rc = this.mRscene;rc.initialize();this.initEvent();this.initScene();}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 => {}private createMaterial(shdSrc: WGRShderSrcType, color?: Color4, arm?: number[]): WGMaterial {color = color ? color : new Color4();let pipelineDefParam = {depthWriteEnabled: true,blendModes: [] as string[]};const material = new WGMaterial({shadinguuid: "simple-pbr-materialx",shaderCodeSrc: shdSrc,pipelineDefParam});let albedoV = new WGRStorageValue(new Float32Array([color.r, color.g, color.b, 1]));// arm[0]: ao, arm[1]: roughness, arm[2]: metalliclet armV = new WGRStorageValue(new Float32Array([arm[0], arm[1], arm[2], 1]));material.uniformValues = [albedoV, armV];return material;}private createGeom(rgd: GeomRDataType, normalEnabled = false): WGGeometry {const geometry = new WGGeometry().addAttribute({ position: rgd.vs }).addAttribute({ uv: rgd.uvs }).setIndices(rgd.ivs);if (normalEnabled) {geometry.addAttribute({ normal: rgd.nvs });}return geometry;}private initScene(): void {const rc = this.mRscene;const geometry = this.createGeom(this.geomData.createSphere(50), true);const shdSrc = {vertShaderSrc: { code: vertWGSL, uuid: "vertShdCode" },fragShaderSrc: { code: fragWGSL, uuid: "fragShdCode" }};let tot = 5;const size = new Vector3(150, 150, 150);const pos = new Vector3().copyFrom(size).scaleBy(-0.5 * (tot - 1));let pv = new Vector3();for (let i = 0; i < tot; ++i) {for (let j = 0; j < tot; ++j) {// params[0]: ao, params[1]: roughness, params[2]: metalliclet params = [1.5, (i / tot) * 0.95 + 0.05, (j / tot) * 0.95 + 0.05];let material = this.createMaterial(shdSrc, new Color4(0.5, 0.0, 0.0), params);let entity = new Entity3D();entity.materials = [material];entity.geometry = geometry;pv.setXYZ(i * size.x, j * size.y, size.z).addBy(pos);entity.transform.setPosition(pv);rc.addEntity(entity);}}}run(): void {this.mRscene.run();}
}

这篇关于轻量封装WebGPU渲染系统示例<11>- WebGPU简单PBR效果(源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/330587

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直