Git Product home page Git Product logo

js-three's Introduction

Google Maps ThreeJS Overlay View and Utilities

npm Build Release codecov GitHub contributors semantic-release Discord

Description

Add three.js objects to Google Maps Platform JS. The library provides a ThreeJSOverlayView class extending google.maps.WebGLOverlayView and utility functions for converting geo-coordinates (latitude/longitude) to vectors in the coordinate system used by three.js.

Install

Available via npm as the package @googlemaps/three.

npm i @googlemaps/three

Alternatively you can load the package directly to the html document using unpkg or other CDNs. In this case, make sure to load three.js before loading this library:

<script src="https://unpkg.com/three/build/three.min.js"></script>
<script src="https://unpkg.com/@googlemaps/three/dist/index.min.js"></script>

When adding via unpkg, the package can be accessed as google.maps.plugins.three. A version can be specified by using https://unpkg.com/@googlemaps/three@VERSION/dist/....

The third option to use it is via ES-Module imports, similar to how the three.js examples work. For this, you first need to specify an importmap (example using unpkg.com, but it works the same way with any other CDN or self-hosted files):

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three/build/three.module.js",
      "@googlemaps/three": "https://unpkg.com/@googlemaps/three/dist/index.esm.js"
    }
  }
</script>

In order to support browsers that don't yet implement importmap, you can use the es-module-shims package.

After that, you can use three.js and the ThreeJSOverlayView like you would when using a bundler.

<script type="module">
  import * as THREE from "three";
  import { ThreeJSOverlayView } from "@googlemaps/three";

  // ...
</script>

Documentation

Checkout the reference documentation.

Coordinates, Projection and Anchor-Points

The coordinate system within the three.js scene (so-called 'world coordinates') is a right-handed coordinate system in z-up orientation. The y-axis is pointing true north, and the x-axis is pointing east. The units are meters. So the point new Vector3(0, 50, 10) is 10 meters above ground and 50 meters east of the specified anchor point.

This anchor-point and orientation can be set in the constructor, or by using the setAnchor() and setUpAxis()-methods (be aware that all object-positions in your scene depend on the anchor-point and orientation, so they have to be recomputed when either of them is changed):

import { ThreeJSOverlayView } from "@googlemaps/three";

const overlay = new ThreeJSOverlayView({
  anchor: { lat: 37.7793, lng: -122.4192, altitude: 0 },
  upAxis: "Y",
});

overlay.setAnchor({ lat: 35.680432, lng: 139.769013, altitude: 0 });
overlay.setUpAxis("Z");
// can also be specified as Vector3:
overlay.setUpAxis(new Vector3(0, 0, 1));

The default up-axis used in this library is the z-axis (+x is east and +y is north), which is different from the y-up orientation normally used in three.

All computations on the GPU related to the position use float32 numbers, which limits the possible precision to about 7 decimal digits. Because of this, we cannot use a global reference system and still have the precision to show details in the meters to centimeters range.

This is where the anchor point is important. The anchor specifies the geo-coordinates (lat/lng/altitude) where the origin of the world-space coordinate system is, and you should always define it close to where the objects are placed in the scene - unless of course you are only working with large-scale (city-sized) objects distributed globally.

Another reason why setting the anchor close to the objects in the scene is generally a good idea: In the mercator map-projection used in Google Maps, the scaling of meters is only accurate in regions close to the equator. This can be compensated for by applying a scale factor that depends on the latitude of the anchor. This scale factor is factored into the coordinate calculations in WebGlOverlayView based on the latitude of the anchor.

Converting coordinates

When you need more than just a single georeferenced object in your scene, you need to compute the world-space position for those coordinates. The ThreeJSOverlayView class provides a helper function for this conversion that takes the current anchor and upAxis into account:

const coordinates = { lat: 12.34, lng: 56.78 };
const position: Vector3 = overlay.latLngAltitudeToVector3(coordinates);

// alternative: pass the Vector3 to write the position
// to as the second parameter, so to set the position of a mesh:
overlay.latLngAltitudeToVector3(coordinates, mesh.position);

Raycasting and Interactions

If you want to add interactivity to any three.js content, you typically have to implement raycasting. We took care of that for you, and the ThreeJSOverlayView provides a method overlay.raycast() for this. To make use of it, you first have to keep track of mouse movements on the map:

import { Vector2 } from "three";

// ...

const mapDiv = map.getDiv();
const mousePosition = new Vector2();

map.addListener("mousemove", (ev) => {
  const { domEvent } = ev;
  const { left, top, width, height } = mapDiv.getBoundingClientRect();

  const x = domEvent.clientX - left;
  const y = domEvent.clientY - top;

  mousePosition.x = 2 * (x / width) - 1;
  mousePosition.y = 1 - 2 * (y / height);

  // since the actual raycasting is performed when the next frame is
  // rendered, we have to make sure that it will be called for the next frame.
  overlay.requestRedraw();
});

With the mouse position being always up to date, you can then use the raycast() function in the onBeforeDraw callback. In this example, we change the color of the object under the cursor:

const DEFAULT_COLOR = 0xffffff;
const HIGHLIGHT_COLOR = 0xff0000;

let highlightedObject = null;

overlay.onBeforeDraw = () => {
  const intersections = overlay.raycast(mousePosition);
  if (highlightedObject) {
    highlightedObject.material.color.setHex(DEFAULT_COLOR);
  }

  if (intersections.length === 0) return;

  highlightedObject = intersections[0].object;
  highlightedObject.material.color.setHex(HIGHLIGHT_COLOR);
};

The full examples can be found in ./examples/raycasting.ts.

Example

The following example provides a skeleton for adding objects to the map with this library.

import * as THREE from "three";
import { ThreeJSOverlayView, latLngToVector3 } from "@googlemaps/three";

// when loading via UMD, remove the imports and use this instead:
// const { ThreeJSOverlayView, latLngToVector3 } = google.maps.plugins.three;

const map = new google.maps.Map(document.getElementById("map"), mapOptions);
const overlay = new ThreeJSOverlayView({
  map,
  upAxis: "Y",
  anchor: mapOptions.center,
});

// create a box mesh
const box = new THREE.Mesh(
  new THREE.BoxGeometry(10, 50, 10),
  new THREE.MeshMatcapMaterial()
);
// move the box up so the origin of the box is at the bottom
box.geometry.translateY(25);

// set position at center of map
box.position.copy(overlay.latLngAltitudeToVector3(mapOptions.center));

// add box mesh to the scene
overlay.scene.add(box);

// rotate the box using requestAnimationFrame
const animate = () => {
  box.rotateY(THREE.MathUtils.degToRad(0.1));

  requestAnimationFrame(animate);
};

// start animation loop
requestAnimationFrame(animate);

This adds a box to the map.

threejs box on map

Demos

View the package in action:

js-three's People

Contributors

amuramoto avatar dependabot[bot] avatar googlemaps-bot avatar jpoehnelt avatar semantic-release-bot avatar squishyu avatar usefulthink avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-three's Issues

Replace handling of three.js dependency with peerDependencies

The way the three.js dependencies are currently implemented is to pass an object with the three.js constructors and functions needed inside the library as a parameter to the constructor.

This isn't Ideal since it exposes implementation details to the user and requires users to update their code when new features or even bugfixes are added that use new or different classes from the three.js library. This would unnecessarily make a lot of changes breaking changes.

Instead, the same behaviour can be implemented using package peerDependencies without putting too much burden on users.

In the library code, three.js objects are imported as usual using the ESM syntax with the three module alias:

import {PerspectiveCamera, Scene, WebGlRenderer} from 'three'; 

The three-module referenced here isn't installed by @googlemaps/three, but has to be provided by the user and npm will check that a compatible version of three.js is used when installing.

The way this works in production is like this:

  • users building their apps using a bundler will be just fine, the import is resolved to the user-installed version of three.js
  • when using the UMD / ES5 build (via a script-tag from a CDN for example), users have to expose the three.js library via the global THREE object (which is the default when loading three.js via UMD)
  • when using the ESM build (e.g. a <script type="module"> in html), users have to add an importmap to specify the url for the three module alias used in the library

As reference, here is another Addon for three.js that uses the exact same method described here (only that it is using microbundle instead of rollup): https://github.com/donmccurdy/three-pathfinding

Virtual Camera

