Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
microaaron opened this issue May 3, 2023 · 18 comments
Open

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

microaaron opened this issue May 3, 2023 · 18 comments

Comments

@microaaron
Copy link
Contributor

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

@andreasplesch
Copy link
Contributor

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

@brutzman
Copy link

brutzman commented Jul 14, 2023

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
Copy link
Contributor

andreasplesch commented Jul 15, 2023

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
Copy link
Contributor Author

microaaron commented Apr 26, 2024

@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
Copy link
Contributor

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
Copy link
Contributor Author

microaaron commented Apr 26, 2024

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
Copy link
Contributor

Yeah, quite intimidating. Thanks for sharing !

@microaaron
Copy link
Contributor Author

microaaron commented Apr 26, 2024

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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

@andreasplesch
Copy link
Contributor

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

getProjectionMatrix : function ( aspect )

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
Copy link
Contributor

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
Copy link
Contributor Author

microaaron commented May 7, 2024

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.

this._projMatrix._22 = ( znear + zfar ) / div;
this._projMatrix._23 = 2 * znear * zfar / div;

x3dom/src/fields.js

Lines 315 to 325 in c548975

x3dom.fields.SFMatrix4f.perspective = function ( fov, aspect, near, far )
{
var f = 1 / Math.tan( fov / 2 );
return new x3dom.fields.SFMatrix4f(
f / aspect, 0, 0, 0,
0, f, 0, 0,
0, 0, ( near + far ) / ( near - far ), 2 * near * far / ( near - far ),
0, 0, -1, 0
);
};

@andreasplesch
Copy link
Contributor

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.

this._projMatrix._22 = ( znear + zfar ) / div;
this._projMatrix._23 = 2 * znear * zfar / div;

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 ) ;

x3dom/src/fields.js

Lines 315 to 325 in c548975

x3dom.fields.SFMatrix4f.perspective = function ( fov, aspect, near, far )
{
var f = 1 / Math.tan( fov / 2 );
return new x3dom.fields.SFMatrix4f(
f / aspect, 0, 0, 0,
0, f, 0, 0,
0, 0, ( near + far ) / ( near - far ), 2 * near * far / ( near - far ),
0, 0, -1, 0
);
};

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
Copy link
Contributor

28afa5d#diff-8ebd892c2d2e2ade6fcd1b6274ecced42d5bf6a7849fa713a03f611612353064L262

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

@microaaron
Copy link
Contributor Author

microaaron commented May 8, 2024

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
Copy link
Contributor Author

microaaron commented May 9, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants