x3dom / x3dom

X3DOM. A framework for integrating and manipulating X3D scenes as HTML5/DOM elements.
http://x3dom.org
Other
811 stars 271 forks source link

Is it time to start transitioning x3dom from webgl2.0 to webgpu? #1272

Open microaaron opened 1 year ago

microaaron commented 1 year ago

With the release of chrome 113, webgpu has been officially supported. Is it time to start transitioning x3dom from webgl2.0 to webgpu?

andreasplesch commented 1 year ago

That would be great if somebody would want to tackle it.

brutzman commented 10 months ago

Suggest adding, not breaking. X3D 4.0 includes full support for glTF 2.0, either as an Inline file or through use of corresponding X3D 4.0 nodes provide equivalent rendering capabilities.

andreasplesch commented 10 months ago

Just to clarify, glTF 2.0 does not depend on WebGPU.

Base glTF 2.0 is already well supported by x3dom. The main piece missing is skinning.

However, glTF extensions became more important, in particular the Khronos ratified ones:

https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos

The added materials in particular would be a priority.

microaaron commented 3 weeks ago

@andreasplesch @brutzman I'm very excited to say that this is achievable. I disabled most of the functionality to make this minimal scene runnable. Yes, it is WebGPU based. https://jsitor.com/yxjz-UVVAf7

andreasplesch commented 3 weeks ago

Very cool, you did it ! It works for me in on Linux in Firefox nightly. I could not get WebGPU in Chrome to work on Linux.

A looked around a bit in the code. A serious deep dive into the gfx rendering and figured how to use WebGPU. For the x3dom.WebGPU classes did you use an existing library or framework as a template ? I found for example

https://pursuit.purescript.org/packages/purescript-webgpu/0.0.0

There are probably many others. https://jmberesford.github.io/webgpu-kit/docs/

I see you adapted the dynamic shader to make it work, more or less directly translating glsl I think.

To be honest, I think the shader generation is not really sustainable the way it is. It may move to #defines et al. and chunks and webgpu may the opportunity to do that. Easier said than done. Ideally, we would want a way to reuse three.js shader chunks, I think. That may mean to also use similar webgpu layout, pipelines and such which may not be feasible.

webgpu is so flexible since lower level than webgl that it may make sense to think more fundamentally about how to map best x3d to webgpu. Is there something which can be moved from the CPU to the GPU ? Porting and trying things may reveal more.

Great progress !

microaaron commented 3 weeks ago

I studied the examples in /webgpu.github.io. Sort out their program flow. Take shadowMapping as an example: shadowMapping I found that matching data in uniform/storage buffers and shader moudles was a tedious and error-prone job. So I wrote a lightweight class myself. (No reference to other frameworks.) The core file is here: https://github.com/microaaron/x3dom/blob/webgpu/src/util/WebGPU/WebGPU.js (it's incompleted yet)

andreasplesch commented 3 weeks ago

Yeah, quite intimidating. Thanks for sharing !

microaaron commented 3 weeks ago

To facilitate portability I wrote this "RenderPassResource" class. https://github.com/microaaron/x3dom/blob/e75c52240d6bfac99f81c17c2d8a904e935b7755/src/util/WebGPU/WebGPU.js#L582 It has similar functions to the previous "shader". It can write data to the corresponding buffer by the variable name. RenderPassResource sp1 sp2 sp3 sp4

microaaron commented 2 weeks ago

Added texture and sampling functionality https://jsitor.com/s4asRDroIR6 Compute shaders are not implemented yet. Webgpu is not difficult for me, but I don't know all the functions of x3dom, and I don't know how the current code works. The porting work is difficult for me to do.

microaaron commented 2 weeks ago

I see you adapted the dynamic shader to make it work, more or less directly translating glsl I think.

To be honest, I think the shader generation is not really sustainable the way it is. It may move to #defines et al. and chunks and webgpu may the opportunity to do that.

Yes, I translated glsl directly. Refactoring some modules is worth considering, but before that I hope to have an architecture diagram for reference.

microaaron commented 2 weeks ago

There's something wrong with the near plane.This may be related to NDC. nearplane nearplane

andreasplesch commented 1 week ago

You probably have seen how znear is automatically calculated if not explicitly provided:

https://github.com/x3dom/x3dom/blob/c5489754e8571fce582978546443c1250b739942/src/nodes/Navigation/Viewpoint.js#L213