The problem

When i was trying to add the Transformation Controls from the Three.js utils and attach it to a 3D object i stumbled upon some issues.

Attaching the TransformationControls to the 3D Object works fine, i can see the Controls and the position and axis is correct after the latest major update to the package. However.. interacting with the TransformationControls does not work. Nothing happens when clicking/dragging the controls.

When dragging the controls it should translate the objects position on the map.
This currently doesnt work due to how the current camera is positioned.

Feature request

After discussing this with Martin we concluded that the solution to this issue would be to add a virtual camera, that "sees" the same as the actual maps viewport sees. Then that virual camera can be passed to the TransformControls and then the internal raycaster of the Transform Controls should work as intended.

There are more use cases for adding a virtual camera that "sees" the same as the actual maps viewport.
Here is a list of some that i can come up with:

Usecases

  • Ability to frustum cull objects outside of the cameras viewport. (A Very great performance improvement, that will allow building a significantly larger 3D world with higher frame rates.)
  • Ability to perform Animations on objects when they enter or leave the Viewport.
  • Ability to trigger any type of function or world event when the a specific object enter / leaves Viewport.
  • Ability to use object.lookAt(virtualCamera.position) which itself has alot of use cases, such as letting floating player names and texts always focus on the virtual camera no matter which rotation, tilt or zoom is being used.
  • Ability to use the controls that Three.js has such as TransformationControls, there are many of them.

Here is a suggested calculation for setting the position of the Virtual Camera on each frame update.
It Almost works, there is one small factor missing but i could really use your guys help to figure out what piece of the puzzle is missing.


function updateVCam() {
    if (!_camera || !_scene || !_renderer)
      return;

    _vCamMvpMatrix.copy(_camera.projectionMatrix)
    _vCamInverseMvpMatrix.copy(_vCamMvpMatrix).invert()

    _v4.set(0, 0, 1, 0)
    _v4.applyMatrix4(_vCamInverseMvpMatrix)
    _v4.multiplyScalar(1 / _v4.w)
    const cameraPosition = new Vector3()
    cameraPosition.set(_v4.x / _v4.w, _v4.y / _v4.w, _v4.z / _v4.w)

    const c = new Vector3(0, 0, 0).applyMatrix4(_vCamInverseMvpMatrix)
    const x = new Vector3(1, 0, 0).applyMatrix4(_vCamInverseMvpMatrix).sub(c).normalize()
    const y = new Vector3(0, 1, 0).applyMatrix4(_vCamInverseMvpMatrix).sub(c).normalize()
    const z = new Vector3(0, 0, -1).applyMatrix4(_vCamInverseMvpMatrix).sub(c).normalize()

    const near = new Vector3(0, 0, -1).applyMatrix4(_vCamInverseMvpMatrix).sub(cameraPosition).length()
    const far = new Vector3(0, 0, 1).applyMatrix4(_vCamInverseMvpMatrix).sub(cameraPosition).length()

    _m4.makeBasis(x, y, z)

    _vCam.position.copy(cameraPosition)
    _vCam.quaternion.setFromRotationMatrix(_m4)
    _vCam.updateMatrixWorld()

    _vCam.matrixWorldInverse.copy(_vCam.matrixWorld).invert()

    const projectionMatrix = new Matrix4().multiplyMatrices(_vCamMvpMatrix, _vCam.matrixWorldInverse)

    const fov = (2 * Math.atan(1 / projectionMatrix.elements[5]) * 180) / Math.PI
    const aspectRatio = projectionMatrix.elements[5] / projectionMatrix.elements[0]

    _vCam.fov = fov
    _vCam.aspect = aspectRatio
    _vCam.near = near
    _vCam.far = far

    _vCam.updateProjectionMatrix()

    _renderer.render(_scene, _camera)
    _renderer.resetState()
  }

Export types in package.json


Is your feature request related to a problem? Please describe.

When installing @googlemaps/three and importing with typescript via import { ThreeJSOverlayView } from '@googlemaps/three';
I get an error Could not find a declaration file for module '@googlemaps/three'. '.../google-maps-webgl/node_modules/@googlemaps/three/dist/index.esm.js' implicitly has an 'any' type. There are types at '.../google-maps-webgl/node_modules/@googlemaps/three/dist/index.d.ts', but this result could not be resolved when respecting package.json "exports". The '@googlemaps/three' library may need to update its package.json or typings.

