Newbie question about offscreen screenshot

Hello all, I’m trying to find my way through api docs and previous old posts but I’m stucked here.

In short I have a couple of display regions and camera which work well. I get some screenshots from them and save without any problem but:

Question:
Is it possible to get screenshot from a display(s) region without rendering them on the screen . (My expectation is higher performence from graphic card since no rendering, I’ll have many of them). Any help / guidance appreciated.

Niyazi

from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from panda3d.core import WindowProperties
from direct.actor.Actor import Actor
from panda3d.core import AmbientLight
from panda3d.core import Vec4
from panda3d.core import DirectionalLight
from panda3d.core import Vec4, Vec3
from panda3d.core import CollisionTraverser
from panda3d.core import CollisionHandlerPusher
from panda3d.core import CollisionSphere, CollisionNode
from panda3d.core import CollisionTube
from panda3d.core import Camera
from panda3d.core import NodePath

from panda3d.core import GraphicsOutput

import numpy as np
from direct.task import Task
from opensimplex import OpenSimplex
from panda3d.core import Texture
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        
        
        properties = WindowProperties()
        properties.setSize(1000, 750)
        
        
        self.dr = self.camNode.getDisplayRegion(0) 
        self.dr.setActive(0) # disable
        print(self.dr.getSort())
        self.dr1 = self.win.makeDisplayRegion(0.0, 0.5, 0, .5) 
        self.dr1.setSort(self.dr.getSort())
        self.dr1.setCamera(self.camList[0])

        self.makeCamera(self.win,sort=0,displayRegion=(0.5,1,0.5,1),camName="cam2")

        self.disableMouse()
        self.useTrackball()

        self.environment = loader.loadModel("environment/environment")
        self.environment.reparentTo(render)
        self.monkey = Actor("models/monkey")
        self.monkey.set_scale(.25)
        self.monkey.reparentTo(render)
        self.monkey.set_pos(0,0,2)   

        self.monkey2 = Actor("models/monkey")
        self.monkey2.set_scale(.25)
        self.monkey2.reparentTo(render)
        self.monkey2.set_pos(0,3,2)
        self.camList[0].reparentTo(self.monkey)
        self.camList[1].reparentTo(self.monkey2)
        self.taskMgr.add(self.example_Task, "updateTask")
        
        ambientLight = AmbientLight("ambient light")
        ambientLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        self.ambientLightNodePath = render.attachNewNode(ambientLight)
        render.setLight(self.ambientLightNodePath)
        # In the body of your code
        mainLight = DirectionalLight("main light")
        self.mainLightNodePath = render.attachNewNode(mainLight)
        # Turn it around by 45 degrees, and tilt it down by 45 degrees
        self.mainLightNodePath.setHpr(45, -45, 0)
        render.setLight(self.mainLightNodePath)
        render.setShaderAuto()
        
        print('Cameras')
        print(self.camList)
        print('Number Of Display Regions')
        print(self.win.getNumDisplayRegions())
        print('Active Display Regions')
        print(self.win.getActiveDisplayRegions())
        print(self.win.getDisplayRegions())        
        print('Number Of Display Regions')
        print(self.win.getNumDisplayRegions())
        

        #self.win.getDisplayRegion(2).saveScreenshotDefault('www')

        #this works but I get black screen  because it gets the SC before the rendering
        texture = self.win.getDisplayRegion(1).getScreenshot()        
        numpy_image_data=np.array(texture.getRamImageAs("RGB"), np.float32)
        print(np.max(numpy_image_data[123456]))

        
        

        
    def example_Task(self,task):
        if task.time <5.0:
            self.monkey.setPos(self.monkey.getPos() + Vec3(0, 0.01, 0))            
            
            return Task.cont
        #this really works because it saves the SC during rendering
        self.win.getDisplayRegion(1).saveScreenshotDefault('www')
        print('matask Done')
        return Task.done   

game = Game()
game.run()

This should be what you are looking for.

However, performance will not increase, since the actual rendering is happening and write to disk.

Thank you serega-kkz. I’m trying to do it that way. I’ll share when (if) I succeed and ask your opinion.

Ok, thanks for the help. I managed to get two display region’s screenshot and float image without any problem. Here is the code and images. Two cameras loking at same cube from different angles. Code is messy, sorry about that.

