当前位置: 首页 > news >正文

WebAssembly与WebGPU:游戏开发的新时代

文章目录

      • WebAssembly简介
      • WebGPU简介
      • Wasm + WebGPU 在游戏开发中的优势
      • 创建一个简单的WebAssembly模块
      • 使用WebGPU绘制一个三角形
      • WebAssembly 的高级特性
        • 内存管理
        • 异步加载与多线程
      • WebGPU 的高级特性
        • 着色器编程
        • 计算着色器
      • 实战案例:创建一个简单的 2D 游戏
        • 游戏逻辑设计
        • 结合 WebAssembly

WebAssembly简介

  • 定义: WebAssembly是一种二进制指令格式,旨在为高性能应用程序提供一种可移植的目标平台。
  • 特点:
    • 小而快加载
    • 运行速度快
    • 支持多种编程语言编译
  • 用途: 主要用于加速网页应用性能,特别是在计算密集型任务上。

WebGPU简介

  • 定义: WebGPU API 是一个用于访问现代图形和计算硬件的新 JavaScript API。
  • 特点:
    • 基于现代图形API (如DirectX 12, Metal)
    • 提供低级别访问GPU的能力
    • 支持并行计算
  • 用途: 适用于复杂3D渲染、物理模拟等高性能需求场景。

Wasm + WebGPU 在游戏开发中的优势

  • 高性能: 利用Wasm的高效执行环境结合WebGPU对GPU的直接控制,可以实现接近原生应用的性能表现。
  • 跨平台: 由于Wasm本身的设计就是跨平台的,加上WebGPU也支持多种硬件后端,使得游戏能够更容易地部署到不同设备上。
  • 易维护与更新: 基于Web技术栈,开发者可以利用现有的工具链进行开发、调试及维护。

创建一个简单的WebAssembly模块

