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

Allow modifying farZ camera plane variable #5091

Open
kamil-sienkiewicz-asi opened this issue Nov 21, 2024 · 4 comments
Open

Allow modifying farZ camera plane variable #5091

kamil-sienkiewicz-asi opened this issue Nov 21, 2024 · 4 comments
Labels
enhancement New feature or request need more info Further information is requested

Comments

@kamil-sienkiewicz-asi
Copy link

User Story

I want to add a simple skybox to globe view, instead of black screen behind it I want to add some stars etc. However,

globe_transform.ts

628 this._farZ = this.cameraToCenterDistance + globeRadiusPixels * 2.0; // just set the far plane far enough - we will calculate our own z in the vertex shader anyway

does not let me render things behind the globe:
Image

I tried to modify projection matrix to change farZ value, however with no luck, changing 10th and 14th elements of the projection matrix were messing up rendering, also I'm not sure if having different projection matrices in one "scene" makes sense, I'm concerned about some unpredictable issues by such approach.
Image

  render(gl: WebGL2RenderingContext, options: CustomRenderMethodInput): void {
    const {
      nearZ,
      farZ,
      projectionMatrix,
      defaultProjectionData: { mainMatrix },
    } = options;

    const projMatrix = new Matrix4().fromArray(projectionMatrix);
    const modelViewProjMatrix = new Matrix4().fromArray(mainMatrix);
    const projMatrixInverse = new Matrix4().copy(projMatrix).invert();
    const modelViewMatrix = new Matrix4().multiplyMatrices(modelViewProjMatrix, projMatrixInverse);
    const newProjMatrix = new Matrix4().copy(projMatrix);
    const n = nearZ;
    const f = farZ * 4.0; // editing this messes up scene
    newProjMatrix.elements[10] = -(f + n) / (f - n);
    newProjMatrix.elements[14] = (-2 * f * n) / (f - n);
    this.camera.projectionMatrix = modelViewMatrix.multiply(newProjMatrix);

after modifying farZ value, by simply multiplying it by 5.0, scene is looking as expected:
Image

So in the end it seems like I would like to keep same projection matrix as maplibre uses, but I want to be able to modify and extend far plane of the camera, to render skybox/rockets/moon/satellites etc.

@HarelM
Copy link
Collaborator

HarelM commented Nov 21, 2024

I think i have the same concerns as I had for the following PR:
#4914

I'm not sure this world be the right API to expose.
Is there a different way this can be solved?

@bartosz-banachewicz-asi
Copy link

bartosz-banachewicz-asi commented Nov 22, 2024

@HarelM Yes, by setting the default value to a less conservative one. (cc @kubapelc)

The depth buffer is a resource shared by everything rendering to the same frame in WebGL. In order to do any sort of 3D compositing, there needs to be a sufficient range of values usable to make everything fit. The way the current farZ is computed for the globe means that the sphere itself occupies virtually everything, spanning all possible depth values. Increasing this value by a factor of 2-5 would similarly increase the amount of "space" in the Z coordinate for skyboxes and objects in space or on orbits.

Other solutions to this issue that we've thought about/evaluated all seem to have significant complexity and downsides in comparison:

  • clamping the Z value of things behind the globe to 1.0 results in unpredictable artifacts
  • rendering the scene in specific order with depth testing bypassed enables much more complicated and fragile setup

There are no significant downsides to setting the value to something like 4x the current one, other than 2 bits of precision in the depth testing lost in the range used by the sphere; however considering it's mostly a single mesh that gets back-culled anyway, I don't think it would be problematic for any other user. If there's concern about that, rather than exposing farZ directly, having two predefined values ("narrow" and "wide", for example) would both solve our issues in an elegant way and hopefully prevent API misuse.

@HarelM
Copy link
Collaborator

HarelM commented Nov 23, 2024

As far as I read the code right now, and according to what you described there might be an "easy" solution, let me know if that can work.
Currently, farZ is multiplied by a factor of 1.01. this is hard coded and I don't like hard coded stuff.
The default should be kept at 1.01.
Will allowing this to be configured when creating the map object solve your problem?

@HarelM HarelM added enhancement New feature or request need more info Further information is requested labels Nov 23, 2024
@kubapelc
Copy link
Collaborator

My thoughts: Fixing this by multiplying farZ by some hardcoded constant is not great, since other users might have need for even larger farZ values in the future - it should be configurable. Also, I think making a public property on the transform interface (map.transform.farZ or something similar) could be the solution, since it would make it configurable by the user, but also keep it a bit out of sight, compared to placing it in the map constructor - most maps should not change this value. If a user is making a custom layer complex enough to need the Z buffer, they already need to interact with the transform directly anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request need more info Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants