From b7e897e277a90c2de40f17a9d12fdf0c1b35a367 Mon Sep 17 00:00:00 2001 From: wuhaoyuan Date: Fri, 22 May 2026 15:55:22 +0800 Subject: [PATCH 1/3] docs: rewrite README in open-source community style - Add badges (npm version, license, WebGPU, TypeScript) - Add Features, Requirements, Installation, Quick Start sections - Add Development commands and Documentation table - Add Examples table and Contributing/License sections - Add language switcher linking to README.zh-CN.md --- README.md | 348 +++++++++++++++++++++++++----------------------------- 1 file changed, 159 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index c107451..70c82d9 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,191 @@ # GEngine.js -WebGPU Engine - -## install +

+ A modern 3D rendering engine built on WebGPU +

+ +

+ English | 中文 +

+ +

+ + npm version + + + license + + WebGPU required + TypeScript +

+ +--- + +## Features + +- 🎨 **Forward Rendering Pipeline** — shadow pass + color pass + post-process chain +- 💡 **4 Light Types** — Ambient, Directional, Point, Spot, all with shadow support +- 🌊 **Cascaded Shadow Maps** — high-quality directional light shadows over large scenes +- 🔮 **3 Built-in Materials** — Blinn-Phong, PBR (with IBL), and fully custom ShaderMaterial +- 🧊 **Geometry Library** — Box, Plane, Sphere, TorusKnot, Point cloud, SkyBox +- 🚀 **Instance Rendering** — `InstanceMesh` for large numbers of identical objects +- ✨ **Bloom Post-Effect** — threshold-based bloom with multi-level blur +- 📦 **GLTF Loader** — meshes, materials, textures, skeletal animation +- ✂️ **Frustum Culling** — BoundingSphere / BoundingBox based culling +- ⚡ **Compute Shaders** — WebGPU compute pipeline support +- 🔧 **WGSL Preprocessor** — `#ifdef` / `#if` conditional shader compilation + +## Requirements + +| Requirement | Version | +|-------------|---------| +| Browser | Chrome ≥ 113 / Edge ≥ 113 | +| Node.js | ≥ 16 (for building) | + +> WebGPU is enabled by default in Chrome 113+ and Edge 113+. Firefox and Safari require experimental flags. + +## Installation ```shell -$ yarn add @gengine-js/gengine +npm install @gengine-js/gengine +# or +yarn add @gengine-js/gengine ``` -## develop +## Quick Start -```shell -# install -$ yarn +```html + + + +
+ + + +``` -# dev -$ yarn dev +## Development -# build -$ yarn build -``` +```shell +# Clone +git clone https://github.com/hpugis/GEngine.git +cd GEngine -## Usage +# Install dependencies +yarn install -```html - -``` +## Native WebGPU Usage -## Native +For advanced use cases requiring direct WebGPU access: ```html ``` -## feature - -- [✔] Camera - - [✔] PerspectiveCamera - - [✔] OrthographicCamera -- [✔] Math -- [✔] control - - [✔] OrbitControl -- [✔] Light - - [✔] AmbientLight - - [✔] DirectionalLight - - [✔] PointLight - - [✔] SpotLight -- [✔] Loader - - [✔] GLTFLoader - - [✔] CubeTextureLoader -- [✔] Materials - - [✔] ColorMaterial - - [✔] Material - - [✔] PbrMaterial(IBL/Light Render) - - [✔] BlinPhongMaterial - - [✔] ShaderMaterial - - [✔] SkyBoxMaterial -- [✔] Post-Effect - - [✔] BloomPostEffect -- [✔] Shadow - - [✔] DirectionalLightShadow - - [✔] PointLightShadow - - [✔] SpotLightShadow - -## Next - -1. Complete animation -2. Complete core glTF 2.0 -3. Text and Sprite -4. Pick From 983167bd3d350a7c969180e20d180840b346e0c6 Mon Sep 17 00:00:00 2001 From: wuhaoyuan Date: Fri, 22 May 2026 15:55:32 +0800 Subject: [PATCH 2/3] docs: add Chinese README (README.zh-CN.md) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Full Chinese translation of README.md - Add bidirectional language switcher (English | 中文) --- README.zh-CN.md | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 README.zh-CN.md diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..c6e2d79 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,218 @@ +# GEngine.js + +

+ 基于 WebGPU 的现代 3D 渲染引擎 +

+ +

+ + npm 版本 + + + 开源协议 + + 需要 WebGPU + TypeScript +

+ +

+ English | 中文 +

+ +--- + +## 功能特性 + +- 🎨 **前向渲染管线** — 阴影通道 + 颜色通道 + 后处理链 +- 💡 **四种光源类型** — 环境光、方向光、点光源、聚光灯,均支持阴影 +- 🌊 **级联阴影贴图** — 大场景下高质量方向光阴影(CSM) +- 🔮 **三种内置材质** — Blinn-Phong、PBR(含 IBL)、完全自定义 ShaderMaterial +- 🧊 **几何体库** — Box、Plane、Sphere、TorusKnot、点云、天空盒 +- 🚀 **实例渲染** — `InstanceMesh` 支持大量同形状物体的高效绘制 +- ✨ **Bloom 后处理** — 基于亮度阈值的多级高斯模糊泛光效果 +- 📦 **GLTF 加载器** — 网格、材质、贴图、骨骼动画 +- ✂️ **视锥剔除** — 基于 BoundingSphere / BoundingBox 的可见性判断 +- ⚡ **计算着色器** — WebGPU Compute Pipeline 支持 +- 🔧 **WGSL 预处理器** — `#ifdef` / `#if` 条件编译 + +## 环境要求 + +| 需求 | 版本 | +|------|------| +| 浏览器 | Chrome ≥ 113 / Edge ≥ 113 | +| Node.js | ≥ 16(仅构建时需要) | + +> WebGPU 在 Chrome 113+ 和 Edge 113+ 中已默认启用。Firefox 和 Safari 仍需手动开启实验性标志。 + +## 安装 + +```shell +npm install @gengine-js/gengine +# 或 +yarn add @gengine-js/gengine +``` + +## 快速开始 + +```html + + + +
+ + + +``` + +## 本地开发 + +```shell +# 克隆仓库 +git clone https://github.com/hpugis/GEngine.git +cd GEngine + +# 安装依赖 +yarn install + +# 启动开发模式(watch) +yarn dev + +# 生产构建 +yarn build + +# 代码检查 +yarn lint +``` + +用任意静态文件服务器预览示例: + +```shell +npx serve . +# 然后访问 http://localhost:3000/example/mesh/mesh.html +``` + +## 文档 + +| 文档 | 说明 | +|------|------| +| [架构设计](./ai-docs/ARCHITECTURE.md) | 渲染管线、数据流、类继承图 | +| [API 参考](./ai-docs/API.md) | 完整公共 API — Scene、Mesh、Material、Light、Camera、Math… | +| [开发指南](./ai-docs/DEVELOPMENT.md) | 环境搭建、添加新功能、调试技巧 | +| [构建与发布](./ai-docs/DEPLOYMENT.md) | 构建产物、npm 发布流程 | +| [贡献指南](./ai-docs/CONTRIBUTING.md) | 分支规范、提交规范、PR 检查清单 | + +## 示例 + +浏览 [`example/`](./example/) 目录查看可运行的演示: + +| 分类 | 示例 | +|------|------| +| 几何体 | Box、Plane、Sphere、TorusKnot | +| 材质 | Blinn-Phong、PBR、ShaderMaterial | +| 光源 | 环境光、方向光、点光源、聚光灯 | +| 阴影 | 方向光、级联、点光源、聚光灯阴影 | +| 网格 | 实例渲染、点云、天空盒、精灵 | +| 加载器 | GLTF 模型、GLTF 骨骼动画 | +| 后处理 | Bloom 泛光 | + +## 参与贡献 + +欢迎贡献代码!请在提交 Pull Request 前阅读[贡献指南](./ai-docs/CONTRIBUTING.md)。 + +1. Fork 本仓库 +2. 创建分支:`git checkout -b feat/your-feature` +3. 使用规范提交:`yarn commit` +4. Push 并发起 Pull Request + +## 开源协议 + +[MIT](./LICENSE) + +--- + +## 底层 WebGPU 用法 + +如需直接操作 WebGPU 原语: + +```html + +``` From 2e1bb577e130dc9c899535edb8a17f9ad4c915db Mon Sep 17 00:00:00 2001 From: wuhaoyuan Date: Fri, 22 May 2026 15:55:44 +0800 Subject: [PATCH 3/3] docs: add comprehensive developer documentation in ai-docs/ - README.md: project overview, quick start, core concepts - ARCHITECTURE.md: system design with Mermaid diagrams - API.md: full public API reference - DEVELOPMENT.md: local setup, build flow, contribution guide - DEPLOYMENT.md: build output and npm publish workflow - CONTRIBUTING.md: PR conventions and code standards --- ai-docs/API.md | 723 ++++++++++++++++++++++++++++++++++++++++ ai-docs/ARCHITECTURE.md | 575 ++++++++++++++++++++++++++++++++ ai-docs/CONTRIBUTING.md | 138 ++++++++ ai-docs/DEPLOYMENT.md | 118 +++++++ ai-docs/DEVELOPMENT.md | 378 +++++++++++++++++++++ ai-docs/README.md | 143 ++++++++ 6 files changed, 2075 insertions(+) create mode 100644 ai-docs/API.md create mode 100644 ai-docs/ARCHITECTURE.md create mode 100644 ai-docs/CONTRIBUTING.md create mode 100644 ai-docs/DEPLOYMENT.md create mode 100644 ai-docs/DEVELOPMENT.md create mode 100644 ai-docs/README.md diff --git a/ai-docs/API.md b/ai-docs/API.md new file mode 100644 index 0000000..256e861 --- /dev/null +++ b/ai-docs/API.md @@ -0,0 +1,723 @@ +# GEngine — 完整 API 参考 + +## 目录 + +- [Scene(场景)](#scene) +- [Camera(相机)](#camera) +- [Mesh 与场景对象](#mesh-与场景对象) +- [Geometry(几何体)](#geometry) +- [Material(材质)](#material) +- [Light(光源)](#light) +- [Math(数学库)](#math) +- [Loader(加载器)](#loader) +- [Control(控制器)](#control) +- [PostEffect(后处理)](#posteffect) +- [渲染基础设施](#渲染基础设施) +- [常量与枚举](#常量与枚举) + +--- + +## Scene + +**文件**:[src/Scene.ts](../src/Scene.ts) + +```typescript +class Scene extends EventDispatcher +``` + +### 构造参数 + +```typescript +new Scene(options: { + container: string | HTMLElement; // canvas 容器 ID 或元素 +}) +``` + +### 方法 + +| 方法 | 说明 | +|------|------| +| `add(object: RenderObject)` | 添加 Mesh / Light / Node 到场景 | +| `remove(object: RenderObject)` | 从场景移除对象 | +| `setCamera(camera: Camera)` | 设置主渲染相机 | +| `render(node?, camera?)` | 执行一帧渲染(通常在 `requestAnimationFrame` 中调用) | +| `resize(width, height)` | 响应容器尺寸变化 | +| `addPostEffect(effect: PostEffect)` | 添加后处理效果 | +| `removePostEffect(effect: PostEffect)` | 移除后处理效果 | +| `destroy()` | 释放所有 GPU 资源 | + +### 属性 + +| 属性 | 类型 | 说明 | +|------|------|------| +| `camera` | `PerspectiveCamera` | 当前主相机 | +| `context` | `Context` | WebGPU 上下文 | +| `frameState` | `FrameState` | 当前帧状态 | +| `background` | `Color \| Texture` | 背景颜色或天空盒纹理 | + +--- + +## Camera + +### PerspectiveCamera + +**文件**:[src/camera/PerspectiveCamera.ts](../src/camera/PerspectiveCamera.ts) + +```typescript +new PerspectiveCamera( + fov: number, // 垂直视野角(度),如 60 + aspect: number, // 宽高比 width/height + near: number, // 近裁剪面 + far: number // 远裁剪面 +) +``` + +| 属性 | 类型 | 说明 | +|------|------|------| +| `position` | `Vector3` | 相机位置 | +| `fov` | `number` | 视野角(修改后需调用 `updateProjectionMatrix()`) | +| `aspect` | `number` | 宽高比 | +| `near` / `far` | `number` | 近 / 远裁剪面 | +| `viewMatrix` | `Matrix4` | 视图矩阵(只读) | +| `projectionMatrix` | `Matrix4` | 投影矩阵(只读) | + +| 方法 | 说明 | +|------|------| +| `lookAt(x, y, z)` | 朝向目标点 | +| `updateProjectionMatrix()` | 更新投影矩阵(修改 fov/aspect 后调用) | + +### OrthographicCamera + +**文件**:[src/camera/OrthographicCamera.ts](../src/camera/OrthographicCamera.ts) + +```typescript +new OrthographicCamera( + left, right, top, bottom, near, far +) +``` + +--- + +## Mesh 与场景对象 + +### RenderObject(基类) + +**文件**:[src/core/RenderObject.ts](../src/core/RenderObject.ts) + +所有可放入场景的对象的基类。 + +| 属性 | 类型 | 说明 | +|------|------|------| +| `position` | `Vector3` | 本地坐标位置 | +| `scale` | `Vector3` | 缩放 | +| `quaternion` | `Quaternion` | 旋转四元数 | +| `modelMatrix` | `Matrix4` | 世界变换矩阵 | +| `castShadow` | `boolean` | 是否投射阴影 | +| `receiveShadow` | `boolean` | 是否接收阴影 | +| `visible` | `boolean` | 是否可见 | +| `parent` | `RenderObject` | 父节点 | + +| 方法 | 说明 | +|------|------| +| `lookAt(x, y, z)` | 朝向目标 | +| `rotateX/Y/Z(angle)` | 绕轴旋转(弧度) | +| `updateMatrix(parentMatrix?)` | 更新变换矩阵 | + +--- + +### Mesh + +**文件**:[src/mesh/Mesh.ts](../src/mesh/Mesh.ts) + +```typescript +new Mesh(geometry: Geometry, material: Material) +``` + +| 属性 | 类型 | 说明 | +|------|------|------| +| `geometry` | `Geometry` | 绑定的几何体 | +| `material` | `Material` | 绑定的材质 | +| `frustumCull` | `boolean` | 是否启用视锥剔除(默认 `true`) | +| `ready` | `boolean` | 材质和几何体是否均已准备好(只读) | + +--- + +### Node + +**文件**:[src/mesh/Node.ts](../src/mesh/Node.ts) + +场景层级容器,继承 `Mesh`。 + +```typescript +const parent = new Node(); +const child = new Mesh(geometry, material); +parent.add(child); +scene.add(parent); +``` + +| 方法 | 说明 | +|------|------| +| `add(child: RenderObject)` | 添加子节点 | +| `remove(child: RenderObject)` | 移除子节点 | + +--- + +### InstanceMesh + +**文件**:[src/mesh/InstanceMesh.ts](../src/mesh/InstanceMesh.ts) + +使用 GPU 实例渲染,一次 drawCall 渲染大量相同形状。 + +```typescript +const count = 1000; +const mesh = new InstanceMesh(geometry, material, count); + +// 设置每个实例的变换矩阵 +for (let i = 0; i < count; i++) { + const matrix = new Matrix4(); + matrix.compose(position, rotation, scale); + mesh.setMatrixAt(i, matrix); +} +scene.add(mesh); +``` + +--- + +### SkyBox + +**文件**:[src/mesh/SkyBox.ts](../src/mesh/SkyBox.ts) + +```typescript +const cubeTexture = await new CubeTextureLoader().loadCubeTexture([ + px, nx, py, ny, pz, nz // 6 张图片 URL +]); +const skybox = new SkyBox(cubeTexture); +scene.add(skybox); +``` + +--- + +### Sprite + +**文件**:[src/mesh/Sprite.ts](../src/mesh/Sprite.ts) + +始终朝向相机的 2D 图片精灵,常用于粒子或图标。 + +```typescript +const sprite = new Sprite(texture); +sprite.position.set(0, 10, 0); +scene.add(sprite); +``` + +--- + +### Points + +**文件**:[src/mesh/Points.ts](../src/mesh/Points.ts) + +```typescript +const geometry = new PointGeometry(positionsArray); +const points = new Points(geometry, material); +scene.add(points); +``` + +--- + +## Geometry + +### Geometry(基类) + +**文件**:[src/geometry/Geometry.ts](../src/geometry/Geometry.ts) + +| 属性 | 类型 | 说明 | +|------|------|------| +| `positions` | `number[]` | 顶点位置数组 | +| `normals` | `number[]` | 法线数组 | +| `uvs` | `number[]` | 纹理坐标 | +| `tangents` | `number[]` | 切线(法线贴图) | +| `indices` | `number[]` | 索引数组 | +| `boundingSphere` | `BoundingSphere` | 包围球(用于视锥剔除) | +| `boundingBox` | `BoundingBox` | AABB | + +| 方法 | 说明 | +|------|------| +| `setAttribute(attribute)` | 添加顶点属性 | +| `setIndice(indices)` | 设置索引数据 | +| `calculateTangents()` | 自动计算切线向量 | + +--- + +### 预置几何体 + +#### BoxGeometry +```typescript +new BoxGeometry( + width?: number, // 默认 1 + height?: number, // 默认 1 + depth?: number // 默认 1 +) +``` + +#### PlaneGeometry +```typescript +new PlaneGeometry( + width?: number, // 默认 1 + height?: number // 默认 1 +) +``` + +#### SphereGeometry +```typescript +new SphereGeometry( + radius?: number, // 默认 1 + widthSegments?: number, // 默认 32 + heightSegments?: number // 默认 16 +) +``` + +#### TorusKnotGeometry +```typescript +new TorusKnotGeometry( + radius?: number, // 默认 1 + tube?: number, // 默认 0.4 + tubularSegments?: number, // 默认 64 + radialSegments?: number, // 默认 8 + p?: number, // 默认 2 + q?: number // 默认 3 +) +``` + +#### PointGeometry +```typescript +new PointGeometry(positions: number[]) // 平铺的 XYZ 数组 +``` + +--- + +## Material + +### Material(基类) + +**文件**:[src/material/Material.ts](../src/material/Material.ts) + +| 属性 | 类型 | 说明 | +|------|------|------| +| `color` | `Color` | 基础颜色 | +| `baseTexture` | `Texture` | 基础贴图 | +| `baseSampler` | `Sampler` | 贴图采样器 | +| `transparent` | `boolean` | 是否为透明材质 | +| `opacity` | `number` | 透明度 0~1 | +| `light` | `boolean` | 是否参与光照计算 | +| `emissive` | `Color` | 自发光颜色 | +| `renderState` | `RenderState` | GPU 管线状态 | +| `shaderSource` | `ShaderSource` | 着色器源码 | +| `shaderData` | `ShaderData` | GPU Uniform / Texture 绑定 | + +--- + +### BlinnPhongMaterial + +**文件**:[src/material/BlinnPhongMaterial.ts](../src/material/BlinnPhongMaterial.ts) + +```typescript +const mat = new BlinnPhongMaterial(); +mat.color = new Color(1, 0.5, 0); // RGB 0~1 +mat.specular = new Color(1, 1, 1); +mat.shininess = 64; // 高光强度 +mat.normalTexture = normalTex; // 法线贴图(可选) +mat.light = true; // 默认 true +``` + +--- + +### PbrMaterial + +**文件**:[src/material/PbrMaterial.ts](../src/material/PbrMaterial.ts) + +```typescript +const mat = new PbrMaterial(); +mat.baseTexture = albedoTex; +mat.normalTexture = normalTex; +mat.roughness = 0.5; // 0=光滑 1=粗糙 +mat.metalness = 0.0; // 0=非金属 1=金属 +mat.aoTexture = aoTex; // 环境遮蔽 +mat.metalnessRoughnessTexture = mrTex; + +// IBL(图像照明) +mat.specularEnvTexture = specEnvTex; +``` + +--- + +### ShaderMaterial + +**文件**:[src/material/ShaderMaterial.ts](../src/material/ShaderMaterial.ts) + +```typescript +const mat = new ShaderMaterial({ + // 自定义 WGSL 着色器 + shaderId: "myShader", + vertexShader: `...wgsl...`, + fragmentShader: `...wgsl...`, + + // 自定义 Uniform + uniforms: { + time: { value: 0.0 }, + color: { value: new Color(1, 0, 0) } + } +}); + +// 每帧更新 +mat.setUniform("time", performance.now() / 1000); +``` + +--- + +## Light + +### AmbientLight + +**文件**:[src/light/AmbientLight.ts](../src/light/AmbientLight.ts) + +```typescript +new AmbientLight( + color: Vector3, // RGB 颜色 + intensity: number // 强度 +) +``` + +### DirectionalLight + +**文件**:[src/light/DirectionalLight.ts](../src/light/DirectionalLight.ts) + +```typescript +const light = new DirectionalLight( + new Vector3(1, 1, 1), // 颜色 + 1.0 // 强度 +); +light.position = new Vector3(100, 100, 0); +light.target = new Vector3(0, 0, 0); + +// 启用阴影 +light.shadow = new DirectionalLightShadow(); +// 或级联阴影 +light.shadow = new DirectionalLightCascadedShadow(); +``` + +### PointLight + +**文件**:[src/light/PointLight.ts](../src/light/PointLight.ts) + +```typescript +const light = new PointLight( + new Vector3(1, 1, 1), // 颜色 + 1.0, // 强度 + 60, // 衰减距离 + 1.0 // 衰减指数 +); +light.position = new Vector3(0, 30, 0); + +// 启用阴影(立方体贴图) +light.shadow = new PointLightShadow(); +``` + +### SpotLight + +**文件**:[src/light/SpotLight.ts](../src/light/SpotLight.ts) + +```typescript +const light = new SpotLight( + new Vector3(1, 1, 1), // 颜色 + 1.0, // 强度 + 100, // 距离 + 15, // 内锥角(度) + 1.0 // 衰减 +); +light.position = new Vector3(0, 50, 0); +light.target = new Vector3(0, 0, 0); +``` + +--- + +## Math + +### Vector3 + +```typescript +const v = new Vector3(x, y, z); + +// 静态工具 +Vector3.UNIT_X // (1, 0, 0) +Vector3.UNIT_Y // (0, 1, 0) +Vector3.UNIT_Z // (0, 0, 1) +Vector3.ZERO // (0, 0, 0) + +// 方法 +v.set(x, y, z) +v.add(other) +v.sub(other) +v.multiplyScalar(s) +v.normalize() +v.dot(other) +v.cross(other) +v.length() +v.distanceTo(other) +v.clone() +v.copy(other) +``` + +### Matrix4 + +```typescript +const m = new Matrix4(); + +m.compose(position, quaternion, scale) // TRS 合成 +m.decompose(position, quaternion, scale) +m.multiply(other) +m.invert() +m.transpose() +m.makeTranslation(x, y, z) +m.makeRotationFromQuaternion(q) +m.makeScale(x, y, z) +Matrix4.makePerspective(left, right, top, bottom, near, far) +Matrix4.makeOrthographic(left, right, top, bottom, near, far) +``` + +### Quaternion + +```typescript +const q = new Quaternion(); + +Quaternion.fromAxisAngle(axis: Vector3, angle: number) +Quaternion.fromRotationMatrix(m: Matrix4) +q.slerp(other, t) +q.multiply(other) +q.normalize() +``` + +### Color + +```typescript +const c = new Color(r, g, b); // 0~1 浮点 + +// 解析 hex +Color.fromHex("#ff8800") + +// 输出 +c.toHex() +c.toArray() // [r, g, b] +``` + +### Euler + +```typescript +const e = new Euler(x, y, z, order); +// order: "XYZ" | "YXZ" | "ZXY" 等 +``` + +--- + +## Loader + +### loadGLTF + +**文件**:[src/loader/GLTFLoader.ts](../src/loader/GLTFLoader.ts) + +```typescript +import { loadGLTF } from "@gengine-js/gengine"; + +const model = await loadGLTF("path/to/model.gltf"); +scene.add(model); + +// 访问子节点 +model.children.forEach(child => { + if (child instanceof Mesh) { + child.material.color = new Color(1, 0, 0); + } +}); +``` + +### CubeTextureLoader + +**文件**:[src/loader/CubeTextureLoader.ts](../src/loader/CubeTextureLoader.ts) + +```typescript +const loader = new CubeTextureLoader(); +const cubeTexture = await loader.loadCubeTexture([ + "px.jpg", "nx.jpg", // +X, -X + "py.jpg", "ny.jpg", // +Y, -Y + "pz.jpg", "nz.jpg" // +Z, -Z +]); +``` + +### loadTexture + +**文件**:[src/utils/utils.ts](../src/utils/utils.ts) + +```typescript +import { loadTexture } from "@gengine-js/gengine"; + +const texture = await loadTexture("path/to/image.png"); +material.baseTexture = texture; +``` + +--- + +## Control + +### OrbitControl + +**文件**:[src/control/OrbitControl.ts](../src/control/OrbitControl.ts) + +```typescript +const control = new OrbitControl( + camera: Camera, + domElement: HTMLElement +); + +// 约束 +control.minDistance = 5; +control.maxDistance = 500; +control.minPolarAngle = 0; // 0 = 正上方 +control.maxPolarAngle = Math.PI / 2; // 最低俯角 +control.minAzimuthAngle = -Infinity; +control.maxAzimuthAngle = Infinity; + +// 功能开关 +control.enableDamping = true; // 阻尼(惯性) +control.enableZoom = true; +control.enableRotate = true; +control.enablePan = true; + +// 速度 +control.rotateSpeed = 1.0; +control.zoomSpeed = 1.0; +control.panSpeed = 1.0; + +// 在动画循环中调用 +function animate() { + requestAnimationFrame(animate); + control.update(); // 必须每帧调用 + scene.render(); +} +``` + +--- + +## PostEffect + +### BloomPostEffect + +**文件**:[src/post-process/BloomPostEffect.ts](../src/post-process/BloomPostEffect.ts) + +```typescript +import { BloomPostEffect } from "@gengine-js/gengine"; + +const bloom = new BloomPostEffect(width, height); +bloom.strength = 1.5; // 强度 +bloom.radius = 0.4; // 扩散半径 +bloom.threshold = 0.85; // 亮度阈值(超过才发光) + +scene.addPostEffect(bloom); +``` + +--- + +## 渲染基础设施 + +这些类用于高级自定义场景,一般不需要直接操作。 + +### Context + +**文件**:[src/render/Context.ts](../src/render/Context.ts) + +WebGPU `GPUDevice` 和 Canvas 的初始化封装。通过 `scene.context` 访问。 + +### Buffer + +**文件**:[src/render/Buffer.ts](../src/render/Buffer.ts) + +```typescript +// 工厂方法 +Buffer.createVertexBuffer(label, device, data) +Buffer.createIndexBuffer(label, device, data) +Buffer.createUniformBuffer(label, device, byteSize) +Buffer.createStorageBuffer(label, device, byteSize) + +// 更新 +buffer.setSubData(offsetBytes, data) +``` + +### Texture + +**文件**:[src/render/Texture.ts](../src/render/Texture.ts) + +```typescript +const tex = new Texture(); +tex.data = imageData; // HTMLImageElement 或 ImageData +tex.generateMipmap = true; +tex.flipY = true; +tex.sampleType = "float"; // "float" | "depth" | "uint" +``` + +### RenderTarget + +**文件**:[src/render/RenderTarget.ts](../src/render/RenderTarget.ts) + +```typescript +const rt = new RenderTarget(width, height); +rt.getColorTexture(0) // 颜色附件纹理 +rt.getDepthTexture() // 深度附件纹理 +rt.setSize(w, h) // 响应 resize +``` + +### ShaderData + +**文件**:[src/render/ShaderData.ts](../src/render/ShaderData.ts) + +```typescript +const sd = new ShaderData(bindGroupLayoutDescriptor); + +sd.setUniformBuffer("model", buffer, binding); +sd.setTexture("baseTexture", texture, binding); +sd.setSampler("baseSampler", sampler, binding); +sd.setDefine("HAS_NORMAL", true); +sd.setDefine("USE_IBL", 1); + +// 在 passEncoder 中绑定 +sd.bind(device, passEncoder); +``` + +--- + +## 常量与枚举 + +**文件**:[src/core/WebGPUConstant.ts](../src/core/WebGPUConstant.ts) + +| 枚举 | 值(示例) | +|------|-----------| +| `TextureFormat` | `rgba8unorm`, `depth24plus`, `bc1-rgba-unorm` ... | +| `FilterMode` | `linear`, `nearest` | +| `AddressMode` | `repeat`, `clamp-to-edge`, `mirror-repeat` | +| `BlendFactor` | `one`, `zero`, `src-alpha`, `one-minus-src-alpha` ... | +| `CullMode` | `none`, `front`, `back` | +| `PrimitiveTopology` | `triangle-list`, `point-list`, `line-list` | +| `CompareFunction` | `less`, `less-equal`, `always`, `never` ... | +| `ShaderStage` | `VERTEX = 1`, `FRAGMENT = 2`, `COMPUTE = 4` | +| `BufferUsage` | `VERTEX`, `INDEX`, `UNIFORM`, `STORAGE`, `COPY_SRC` ... | + +```typescript +import { + TextureFormat, + FilterMode, + CullMode, + PrimitiveTopology +} from "@gengine-js/gengine"; + +// 示例:自定义渲染状态 +mesh.material.renderState.primitive = { + topology: PrimitiveTopology.TriangleList, + cullMode: CullMode.Back, + frontFace: "ccw" +}; +``` diff --git a/ai-docs/ARCHITECTURE.md b/ai-docs/ARCHITECTURE.md new file mode 100644 index 0000000..2eba9cc --- /dev/null +++ b/ai-docs/ARCHITECTURE.md @@ -0,0 +1,575 @@ +# GEngine — 系统架构 + +## 目录 + +1. [整体架构](#整体架构) +2. [目录结构](#目录结构) +3. [渲染管线](#渲染管线) +4. [数据流:从场景创建到画面输出](#数据流从场景创建到画面输出) +5. [类继承关系](#类继承关系) +6. [核心子系统详解](#核心子系统详解) + - [Scene 与 FrameState](#scene-与-framestate) + - [Material 系统](#material-系统) + - [Geometry 系统](#geometry-系统) + - [Mesh 系统](#mesh-系统) + - [Light 与 Shadow 系统](#light-与-shadow-系统) + - [Shader 系统](#shader-系统) + - [后处理系统](#后处理系统) + - [渲染基础设施](#渲染基础设施) + +--- + +## 整体架构 + +```mermaid +graph TD + User["用户代码"] -->|add / setCamera| Scene + Scene -->|update| MeshManger + Scene -->|update| LightManger + Scene -->|render| ForwardRenderLine + + ForwardRenderLine -->|1. 阴影通道| ShadowPass + ForwardRenderLine -->|2. 颜色通道| BasicPass + + BasicPass -->|绘制| DrawCommand + ShadowPass -->|深度绘制| DrawCommand + + DrawCommand --> WebGPU["WebGPU Device / Encoder"] + + Scene -->|后处理| PostEffectCollection + PostEffectCollection -->|Bloom 等| Canvas["屏幕"] +``` + +--- + +## 目录结构 + +``` +src/ +├── index.ts ← 公共 API 出口(70+ 导出) +├── Scene.ts ← 场景入口,驱动渲染循环 +├── wgsl.d.ts ← .wgsl 文件 TypeScript 声明 +│ +├── camera/ ← 相机系统 +│ ├── Camera.ts ← 抽象基类 +│ ├── PerspectiveCamera.ts ← 透视相机 +│ ├── OrthographicCamera.ts ← 正交相机 +│ └── PointLightShadowCamera.ts ← 点光阴影专用 +│ +├── compute/ ← WebGPU Compute 支持 +│ └── Compute.ts +│ +├── control/ +│ └── OrbitControl.ts ← 轨道相机控制器 +│ +├── core/ ← 引擎核心基础设施 +│ ├── FrameState.ts ← 每帧状态(渲染队列、灯光、视锥) +│ ├── RenderQueue.ts ← 不透明 / 透明 / 天空盒队列 +│ ├── DerivedCommands.ts ← DrawCommand 缓存工厂 +│ ├── LightManger.ts ← 灯光管理与阴影贴图数组 +│ ├── MeshManger.ts ← 场景 Mesh 管理 +│ ├── RenderObject.ts ← 所有场景实体的变换基类 +│ ├── ShaderDataFactory.ts ← ShaderData 创建工具 +│ ├── TextureCache.ts ← GPU 纹理缓存管理 +│ ├── BoundingBox.ts ← AABB 包围盒 +│ ├── BoundingSphere.ts ← 球形包围体 +│ ├── Frustum.ts ← 视锥体裁剪 +│ ├── CullingVolume.ts +│ └── WebGPUConstant.ts ← WebGPU 枚举常量 +│ +├── geometry/ ← 几何体 +│ ├── Geometry.ts ← 抽象基类 +│ ├── BoxGeometry.ts +│ ├── PlaneGeometry.ts +│ ├── SphereGeometry.ts +│ ├── TorusKnotGeometry.ts +│ ├── PointGeometry.ts +│ └── SkyBoxGeometry.ts +│ +├── light/ ← 光源 +│ ├── Light.ts ← 基类 +│ ├── AmbientLight.ts +│ ├── DirectionalLight.ts +│ ├── PointLight.ts +│ ├── SpotLight.ts +│ └── shadows/ ← 各光源的阴影实现 +│ +├── loader/ ← 资源加载 +│ ├── GLTFLoader.ts +│ ├── CubeTextureLoader.ts +│ └── gltf/ ← GLTF 解析子模块 +│ +├── material/ ← 材质系统 +│ ├── Material.ts ← 基类 +│ ├── BlinnPhongMaterial.ts +│ ├── PbrMaterial.ts +│ └── ShaderMaterial.ts +│ +├── math/ ← 数学库 +│ ├── Vector2/3/4.ts +│ ├── Matrix3/4.ts +│ ├── Quaternion.ts +│ ├── Euler.ts +│ ├── Color.ts +│ └── Spherical.ts +│ +├── mesh/ ← 可渲染对象 +│ ├── Mesh.ts ← 核心网格 +│ ├── Node.ts ← 层级容器 +│ ├── Instance.ts +│ ├── InstanceMesh.ts ← 实例渲染 +│ ├── SkyBox.ts +│ ├── Sprite.ts +│ ├── Points.ts +│ └── Axes.ts +│ +├── pass/ ← 渲染通道 +│ ├── BasicPass.ts ← 颜色渲染通道 +│ ├── ShadowPass.ts ← 阴影深度通道 +│ └── RenderPass.ts +│ +├── post-process/ ← 后处理 +│ ├── PostEffect.ts ← 基类 +│ ├── BloomPostEffect.ts +│ └── PostEffectCollection.ts +│ +├── render/ ← WebGPU 原语封装 +│ ├── Context.ts ← GPUDevice / Canvas 初始化 +│ ├── Buffer.ts ← GPU Buffer +│ ├── Texture.ts ← GPU Texture +│ ├── Sampler.ts +│ ├── BindGroup.ts +│ ├── DrawCommand.ts ← 单次绘制调用 +│ ├── RenderState.ts ← 管线状态 +│ ├── RenderTarget.ts ← 离屏渲染目标 +│ ├── Pipeline.ts ← Pipeline 缓存 +│ └── ShaderData.ts ← BindGroup 管理 +│ +├── renderpipeline/ ← 渲染管线策略 +│ └── ForwardRenderLine.ts ← 前向渲染实现 +│ +├── shader/ ← 着色器系统 +│ ├── ShaderSource.ts ← 着色器编译与缓存 +│ ├── Shaders.ts ← 预置着色器注册表 +│ ├── WGSLParseDefines.ts ← #ifdef 预处理器 +│ └── shaderChunk/ ← 可复用 WGSL 代码片段 +│ +├── type/ ← TypeScript 类型声明 +└── utils/ ← 工具函数(loadTexture 等) +``` + +--- + +## 渲染管线 + +```mermaid +sequenceDiagram + participant App as 用户代码 + participant Scene + participant FrameState + participant ShadowPass + participant BasicPass + participant PostProcess as 后处理链 + + App->>Scene: scene.render() + Scene->>FrameState: update(camera) + FrameState->>FrameState: 更新视锥、灯光、队列 + Scene->>Scene: meshManger.update()
(视锥剔除、入队列) + + Scene->>ShadowPass: render(frameState, camera) + ShadowPass->>ShadowPass: 对每个有阴影的灯光
渲染深度图 + + Scene->>BasicPass: render(frameState, camera) + BasicPass->>BasicPass: 队列排序
(不透明前后,透明后前) + BasicPass->>BasicPass: 执行 DrawCommand
(绑定管线 / 缓冲区 / BindGroup) + + Scene->>PostProcess: render(colorTexture) + PostProcess-->>App: 最终画面输出到 Canvas +``` + +### 渲染通道说明 + +| 通道 | 输入 | 输出 | 说明 | +|------|------|------|------| +| **ShadowPass** | 场景 Mesh、各灯光位置 | 阴影贴图数组(Texture2DArray) | 每个有阴影的灯光各一张深度图 | +| **BasicPass** | 场景 Mesh、相机、光照数据 | 颜色纹理 + 深度纹理 | 排序后顺序绘制所有可见物体 | +| **PostEffect** | BasicPass 颜色纹理 | 处理后颜色纹理 | 可链式叠加多种后处理效果 | + +--- + +## 数据流:从场景创建到画面输出 + +``` +第一帧初始化: + Scene({ container }) + → 获取 canvas / WebGPU Adapter / Device + → 创建 ForwardRenderLine (BasicPass + ShadowPass) + → 初始化 Context / FrameState / MeshManger / LightManger + +场景搭建: + scene.add(mesh) → MeshManger.add(mesh) + scene.add(light) → LightManger.add(light) + scene.setCamera() → 绑定相机 ShaderData + +每帧 scene.render(): + + ① 更新阶段 + FrameState.update(camera) + ├── LightManger.update() — 收集灯光 Uniform + └── Frustum.update() — 更新裁剪平面 + + MeshManger.update(frameState, camera) + └── 对每个 Mesh: + ├── updateMatrix() — 递归更新模型矩阵 + ├── geometry.update() — 视锥剔除 + 相机距离 + ├── material.update() — 更新 Uniform 缓冲区 + └── 按透明度加入 opaque / transparent 队列 + + ② 阴影阶段 (ShadowPass) + 对每个带阴影的灯光: + └── 以灯光视角渲染所有不透明 Mesh 到深度图 + + ③ 颜色阶段 (BasicPass) + RenderQueue.sort() + ├── 不透明队列 (近 → 远,Z-prepass 优化) + └── 透明队列 (远 → 近,正确混合) + + 对每个 Mesh 执行 DrawCommand: + ├── ShaderData.bind() — 材质 BindGroup + ├── LightShaderData.bind() — 全局光照 BindGroup + ├── Camera.ShaderData.bind()— 相机矩阵 BindGroup + ├── RenderState.bind() — 管线状态 + ├── VertexBuffer.bind() + ├── IndexBuffer.bind() + ├── Pipeline.bind() — 从缓存获取 GPURenderPipeline + └── drawIndexed() / draw() + + ④ 后处理阶段 + PostEffectCollection → 按顺序执行效果链 → 输出到屏幕 +``` + +--- + +## 类继承关系 + +```mermaid +classDiagram + class RenderObject { + +modelMatrix Matrix4 + +position Vector3 + +scale Vector3 + +quaternion Quaternion + +castShadow bool + +receiveShadow bool + +updateMatrix() + } + + class Camera { + +viewMatrix Matrix4 + +projectionMatrix Matrix4 + +shaderData ShaderData + } + class PerspectiveCamera { + +fov number + +aspect number + } + class OrthographicCamera + + class Light { + +color Vector3 + +intensity number + +shadow BaseShadow + } + class AmbientLight + class DirectionalLight + class PointLight + class SpotLight + + class Mesh { + +geometry Geometry + +material Material + +derivedCommands DerivedCommands + +update() + +getPassCommand() + } + class Node { +children[] } + class SkyBox + class InstanceMesh + class Sprite + class Points + + class Material { + +shaderData ShaderData + +shaderSource ShaderSource + +renderState RenderState + +update() + } + class BlinnPhongMaterial + class PbrMaterial + class ShaderMaterial + + class Geometry { + +positions number[] + +normals number[] + +uvs number[] + +indices number[] + +boundingSphere BoundingSphere + } + class BoxGeometry + class SphereGeometry + class PlaneGeometry + + class PostEffect { + +render() + +setSize() + } + class BloomPostEffect + + RenderObject <|-- Camera + Camera <|-- PerspectiveCamera + Camera <|-- OrthographicCamera + + RenderObject <|-- Light + Light <|-- AmbientLight + Light <|-- DirectionalLight + Light <|-- PointLight + Light <|-- SpotLight + + RenderObject <|-- Mesh + Mesh <|-- Node + Mesh <|-- SkyBox + Mesh <|-- InstanceMesh + Mesh <|-- Sprite + Mesh <|-- Points + + Material <|-- BlinnPhongMaterial + Material <|-- PbrMaterial + Material <|-- ShaderMaterial + + Geometry <|-- BoxGeometry + Geometry <|-- SphereGeometry + Geometry <|-- PlaneGeometry + + PostEffect <|-- BloomPostEffect +``` + +--- + +## 核心子系统详解 + +### Scene 与 FrameState + +**Scene** ([src/Scene.ts](../src/Scene.ts)) 是引擎入口,负责: +- 创建并持有 WebGPU `Context` +- 管理 `MeshManger`(场景物体)和 `LightManger`(光源) +- 驱动 `ForwardRenderLine` 执行渲染 +- 协调 `PostEffectCollection` 后处理链 + +**FrameState** ([src/core/FrameState.ts](../src/core/FrameState.ts)) 是帧内共享状态: +```typescript +class FrameState { + renderQueue: RenderQueue; // opaque / transparent / pre / debug + lightManger: LightManger; + frustum: Frustum; // 视锥剔除平面 + background: Color | Texture; + drawCallnums: number; // 当帧统计 + frameNumber: number; +} +``` + +--- + +### Material 系统 + +| 材质 | 文件 | 特点 | +|------|------|------| +| `BlinnPhongMaterial` | [src/material/BlinnPhongMaterial.ts](../src/material/BlinnPhongMaterial.ts) | 经典 Blinn-Phong 光照,支持法线贴图 | +| `PbrMaterial` | [src/material/PbrMaterial.ts](../src/material/PbrMaterial.ts) | 基于物理渲染,支持 IBL(图像照明) | +| `ShaderMaterial` | [src/material/ShaderMaterial.ts](../src/material/ShaderMaterial.ts) | 完全自定义 WGSL 着色器 | + +**Material 核心属性** ([src/material/Material.ts](../src/material/Material.ts)): + +```typescript +class Material { + shaderData: ShaderData; // GPU Uniform / Texture 绑定 + shaderSource: ShaderSource; // 编译好的着色器模块 + renderState: RenderState; // 混合、深度、面剔除等管线状态 + color: Color; + baseTexture: Texture; + transparent: boolean; + opacity: number; + light: boolean; // 是否参与光照计算 +} +``` + +--- + +### Geometry 系统 + +所有几何体继承 `Geometry` ([src/geometry/Geometry.ts](../src/geometry/Geometry.ts)),通过 `setAttribute()` 提交顶点数据: + +```typescript +// 典型内部构造 +setAttribute(new Float32Attribute("position", positions, 3)); +setAttribute(new Float32Attribute("normal", normals, 3)); +setAttribute(new Float32Attribute("uv", uvs, 2)); +setIndice(indices); +calculateTangents(); // 自动计算切线(法线贴图所需) +``` + +预置几何体: + +| 类 | 构造参数 | +|----|---------| +| `BoxGeometry` | `(width, height, depth)` | +| `PlaneGeometry` | `(width, height)` | +| `SphereGeometry` | `(radius, widthSegments, heightSegments)` | +| `TorusKnotGeometry` | `(radius, tube, tubularSegments, radialSegments, p, q)` | +| `PointGeometry` | `(positions[])` | +| `SkyBoxGeometry` | 内部构造,无参数 | + +--- + +### Mesh 系统 + +**Mesh** ([src/mesh/Mesh.ts](../src/mesh/Mesh.ts)) 是引擎的基本可渲染单元: + +```typescript +class Mesh extends RenderObject { + geometry: Geometry; + material: Material; + frustumCull: boolean; // 默认 true + derivedCommands: DerivedCommands; // 渲染命令缓存 + + update(frameState, camera) { + // 1. 更新变换矩阵 + // 2. 视锥剔除 + // 3. 更新材质 Uniform + // 4. 推入渲染队列 + } +} +``` + +| 特殊 Mesh | 文件 | 用途 | +|-----------|------|------| +| `Node` | [src/mesh/Node.ts](../src/mesh/Node.ts) | 层级容器,有 `children` | +| `InstanceMesh` | [src/mesh/InstanceMesh.ts](../src/mesh/InstanceMesh.ts) | GPU 实例渲染,适合大量重复物体 | +| `SkyBox` | [src/mesh/SkyBox.ts](../src/mesh/SkyBox.ts) | 总在队列最前面渲染 | +| `Sprite` | [src/mesh/Sprite.ts](../src/mesh/Sprite.ts) | 始终朝向相机的 2D 四边形 | +| `Points` | [src/mesh/Points.ts](../src/mesh/Points.ts) | 点云渲染器 | + +--- + +### Light 与 Shadow 系统 + +```mermaid +graph LR + Scene -->|管理| LightManger + LightManger --> AmbientLight + LightManger --> DirectionalLight + LightManger --> PointLight + LightManger --> SpotLight + + DirectionalLight -->|可选| DirectionalLightShadow + DirectionalLight -->|可选| DirectionalLightCascadedShadow + PointLight -->|可选| PointLightShadow + SpotLight -->|可选| SpotLightShadow + + ShadowPass -->|读取| LightManger + ShadowPass -->|写入| ShadowMapTextureArray + BasicPass -->|采样| ShadowMapTextureArray +``` + +**LightManger** 维护各灯光类型的 `Texture2DArray` 阴影贴图,传递给所有材质 Shader。 + +--- + +### Shader 系统 + +**ShaderSource** ([src/shader/ShaderSource.ts](../src/shader/ShaderSource.ts)) 负责: +1. 维护 `defines`(如 `{ HAS_NORMAL: true, USE_IBL: 1 }`) +2. 在 `defines` 变化时重新编译 WGSL 模块 +3. 缓存编译结果(`dirty` 标志位) + +**WGSL 预处理器** ([src/shader/WGSLParseDefines.ts](../src/shader/WGSLParseDefines.ts)) 支持 C 风格条件编译: + +```wgsl +#ifdef HAS_NORMAL + let normal = normalize(normalMatrix * inNormal); +#endif + +#if USE_IBL == 1 + let env = sampleEnvironment(normal); +#endif +``` + +**预置着色器注册** ([src/shader/Shaders.ts](../src/shader/Shaders.ts)): + +| 键名 | 用途 | +|------|------| +| `phong` | BlinnPhong 材质顶点 / 片元 | +| `pbr` | PBR 材质顶点 / 片元 | +| `skybox` | 天空盒 | +| `shadowMap` | 深度阴影渲染 | +| `point` | 点云渲染 | +| `sprite` | 精灵渲染 | + +**Shader Chunk** 可复用代码片段通过 `#include` 引入: +- `shaderChunk/commonFrag.wgsl` +- `shaderChunk/lightCalc.wgsl` +- `shaderChunk/normal.wgsl` + +--- + +### 后处理系统 + +``` +BasicPass 输出 + ↓ +BloomPostEffect + 1. 提取高亮区域(高通滤波) + 2. 多级 Mip 高斯模糊(可分离) + 3. 合并所有模糊级别 + 4. 与原图混合 + ↓ +PostEffectCollection → Canvas +``` + +后处理效果接口: +```typescript +class PostEffect { + render(context, inputTexture: Texture): Texture; + setSize(width: number, height: number): void; +} +``` + +--- + +### 渲染基础设施 + +| 类 | 文件 | 职责 | +|----|------|------| +| `Context` | [src/render/Context.ts](../src/render/Context.ts) | WebGPU Device / Adapter / Canvas 初始化 | +| `Buffer` | [src/render/Buffer.ts](../src/render/Buffer.ts) | Vertex / Index / Uniform / Storage Buffer | +| `Texture` | [src/render/Texture.ts](../src/render/Texture.ts) | GPU 纹理,支持动态更新、Mipmap | +| `Sampler` | [src/render/Sampler.ts](../src/render/Sampler.ts) | 过滤模式、寻址模式封装 | +| `BindGroup` | [src/render/BindGroup.ts](../src/render/BindGroup.ts) | GPUBindGroup 封装,含动态偏移支持 | +| `DrawCommand` | [src/render/DrawCommand.ts](../src/render/DrawCommand.ts) | 单次绘制调用状态完整封装 | +| `RenderState` | [src/render/RenderState.ts](../src/render/RenderState.ts) | 混合/深度/模板/剔除/图元拓扑 | +| `RenderTarget` | [src/render/RenderTarget.ts](../src/render/RenderTarget.ts) | 离屏渲染目标(颜色 + 深度附件) | +| `Pipeline` | [src/render/Pipeline.ts](../src/render/Pipeline.ts) | `GPURenderPipeline` 缓存(避免重复创建) | +| `ShaderData` | [src/render/ShaderData.ts](../src/render/ShaderData.ts) | BindGroup 抽象,按 binding 绑定资源 | + +**DrawCommand** 执行过程: +```typescript +command.render({ device, passEncoder, camera }) { + shaderData.bind(device, passEncoder); // 材质 group=0 + camera.shaderData.bind(device, passEncoder); // 相机 group=1 + lightShaderData.bind(device, passEncoder); // 光照 group=2 + renderState.bind(); // viewport/depth/blend + vertexBuffers.forEach(vb => vb.bind()); + indexBuffer.bind(); + pipeline.bind(passEncoder); // 从缓存获取 Pipeline + passEncoder.drawIndexed(count, instanceCount); +} +``` diff --git a/ai-docs/CONTRIBUTING.md b/ai-docs/CONTRIBUTING.md new file mode 100644 index 0000000..94d1ba6 --- /dev/null +++ b/ai-docs/CONTRIBUTING.md @@ -0,0 +1,138 @@ +# GEngine — 贡献指南 + +## 目录 + +- [GEngine — 贡献指南](#gengine--贡献指南) + - [目录](#目录) + - [开发工作流](#开发工作流) + - [分支命名规范](#分支命名规范) + - [提交信息规范](#提交信息规范) + - [代码评审标准](#代码评审标准) + - [测试要求](#测试要求) + - [文档更新](#文档更新) + +--- + +## 开发工作流 + +``` +1. Fork 仓库 → 克隆到本地 +2. git checkout -b feat/your-feature +3. yarn install +4. yarn dev (开发 + watch) +5. 编写代码 + 在 example/ 中验证 +6. yarn lint (确保无 lint 错误) +7. yarn commit (使用 commitizen 规范提交) +8. Push → 创建 Pull Request +``` + +--- + +## 分支命名规范 + +| 前缀 | 用途 | 示例 | +|------|------|------| +| `feat/` | 新功能 | `feat/cylinder-geometry` | +| `fix/` | Bug 修复 | `fix/point-light-shadow-uv` | +| `docs/` | 文档更新 | `docs/api-reference` | +| `refactor/` | 重构 | `refactor/shader-data-bind` | +| `perf/` | 性能优化 | `perf/pipeline-cache-key` | +| `chore/` | 工程配置 | `chore/update-rollup` | + +--- + +## 提交信息规范 + +使用 **Conventional Commits**,格式为: + +``` +(): + +[可选 body] + +[可选 footer] +``` + +**类型(type)**: + +| type | 含义 | +|------|------| +| `feat` | 新功能 | +| `fix` | Bug 修复 | +| `docs` | 文档 | +| `refactor` | 重构(不修改功能) | +| `perf` | 性能优化 | +| `test` | 测试 | +| `chore` | 构建/配置/依赖 | +| `ci` | CI/CD 流水线 | + +**示例**: +``` +feat(geometry): 添加 CylinderGeometry +fix(shadow): 修复点光源阴影贴图翻转问题 +docs(api): 更新 BloomPostEffect 参数说明 +``` + +提交前 Git hook 会自动执行: +- `check-keyword.sh`:检查敏感词 +- `commitlint`:校验提交信息格式 +- `pretty-quick`:格式化已暂存文件 + +--- + +## 代码评审标准 + +Pull Request 合并前需满足: + +**功能正确性** +- [ ] 在目标浏览器(Chrome / Edge 113+)中验证通过 +- [ ] 已在 `example/` 中添加或修改相应示例 HTML +- [ ] 不破坏现有示例的渲染结果 + +**代码质量** +- [ ] 通过 `yarn lint` 无错误 +- [ ] 无 TypeScript `any` 滥用 +- [ ] 公共 API 有清晰的类型签名 +- [ ] 新增类/方法在 `src/index.ts` 中正确导出 + +**性能** +- [ ] 无不必要的每帧 GPU 资源创建 +- [ ] 大数量渲染使用 InstanceMesh 而不是多个 Mesh +- [ ] Pipeline 通过缓存复用(不重复创建 `GPURenderPipeline`) + +**安全** +- [ ] 不在着色器中引入未经校验的用户输入 +- [ ] GLTF 加载器对 URL 做基本合法性检查 + +--- + +## 测试要求 + +当前项目以 `example/` 目录下的可视化示例作为集成测试。 + +对于工具函数和数学库(`src/math/`),建议添加单元测试。测试文件放在 `tests/` 目录,可使用 Vitest 或 Jest: + +```shell +# 安装测试工具(尚未在项目中配置,按需添加) +yarn add -D vitest + +# 运行测试 +npx vitest +``` + +**测试文件命名**:`tests/math/Vector3.test.ts` + +--- + +## 文档更新 + +修改以下内容时必须同步更新 `ai-docs/`: + +| 修改内容 | 需更新的文档 | +|----------|-------------| +| 新增公共 API | [ai-docs/API.md](./API.md) | +| 架构变更 | [ai-docs/ARCHITECTURE.md](./ARCHITECTURE.md) | +| 构建流程变更 | [ai-docs/DEPLOYMENT.md](./DEPLOYMENT.md) | +| 开发工具变更 | [ai-docs/DEVELOPMENT.md](./DEVELOPMENT.md) | + +更新文档与代码应在同一个 Pull Request 中提交。 diff --git a/ai-docs/DEPLOYMENT.md b/ai-docs/DEPLOYMENT.md new file mode 100644 index 0000000..fea022e --- /dev/null +++ b/ai-docs/DEPLOYMENT.md @@ -0,0 +1,118 @@ +# GEngine — 构建与发布 + +## 目录 + +1. [构建产物](#构建产物) +2. [构建命令](#构建命令) +3. [Rollup 配置说明](#rollup-配置说明) +4. [发布到 npm](#发布到-npm) +5. [在项目中引用](#在项目中引用) + +--- + +## 构建产物 + +``` +dist/ +└── index.js ← 单文件 ES Module,压缩后约 xxx KB +``` + +| 属性 | 值 | +|------|---| +| 格式 | ES Module (`type: "module"`) | +| 目标 | ES2020 | +| 外部依赖 | 无(WGSL 着色器内联) | +| Source Map | 开发模式输出,生产模式不输出 | + +--- + +## 构建命令 + +```shell +# 生产构建(压缩 + Tree-shaking) +yarn build + +# 开发构建(带 watch,不压缩) +yarn dev +``` + +构建前会自动执行 `hooks/checkDependency.js`,校验必要依赖是否已安装。 + +--- + +## Rollup 配置说明 + +**文件**:[rollup.config.js](../rollup.config.js) + +| 配置项 | 值 | 说明 | +|--------|----|------| +| `input` | `src/index.ts` | 入口文件 | +| `output.file` | `dist/index.js` | 输出文件 | +| `output.format` | `es` | ES Module 格式 | +| TypeScript | `@rollup/plugin-typescript` | TS 编译 | +| WGSL | 自定义 WGSL 插件 | `.wgsl` → JS 字符串 | +| CommonJS | `@rollup/plugin-commonjs` | CJS 依赖兼容 | +| Terser | `@rollup/plugin-terser` | 仅生产环境压缩 | + +**WGSL 着色器插件**:位于 `build/@rollup/plugin-wgsl/`,将 `.wgsl` 文件作为字符串导入,并在构建时内联到 `dist/index.js` 中,无需运行时加载。 + +--- + +## 发布到 npm + +```shell +# 1. 确认版本号(package.json) +npm version patch # 1.0.0 → 1.0.1 +npm version minor # 1.0.0 → 1.1.0 +npm version major # 1.0.0 → 2.0.0 + +# 2. 构建 +yarn build + +# 3. 发布(需要 npm 登录且有包权限) +npm publish --access public +``` + +`package.json` 中 `files` 字段控制发布内容: +```json +{ + "files": ["dist", "package.json", "README.md"] +} +``` + +--- + +## 在项目中引用 + +### CDN(无构建工具) + +```html + +``` + +### npm 安装 + +```shell +npm install @gengine-js/gengine +``` + +```javascript +import { Scene, Mesh, PerspectiveCamera } from "@gengine-js/gengine"; +``` + +### Vite / Webpack 项目 + +直接 import,构建工具会自动处理 ES Module: + +```typescript +import { + Scene, + Mesh, + PerspectiveCamera, + BlinnPhongMaterial, + BoxGeometry +} from "@gengine-js/gengine"; +``` diff --git a/ai-docs/DEVELOPMENT.md b/ai-docs/DEVELOPMENT.md new file mode 100644 index 0000000..4be4663 --- /dev/null +++ b/ai-docs/DEVELOPMENT.md @@ -0,0 +1,378 @@ +# GEngine — 开发指南 + +## 目录 + +1. [环境要求](#环境要求) +2. [本地开发搭建](#本地开发搭建) +3. [项目脚本](#项目脚本) +4. [开发服务器](#开发服务器) +5. [项目结构约定](#项目结构约定) +6. [添加新功能的典型流程](#添加新功能的典型流程) + - [添加新几何体](#添加新几何体) + - [添加新材质](#添加新材质) + - [添加自定义着色器](#添加自定义着色器) + - [添加新的后处理效果](#添加新的后处理效果) +7. [代码规范](#代码规范) +8. [调试技巧](#调试技巧) +9. [常见问题](#常见问题) + +--- + +## 环境要求 + +| 依赖 | 版本要求 | 说明 | +|------|---------|------| +| Node.js | ≥ 16 | 构建工具运行环境 | +| 浏览器 | Chrome 113+ / Edge 113+ | 需支持 WebGPU | +| 操作系统 | 任意 | 无特殊限制 | + +> **注意**:WebGPU 目前需要在支持的浏览器中开启,Chrome/Edge 113+ 已默认启用。Firefox 和 Safari 仍需手动开启实验性标志。 + +--- + +## 本地开发搭建 + +```shell +# 1. 克隆仓库 +git clone https://github.com/hpugis/GEngine.git +cd GEngine + +# 2. 安装依赖(推荐使用国内镜像) +yarn install --registry=https://registry.npmmirror.com +# 或 +npm run install:yarn + +# 3. 启动开发服务器(带 watch) +yarn dev + +# 4. 在浏览器打开示例 +# 直接用 VS Code Live Server 或 http-server 打开 example/ 目录下的 HTML 文件 +``` + +--- + +## 项目脚本 + +| 命令 | 说明 | +|------|------| +| `yarn dev` | 开发模式:TypeScript 增量编译 + 文件监听,输出到 `dist/index.js` | +| `yarn build` | 生产构建:压缩 + Tree-shaking,输出到 `dist/index.js` | +| `yarn lint` | ESLint 检查 `src/` 下的 TS/JS 文件 | +| `yarn commit` | 使用 commitizen 规范化 Git 提交 | +| `yarn pretty-quick` | 格式化已暂存文件(Prettier) | + +### 构建流程 + +``` +yarn build + ├── npm run pre-build ← 检查依赖(hooks/checkDependency.js) + └── rollup -c ← rollup.config.js + ├── 读取 src/index.ts + ├── TypeScript 编译(tsconfig.json) + ├── 加载 .wgsl 着色器文件(自定义 rollup 插件) + ├── CommonJS 兼容处理 + └── Terser 压缩(仅 production) + → 输出 dist/index.js(ES Module) +``` + +--- + +## 开发服务器 + +Rollup watch 模式只负责编译,不提供 HTTP 服务器。可用以下方式预览示例: + +```shell +# 方案一:VS Code Live Server 插件(推荐) +# 在 example/ 目录右键 → Open with Live Server + +# 方案二:npx +npx serve . + +# 方案三:http-server +npm install -g http-server +http-server . -p 8080 +``` + +然后访问 `http://localhost:8080/example/mesh/mesh.html` 等示例页面。 + +--- + +## 项目结构约定 + +### 文件命名 + +| 类型 | 规范 | 示例 | +|------|------|------| +| 类文件 | PascalCase | `BlinnPhongMaterial.ts` | +| 工具文件 | camelCase | `utils.ts` | +| WGSL 着色器 | camelCase | `phongFrag.wgsl` | +| 示例文件 | camelCase | `pointLight.html` | + +### 模块边界 + +- `src/render/` — 仅处理 WebGPU 原语(Buffer、Texture、Pipeline…),不包含业务逻辑 +- `src/core/` — 引擎框架基础设施(FrameState、RenderQueue、DerivedCommands…) +- `src/material/`、`src/geometry/`、`src/mesh/` — 业务层对象 +- `src/shader/` — WGSL 着色器源码与编译 +- `src/math/` — 纯数学,无 WebGPU 依赖 +- `src/index.ts` — 唯一公共出口,按需 `export` + +--- + +## 添加新功能的典型流程 + +### 添加新几何体 + +1. 在 `src/geometry/` 新建 `XxxGeometry.ts` +2. 继承 `Geometry` 基类,在构造函数中调用 `setAttribute()` 和 `setIndice()` +3. 根据需要调用 `calculateTangents()` +4. 在 `src/index.ts` 追加导出 + +```typescript +// src/geometry/CylinderGeometry.ts +import Geometry from "./Geometry"; +import { Float32Attribute } from "../core/WebGPUTypes"; + +export default class CylinderGeometry extends Geometry { + constructor( + radiusTop = 1, + radiusBottom = 1, + height = 1, + radialSegments = 32 + ) { + super(); + const { positions, normals, uvs, indices } = buildCylinder( + radiusTop, radiusBottom, height, radialSegments + ); + this.setAttribute(new Float32Attribute("position", positions, 3)); + this.setAttribute(new Float32Attribute("normal", normals, 3)); + this.setAttribute(new Float32Attribute("uv", uvs, 2)); + this.setIndice(indices); + this.calculateTangents(); + } +} +``` + +--- + +### 添加新材质 + +1. 在 `src/material/` 新建 `XxxMaterial.ts` +2. 继承 `Material` 基类 +3. 在 `src/shader/Shaders.ts` 注册对应 WGSL 着色器 +4. 在 `update()` 方法中同步 GPU Uniform + +```typescript +// src/material/XxxMaterial.ts +import Material from "./Material"; + +export default class XxxMaterial extends Material { + private _customParam: number = 1.0; + + constructor() { + super(); + this.shaderSource.shaderId = "xxx"; // 映射到 Shaders.ts 中的键 + this.light = true; + } + + set customParam(v: number) { + this._customParam = v; + this.shaderData.setFloat("customParam", v); + } + + update(frameState, mesh) { + super.update(frameState, mesh); + // 更新动态 Uniform + } +} +``` + +--- + +### 添加自定义着色器 + +使用 `ShaderMaterial` 直接注入自定义 WGSL: + +```typescript +import { ShaderMaterial, Mesh, BoxGeometry } from "@gengine-js/gengine"; + +const mat = new ShaderMaterial({ + shaderId: "myEffect", + vertexShader: ` + struct VertexInput { + @location(0) position: vec3f, + @location(1) uv: vec2f, + }; + struct VertexOutput { + @builtin(position) pos: vec4f, + @location(0) uv: vec2f, + }; + @group(0) @binding(0) var model: mat4x4f; + @group(1) @binding(0) var view: mat4x4f; + @group(1) @binding(1) var projection: mat4x4f; + + @vertex + fn main(input: VertexInput) -> VertexOutput { + var out: VertexOutput; + out.pos = projection * view * model * vec4f(input.position, 1.0); + out.uv = input.uv; + return out; + } + `, + fragmentShader: ` + @group(0) @binding(1) var baseTexture: texture_2d; + @group(0) @binding(2) var baseSampler: sampler; + @group(0) @binding(3) var time: f32; + + @fragment + fn main(@location(0) uv: vec2f) -> @location(0) vec4f { + let color = textureSample(baseTexture, baseSampler, uv); + return color * abs(sin(time)); + } + `, + uniforms: { + time: { value: 0.0 } + } +}); + +// 每帧更新 +function animate() { + mat.setUniform("time", performance.now() / 1000); + scene.render(); + requestAnimationFrame(animate); +} +``` + +--- + +### 添加新的后处理效果 + +1. 在 `src/post-process/` 新建 `XxxPostEffect.ts` +2. 继承 `PostEffect`,实现 `render()` 方法 +3. 在 `src/index.ts` 导出 + +```typescript +// src/post-process/GrayscalePostEffect.ts +import PostEffect from "./PostEffect"; +import { Texture } from "../render/Texture"; + +export default class GrayscalePostEffect extends PostEffect { + render(context, inputTexture: Texture): Texture { + // 1. 在 fullScreenQuad 上绘制灰度着色器 + // 2. 返回输出纹理 + return this.currentRenderTarget.getColorTexture(0); + } +} + +// 使用 +const grayscale = new GrayscalePostEffect(width, height); +scene.addPostEffect(grayscale); +``` + +--- + +## 代码规范 + +### TypeScript + +- 使用 `strict: true` 模式(已在 `tsconfig.json` 配置) +- 公共 API 必须有明确的类型声明,避免 `any` +- 枚举值统一定义在 `src/core/WebGPUConstant.ts` + +### 提交信息 + +使用 Conventional Commits 规范(由 `commitlint` 强制检查): + +``` +feat: 添加 CylinderGeometry 几何体 +fix: 修复点光源阴影贴图 UV 偏移 +docs: 更新 API 文档 +refactor: 重构 ShaderData 绑定逻辑 +perf: 优化 Pipeline 缓存 Key 生成 +test: 添加 Matrix4.compose 单元测试 +``` + +### WGSL 着色器 + +- 着色器文件放在 `src/shader/` 或 `src/shader/shaderChunk/` +- 公共片段通过 `#include ` 引入 +- 条件编译使用 `#ifdef` / `#if` / `#endif`(不使用 `#else`) + +--- + +## 调试技巧 + +### 查看渲染统计 + +```typescript +// 当帧绘制调用次数 +console.log(scene.frameState.drawCallnums); + +// 当前帧号 +console.log(scene.frameState.frameNumber); +``` + +### 关闭视锥剔除 + +```typescript +mesh.frustumCull = false; +``` + +### 使用 RenderDoc 捕获 WebGPU 帧 + +Chrome 支持 RenderDoc 集成,在 `chrome://flags` 中启用 `WebGPU Developer Features` 后可使用。 + +### 打印 WGSL 编译结果 + +在 `ShaderSource.ts` 中临时添加: +```typescript +console.log("WGSL vert:", processedVertSource); +console.log("WGSL frag:", processedFragSource); +``` + +### 自定义错误边界 + +监听 WebGPU 设备丢失事件: +```typescript +scene.context.device.lost.then((info) => { + console.error("WebGPU device lost:", info.message, info.reason); +}); +``` + +--- + +## 常见问题 + +### Q: 页面空白,没有渲染输出 + +1. 检查浏览器是否支持 WebGPU(打开 `chrome://gpu`) +2. 确认已调用 `scene.setCamera(camera)` +3. 确认材质和几何体均已就绪(`mesh.ready === true`) +4. 检查浏览器控制台的 WebGPU 验证错误 + +### Q: 模型加载后不显示 + +1. 确认 GLTF 文件路径正确 +2. 检查网络请求是否有 CORS 错误 +3. 尝试设置 `model.position.set(0, 0, 0)` 确认模型不在视野外 + +### Q: 阴影不显示 + +1. 确认光源设置了 `shadow` 属性:`light.shadow = new DirectionalLightShadow()` +2. 确认 Mesh 开启了 `castShadow = true` 和 `receiveShadow = true` + +### Q: 透明物体渲染顺序错误 + +1. 确认材质设置了 `transparent = true` +2. GEngine 自动将透明物体按从远到近排序,但多个透明物体相交时仍可能出现问题 + +### Q: 窗口 resize 后画面拉伸 + +监听 resize 事件并更新相机和场景: +```javascript +window.addEventListener("resize", () => { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + scene.resize(window.innerWidth, window.innerHeight); +}); +``` diff --git a/ai-docs/README.md b/ai-docs/README.md new file mode 100644 index 0000000..1b5155f --- /dev/null +++ b/ai-docs/README.md @@ -0,0 +1,143 @@ +# GEngine.js — 开发者文档 + +> 基于 WebGPU 的现代 3D 渲染引擎 + +## 目录 + +- [项目概述](#项目概述) +- [快速开始](#快速开始) +- [核心概念](#核心概念) +- [文档导航](#文档导航) + +--- + +## 项目概述 + +GEngine.js 是一款基于 **WebGPU API** 构建的高性能 3D 渲染引擎,使用 TypeScript 编写,通过 Rollup 打包为 ES 模块发布。 + +| 属性 | 详情 | +|------|------| +| 包名 | `@gengine-js/gengine` | +| 版本 | 1.0.0 | +| 语言 | TypeScript (目标 ES2020) | +| 渲染 API | WebGPU | +| 着色器语言 | WGSL | +| 模块格式 | ES Module | +| 仓库 | https://github.com/hpugis/GEngine | + +### 主要特性 + +- **前向渲染管线**:包含阴影渲染 Pass 和颜色渲染 Pass +- **三种内置材质**:Blinn-Phong、PBR(基于物理渲染)、自定义 Shader +- **四种光源类型**:环境光、方向光、点光源、聚光灯,均支持阴影 +- **级联阴影贴图**:DirectionalLight 支持 CSM 技术 +- **后处理系统**:Bloom 效果,可链式组合多种后处理 +- **几何体库**:Box、Plane、Sphere、TorusKnot、Point、SkyBox +- **GLTF 加载器**:支持网格、材质、贴图、骨骼动画 +- **视锥剔除**:基于 BoundingSphere/BoundingBox +- **实例渲染**:通过 InstanceMesh 支持大量重复物体 +- **计算管线**:支持 WebGPU Compute Shader + +--- + +## 安装 + +```shell +# yarn +yarn add @gengine-js/gengine + +# npm +npm install @gengine-js/gengine +``` + +## 快速开始 + +```html + + + +
+ + + +``` + +--- + +## 核心概念 + +| 概念 | 说明 | +|------|------| +| **Scene** | 场景根对象,管理所有 Mesh / Light,驱动渲染循环 | +| **Mesh** | 几何体 + 材质的组合,是可渲染的基本单元 | +| **Geometry** | 顶点数据(位置、法线、UV、切线、索引) | +| **Material** | 着色参数 + ShaderData + RenderState | +| **Light** | 光源,可携带 Shadow 对象 | +| **Camera** | 观察视角,输出 View × Projection 矩阵 | +| **DrawCommand** | 单次 GPU 绘制调用的所有状态封装 | +| **ShaderData** | BindGroup 封装,管理 Uniform / Texture / Sampler | +| **RenderTarget** | 离屏渲染目标(颜色 + 深度附件) | + +--- + +## 文档导航 + +| 文档 | 内容 | +|------|------| +| [ARCHITECTURE.md](./ARCHITECTURE.md) | 系统架构、渲染管线、数据流、类继承图 | +| [DEVELOPMENT.md](./DEVELOPMENT.md) | 开发环境搭建、构建、调试、贡献指南 | +| [API.md](./API.md) | 完整公共 API 参考 | +| [DEPLOYMENT.md](./DEPLOYMENT.md) | 构建产物、发布流程 | +| [CONTRIBUTING.md](./CONTRIBUTING.md) | 贡献规范 |