Live demo Use Edge/Chrome Canary and enter the following to the address field:
For Edge:
- edge://flags/#enable-unsafe-webgpu
For Chrome:
- Chrome://flags/#enable-unsafe-webgpu
glTF is not "yet another file format."
There are more than 70 different file formats for 3D data. Why do we need one more? glTF can significantly simplify the 3D content pipeline. Instead of implementing hundreds of importers and converters for various file formats, runtime applications only need to support glTF that is provided by custom converters such as obj2gltf.
WebGPU is an unreleased Javascript Graphics API with its own shading language called WGSL. However, this project uses GLSL as the shading language. @webgpu/glslang converts GLSL to SPIR-V so that it can be used on WebGPU.
This projects uses glTF-Transform, a glTF 2.0 SDK for TypeScript, to load glTF files from the web. With this SDK, we can easily query the data inside glTF without implementing the glTF loading structure from scratch.
It was quite an adventure to explore this new API and implement something really cool 😎.
✅: fully supported
❗: partially supported (undesirable loading time)
- Loading glTF and glb files (supported by
gl-Transform
) ✅
- Core glTF 2.0 Sample Models
Antique Camera✅ | Avocado✅ | Barramundi Fish✅ |
---|---|---|
Boom Box✅ | Corset✅ | Damaged Helmet✅ |
---|---|---|
Flight Helmet✅ | Lantern✅ | Sci Fi Helmet✅ |
---|---|---|
Suzanne✅ | Water Bottle✅ |
---|---|
- Standard glTF 2.0 Sample Models
- Box ✅
- Box Interleaved✅
- Box Textured✅
- Box Textured NPOT✅
- Box With Spaces✅
- Box Vertex Colors✅
- Cube✅
- Duck✅
- 2 Cylinder Engine ❗
- Reciprocating Saw ❗
- Gearbox Assy ❗
- Buggy ❗
- Sponza❗
- Two Sided Plane✅
- Feature Tests glTF 2.0 Sample Models
- Boom Box With Axes ✅
- TextureSettingsTest ✅
- KHR_lights_punctual ✅: 6 directional lights are used to light the scene.
The simplified structure of the project can be summarized using the following graph:
gl-Transform
provides an easy-to-use interface (such as Doc
, Root
, Node
, etc.) to access the data from glTF files. Only a single set of vertex and fragment shader is used. The functionality of the shaders is determined by #define
preprocessor. These #define
s are dynamically generated and inserted into the shaders. This is very similar to the shader architecture used in glTF-Sample-Viewer by KhronosGroup.
It is interesting to note that shaders used in WebGL cannot be used directly in the WebGPU pipeline, mostly due to the different uses of uniforms and textures. A comparison between GLSL, WGSL, and GLSL(WebGL) is shown below:
Major modifications will be needed to convert shaders used in WebGL to those in WebGPU. All uniforms need to be put in the uniform block and assigned a layout and binding, and all samplers are replaced by pairs of texture
and sampler
. The rest of the job is to carefully pass glTF data into the pipeline. Since primitives in a glTF file may use different shader programs, we need to use multiple pipelines to render multiple objects on the scene.
To test out this project:
- Clone the repo
- Install NPM packages and Use Chrome Canary to open a localhost
npm start
- There are two reasons why I choose to use GLSL in this project:
- GLSL sits in the middle of the complexity diagram. It grants you more control over the rendering pipeline, but is less verbose than WGSL.
- GLSL can be manually converted to WGSL, without modifying the renderer code (since they all use the same concepts like binding and grouping).
However, adding an extra layer of conversion means that models with lots of primitives/meshes are loaded very slowly since the renderer creates and converts shaders per primitive. This is one of the disadvantages of using GLSL as the shading language.
- Most of the rendering codes are squeezed into a single file. Also, there are some obvious opportunities for refactoring due to my initial unfamiliarity with WebGPU. My future plan is to make the renderer more object-oriented for readability and refactor some repeating code to follow DRY principle.
- Improve loading time of large models
- Support more models from feature test
- Support Animation and Skin
- Support materials extensions such as transmission
- Support for user camera
- Make renderer more object-oriented and refactor repeating codes
Thank you for all the authors below for making this project possible.
- KhronosGroup/glTF-Sample-Viewer for providing a wonderful place to study glTF renderer. Importantly, the shader source codes are derived from this project.
- glTF-Transform by Don McCurdy for providing an easy-to-use SDK for loading and reading glTF files.
- kainino0x/glslang for providing a way to use GLSL shaders in WebGPU.
- mikolalysenko/3d-view-controls for providing a user-friendly camera system.
- Practical WebGPU Graphics by Jack Xu, PhD for introducing me to the world of WebGPU and providing the base code for this project.
- The Complete JavaScript Course 2022: From Zero to Expert! by Jonas Schmedtmann for teaching me what "async/await" means and the fundamental of Javascript. Highly recommend this course!
- Understanding TypeScript - 2022 Edition by Maximilian Schwarzmüller for teaching me those finer details about Typescript.
- If you use Webpack as the module bundler, remember to use development mode. Otherwise, class and variable names will not be properly displayed (i, S instead of class name, breakpoints not hit all the time)
- Need at least #version 310 es to use glslang
- Existing shaders in Khronos are NOT compatible with WebGPU. To make it work, we need to add layout and non-opaque uniforms.
- The Map object holds key-value pairs and remembers the original insertion order of the keys.
Number of entries (3) did not match the number of entries (1) specified in [BindGroupLayout]
If we declare uniform in the shader, we need to use them in the main() function.