gavinyork / zephyr3d

3d rendering framework for browsers, supports both WebGL and WebGPU
https://gavinyork.github.io/zephyr3d/
MIT License
68 stars 4 forks source link

Love this lib #1

Open rbenzazon opened 3 weeks ago

rbenzazon commented 3 weeks ago

I've been browsing this code for hours, I love the effort to make something similar than three but way better and more modern.

I'm contemplating the idea of writing a new kind of webgl engine, yours is doing many things that I want. All began when browsing threejs source code, I was a bit disappointed about the patterns used. I wanted to see if the tree shaking was really there. It wasn't. Mainly due to poor coding practices ( some were pre esm leftovers, other plain bad ideas ). I get the feeling that the lib was never designed to be truly optimized.

I want to create one similar to svelte, which compiles the app to a more static code, which has tailor made shaders (pre compiled not full of conditions) which has a perfect tree shaking using polymorphism and proper de-coupling. When you take three, and you create a rotating cube example, you get 1KB of your app, +600KB of three, even if you bundle three within the app, not using the pre bundled version. Now you do the same ex in pure JS webgl, without engine, using m4 imported in ESM function by function (important detail, never *), you get 7KB. OK there are some things missing here and there but clearly not 600KB.

I managed to get to 220KB re-creating the Three repo, copying class by class, deleting huge unused module chunks, not even bothering to make it work, it requires a bit of redesign in some cases to work, for instance shaderlib and shaderchunk load everything always, I just kept them but empty. Still huge in my opinion. I had to activate class property mangle, which forces apps that would use the lib to bundle together in the same bundle context I guess, not necessarily bad.

Then I started understanding the threejs lib job, and how it achieves it. It's a kind of reactive engine, but without being truly one. There is no declarative reactive statements. The GLSL is string. The clever bit relies on JS replace function, which I don't like. The invalidation mechanism is specific in each case, reinventing the wheel each time.

threlte is clever, but the reactive part that I want is the engine, but threlte only makes the app reactive and relies solely on three as engine.

I would prefer having glsl in dedicated files to empower the shader dev with the best IDE integration, but make them a template as well with language extension, like what svelte is doing with HTML in .svelte files, but keep the JS outside. Components would be a JS function/class that ties potentially to shader(s) templates which expose a prop API. In 3d engines and apps, including custom 3d components, you don't always need to associate the JS code with shaders.

Ideally a compiler would calculate what's static within the app and what is runtime reactive, so no complete lib is needed, components and models are the most static possible and only the actually used webgl API code is bundled, either shared or inlined if used once. Shader pre compiled with used materials and options only.

I don't know about the behavior of zephyr3d completely, it seems that it's doing most of what I'm looking for, except that some part is runtime instead of pre compiled, is that correct? I checked out one example (gltf helmet) and it seems that it's only 300KB including everything like gltf loader, which is impressive. I plan on trying it out and discover the details. From what I've see this lib is a huge contribution to the worlds of webgl/gpu rendering, thank you so much.

The only thing I found super impressive but I would prefer different, is the choice of JS for the shaders. I think we can achieve the same with glsl directly, but we need to add templating to the language. The JS version avoids the language extension but at the cost of not being glsl files with language tools. Also your approach makes the JS variables used in glsl easy to track, so there is no bundler/minifyer challenge. In the glsl extension path, this is a big difficulty, write bundler plugins to minimize the glsl and its template variables knowing where they originate from.

gavinyork commented 3 days ago

Hi rbenzazon,

Thanks a ton for diving into my project and giving such detailed feedback! I'm super excited to hear that you find it impressive and that it matches up with a lot of your ideas and goals.

One of my main goals has been to keep the compiled js as small as possible. I've put a lot of effort into effective tree shaking, though I know there's always room to get better.

Using js for shaders instead of GLSL/WGSL is definitely a bit of an experiment. I'm not a big fan of the traditional string assembly method for shaders. String templating can be a pain and isn't very flexible. Plus, supporting multiple shader languages with string templates would mean different implementations, which just adds complexity. By writing shaders directly in js, I was aiming for more flexibility and dynamic shader definitions.

For zephyr3d, all shaders are currently generated at runtime because of the Javascript-based shader generation. There's no system for using pre-compiled shaders right now. I chose this approach to maximize flexibility, but I get that pre-compilation could have its perks, and I'm open to exploring it in future updates.

I'd love to hear more about what you're working on and any other ideas you have. If you try out zephyr3d and have any questions or more feedback, feel free to reach out.

Best regards,

Gavinyork