Describe the solution you'd like
Export the dist/index.d.ts as well.

package.json before:

  "main": "dist/index.umd.js",
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.umd.js",
      "umd": "./dist/index.umd.js",
      "browser": "./dist/index.esm.js",
    }
  },
  "unpkg": "dist/index.min.js",

package.json after:

  "main": "dist/index.umd.js",
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.umd.js",
      "umd": "./dist/index.umd.js",
      "browser": "./dist/index.esm.js",
      "types": "./dist/index.d.ts"
    }
  },
  "unpkg": "dist/index.min.js",

Describe alternatives you've considered
Making that change manually by editing the dependency inside my node_modules folder.

Rendering on demand

i want to render scene only when things changed. I have tried extending the onDraw() function like this but the scene only gets rendered for a few frames and then disappers.

` onDraw(
gl: WebGLRenderingContext,
transformer: google.maps.CoordinateTransformer
): void {
const { lat, lng, altitude } = this.anchor;

this.camera.projectionMatrix.fromArray(
  transformer.fromLatLngAltitude(
    { lat, lng },
    altitude,
    this.rotation,
    this.scale
  )
);
if(!this.camera.projectionMatrix.equals(this.oldCameraMatrix)){
  this.oldCameraMatrix.copy(this.camera.projectionMatrix);
  this.canRender=true;
  console.warn("cameraprojectionmatrix changed");
}
else{
  this.canRender=false;
}
gl.disable(gl.SCISSOR_TEST);

console.log("Render loop");

this.requestRedraw();
if(this.canRender){
 
  console.log("Rendering on demand");
  
  this.renderer.render(this.scene, this.camera);
  this.protectedBox.position.y+=0.01;
  this.canRender=false;




  }
   // reset state using renderer.resetState() and not renderer.state.reset()
  this.renderer.resetState();

}
renderOndemand(){
this.requestRedraw();
//this.renderer.render(this.scene, this.camera);
this.canRender=true;

}
}`

Combining with google.maps.Polygon

When I combined the use of ThreeJSOverlayView, just following the basic tutorials, it appears like the Overlay that google.maps.Polygon is drawn is messed with.

You can see the overlay does not follow the map
2021-09-16 02 46 34

and the code to add the gltf is the example:

const scene = new Scene();
      const ambientLight = new AmbientLight(0xffffff, 0.75);

      scene.add(ambientLight);

      const directionalLight = new DirectionalLight(0xffffff, 0.25);

      directionalLight.position.set(0, 10, 50);
      scene.add(directionalLight);

      const center = map.getCenter();
      if (!center) return;
      new ThreeJSOverlayView({
        map,
        scene,
      });

      const loader = new GLTFLoader();
      const url =
        "https://raw.githubusercontent.com/googlemaps/js-samples/master/assets/pin.gltf";

      loader.load(url, (gltf) => {
        gltf.scene.scale.set(100, 100, 100);
        gltf.scene.position.copy(
          latLngToVector3({ lat: 55.6832338, lng: 12.5819998 })
        );
        gltf.scene.position.setY(500);
        gltf.scene.rotation.x = Math.PI / 2;
        scene.add(gltf.scene);
        console.log(gltf);
      });

If new ThreeJSOverlayView({ map, scene, }); is commented out, then the problem disappears

2021-09-16 02 48 56

The code to draw the polygons are just this

const path = new google.maps.Polygon({
        paths: line,
        geodesic: true,
        strokeColor: color,
        strokeOpacity: 1.0,
        strokeWeight: 2,
        fillColor: color,
        fillOpacity: 0.1,
      });
      path.setMap(map);

and the map is initialized with mapid
{ zoom: 12, mapId: mapid, heading: 0, tilt: 45 } and this script https://maps.googleapis.com/maps/api/js?key=${apiKey}&v=beta&callback=initMap;

and important detail is also, if I remove all old new google.maps.Polygon, then the ThreeJSOverlayView works great.

2021-09-16 02 56 04

Error after update Three dependency: export 'sRGBEncoding' (imported as 'c') was not found in 'three'

