3d marker in Google maps

Hilal Alhakani
6 min readJan 18, 2020

i was developing a taxi application ,and i used a car image as an icon for the marker similar to this one

then i checked Uber and saw how their marker is being turned , find more about it in this link below

https://medium.com/uber-design/upgrading-ubers-3d-fleet-4662c3e1081

so i searched online for implementing a 3d model in Google Maps. and i stumbled on this project
https://medium.com/@litoarias/scenekit-to-show-3d-content-in-swift-5-5253afbe63b1

so i had an idea of implementing a car instead of the converse and turning it according to the Heading provided by the didUpdateHeading function

so i downloaded a car model and i placed every component in that model inside a node container named parent .

as for the code i created a marker called HHMarker that inherits GMSMarker

1)first we set up our camera called cameraNode by adding the following lines
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3.init(7, 8, 0.0)
the SCNVector has 3 arguments x, y, z shown in the picture below

i got them from double clicking the SCNScene from the Debug hierarchy

i set the camera to untitled ,and changed the position (x,y,z) and the orientation called euleur angles (x,y,z) to properly position the camera

i titled the orientation of the camera towards bottom by setting the y euler angle to Double.pi/2 .

cameraNode.eulerAngles = SCNVector3(x: Float(deg2rad(3)), y: Float(Double.pi/2), z: Float(deg2rad(40)))

then i added this camera to the main scene

then i added a SceneView that renders the content of the SCNScene on the display and it’s equal to the bounds of the container view which will be set to the icon view of the marker .

then i got the car node instance by writing
car = scene.rootNode.childNode(withName: “parent”, recursively: false)!

where i searched the childNodes of the scene subtree with the specified name

that’s for the HHMarker ,let’s move to the view Controller

first i setup the location manager , then i setup the map and hide the location button and disabled the rotationGestures , and i defined a HHMarker and added it to the map , as for the delegate functions i used the didUpdateLocation to change position of the marker
and didUpdateHeading to tilt the marker

when setting the heading the DidSet block will get called where i’m changing the y value (since the car is rotated a bit i subtracted pi/2 to make it collinear with the user’s heading)

var heading:CLHeading = CLHeading(){

didSet {

self.car.eulerAngles = SCNVector3(x:0, y: -Float(deg2rad(self.heading.trueHeading)) — Float(Double.pi/2) , z: 0.0)

}

}

as you can see it worked

that’s before subtracting the pi/2

it worked but i had an issue when i inserted 3 HH markers ,the ram consumption was very high same for the cpu

i was stuck with that approach to reduce the ram consumption (since inserting 10 cars would make the app crash)
so i tried another approach where i created almost (Orientation x Scale)Images representing a double array containing the scale and orientation of the car instead of changing the euler angle of the dae model, with that approach no matter the number of markers increases , the ram and cpu consumption will be normal .
While using that double Array [Scale][Orientation] ,for each Scale contains all the orientations for the model equal to 360/divCount since we can represent 5 angles for example with one image instead of creating 5 images and load them as an Image using the icon property of the marker

so here’s the modified HHMarker class

the roundedHeading as defined before it’s the rounded Heading where i divide the heading over the step (since no need to have 360 angles ==> 360 images)
as for the rest same logic as before but i defined a new class called ImageCache to get the corresponding image using the scale and heading and type of the model (in this example we’re using only 1 model but it can be a motorcycle , SUV, premium car)

i created a Utilities class to resize an image and to transform degrees to radiant

as for the ImageCache class

  • the cache Array contains all the images (scalexOrientation) for a specified CarName value
  • the divCount represent the number of samples(adjusting this changes the smoothness of the rotation animation, larger is smoother but consumes more resources)
  • the step is equal to 360/divCount which is the sampling ratio
  • scaleCount is the number of scales in the cacheArray (scalexOrientation)
  • scalesArray represent all the possibilities varying from 0 till 1 for example if scale = 5 the possibilities would be equal to 0,1/5,2/5/,3/4/,4/5,1 those will be used in the cache Array to represent all scales
  • get Image is used to return a car with a scale ,orientation,and a CarName value (i rounded the scale to the nearest scales value)

After preparing the scales we should start generating the images which is done in the load function

first we check if the car is not cached ,if it is then there’s no need to do anything so we hit return
as explained before i inserted a camera and placed it above the car , then i defined an array called original images that will contain all the orientation for the car .

So i looped from 0 till divCount and appended a scaled image to the originalImages array that will be the first row in our cacheArray
the second row will be all orientations scaled 1/divCount
third row will be all orientations scaled 2/divCount etc …i obtained the corresponding size then i scaled the image and added it to the images Array

after completing the loop i add the images to an imageContainer that will be added to the cache Array this will take around 6 seconds to get all images and appending them to the array (for later use or in production those images should be saved instead of generating them each time)

that’s for the imageCache class ,as for the view controller

  • i added an offset to create many markers
  • all i have to do is change the scale or heading value of the marker and get the image that matches the scale and orientation

here’s the ram and cpu consumption after adding 60 markers

here’s a gif showing 60 markers in action

download the full project here :
https://github.com/HilalAH/HHMarker

--

--