1111-Sun-Apr-26-20-52-44-2020-2 2222-Sun-Apr-26-20-52-44-2020-2

from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from panda3d.core import WindowProperties
from direct.actor.Actor import Actor
from panda3d.core import AmbientLight
from panda3d.core import Vec4
from panda3d.core import DirectionalLight
from panda3d.core import Vec4, Vec3
from panda3d.core import CollisionTraverser
from panda3d.core import CollisionHandlerPusher
from panda3d.core import CollisionSphere, CollisionNode
from panda3d.core import CollisionTube
from panda3d.core import Camera

from panda3d.core import NodePath
from panda3d.core import Filename
from panda3d.core import GraphicsOutput

import numpy as np
from direct.task import Task
from opensimplex import OpenSimplex
from panda3d.core import Texture
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        
        
        properties = WindowProperties()
        properties.setSize(1000, 750)
        
        
        

        self.disableMouse()
        self.environment = loader.loadModel("environment/environment")
        self.environment.reparentTo(render)
        
        """ In this block I create a textureBuffer and create camera 
        on that buffer that its display region is upper right corner of the window
        I use that region to create saveScreenShot xxxx or create a numpy array out of it
        (numpy_image_data) 
        second try is to make a screenshot directly from the buffer which is not so important
        Both works though """
        self.useTrackball()
        ambientLight = AmbientLight("ambient light")
        ambientLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        self.ambientLightNodePath = render.attachNewNode(ambientLight)
        render.setLight(self.ambientLightNodePath)
        # In the body of your code
        mainLight = DirectionalLight("main light")
        self.mainLightNodePath = render.attachNewNode(mainLight)
        # Turn it around by 45 degrees, and tilt it down by 45 degrees
        self.mainLightNodePath.setHpr(45, -45, 0)
        render.setLight(self.mainLightNodePath)
        render.setShaderAuto()

        self.tempActor2 = Actor("models/cube.bam")
        self.tempActor2.reparentTo(render)
        self.tempActor2.setPos(-5, 3, 0)
        
        self.monkey = Actor("models/monkey")
        self.monkey.set_scale(.25)
        self.monkey.reparentTo(render)
        self.monkey.set_pos(3,0,2) 
        self.monkey.lookAt(self.tempActor2)  

        self.monkey2 = Actor("models/monkey")
        self.monkey2.set_scale(.25)
        self.monkey2.reparentTo(render)
        self.monkey2.set_pos(0,3,1)
        self.monkey2.lookAt(self.tempActor2)



        

        tex=Texture()
        mybuffer = self.win.makeTextureBuffer("My Buffer", 512, 512,tex,to_ram=True)
        mybuffer.setSort(-100)
        mycamera = self.makeCamera(mybuffer,displayRegion=(.5,1,.5,1))
        mycamera.reparentTo(self.monkey)



        tex2=Texture()
        mybuffer2 = self.win.makeTextureBuffer("My Buffer2", 512, 512,tex,to_ram=True)
        mybuffer2.setSort(-500)
        mycamera2 = self.makeCamera(mybuffer2,displayRegion=(0,.5,0,.5))
        mycamera2.reparentTo(self.monkey2)

        self.graphicsEngine.renderFrame()

        
        print(mybuffer.getActiveDisplayRegions())

        save_it=mybuffer.getActiveDisplayRegion(0).saveScreenshotDefault('1111')
        my_output=mybuffer.getActiveDisplayRegion(0).getScreenshot()
        numpy_image_data=np.array(my_output.getRamImageAs("RGB"), np.float32)
        
        save_it2=mybuffer2.getActiveDisplayRegion(0).saveScreenshotDefault('2222')
        my_output2=mybuffer2.getActiveDisplayRegion(0).getScreenshot()
        numpy_image_data2=np.array(my_output2.getRamImageAs("RGB"), np.float32)
        print(numpy_image_data)



        file_name=Filename.fromOsSpecific("save_gameDat_001.png")
        mybuffer.saveScreenshot(file_name)
        print('Cameras')
        print(self.camList)
        print('Number Of Display Regions')
        print(self.win.getNumDisplayRegions())
        print('Active Display Regions')
        print(self.win.getActiveDisplayRegions())

        print(self.win.getDisplayRegions())
        
        print('Number Of Display Regions')
        print(self.win.getNumDisplayRegions())

        
        
    
game = Game()
game.run()