Using the latest version of @googlemaps/three: 4.0.11
After updating "three" dependency to latest (0.164.0 at time of writing). We are seeing below error when bundling our application:

./node_modules/@googlemaps/three/dist/index.esm.js:112:196-197 - Error: export 'sRGBEncoding' (imported as 'c') was not found in 'three' (possible exports: ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderChunk, ShaderLib, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, createCanvasElement)

Seems like Three deprecated it with v152. See this Migration Guide: https://github.com/mrdoob/three.js/wiki/Migration-Guide#151--152

THREE.sRGBEncoding is now THREE.SRGBColorSpace

I notice in code this is kept in place for backwards compatibility:

if (Number(REVISION) < 152) this.renderer.outputEncoding = sRGBEncoding;

But the export is no longer available with latest Three version, so unable to update at the moment.

Could this backwards compatibility be removed or is there an other work-around?

Access to renderer

I wanted to access the overlay's renderer so I can apply post processing to the map.

Is there a way to access the renderer, currently it returns null?

@googlemaps/js-three latLngToVector3 inconsistent on different hemispheres

I've noticed inconsistencies with the latLngToVector3 function based on which hemisphere the coordinates are on. Manipulating the Threejs Scene rotation seems to fix this issue, but I was just wondering if this is expected behavior or not?

Steps to reproduce / Code example

In this code example I placed a sphere at the coordinates of NYC and the coordinates of Sydney, Australia. As you can see in the example the sphere for Australia lands on Sydney just fine but the sphere for NY ends up in the middle of the ocean. To fix this you need to add a negative sign to scene.rotation.x and add the line scene.rotation.z = Math.PI. Unfortunately this makes it so that the Australian sphere is no longer in the correct location. In my code I simply have an if statement that changes these parameters depending on the latitude and longitude, but I'm worried that there may be other inconsistencies that I haven't run into just yet.

https://codesandbox.io/s/vibrant-flower-z9tyt?file=/src/index.ts

Please let me know if you need anymore details!

Usage with React Three fiber

Usage with React Three fiber.

I've been using the googlemaps/three library for integrating Three.js with Google Maps, and it has been a valuable tool for my projects. However, I've recently been working on a project where I'd like to use React Three Fiber alongside Google Maps and googlemaps/three. Currently, the library doesn't provide direct support for React Three Fiber integration, making it challenging to achieve the desired functionality.

I would like to request an enhancement to the googlemaps/three library that extends support for usage with React Three Fiber. This enhancement could involve providing documentation, examples, or code updates that facilitate the seamless integration of React Three Fiber with Google Maps through the googlemaps/three library.

I also believe that

  • Support for React Three Fiber would make the googlemaps/three library even more versatile and attractive to developers.
  • Providing examples and documentation for React Three Fiber integration would greatly benefit the developer community.

Thank you for considering this feature request. I believe that extending support for React Three Fiber in the googlemaps/three library would enhance the usability and versatility of the library, and I look forward to its potential implementation.

Objects noticeably jitter / anchor issue

While using @googlemaps/three I've noticed that 3D objects rendered onto the map using ThreeJSOverlayView jitter.
https://drive.google.com/file/d/1uacSEtHdXIxr5tLRQtKwhRqog6vY_w5T/view?usp=sharing
Apparently this is related to the fact that the objects and the camera are too far from the world's origin. So when the vertices' positions are computed by the shader there's not enough fp precision (see src/fp-precision directory in the linked repo).
So I tried moving the world's origin closer to the camera for which the anchor property of ThreeJSOverlayView exists it seems. And indeed the jittering of the objects in this case is not observed (see src/rel-coords directory in the linked repo). However the coordinates (computed using latLngToVector3Relative) at which the objects are rendered are way off (except for the object which is located exactly at the anchor's position). Compare positions of red boxes which are not in the initial center in fp-precision and rel-coords in the linked repo.
So how to go about these issues?

Environment details

Windows 10 x64, Chrome (latest)

Steps to reproduce

Just clone the repo linked below and follow the README.

Code example

Here's the repo with the described issues:
https://github.com/MadOPcode/googlemaps-threejsoverlayview-issues

The automated release is failing 🚨

