visgl / deck.gl

WebGL2 powered visualization framework
https://deck.gl
MIT License
12.29k stars 2.09k forks source link

Mesh model reversed in globe view #7362

Open ondave opened 2 years ago

ondave commented 2 years ago

Description

When using a SimpleMeshLayer, the orientation angle of a mesh model is reversed when in GlobeView.

Mapview

Screenshot from 2022-10-28 17-04-26

Globeview

Screenshot from 2022-10-28 17-04-12

Flavors

Expected Behavior

The same rendered angle in both views

Steps to Reproduce

import React, { useState } from "react";
import DeckGL from "@deck.gl/react";
import { BitmapLayer } from "@deck.gl/layers";
import { TileLayer } from "@deck.gl/geo-layers";
import { MapView, _GlobeView as GlobeView } from "@deck.gl/core";
import { SimpleMeshLayer } from "@deck.gl/mesh-layers";
import { ConeGeometry } from "@luma.gl/core";

// Viewport settings
const INITIAL_VIEW_STATE = {
  longitude: 0,
  latitude: 0,
  zoom: 5,
  pitch: 0,
  bearing: 0
};

const mapview = {
  map: new MapView({ id: "mapview", controller: true }),
  globe: new GlobeView({ id: "globe", controller: true })
};

const baselayer = new TileLayer({
  // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers
  data: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",

  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,

  renderSubLayers: (props) => {
    const {
      bbox: { west, south, east, north }
    } = props.tile;

    return new BitmapLayer(props, {
      data: null,
      image: props.data,
      bounds: [west, south, east, north]
    });
  }
});

const meshlayer = new SimpleMeshLayer({
  id: "mesh-layer",
  sizeScale: 100000,
  data: [{ position: [0, 0, 10000], angle: [0, 90, 0], color: [0, 0, 0] }],
  mesh: new ConeGeometry(),
  getPosition: (d) => d.position,
  getColor: (d) => d.color,
  getOrientation: (d) => d.angle
});

const layers = [baselayer, meshlayer];

export const App = () => {
  const [view, setView] = useState("map");
  const toggleView = (e) => {
    setView(view === "map" ? "globe" : "map");
  };
  return (
    <DeckGL
      initialViewState={INITIAL_VIEW_STATE}
      controller={true}
      layers={layers}
      views={mapview[view]}
    >
      <button onClick={toggleView}>Toggle view</button>
    </DeckGL>
  );
};

Environment

Logs

No response

felixpalmer commented 1 year ago

The angle is not reversed, it is offset by 180 degrees. If the following data is used it is easier to see what is happening.

[
  {position: [0, 1, 100000], angle: [0, 0, 0], color: [255, 0, 0]},
  {position: [-1, 0, 100000], angle: [0, 90, 0], color: [0, 255, 0]},
  {position: [0, 0, 100000], angle: [0, 0, 90], color: [0, 0, 255]}
];

MapView

Screenshot 2022-12-01 at 13 03 10

GlobeView

Screenshot 2022-12-01 at 13 03 21

My theory as to why this is happening is due to a different coordinate handedness between the coordinate systems. It is possible to fix this by shifting the yaw (angle[1]) angle by 180 degrees.

Due to the way the transform matrix is constructed (and trig identities) it is possible to apply this shift as a modification to the modelMatrix in the vertex shader:

mat3 modelMatrix = instanceModelMatrix;
  if (project_uProjectionMode == PROJECTION_MODE_GLOBE) {
    // Globe mode uses opposite handedness, need to shift yaw by 180 to compensate
    const vec3 yawShift = vec3(-1.0, -1.0, 1.0);
    modelMatrix[0] *= yawShift;
    modelMatrix[1] *= yawShift;
    modelMatrix[2] *= yawShift;
}

@Pessimistress what do think of this approach?