Adding

<viewpoint znear='0.1'></viewpoint>

to the example avoids the clipping. So perhaps something is off how znear is automatically calculated or then used.

andreasplesch commented 1 week ago

Maybe it is time again to consider an option for the infinite projection matrix, #1207.

It would be a good default, or a default if only znear is provided and no zfar.

microaaron commented 1 week ago

You probably have seen how znear is automatically calculated if not explicitly provided:

I got it, these two codes need to be modified together.The same code exists in two files. https://github.com/x3dom/x3dom/blob/c5489754e8571fce582978546443c1250b739942/src/nodes/Navigation/Viewpoint.js#L297-L298 https://github.com/x3dom/x3dom/blob/c5489754e8571fce582978546443c1250b739942/src/fields.js#L315-L325

andreasplesch commented 1 week ago

You probably have seen how znear is automatically calculated if not explicitly provided:

I got it, these two codes need to be modified together.The same code exists in two files.

https://github.com/x3dom/x3dom/blob/c5489754e8571fce582978546443c1250b739942/src/nodes/Navigation/Viewpoint.js#L297-L298

This looks like a perhaps unnecessary optimization to avoid having to generate a completely new SFMatrix4f object.

Depending on how often this gets called (probably not every frame), it should be possible to replace it with something like

this._projMatrix = x3dom.fields.SFMatrix4f.perspective ( fovy, aspect, znear, zfar ) ;

https://github.com/x3dom/x3dom/blob/c5489754e8571fce582978546443c1250b739942/src/fields.js#L315-L325

For infinite projection, perhaps it works best to special case in this function far == null (or -2 ?) and then return the infinite projection matrix ?

andreasplesch commented 1 week ago

https://github.com/x3dom/x3dom/commit/28afa5d262d6114d8fef28ecc4e0f56e6fe250d5#diff-8ebd892c2d2e2ade6fcd1b6274ecced42d5bf6a7849fa713a03f611612353064L262

shows when that the recalculation of perspective in Viewpoint was optimized.

microaaron commented 1 week ago

shows when that the recalculation of perspective in Viewpoint was optimized.

This might be better:

//fields.js
x3dom.fields.SFMatrix4f.Perspective = class Perspective extends x3dom.fields.SFMatrix4f
{
    //Normalized device coordinates X:[-1~1] Y:[-1~1] Z:[0~1]
    constructor ( fov, aspect, near, far )
    {
        var f = 1 / Math.tan( fov / 2 );
        if ( far )
        {
            var m_22 = far / ( near - far );
            var m_23 = near * far / ( near - far );
        }
        else //lim far->+∞
        {
            var m_22 = -1;
            var m_23 = -near;
        }
        super(
            f / aspect, 0, 0, 0,
            0, f, 0, 0,
            0, 0, m_22, m_23,
            0, 0, -1, 0
        );
        this.aspect = aspect;
        this.nearDistance = near;
        this.farDistance = far;
    }

    setDistances ( near, far )
    {
        this.nearDistance = near;
        this.farDistance = far;
        if ( far )
        {
            this._22 = far / ( near - far ); this._23 = near * far / ( near - far );
        }
        else //lim far->+∞
        {
            this._22 = -1; this._23 = -near;
        }
    }

    setNearDistance ( near )
    {
        setDistances( near, this.farDistance );
    }

    setFarDistance ( far )
    {
        setDistances( this.nearDistance, far );
    }

    setFieldOfView ( fov )
    {
        var f = 1 / Math.tan( fov / 2 );
        this._00 = f / this.aspect;
        this._11 = f;
    }

    setAspect ( aspect )
    {
        this.aspect = aspect;
        this._00 = this._11 / aspect;
    }
};
//Viewpoint.js
                if ( this._projMatrix == null )
                {
                    this._projMatrix = new x3dom.fields.SFMatrix4f.Perspective( fovy, aspect, znear, zfar );
                }
                else if ( this._zNear != znear || this._zFar != zfar )
                {
                    this._projMatrix.setDistances( znear, zfar );
                }
                else if ( this._lastAspect != aspect )
                {
                    this._projMatrix.setAspect( aspect );
                    this._lastAspect = aspect;
                }
microaaron commented 1 week ago

Textured shapes does not seem to be affected by head light, is this expected?