🚨 The automated release from the main branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this 💪.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the main branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://wombat-dressing-room.appspot.com.


Good luck with your project ✨

Your semantic-release bot 📦🚀

Polygons and MapMarkers are overlapping differently on Apple Safari

google.maps.version
'3.46.6-beta'

You can see the MapMarker, the polyline can be seen through it on safari, even on the part that is not transparent.

Now that I am writing this ticket, I have to verify that it is not the SVG handling in the browser that is causing the problem.

I will create a small POC.

Chrome:
image

Safari on Mac, and Safari on iPad OS:
image

Renderer does not clip all objects outside of viewport

Objects that are added to the scene of the WebGLOverlay are being rendered by the renderer even when the objects are outside of the current viewport.
This has very bad effect on the performance of the map when having objects scattered all over the world. The renderer should not do any drawcalls to objects outside of the viewport.
Currently objects are being clipped between zoomlevel 1-4 but not between zoomlevel 4-22.

For example: Half of the maps worldspace are always being rendered even if on zoomLevel 22.

Environment details

Chrome @latest
"@googlemaps/three": "^3.0.3",
Node 16.15.0

Steps to reproduce

  1. Clone repo from https://github.com/crunchwrap89/googlemaps-three-frustumculling
  2. follow instructions in the readme.md

Code example

see repo above and read readme.md

Anti-aliasing: Enable Access to Renderer

I want access to the renderer so that I can enable antialiasing and other options that can be passed to THREE.WebGLRenderer

renderer = new THREE.WebGLRenderer( { antialias: true} );

this resource mentions that "WebGL resources can not be shared across contexts", which will force us to upload assets twice if we want to clone the scene to another canvas. However, if we have access to the renderer, we can use the workaround mentioned on the linked resource.

Converting coordinates (Vector3 to latlngAltitude)

Hello,

I've noticed that the library provides support for converting from latitude, longitude, and altitude (latLngAltitude) to vector3 coordinates. However, I'm unable to figure out how to convert from vector3 coordinates to a latLng literal. Is this something that is planned for the future roadmap? I did see a pull request mentioning this (#618), but it seems that the pull request has been closed.

It would be a great help if you could provide an update on this matter.

Thanks.

Manipulate tiles

It would be super cool to be able to access the 3d tiles on the map and manipulate them on runtime.
That would be a complete game changer.

Some things I would do if that feature was available:

  • Add a physics engine such as ammo.js so 3d objects cannot pass through buildings.
  • Animate the buildings in sync with music.
  • Add shadows to the buildings
  • Add Elevation to the map to create hills and valleys and adjust the elevation for the 3d tiles accordingly.

Render with WebGPURenderer

WebGPU is now generally available in newer versions of chrome and firefox and is also supported with Three.js with a new renderer ( WebGPURenderer ).
It would be great if we could make use of this in the WebGLOverlayView, or perhaps a new WebGPUOverlayView (?).

We could drastically improve the performance when rendering complex 3d scenes on the map. <3

I guess this is something that needs to be developed within the google maps js api as well?.
I am curious to hear if its already being worked on and when it might be publicly available? :)

Enable casting Shadows

I want to cast shadows of objects on the map (ground) and on other objects in the threejs scene.

in the meantime, is there any workaround to cast/receive shadows?

@googlemaps/js-three accept a reference to three module rather than importing it directly?

I was really excited to see this library pop up but I'm struggling a bit to use it in my vue-cli project.

The first issue I had was syncing up the version of three from my project with that of @googlemaps/js-three. Three is a very large import and given that @googlemaps/js-three usage of Three is actually very light, I was wondering if it might make more sense for ThreeJSOverlayView to accept Three as a parameter, or maybe modify the library to have more of a factory workflow? My vue-cli tools don't optimize out the second instance of Three until I run it in production mode.

The second issue I'm seeing is some sort of memory leak or stack overflow with respect to requestRedraw/requestAnimationFrame in webgl.js. I'm gonna keep investigating on that to see if it's related to my usage, but I make no calls to requestAnimationFrame yet. Just wanted to mention it in passing in case others were experiencing it.

