ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

vgpu/scene完整指南:用自有着色器构建3D场景——变换层级、实例化与相机控制

vgpu/scene完整指南:用自有着色器构建3D场景——变换层级、实例化与相机控制 vgpu/scene完整指南用自有着色器构建3D场景——变换层级、实例化与相机控制【免费下载链接】vgpuModular cross-runtime WebGPU library for shaders, 3D scenes, GPU tensors, neural networks, and math viz项目地址: https://gitcode.com/gh_mirrors/vgpu/vgpuvgpu/scene 是开源 WebGPU 图形库 vgpu 中的 3D 场景工具集变换层级、父子节点、实例化渲染和相机控制全部在 CPU 端完成而着色器、光照和渲染循环完全由你自己掌控。本文将带你用最小代码搭建一个由自有 WGSL 着色器驱动的完整 3D 场景。 vgpu/scene 能做什么三个模块的清晰分工vgpu/scene 不是一套渲染器而是一个场景计算层——它提供矩阵运算、层级求值、实例集合和相机状态但不注入任何着色器代码、不预留任何绑定组。你的 WGSL 决定一切vgpu/scene 只负责把数据送到你声明的位置。模块提供什么需要 GPUvgpu/scene几何配方box、sphere等、变换数学、group节点、实例集合、相机函数否纯 CPUvgpu/scene/gpuinstanceGeometry——把实例集合作为顶点流发布给 GPU是vgpu/wgsl-std/sceneinstanceWorldMatrix、transformNormal等纯 WGSL 辅助函数着色器端整个数据流只有一条单向链路每一步都是你主动调用的显式函数局部变换 ──► 世界矩阵 ──► 实例记录 ──► GPU 实例流 ──► 你的 draw 官方完整指南见 docs/topics/scene-composition.docs.md配合 docs/topics/scene-math.docs.md 理解外部矩阵如何接入。 构建变换层级父子节点 vs 你自己的数组用group()描述几个联动的零件当你只有少量需要联动旋转的部件比如底座→手臂→夹爪三段机械臂group()是最简单的选择。它创建一个SceneNode一个带父子和子节点的变换没有几何、没有材质const claw group({ label: claw, position: [0, 1.6, 0] }); const arm group({ label: arm, position: [0, 0.5, 0], children: [claw] }); const base group({ label: base, position: [0, 0.25, 0], children: [arm] }); base.set({ rotation: [0, time * 0.3, 0] }); // 只改底座 claw.worldPosition; // 自动得到 base * arm * claw 的世界坐标节点是惰性求值的set()只把该节点及后代标记为脏读取worldMatrix时才重新计算变化部分。旋转用四元数或欧拉角均可坐标系是右手系、Y 向上。用扁平数组求值大型层级ECS / 物理引擎如果层级数据已经存在你的 ECS 或物理引擎里不必镜像成节点。hierarchyOrder一次性编译拓扑evaluateHierarchy从局部矩阵算出全部世界矩阵const parents new Int32Array([-1, 0, 1]); // base 是根arm 的父是 baseclaw 的父是 arm const locals new Float32Array(3 * 16); // 每行一个局部矩阵 const worlds new Float32Array(3 * 16); // 输出世界矩阵 const order hierarchyOrder(parents); evaluateHierarchy({ order, parents, locals, worlds, changed });配合changed脏标记每帧只重算变化的行及其后代——这是官方 examples/by-example-s06-scene/src/composition.ts 中三条求值路径nodes / hierarchy / final-worlds之一。变换数学函数composeMatrix、multiplyMatrices、invertAffine的实现在 packages/vgpu-api/src/scene/transforms.ts节点在 packages/vgpu-api/src/scene/nodes.ts。 一次绘制调用画出成千上万个物体实例化渲染声明一个紧凑的实例集合instances()创建固定容量的 CPU 实例集合每条记录 一个 64 字节世界矩阵 你声明的自定义属性颜色、尺寸、拾取 ID 等。它没有几何、没有材质、没有 GPU 资源const boxes instances({ capacity: 2003, attributes: { size: float32x3, tint: { format: float32x4, default: [1, 1, 1, 1] }, }, }); boxes.add({ size: [0.4, 0.4, 0.4], tint: [0.6, 0.45, 0.3, 1] }); // 返回稳定句柄 InstanceId世界矩阵有三种写入方式按需选择方式调用适用场景直接写入setWorld(id, world)单次放置、偶尔移动批量写入setWorlds(ids, worlds)物理引擎每帧输出一大批矩阵绑定来源bindWorld(id, () node.worldMatrix) 每帧syncWorlds()让实例自动跟随某个节点发布到 GPU一座桥接instanceGeometry来自vgpu/scene/gpu实现在 packages/vgpu-api/src/scene/instance-geometry.ts把基础网格和实例流合成一个新的Geometry。实例流是stepMode: instance的顶点缓冲每条记录按顺序携带world0..world3世界矩阵四列和自定义属性在你的着色器里按名字声明location(3) world0: vec4f, location(4) world1: vec4f, location(5) world2: vec4f, location(6) world3: vec4f, location(7) size: vec3f, // 实例属性 size: float32x3 location(8) tint: vec4f, // 实例属性 tint: float32x4vgpu/wgsl-std/scene提供了每个实例化着色器都要写的数学见 packages/wgsl-std/src/scene/import { instanceWorldMatrix, transformPosition, transformNormal } from vgpu/wgsl-std/scene; let world instanceWorldMatrix(input.world0, input.world1, input.world2, input.world3); out.clip camera.viewProjection * vec4f(transformPosition(model, input.position), 1.0); out.normal transformNormal(model, input.normal); // 正确处理非均匀缩放的法线每帧先bridge.publish()上传变化并拿到实例数量再传给绘制调用pass.draw(boxDraw, { instances: count })。一个基础网格 一次绘制调用即可渲染整个粒子矩阵——这正是 instanced-rendering 示例的效果⚠️ 一个易踩的坑所有使用该 bridge 的着色器都必须声明全部实例输入world0..world3 你的每个自定义属性即使某个 pass 用不到它否则管线创建时就会抛出VGPU-MESH-ATTRIBUTE-UNMATCHED。 相机控制轨道、平移、推拉与平滑跟随相机函数操作的是你自己分配并持有的普通对象——不监听 DOM、不调度帧。核心是一个OrbitRig轨道装置围绕支点target pan旋转函数作用orbit(rig, deltaYaw, deltaPitch)水平/俯仰旋转俯仰自动限位pan(rig, right, up)沿相机的右/上轴平移dolly(rig, factor)缩放距离factor 1 拉远zoom(lens, factor)改变镜头 FOV不移动相机smoothRig(current, goal, dt, { timeConstant })指数平滑产生惯性感推荐模式是双 rig 平滑输入只写入goal渲染用smoothRig让current逐帧逼近goal得到带阻尼的运镜const goal orbitRig({ yaw: 0.6, pitch: 0.35, distance: 9 }); const current orbitRig(goal); orbit(goal, input.yaw, input.pitch); // 1. 输入 → goal smoothRig(current, goal, dt, { timeConstant: 0.15 }); // 2. current 平滑逼近 perspective(lens, aspect, projection); // 3. 投影矩阵 viewMatrices(rigPose(current, pose), projection, matrices); // 4. 视图 视图投影 boxDraw.set({ camera: { viewProjection: matrices.viewProjection } }); // 5. 按绑定名连接着色器最后一步是关键相机矩阵通过set()以WGSL 绑定名而不是 group/binding 编号传给着色器着色器里声明group(1) binding(0) varuniform camera: CameraData;即可。注意set()在调用时就打包数据——每帧viewMatrices之后都要重新set()一次。指针输入留在你的应用里把movementX/Y换算成弧度增量累加每 tick 应用一次。worldPerPixel(distance, lens, heightPixels)返回支点上一个像素对应多少世界单位让平移跟手。相机源码在 packages/vgpu-api/src/scene/camera-state.ts。 串起来一帧的数据流把上面三块拼起来每帧的固定顺序是输入 →goalrigorbit / pan / dolly 后清零更新局部变换group().set()或你的局部矩阵数组求解世界矩阵节点惰性读取或evaluateHierarchy把世界矩阵写入集合syncWorlds/setWorlds让goal.target跟随目标物体如夹爪的worldPositionsmoothRig→perspective→viewMatricesdraw.set({ camera: { viewProjection } })bridge.publish()拿到实例数编码 passpass.draw(draw, { instances: count })可运行的完整示例在 examples/by-example-s06-scene/composition.ts 演示了 group、外部层级、直接世界矩阵三条路径渲染同一场景配套着色器 composition.wgsl 展示了世界矩阵 自定义属性tint、pickingId的完整顶点入口声明。批量绘制同一网格的大规模效果可参考 apps/docs/examples/batch-rendering/。 官方文档与源码索引资料路径场景组合完整指南docs/topics/scene-composition.docs.md场景数学外部矩阵接入docs/topics/scene-math.docs.md从旧版vgpu/scene迁移docs/topics/scene-migration.docs.md变换数学源码packages/vgpu-api/src/scene/transforms.ts节点与层级源码packages/vgpu-api/src/scene/WGSL 场景辅助函数packages/wgsl-std/src/scene/可运行示例examples/by-example-s06-scene/AI 技能场景指引skills/vgpu/scene.md现在你手里已经有了全部零件用group或自己的数组搭建层级用instancesinstanceGeometry一次绘制海量物体用OrbitRig加平滑写出手感出色的相机——着色器、光照、渲染循环始终是你的。【免费下载链接】vgpuModular cross-runtime WebGPU library for shaders, 3D scenes, GPU tensors, neural networks, and math viz项目地址: https://gitcode.com/gh_mirrors/vgpu/vgpu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表