Thank you for this question.
With a custom Python script, there is a way to accomplish this task.
Copy the attached script into your workspace, and add it to the scrips menu:
'''
Created on Oct 31, 2017
Modified on Apr 4, 2018
@author: Esri R&D Zurich
'''
from scripting import *
import math
# get a CityEngine instance
ce = CE()
hRes = 1080
def getCamera(view):
camPos = view.getCameraPosition()
camRot = view.getCameraRotation()
camAoV = view.getCameraAngleOfView()
camPoI = view.getCameraPoI()
camPoIDist = math.sqrt(math.pow(camPoI[0]-camPos[0],2)+ \
math.pow(camPoI[1]-camPos[1],2)+ \
math.pow(camPoI[2]-camPos[2],2))
camPersp = view.getCameraPerspective()
return camPos,camRot,camAoV,camPoIDist,camPersp
def setCamera(view,camPos,camRot,camAoV,camPoIDist,camPersp = True):
view.setCameraPosition(camPos[0],camPos[1],camPos[2])
view.setCameraRotation(camRot[0],camRot[1],camRot[2])
view.setPoIDistance(camPoIDist)
view.setCameraAngleOfView(min(160.0,camAoV))
view.setCameraPerspective(camPersp)
def getViewshed(viewshed):
vsPos = ce.getObserverPoint(viewshed)
vsRot = [0.0, 0.0, 0.0]
if ce.isViewshed(viewshed):
vsRot[0] = ce.getTiltAndHeadingAngles(viewshed)[0]
vsRot[1] = -ce.getTiltAndHeadingAngles(viewshed)[1]
vsAoV = ce.getAnglesOfView(viewshed)[0]
vsPoIDist = ce.getViewDistance(viewshed)
vsRatio = vsAoV/ce.getAnglesOfView(viewshed)[1]
elif ce.isViewDome(viewshed):
vsAoV = 360.0
vsPoIDist = ce.getViewDistance(viewshed)
vsRatio = 1
elif ce.isViewCorridor(viewshed):
vsPoI = ce.getPOI(viewshed)
vsRot[0] = math.atan2(vsPoI[1]-vsPos[1], \
math.sqrt(math.pow(vsPoI[0]-vsPos[0],2)+ \
math.pow(vsPoI[2]-vsPos[2],2)))*180/math.pi
vsRot[1] = -math.atan2(vsPoI[0]-vsPos[0], \
-(vsPoI[2]-vsPos[2]))*180/math.pi
vsAoV = ce.getAnglesOfView(viewshed)[0]
vsPoIDist = math.sqrt(math.pow(vsPoI[0]-vsPos[0],2)+ \
math.pow(vsPoI[1]-vsPos[1],2)+ \
math.pow(vsPoI[2]-vsPos[2],2))
vsRatio = vsAoV/ce.getAnglesOfView(viewshed)[1]
else:
return
vsName = ce.getName(viewshed)
return vsPos,vsRot,vsAoV,vsPoIDist,vsRatio,vsName
def snapshot360(view,vsName):
# make six square snapshots
view.setCameraAngleOfView(90.0)
vdAoV = [(0,0),(0,90),(0,180),(0,-90),(90,0),(-90,0)]
suffixes = ["_f","_l","_b","_r","_u","_d"]
for i, suffix in enumerate(suffixes):
view.setCameraRotation(vdAoV[i][0],vdAoV[i][1],0)
view.snapshot(ce.toFSPath('images/'+vsName+suffix+'.png'),hRes,hRes)
def snapshotViewshed(view,viewshed):
# get initial camera parameters
camPos,camRot,camAoV,camPoIDist,camPersp = getCamera(view)
# get viewshed parameters
vsPos,vsRot,vsAoV,vsPoIDist,vsRatio,vsName = getViewshed(viewshed)
if ce.isViewDome(viewshed):
snapshot360(view,vsName)
else:
# set camera to viewshed parameters
setCamera(view,vsPos,vsRot,vsAoV,vsPoIDist)
# make a snapshot
view.snapshot(ce.toFSPath('images/'+vsName+'.png'),hRes*vsRatio,hRes)
# reset camera to initial camera parameters
setCamera(view,camPos,camRot,camAoV,camPoIDist,camPersp)
if __name__ == '__main__':
# get selected viewsheds, view domes and view corridors
view = ce.getObjectsFrom(ce.get3DViews())[0]
viewsheds = ce.getObjectsFrom(ce.selection(),ce.isViewshed)
viewdomes = ce.getObjectsFrom(ce.selection(),ce.isViewDome)
viewCorridors = ce.getObjectsFrom(ce.selection(),ce.isViewCorridor)
# preparations
initialSelection = ce.selection()
ce.setSelection([])
for al in ce.getObjectsFrom(ce.scene,ce.isAnalysisLayer):
ce.setLayerPreferences(al,"Visible",False)
tmpLayer = ce.addAnalysisLayer('TEMP Analysis Layer')
# make snapshots
for viewshed in (viewsheds+viewdomes+viewCorridors):
if ce.isViewCorridor(viewshed):
ce.setLayerPreferences(tmpLayer,"Visible",True)
else:
ce.setLayerPreferences(tmpLayer,"Visible",False)
tmpViewshed = ce.copy(viewshed,False,tmpLayer)
snapshotViewshed(view,tmpViewshed[0])
ce.delete(tmpViewshed)
# clean up
ce.delete(tmpLayer)
for al in ce.getObjectsFrom(ce.scene,ce.isAnalysisLayer):
ce.setLayerPreferences(al,"Visible",True)
ce.setSelection(initialSelection)
Hi Thomas
EDIT: How it works? I´m just trying to use the script and after add and run were the snapshot was saved?
I found the snapshot. It´s not the same image from View Dome (360 perspective).
I´m not python expert but...it´s possible to get exactly the same view? Here my printscreen (I got poor quality from printscreens)
I´m creating 360 panoramas from my project using printscreens from DomeView (low quality) and the script will be really usefull.
Here a sample of my CityEngine project in 360 panorama(Low quality) Roundme - create Stock 360 VR panoramic pictures virtual tour online . Also it´s possible to upload the same image on Facebook to view 360 on smartphones.
Hi Luiz
Thank you for your input. I changed the script in my post above to add export support for 360 panoramas from CityEngine View Domes.
For View Domes it now creates six 90° x 90° square snapshots (back, down, front, left, right, up).
These can be stitched and re-projected from cubemap to equirectangular format with common VR/panorama tools.
Here is a link to a free online tool: 360Toolkit - Convert and View Panorama Pictures Instantly
Amazing
I´ll try in few minutes and I´ll share here the result
It works very well
Here the new panorama Roundme - create Stock 360 VR panoramic pictures virtual tour online
Thank you so much.
I have been looking for this as well! Thanks Thomas!
Hi Thomas,
Is there any concern with me adapting this as a distributed script?
geodesign-toolkit-gis-cityengine-integration-tools/Scripts at master · Holisticnature/geodesign-tool...
I was thinking about put a folder call "Esri Scripts". One concern that I had is a lot of the geonet snippits have no license attached. Should I assume it is Apache 2.0 like most esri projects?
Code snippets published on Esri GeoNet protected by any license, need to respect the associated usage rights. They must be marked accordingly by the publisher. Any license violations need to be reported to the forum administrator.
Generally, CityEngine CGA and Python snippets published by Esri employees, are meant to support our customers in achieving their goals in accordance with the product's software license. For further information please visit Esri Legal Information | Overview
In your case distribution of GeoNet snippets under the Apache 2.0 license in a folder called "Esri Scripts" is appropriate.
Hi Thomas,
Understood. This is the set up I did. If you have any required edits you can let me know.
I made minor edits to the script (I think for domes I need a small edit or two). I might work with it a little more to iterate through layers/ scenarios (not sure the API exposes scenarios yet).
Thanks for sharing this. I have a sample image I did in a street scene.
This is awesome, and I wish it was a one button click feature.