Hey hey! Yet another issue arose and I need your help.
I’m generating a cubemap of my scene to then use the nonlinearimager to render it through a fisheye lens. My animated models now seem to vanish at the boundaries of the stitched field of views (see picture), since no camera seems to cover that part.
What’s weird is that the shadows are rendered correctly beneath the invisible fish…
Any idea how I can get around this issue?
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 27 15:33:18 2023
@author: leco10
cylindrical lens VR
"""
import simplepbr
# Make the camera into a fisheye camera using the NonlinearImager.
from direct.showbase.ShowBase import ShowBase
from panda3d.core import loadPrcFile
loadPrcFile("VR_config.prc")
#load config manager and print config vars
#from panda3d.core import ConfigVariableManager
#ConfigVariableManager.getGlobalPtr().listVariables()
from panda3d.core import *
from panda3d.fx import NonlinearImager, ProjectionScreen, FisheyeLens
# import task, a task is a procedure that is called every frame
from direct.task import Task
from direct.particles.ParticleEffect import ParticleEffect
#import actor for animations
from direct.actor.Actor import Actor
import time
#------------------------------------------------------------------------------
#make dictionary to map keys press events to true/false
keyMap = {
"up": False,
"down": False,
"left": False,
"right": False,
"rcon": False,
"zero": False,
"1": False,
"2": False,
'+': False,
'-': False
}
#callback update function
def updateKeyMap(key,state):
keyMap[key] = state
start = time.time()
#------------------------------------------------------------------------------
class VR(ShowBase):
def __init__(self, tex_res = 4096):
super().__init__()
self.win.setClearColorActive(False)
self.win.setClearColor((1, 0, 0, 0))
self.setBackgroundColor(1,0,0,0,self.win)
#parameters
color = (0.10, 0.215, 0.443, 1)
self.scaling_factor = 0.01*12.96/2 # 12.96 cm (panda) = 2 cm (real)
self.exp_decay = 3
#variables
self.base_speed = 0
self.gain = 1
self.velocity = 5
self.T = [0,0]
#set speed
self.camera_speed = 1.5
self.turning_speed = 1.5
#load scene seafloor_pebbles
self.room = self.loader.load_model("/e/leos data/VR environments/seafloor_pebbles_flat.gltf")
self.room = NodePath(self.room)
self.room.setScale(1,1,1)
self.room.setHpr(0,0,0)
self.room.reparentTo(self.render)
#set lightning
alight = AmbientLight('alight')
alight.setColor((0.1, 0.2, 0.3, 1)) #for naturalistic environment
alnp = self.render.attachNewNode(alight)
self.render.setLight(alnp)
slight = Spotlight('slight')
slight.setColor((2, 2, 2, 0))
lens = PerspectiveLens()
slight.setLens(lens)
slnp = self.render.attachNewNode(slight)
slnp.setPos(0.15, 0, 130)
slnp.setHpr(0,-90,0)
self.render.setLight(slnp)
# Use a 512x512 resolution shadow map
slight.setShadowCaster(True, 1024, 1024)
# Enable the shader generator for the receiving nodes
self.render.setShaderAuto()
#initialize gltf interpreter
simplepbr.init(enable_fog=True, enable_shadows = True ,render_node=self.room)
#load instances of fish
fish_locations = [(-1,0,.6),(-0.8,0.4,.7),(-0.9,0.3,.7),(-0.7,0.3,.8),(-1.2,0.1,.6),(-0.8,0.8,.7),(-0.4,0.5,.9)]
self.object = Actor("/e/leos data/VR environments/Dc_animation.egg")
animation_names = self.object.get_anim_names()
for i in range(len(animation_names)):
if animation_names[i] == 'ArmatureAction.001':
animation = animation_names[i]
self.object.loop(animation)
self.object.setScale(0.5)
for i in range(0,7):
placeholder = self.room.attachNewNode('fish' + str(i+1))
placeholder.setPos(fish_locations[i])
self.object.instanceTo(placeholder) # instanstiate geometry to empty nodepath
#create subject
self.subject = self.loader.load_model('smiley.egg')
self.subject = NodePath(self.subject)
self.subject.hide()
self.subject.reparent_to(self.render)
self.cam.reparentTo(self.subject)
#set fog
self.expfog = Fog("Scene-wide exponential Fog object")
elf.expfog.setColor(color)
self.expfog.setExpDensity(0.4)
self.render.setFog(self.expfog)
#create dark room nodepath and define cube cams1
screens = NodePath('dark_room')
cubeCam = self.cam.attachNewNode('cubeCam')
cubeForward = (1, 1, 1)
#----------------------------------------------------------------------
class CubeFace:
def __init__(self, name, view, up, res):
self.name = name
# A camera, for viewing the world under render.
self.camNode = Camera('cam' + self.name)
self.camNode.setScene(render)
self.cam = cubeCam.attachNewNode(self.camNode)
self.cam.setHpr(0,0,0)
# A projector, for projecting the generated image of the world
# onto our screen.
self.projNode = LensNode('proj' + self.name)
self.proj = screens.attachNewNode(self.projNode)
self.lens = PerspectiveLens()
self.lens.setFov(92)
self.lens.setNear(0.01)
self.lens.setFar(1000)
self.lens.setViewVector(view[0], view[1], view[2], up[0], up[1], up[2])
self.camNode.setLens(self.lens)
self.projNode.setLens(self.lens)
# Now the projection screen itself, which is tied to the
# projector.
self.psNode = ProjectionScreen('ps' + self.name)
self.ps = self.proj.attachNewNode(self.psNode)
self.psNode.setProjector(self.proj)
# Generate a flat, rectilinear mesh to project the image onto.
self.psNode.regenerateScreen(self.proj, "screen", res[0], res[1], 10, 0.97)
#----------------------------------------------------------------------
cubeCam.lookAt(cubeForward)
m = Mat4()
m.invertFrom(cubeCam.getMat())
cubeCam.setMat(m)
# Get the base display region.
self.dr = self.camNode.getDisplayRegion(0)
# Now make a fisheye lens to view the whole thing
ccamNode = Camera('ccam')
ccam = screens.attachNewNode(ccamNode)
clens = FisheyeLens()#PerspectiveLens()#
clens.setViewVector(cubeForward[0], cubeForward[1], cubeForward[2], 0, 0, 1)
clens.setFov(180)
clens.setFilmSize(self.dr.getPixelWidth(), self.dr.getPixelHeight())
ccamNode.setLens(clens)
# Set the cylindrical lens
self.dr.setCamera(ccam)
# And create the NonlinearImager to do all the fancy stuff.
nli = NonlinearImager()
nli.addViewer(self.dr)
# Define the six faces.
cubeFaces = [
CubeFace('Right', (1, 0, 0), (0, 0, 1), (10, 40)),
CubeFace('Back', (0, -1, 0), (0, 0, 1), (40, 40)),
CubeFace('Left', (-1, 0, 0), (0, 0, 1), (10, 40)),
CubeFace('Front', (0, 1, 0), (0, 0, 1), (20, 20)),
CubeFace('Up', (0, 0, 1), (0, -1, 0), (40, 10)),
CubeFace('Down', (0, 0, -1), (0, 1, 0), (40, 10)),
]
for face in cubeFaces:
i = nli.addScreen(face.ps, face.name)
nli.setTextureSize(i, tex_res, tex_res)
nli.setSourceCamera(i, face.cam)
#change camera view to look at the ground and shift downwards
self.cam.setHpr(0,-90,0)
self.cam.setPos(0,0,0.7) # for naturalistic ground
self.camLens.setNearFar(0.1,50)
#self.cam.setPos(0,0,-3.5) # for corridor
# activate keyboard control
self.keyboard_control()
# Add the move tasks procedure to the task manager.
self.taskMgr.add(self.move_subject, "move_sub")
#----------------------------------------------------------------------
def keyboard_control(self):
#create camera control for cam
#use build-in keyboard support: self.accept. see doc for key (event) names
self.accept("arrow_left",updateKeyMap,["left", True])
self.accept("arrow_right",updateKeyMap,["right", True])
self.accept("arrow_up",updateKeyMap,["up", True])
self.accept("arrow_down",updateKeyMap,["down", True])
self.accept("rcontrol",updateKeyMap,["rcon", True])
self.accept("0",updateKeyMap,["zero", True])
self.accept("1",updateKeyMap,["1", True])
self.accept("2",updateKeyMap,["2", True])
self.accept("+",updateKeyMap,["+", True])
self.accept("-",updateKeyMap,["-", True])
#key release events
self.accept("arrow_left-up",updateKeyMap,["left", False])
self.accept("arrow_right-up",updateKeyMap,["right", False])
self.accept("arrow_up-up",updateKeyMap,["up", False])
self.accept("arrow_down-up",updateKeyMap,["down", False])
self.accept("rcontrol-up",updateKeyMap,["rcon", False])
self.accept("0-up",updateKeyMap,["zero", False])
self.accept("1-up",updateKeyMap,["1", False])
self.accept("2-up",updateKeyMap,["2", False])
self.accept("+-up",updateKeyMap,["+", False])
self.accept("--up",updateKeyMap,["-", False])
#--------------------------------------------------------------------------
def move_subject(self, task):
#exp time
t = time.time()-start
#get delta t
self.T.append(t)
self.dt = self.T[-1]-self.T[-2]
#get subject Hpr
sub_hpr = self.subject.getHpr()
sub_pos = self.subject.getPos()
quat = self.subject.getQuat()
forwardVec = quat.getForward()
#relevant movement for omr
final_velocity = self.base_speed*self.scaling_factor*self.dt + self.velocity*self.scaling_factor*self.dt*self.gain
#update camera based on key pressing
if keyMap["up"]:
self.subject.setPos(self.subject.getPos() + forwardVec*final_velocity)
# self.expfog = Fog("Scene-wide exponential Fog object")
# x = 0.1*(sub_pos.y)/10
# color = (0.1, 0.1, x,1)
# self.expfog.setColor(color)
# self.render.setFog(self.expfog)
if keyMap["down"]:
self.subject.setPos(self.subject.getPos() + forwardVec*(-final_velocity))
if keyMap["rcon"]:
sub_hpr.x += self.turning_speed
if keyMap["zero"]:
sub_hpr.x -= self.turning_speed
if keyMap["1"]:
sub_hpr.y += self.turning_speed
if keyMap["2"]:
sub_hpr.y -= self.turning_speed
#teleport
if sub_pos.y < -100:
self.subject.setPos(Vec3(0,100,0) + forwardVec*final_velocity)
if sub_pos.y >100:
self.subject.setPos(Vec3(0,-100,0) + forwardVec*final_velocity)
if sub_pos.x < -100:
self.subject.setPos(Vec3(100,0,0) + forwardVec*final_velocity)
if sub_pos.x > 100:
self.subject.setPos(Vec3(-100,0,0) + forwardVec*final_velocity)
#update camera position and Hpr
#self.cam.setPos(cam_pos)
self.subject.setHpr(sub_hpr)
return Task.cont
#--------------------------------------------------------------------------
VR_instance = VR() #read out variables with test_instance.variable
VR_instance.run()