Also setMap(null) doesn't clean out the scene. User has a sort of dangling reference to the scene after doing that. Just something to be aware of. Who owns the 'scene' being passed around and modified?

I was also having troubles placing objects at specific latlngs but the prior issues may have played into that.

Thanks for stopping by to let us know something could be better!


PLEASE READ

If you have a support contract with Google, please create an issue in the support console. This will ensure a timely response.

Discover additional support services for the Google Maps Platform, including developer communities, technical guidance, and expert support at the Google Maps Platform support resources page.

If your bug or feature request is not related to this particular library, please visit the Google Maps Platform issue trackers.

Check for answers on StackOverflow with the google-maps tag.


Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

What projection is used for the ThreeJS coordinate system?

Hello,
I'm currently struggling with placing a few geometries and I can't quite figure out the coordinate system used.

Although the comment https://github.com/googlemaps/js-three/blob/main/src/util.ts#L89-L96
states that it is (WebMercator (EPSG:3857) --> WGS84) I get different result when I put a coordinate into epsg.io:
https://epsg.io/transform#s_srs=3857&t_srs=4326&x=1820541.7625204&y=6134799.8559301
vs.
xyToLatLng([ 1820541.7625204194 , 6134799.8559301235 ]) -> { lat: 48.20880202465933 , lng: 16.372499716642768 }

epsg.io: 48.1677013 16.354205
xyToLL : 48.2088020 16.372499

It would be really great if you could help me!
Thank you!

Default lighting

It would be beneficial to have the parameters for lighting to match the lighting used internally. A helper function could apply this lighting to the scen and a flag could enable/disable default lighting.

Request documentation

Hi,
I am making use of (almost) all functions in this repo for a metaverse game engine i am building. But I am curious about what these functions do and what use cases i could or should use them for.

Could you perhaps update the documentation for these or maybe provide some additional info about them here?

/**
   * Binds a View to a Model.
   */
  public bindTo(
    key: string,
    target: google.maps.MVCObject,
    targetKey?: string,
    noNotify?: boolean
  ): void {
    this.overlay.bindTo(key, target, targetKey, noNotify);
  }

  /**
   * Gets a value.
   */
  public get(key: string) {
    return this.overlay.get(key);
  }

  /**
   * Notify all observers of a change on this property. This notifies both
   * objects that are bound to the object's property as well as the object
   * that it is bound to.
   */
  public notify(key: string): void {
    this.overlay.notify(key);
  }

  /**
   * Sets a value.
   */
  public set(key: string, value: unknown): void {
    this.overlay.set(key, value);
  }

  /**
   * Sets a collection of key-value pairs.
   */
  public setValues(values?: object): void {
    this.overlay.setValues(values);
  }

  /**
   * Removes a binding. Unbinding will set the unbound property to the current
   * value. The object will not be notified, as the value has not changed.
   */
  public unbind(key: string): void {
    this.overlay.unbind(key);
  }

  /**
   * Removes all bindings.
   */
  public unbindAll(): void {
    this.overlay.unbindAll();
  }

Implement floating anchors

This is a follow-up to #618.

Is your feature request related to a problem? Please describe.

When handling globally distributed 3d-objects in a single overlay, one of the problems is that a single anchor-point isn't enough to maintain acceptable precision in all locations.

Describe the solution you'd like

To solve this, we could add a feature I would call "floating anchor". With this, users would provide the geo-reference of an object in a property object.userData.geoPosition (see three.js documentation) and the overlay would automatically calculate the anchored world-space position for those geo-coordinates.

The anchor-point could then be automatically updated from map-movement. With every update, the scene is traversed and world-space coordinates are recomputed from the specified geo-reference.

Unable to extend ThreeJSOverlayView

I am trying to extend the class like this:

let threeOverlay=new CustomeOverlay({ map, scene, anchor: { ...mapOptions.center, altitude: 0 }, });