// 定义Wasm模块接口
const importObject = {env: {memoryBase: 0,tableBase: 0,memory: new WebAssembly.Memory({initial: 1}),table: new WebAssembly.Table({initial: 0, element: 'anyfunc'}),}
};// 加载Wasm模块
fetch('example.wasm').then(response => response.arrayBuffer()).then(bytes => WebAssembly.instantiate(bytes, importObject)).then(results => {const instance = results.instance;// 调用Wasm模块中的函数instance.exports.add(1, 2); // 假设该函数接收两个参数并返回它们的和});

使用WebGPU绘制一个三角形

// 获取WebGPU设备
navigator.gpu.requestAdapter().then(adapter => {return adapter.requestDevice();
}).then(device => {// 创建渲染管线const pipeline = device.createRenderPipeline({layout: device.createPipelineLayout({ bindGroupLayouts: [] }),vertexStage: {module: device.createShaderModule({code: `[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {var positions : array<vec2<f32>, 3> = array<vec2<f32>, 3>(vec2<f32>(-0.5, -0.5),vec2<f32>(0.5, -0.5),vec2<f32>(0.0, 0.5));var position = positions[0u]; // 简化起见,这里只取第一个顶点位置return vec4<f32>(position, 0.0, 1.0);}`,}),entryPoint: 'main',},primitiveTopology: 'triangle-list',colorStates: [{ format: 'bgra8unorm' }],});// 创建帧缓冲区const swapChain = device.createSwapChain(canvas, {usage: GPUTextureUsage.RENDER_ATTACHMENT,format: 'bgra8unorm',});// 渲染循环function render() {const context = device.getContext();const commandEncoder = device.createCommandEncoder();const textureView = swapChain.getCurrentTexture().createView();const renderPassDescriptor = {colorAttachments: [{attachment: textureView,loadValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 },}],};const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);passEncoder.setPipeline(pipeline);passEncoder.draw(3, 1, 0, 0);passEncoder.endPass();device.queue.submit([commandEncoder.finish()]);requestAnimationFrame(render);}requestAnimationFrame(render);
});

WebAssembly 的高级特性

内存管理
  • 内存布局: WebAssembly 使用线性内存布局,可以通过 memory 对象进行访问。
  • 内存操作: 可以通过 get 和 set 方法读写内存。
  • 内存增长: 可以动态增加内存大小。
const memory = new WebAssembly.Memory({ initial: 1, maximum: 10 });
console.log(memory.buffer.byteLength); // 输出 65536 (1 MB)// 扩展内存
memory.grow(1);
console.log(memory.buffer.byteLength); // 输出 131072 (2 MB)
异步加载与多线程
  • 异步加载: 可以通过 fetch 或其他异步方法加载 Wasm 模块。
  • 多线程: 使用 WebAssembly.Threading API 支持多线程操作。
// 异步加载 Wasm 模块
fetch('example.wasm').then(response => response.arrayBuffer()).then(bytes => WebAssembly.compileAsync(bytes)).then(module => {WebAssembly.instantiate(module, importObject).then(results => {const instance = results.instance;// 调用 Wasm 函数instance.exports.add(1, 2);});});// 多线程支持
if ('workerGlobalScope' in self) {self.importScripts('wasm_worker.js');const worker = new Worker('wasm_worker.js');worker.postMessage({ type: 'run', data: [1, 2] });
}

WebGPU 的高级特性

着色器编程
  • 顶点着色器: 处理顶点数据。
  • 片段着色器: 处理像素颜色。
[[block]]
struct VertexInput {@builtin(position) pos: vec4<f32>,
};[[block]]
struct VertexOutput {@builtin(position) pos: vec4<f32>,
};[[stage(vertex)]]
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {var input: VertexInput = VertexInput(pos: vec4<f32>(0.0, 0.0, 0.0, 1.0));var output: VertexOutput = VertexOutput(pos: input.pos);return output;
}[[stage(fragment)]]
fn fs_main() -> @location(0) vec4<f32> {return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
计算着色器

计算着色器: 执行并行计算任务。

[[block]]
struct ComputeData {result: array<i32, 1>,
};[[group(0), binding(0)]]
var<storage, read_write> data: array<i32, 1>;[[stage(compute), workgroup_size(1)]]
fn cs_main([[builtin(global_invocation_id)]] global_id: vec3<u32>) {data[0] = global_id.x * global_id.y * global_id.z;
}

实战案例:创建一个简单的 2D 游戏

游戏逻辑设计
  • 状态管理: 使用对象或类来管理游戏状态。
  • 事件处理: 监听键盘和鼠标事件。
class Game {constructor(canvas) {this.canvas = canvas;this.context = canvas.getContext('2d');this.width = canvas.width;this.height = canvas.height;this.player = { x: 100, y: 100 };this.enemies = [];this.init();}init() {this.enemies.push({ x: 200, y: 200 });this.enemies.push({ x: 300, y: 300 });window.addEventListener('keydown', event => {if (event.key === 'ArrowUp') {this.player.y -= 10;} else if (event.key === 'ArrowDown') {this.player.y += 10;} else if (event.key === 'ArrowLeft') {this.player.x -= 10;} else if (event.key === 'ArrowRight') {this.player.x += 10;}});this.animate();}animate() {requestAnimationFrame(() => this.animate());this.update();this.render();}update() {// 更新敌人位置for (let enemy of this.enemies) {enemy.x += Math.random() * 10 - 5;enemy.y += Math.random() * 10 - 5;}}render() {this.context.clearRect(0, 0, this.width, this.height);this.context.fillStyle = 'blue';this.context.fillRect(this.player.x, this.player.y, 20, 20);this.context.fillStyle = 'red';for (let enemy of this.enemies) {this.context.fillRect(enemy.x, enemy.y, 20, 20);}}
}const canvas = document.getElementById('gameCanvas');
const game = new Game(canvas);
结合 WebAssembly
  • 加载 Wasm 模块: 在游戏初始化时加载 Wasm 模块。
  • 调用 Wasm 函数: 在游戏更新和渲染过程中调用 Wasm 函数。
class Game {constructor(canvas) {this.canvas = canvas;this.context = canvas.getContext('2d');this.width = canvas.width;this.height = canvas.height;this.player = { x: 100, y: 100 };this.enemies = [];this.init();}async init() {const importObject = {env: {memoryBase: 0,tableBase: 0,memory: new WebAssembly.Memory({ initial: 1 }),table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' }),}};const response = await fetch('game_wasm.wasm');const bytes = await response.arrayBuffer();const { instance } = await WebAssembly.instantiate(bytes, importObject);this.wasm = instance.exports;this.enemies.push({ x: 200, y: 200 });this.enemies.push({ x: 300, y: 300 });window.addEventListener('keydown', event => {if (event.key === 'ArrowUp') {this.player.y -= 10;} else if (event.key === 'ArrowDown') {this.player.y += 10;} else if (event.key === 'ArrowLeft') {this.player.x -= 10;} else if (event.key === 'ArrowRight') {this.player.x += 10;}});this.animate();}animate() {requestAnimationFrame(() => this.animate());this.update();this.render();}update() {// 更新敌人位置for (let enemy of this.enemies) {enemy.x += this.wasm.randomMove(10);enemy.y += this.wasm.randomMove(10);}}render() {this.context.clearRect(0, 0, this.width, this.height);this.context.fillStyle = 'blue';this.context.fillRect(this.player.x, this.player.y, 20, 20);this.context.fillStyle = 'red';for (let enemy of this.enemies) {this.context.fillRect(enemy.x, enemy.y, 20, 20);}}
}const canvas = document.getElementById('gameCanvas');
const game = new Game(canvas);

相关文章:

  • 代码随想录训练营第45天|编辑距离
  • 如何构建鲁棒高性能 Prompt 的方法?
  • IIS HTTPS 网页可能暂时无法连接,或者它已永久性地移动到了新网址 ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY
  • docker简单熟悉
  • 技术分享|一文读懂三维建模技术
  • 18年408数据结构
  • Python Web架构:微服务与服务网格的实践
  • Subdominator:一款针对漏洞奖励计划的子域名安全枚举工具
  • SD2.0 Specification之功能切换
  • 【Diffusion分割】FDiff-Fusion:基于模糊学习的去噪扩散融合网络
  • 群晖套娃:群晖+飞牛fnOS二合一,群晖nas安装飞牛fnOS系统实录(飞牛fnOS初体验,如何挂载网盘视频,轻松实现影视刮削)
  • gtk4学习
  • SPI驱动学习七(SPI_Slave_Mode驱动程序框架)
  • AI驱动的Java开发框架:Spring AI Alibaba实战部署教程
  • C++之STL—常用排序算法
  • 【译】理解JavaScript:new 关键字
  • Docker容器管理
  • gulp 教程
  • js递归,无限分级树形折叠菜单
  • python学习笔记-类对象的信息
  • Python学习之路13-记分
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • Webpack 4x 之路 ( 四 )
  • 编写高质量JavaScript代码之并发
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 推荐一个React的管理后台框架
  • 微信支付JSAPI,实测!终极方案
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • puppet连载22:define用法
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • # include “ “ 和 # include < >两者的区别
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (2)(2.10) LTM telemetry
  • (Java企业 / 公司项目)点赞业务系统设计-批量查询点赞状态(二)
  • (k8s)kubernetes 部署Promehteus学习之路
  • (MATLAB)第五章-矩阵运算
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (顺序)容器的好伴侣 --- 容器适配器
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .describe() python_Python-Win32com-Excel
  • .gitignore文件忽略的内容不生效问题解决
  • .JPG图片,各种压缩率下的文件尺寸
  • .NET Core WebAPI中封装Swagger配置
  • .net core 依赖注入的基本用发
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net Remoting常用部署结构
  • .NET 解决重复提交问题
  • .NET 通过系统影子账户实现权限维持
  • @private @protected @public