export class CustomeThreeOverlay extends ThreeJSOverlayView{ constructor(options: ThreeJSOverlayViewOptions){ super(options) }

however, this doesn't work and doesn't throw any error.
the following works when i am not using super.

export class CustomeThreeOverlay extends ThreeJSOverlayView{ constructor(options: ThreeJSOverlayViewOptions){ }

but i want to pass the options to ThreeJSOverlayView

by working, i meant console logs after new customeOverlay . if super is used in the constructor as shown above, the console logs doesnt even work:

let threeOverlay=new CustomeOverlay({ map, scene, anchor: { ...mapOptions.center, altitude: 0 }, }); console.log("This doesnt get logged")

Ability to combine WebGLOverlayView with other libraries

Is your feature request related to a problem? Please describe.
I am using map.data.loadGeoJson() to set border colors and fillColors to specific countries and cities.
I am also using the googlemaps/three package to add 3D objects to the map. However when i add 3D Objects i would like the 3D objects to be placed on a higher zIndex than the borderColor and fillColor from the google.maps.Data.StyleOptions.

Currently the 3D objects will be placed on a lower zIndex so the objects will be placed below the borderColor and fillColor.

I have tried to control this with the zIndex parameter in "google.maps.Data.StyleOptions" without success.

Describe the solution you'd like
I would like to control the zIndex of the gl.canvas within ThreeJSOverlayView so that i can place layers of other libraries such as the drawing library, visualization library and google.maps.Data.StyleOptions below the ThreeJSOverlay.

Additional context
To reproduce the issue and play around with other libraries combined with googlemaps/three, follow instructions of readme.md in below repo.
https://github.com/crunchwrap89/googlemaps-three-zIndex

screenshot

Improve coordinate handling and documentation

Is your feature request related to a problem? Please describe.

Handling the geographic and three.js world-coordinate systems tends to be problematic due to missing precision in the 32bit float numbers used on the GPU. The maximum theoretical precision (not taking numerical problems from matrix multiplication etc into account) on the GPU is around 7.2 decimal digits (log10(2^24)), and with earths circumference of 40,000 km, distances from the anchor-point can quickly go well beyond 10-20M meters if the anchor isn't specified, which drops the possible precision well below 1m.

This is why users should always use an anchor-point close to where the 3d-objects are located. This isn't mentioned in the documentation and leads to users experiencing jittering and other weird behaviour.

Describe the solution you'd like

All this is to say, we should really work on making handling of the coordinates of objects in the scene easier. Currently I see the following steps we could take to make this happen:

  • update the documentation to explain the precision-problems and the necessity to provide an anchor-point

  • introduce new helper functions overlay.latLngAltToVector3() and overlay.vector3ToLatLngAlt() to convert between geo-coordinates and three.js world-coordinates. This will do almost the same as the current utility functions, but it will take the current scene-anchor, rotation and scaling into accoun. This would also allow for different rotations and scales (e.g. using z-up orientation or using imperial units for world-scale if that's your kind of thing)

  • another approach for this is to implement floating anchors, I will open another ticket for this.

z-up vs y-up

Three uses a default of y-up as does this library currently. This requires a rotation where +z = south, -z = north. This is not intuitive. However rotating all objects isn't either.

From the current readme:

Screen Shot 2021-06-16 at 12 36 28 PM

polyline over 3d object

Environment details

javascript, google maps, threejs

Steps to reproduce

  1. i draw a polyline with google maps and put the 3d objects whit threejs but the line draw over the 3d object

example

ejemplo

Following these steps will guarantee the quickest resolution possible.

Thanks!

Pure HTML + JS - Uncaught ReferenceError: three is not defined

Hi,

I'm trying to modify a shipment tracking demo app that uses WebGL maps to use ThreeJS.
I'm purely using HTML + JS, no frameworks.

In my HTML code I have after before :

<script src="three.min.js"></script>
<script src="https://unpkg.com/@googlemaps/three/dist/index.min.js"></script>

When I load the HTML page, in Chrome dev tool's console, I see this error coming from the second javascript file listed above:

Uncaught ReferenceError: three is not defined
    at index.min.js:1:39366

If I also check the Network tab I see that three.min.js is loaded before index.min.js so it should've loaded three.min.js which seems to be a dependency in index.min.js.

I tried using a local version of three-js but also before that I tried using a CDN hosted version but nothing worked. I'm using r136 which is the same one that you have in the examples on https://github.com/googlemaps/js-three.

I'm running this on MacOS, starting my local webserver with gradlew appengineRun which will just create a local server.

Can you provide a pure HTML + JS sample code that would work?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.