def _initArrays(self): # Max Visible Lights (limited because shaders can have max 1024 uniform # floats) # If you change this, don't forget to change it also in # Shader/Includes/Configuration.include! self.maxLights = { "PointLight": 8, # "DirectionalLight": 2 } # Max shadow casting lights self.maxShadowLights = { "PointLight": 16, # "DirectionalLight": 1 } for lightType, maxCount in self.maxShadowLights.items(): self.maxLights[lightType + "Shadow"] = maxCount # Create array to store number of rendered lights this frame self.numRenderedLights = {} # Also create a PTAInt for every light type, which stores only the # light id self.renderedLightsArrays = {} for lightType, maxCount in self.maxLights.items(): self.renderedLightsArrays[lightType] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType] = PTAInt.emptyArray(1) for lightType, maxCount in self.maxShadowLights.items(): self.renderedLightsArrays[lightType + "Shadow"] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType + "Shadow"] = PTAInt.emptyArray(1)
def _createInputHandles(self): """ Defines various inputs to be used in the shader passes. Most inputs use pta-arrays, so updating them is faster than using setShaderInput all the time. """ self.cameraPosition = PTAVecBase3f.emptyArray(1) self.currentViewMat = PTALMatrix4f.emptyArray(1) self.currentProjMatInv = PTALMatrix4f.emptyArray(1) self.lastMVP = PTALMatrix4f.emptyArray(1) self.currentMVP = PTALMatrix4f.emptyArray(1) self.frameIndex = PTAInt.emptyArray(1) self.frameDelta = PTAFloat.emptyArray(1) self.renderPassManager.registerStaticVariable("lastMVP", self.lastMVP) self.renderPassManager.registerStaticVariable("currentMVP", self.currentMVP) self.renderPassManager.registerStaticVariable("frameIndex", self.frameIndex) self.renderPassManager.registerStaticVariable("cameraPosition", self.cameraPosition) self.renderPassManager.registerStaticVariable("mainCam", self.showbase.cam) self.renderPassManager.registerStaticVariable("mainRender", self.showbase.render) self.renderPassManager.registerStaticVariable("frameDelta", self.frameDelta) self.renderPassManager.registerStaticVariable("currentViewMat", self.currentViewMat) self.renderPassManager.registerStaticVariable("currentProjMatInv", self.currentProjMatInv) self.renderPassManager.registerStaticVariable("zeroVec2", Vec2(0)) self.renderPassManager.registerStaticVariable("zeroVec3", Vec3(0)) self.renderPassManager.registerStaticVariable("zeroVec4", Vec4(0)) self.transformMat = TransformState.makeMat(Mat4.convertMat(CSYupRight, CSZupRight))
def _init_internal_mgr(self): """ Creates the light storage manager and the buffer to store the light data """ self._internal_mgr = InternalLightManager() # Storage for the Lights per_light_vec4s = 4 self._img_light_data = Image.create_buffer( "LightData", self._MAX_LIGHTS * per_light_vec4s, Texture.T_float, Texture.F_rgba16) self._img_light_data.set_clear_color(0) self._img_light_data.clear_image() self._pta_max_light_index = PTAInt.empty_array(1) self._pta_max_light_index[0] = 0 # Storage for the shadow sources per_source_vec4s = 5 self._img_source_data = Image.create_buffer( "ShadowSourceData", self._MAX_SOURCES * per_source_vec4s, Texture.T_float, Texture.F_rgba16) self._img_light_data.set_clear_color(0) self._img_light_data.clear_image() # Register the buffer add_input = self._pipeline.stage_mgr.add_input add_input("AllLightsData", self._img_light_data.get_texture()) add_input("ShadowSourceData", self._img_source_data.get_texture()) add_input("maxLightIndex", self._pta_max_light_index)
def __init__(self): """ Constructs a new Light, subclasses have to call this """ DebugObject.__init__(self, "AbstractLight") ShaderStructElement.__init__(self) self.debugNode = NodePath("LightDebug") self.visualizationNumSteps = 32 self.dataNeedsUpdate = False self.castShadows = False self.debugEnabled = False self.bounds = OmniBoundingVolume() self.shadowSources = [] self.lightType = self.getLightType() self.position = Vec3(0) self.color = Vec3(1) self.posterIndex = -1 self.radius = 10.0 self.typeName = "" self.sourceIndexes = PTAInt.emptyArray(6) self.attached = False self.shadowResolution = 512 self.index = -1 self.iesProfile = -1 self.iesProfileName = None self.mvp = Mat4() # A light can have up to 6 sources for i in range(6): self.sourceIndexes[i] = -1
def init_internal_manager(self): """ Creates the light storage manager and the buffer to store the light data """ self.internal_mgr = InternalLightManager() self.internal_mgr.set_shadow_update_distance( self.pipeline.settings["shadows.max_update_distance"]) # Storage for the Lights per_light_vec4s = 4 self.img_light_data = Image.create_buffer( "LightData", self.MAX_LIGHTS * per_light_vec4s, "RGBA16") self.img_light_data.set_clear_color(0) self.img_light_data.clear_image() self.pta_max_light_index = PTAInt.empty_array(1) self.pta_max_light_index[0] = 0 # Storage for the shadow sources per_source_vec4s = 5 self.img_source_data = Image.create_buffer( "ShadowSourceData", self.MAX_SOURCES * per_source_vec4s, "RGBA16") self.img_light_data.set_clear_color(0) self.img_light_data.clear_image() # Register the buffer inputs = self.pipeline.stage_mgr.inputs inputs["AllLightsData"] = self.img_light_data inputs["ShadowSourceData"] = self.img_source_data inputs["maxLightIndex"] = self.pta_max_light_index
def __init__(self): """ Constructs a new Light, subclasses have to call this """ DebugObject.__init__(self, "AbstractLight") ShaderStructElement.__init__(self) self.debugNode = NodePath("LightDebug") self.visualizationNumSteps = 32 self.dataNeedsUpdate = False self.castShadows = False self.debugEnabled = False self.bounds = OmniBoundingVolume() self.shadowSources = [] self.lightType = self.getLightType() self.position = Vec3(0) self.color = Vec3(1) self.posterIndex = -1 self.direction = Vec3(0) self.radius = 10.0 self.typeName = "" self.sourceIndexes = PTAInt.emptyArray(6) self.attached = False self.shadowResolution = 512 self.index = -1 self.iesProfile = -1 self.iesProfileName = None self.mvp = Mat4() # A light can have up to 6 sources for i in range(6): self.sourceIndexes[i] = -1
def init_internal_manager(self): """ Creates the light storage manager and the buffer to store the light data """ self.internal_mgr = InternalLightManager() self.internal_mgr.set_shadow_update_distance( self.pipeline.settings["shadows.max_update_distance"]) # Storage for the Lights per_light_vec4s = 4 self.img_light_data = Image.create_buffer( "LightData", self.MAX_LIGHTS * per_light_vec4s, "RGBA16") self.img_light_data.clear_image() self.pta_max_light_index = PTAInt.empty_array(1) self.pta_max_light_index[0] = 0 # Storage for the shadow sources per_source_vec4s = 5 # IMPORTANT: RGBA32 is really required here. Otherwise artifacts and bad # shadow filtering occur due to precision issues self.img_source_data = Image.create_buffer( "ShadowSourceData", self.MAX_SOURCES * per_source_vec4s, "RGBA32") self.img_light_data.clear_image() # Register the buffer inputs = self.pipeline.stage_mgr.inputs inputs["AllLightsData"] = self.img_light_data inputs["ShadowSourceData"] = self.img_source_data inputs["maxLightIndex"] = self.pta_max_light_index
def _create_components(self): """ Internal method to init the widgets components """ # Create the buffer which stores the last FPS values self._storage_buffer = Image.create_buffer("FPSValues", 250, "R16") self._storage_buffer.set_clear_color(Vec4(0)) self._storage_buffer.clear_image() self._store_index = PTAInt.empty_array(1) self._store_index[0] = 0 self._current_ftime = PTAFloat.empty_array(1) self._current_ftime[0] = 16.0 self._chart_ms_max = PTAFloat.empty_array(1) self._chart_ms_max[0] = 40 # Create the texture where the gui component is rendered inside self._display_tex = Image.create_2d("FPSChartRender", 250, 120, "RGBA8") self._display_tex.set_clear_color(Vec4(0)) self._display_tex.clear_image() self._display_img = Sprite(image=self._display_tex, parent=self._node, w=250, h=120, x=10, y=10) # Defer the further loading Globals.base.taskMgr.doMethodLater(0.3, self._late_init, "FPSChartInit")
def init_internal_manager(self): """ Creates the light storage manager and the buffer to store the light data """ self.internal_mgr = InternalLightManager() self.internal_mgr.set_shadow_update_distance( self.pipeline.settings["shadows.max_update_distance"]) # Storage for the Lights per_light_vec4s = 4 self.img_light_data = Image.create_buffer( "LightData", self.MAX_LIGHTS * per_light_vec4s, "RGBA16") self.img_light_data.set_clear_color(0) self.img_light_data.clear_image() self.pta_max_light_index = PTAInt.empty_array(1) self.pta_max_light_index[0] = 0 # Storage for the shadow sources per_source_vec4s = 5 # IMPORTANT: RGBA32 is really required here. Otherwise artifacts and bad # shadow filtering occur due to precision issues self.img_source_data = Image.create_buffer( "ShadowSourceData", self.MAX_SOURCES * per_source_vec4s, "RGBA32") self.img_light_data.set_clear_color(0) self.img_light_data.clear_image() # Register the buffer inputs = self.pipeline.stage_mgr.inputs inputs["AllLightsData"] = self.img_light_data inputs["ShadowSourceData"] = self.img_source_data inputs["maxLightIndex"] = self.pta_max_light_index
def _create_components(self): """ Internal method to init the widgets components """ # Create the buffer which stores the last FPS values self._storage_buffer = Image.create_buffer("FPSValues", 250, "R16") self._storage_buffer.set_clear_color(Vec4(0)) self._storage_buffer.clear_image() self._store_index = PTAInt.empty_array(1) self._store_index[0] = 0 self._current_ftime = PTAFloat.empty_array(1) self._current_ftime[0] = 16.0 self._chart_ms_max = PTAFloat.empty_array(1) self._chart_ms_max[0] = 40 # Create the texture where the gui component is rendered inside self._display_tex = Image.create_2d("FPSChartRender", 250, 120, "RGBA8") self._display_tex.set_clear_color(Vec4(0)) self._display_tex.clear_image() self._display_img = Sprite( image=self._display_tex, parent=self._node, w=250, h=120, x=10, y=10) # Defer the further loading Globals.base.taskMgr.doMethodLater(0.3, self._late_init, "FPSChartInit")
def __init__(self, pipeline): RenderStage.__init__(self, pipeline) self.resolution = 128 self.diffuse_resolution = 4 self.regions = [] self.cameras = [] self.rig_node = Globals.render.attach_new_node("EnvmapCamRig") self.pta_index = PTAInt.empty_array(1) self.storage_tex = None self.storage_tex_diffuse = None
def __init__(self, pipeline): DebugObject.__init__(self, "GPUCommandQueue") self._pipeline = pipeline self._commands_per_frame = 512 self._command_list = GPUCommandList() self._pta_num_commands = PTAInt.empty_array(1) self._create_data_storage() self._create_command_target() self._commands = [] self._register_defines()
def __init__(self, pipeline): RPObject.__init__(self) self._pipeline = pipeline self._commands_per_frame = 1024 self._command_list = GPUCommandList() self._pta_num_commands = PTAInt.empty_array(1) self._create_data_storage() self._create_command_target() self._commands = [] self._register_defines()
def _setup_inputs(self): """ Sets all required inputs """ self.pta_probes = PTAInt.empty_array(1) # Construct the UBO which stores all environment probe data self.data_ubo = SimpleInputBlock("EnvProbes") self.data_ubo.add_input("num_probes", self.pta_probes) self.data_ubo.add_input("cubemaps", self.probe_mgr.cubemap_storage) self.data_ubo.add_input("diffuse_cubemaps", self.probe_mgr.diffuse_storage) self.data_ubo.add_input("dataset", self.probe_mgr.dataset_storage) self._pipeline.stage_mgr.input_blocks.append(self.data_ubo) # Use the UBO in light culling CullLightsStage.required_inputs.append("EnvProbes")
def _initArrays(self): """ Inits the light arrays which are passed to the shaders """ # If you change this, don't forget to change it also in # Shader/Includes/Configuration.include! self.maxLights = { "PointLight": 16, "DirectionalLight": 1 } # Max shadow casting lights self.maxShadowLights = { "PointLight": 16, "DirectionalLight": 1, "GIHelperLight": 10 } self.maxTotalLights = 8 for lightType, maxCount in self.maxShadowLights.items(): self.maxLights[lightType + "Shadow"] = maxCount # Create array to store number of rendered lights this frame self.numRenderedLights = {} # Also create a PTAInt for every light type, which stores only the # light id, the lighting shader will then lookup the light in the # global lights array. self.renderedLightsArrays = {} for lightType, maxCount in self.maxLights.items(): self.renderedLightsArrays[lightType] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType] = PTAInt.emptyArray(1) for lightType, maxCount in self.maxShadowLights.items(): self.renderedLightsArrays[ lightType + "Shadow"] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType + "Shadow"] = PTAInt.emptyArray(1)
def _initArrays(self): """ Inits the light arrays which are passed to the shaders """ # If you change this, don't forget to change it also in # Shader/Includes/Configuration.include! self.maxLights = { "PointLight": 16, "DirectionalLight": 1 } # Max shadow casting lights self.maxShadowLights = { "PointLight": 16, "DirectionalLight": 1 } self.maxTotalLights = 8 for lightType, maxCount in self.maxShadowLights.items(): self.maxLights[lightType + "Shadow"] = maxCount # Create array to store number of rendered lights this frame self.numRenderedLights = {} # Also create a PTAInt for every light type, which stores only the # light id, the lighting shader will then lookup the light in the # global lights array. self.renderedLightsArrays = {} for lightType, maxCount in self.maxLights.items(): self.renderedLightsArrays[lightType] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType] = PTAInt.emptyArray(1) for lightType, maxCount in self.maxShadowLights.items(): self.renderedLightsArrays[ lightType + "Shadow"] = PTAInt.emptyArray(maxCount) self.numRenderedLights[lightType + "Shadow"] = PTAInt.emptyArray(1)
def __init__(self): DebugObject.__init__(self, "AbstractLight") self.debugNode = NodePath("LightDebug") self.visualizationNumSteps = 32 self.dataNeedsUpdate = False self.castShadows = False self.debugEnabled = False self.bounds = OmniBoundingVolume() self.shadowSources = [] self.lightType = self._getLightType() self.position = Vec3(0) self.color = Vec3(0) self.posterIndex = -1 self.direction = Vec3(0) self.radius = 0.1 self.typeName = "" self.sourceIndexes = PTAInt.emptyArray(6) for i in xrange(6): self.sourceIndexes[i] = -1
def __init__(self, pipeline): """ Creates a new LightManager. It expects a RenderPipeline as parameter. """ DebugObject.__init__(self, "LightManager") self._initArrays() self.pipeline = pipeline self.settings = pipeline.getSettings() # Create arrays to store lights & shadow sources self.lights = [] self.shadowSources = [] self.queuedShadowUpdates = [] self.allLightsArray = ShaderStructArray(Light, self.maxTotalLights) self.updateCallbacks = [] self.cullBounds = None self.shadowScene = Globals.render # Create atlas self.shadowAtlas = ShadowAtlas() self.shadowAtlas.setSize(self.settings.shadowAtlasSize) self.shadowAtlas.create() self.maxShadowMaps = 24 self.maxShadowUpdatesPerFrame = self.settings.maxShadowUpdatesPerFrame self.numShadowUpdatesPTA = PTAInt.emptyArray(1) self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowMaps) # Create shadow compute buffer self._createShadowComputationBuffer() # Create the initial shadow state self.shadowComputeCamera.setTagStateKey("ShadowPassShader") self._createTagStates() self.shadowScene.setTag("ShadowPassShader", "Default") # Create debug overlay self._createDebugTexts() # Disable buffer on start self.shadowComputeTarget.setActive(False) # Bind arrays self.updateShadowsArray.bindTo(self.shadowScene, "updateSources") self.updateShadowsArray.bindTo( self.shadowComputeTarget, "updateSources") # Set initial inputs for target in [self.shadowComputeTarget, self.shadowScene]: target.setShaderInput("numUpdates", self.numShadowUpdatesPTA) self.lightingComputator = None self.lightCuller = None self.skip = 0 self.skipRate = 0
def __init__(self): RenderPass.__init__(self) self.currentIndex = PTAInt.emptyArray(1) self.currentIndex[0] = 0
def __init__(self): """ Creates this Technique """ AntialiasingTechnique.__init__(self, "SMAA") self.currentIndex = PTAInt.emptyArray(1) self.currentIndex[0] = 0
def create(self): """ Creates this pipeline """ self.debug("Setting up render pipeline") if self.settings is None: self.error("You have to call loadSettings first!") return self.debug("Analyzing system ..") SystemAnalyzer.analyze() self.debug("Checking required Panda3D version ..") SystemAnalyzer.checkPandaVersionOutOfDate(7,8,2014) # Mount everything first self.mountManager.mount() # Store globals, as cython can't handle them self.debug("Setting up globals") Globals.load(self.showbase) Globals.font = loader.loadFont("Data/Font/SourceSansPro-Semibold.otf") Globals.font.setPixelsPerUnit(25) # Setting up shader loading BetterShader._DumpShaders = self.settings.dumpGeneratedShaders # We use PTA's for shader inputs, because that's faster than # using setShaderInput self.temporalProjXOffs = PTAInt.emptyArray(1) self.cameraPosition = PTAVecBase3f.emptyArray(1) self.motionBlurFactor = PTAFloat.emptyArray(1) self.lastMVP = PTALMatrix4f.emptyArray(1) self.currentMVP = PTALMatrix4f.emptyArray(1) self.currentShiftIndex = PTAInt.emptyArray(1) # Initialize variables self.camera = self.showbase.cam self.size = self._getSize() self.cullBounds = None # For the temporal reprojection it is important that the window width # is a multiple of 2 if self.settings.enableTemporalReprojection and self.size.x % 2 == 1: self.error( "The window has to have a width which is a multiple of 2 " "(Current: ", self.showbase.win.getXSize(), ")") self.error( "I'll correct that for you, but next time pass the correct " "window size!") wp = WindowProperties() wp.setSize( self.showbase.win.getXSize() + 1, self.showbase.win.getYSize()) self.showbase.win.requestProperties(wp) self.showbase.graphicsEngine.openWindows() # Get new size self.size = self._getSize() # Debug variables to disable specific features self.haveLightingPass = True # haveCombiner can only be true when haveLightingPass is enabled self.haveCombiner = True self.haveMRT = True # Not as good as I want it, so disabled. I'll work on it. self.blurEnabled = False self.debug("Window size is", self.size.x, "x", self.size.y) self.showbase.camLens.setNearFar(0.1, 50000) self.showbase.camLens.setFov(115) self.showbase.win.setClearColor(Vec4(1.0, 0.0, 1.0, 1.0)) # Create GI handleer if self.settings.enableGlobalIllumination: self._setupGlobalIllumination() # Create occlusion handler self._setupOcclusion() if self.settings.displayOnscreenDebugger: self.guiManager = PipelineGuiManager(self) self.guiManager.setup() # Generate auto-configuration for shaders self._generateShaderConfiguration() # Create light manager, which handles lighting + shadows if self.haveLightingPass: self.lightManager = LightManager(self) self.patchSize = LVecBase2i( self.settings.computePatchSizeX, self.settings.computePatchSizeY) # Create separate scene graphs. The deferred graph is render self.forwardScene = NodePath("Forward-Rendering") self.transparencyScene = NodePath("Transparency-Rendering") self.transparencyScene.setBin("transparent", 30) # We need no transparency (we store other information in the alpha # channel) self.showbase.render.setAttrib( TransparencyAttrib.make(TransparencyAttrib.MNone), 100) # Now create deferred render buffers self._makeDeferredTargets() # Create the target which constructs the view-space normals and # position from world-space position if self.occlusion.requiresViewSpacePosNrm(): self._createNormalPrecomputeBuffer() # Setup the buffers for lighting self._createLightingPipeline() # Setup combiner for temporal reprojetion if self.haveCombiner and self.settings.enableTemporalReprojection: self._createCombiner() if self.occlusion.requiresBlurring(): self._createOcclusionBlurBuffer() self._setupAntialiasing() if self.blurEnabled: self._createDofStorage() self._createBlurBuffer() # Not sure why it has to be 0.25. But that leads to the best result aspect = float(self.size.y) / self.size.x self.onePixelShift = Vec2( 0.125 / self.size.x, 0.125 / self.size.y / aspect) * self.settings.jitterAmount # Annoying that Vec2 has no multliply-operator for non-floats multiplyVec2 = lambda a, b: Vec2(a.x*b.x, a.y*b.y) if self.antialias.requiresJittering(): self.pixelShifts = [ multiplyVec2(self.onePixelShift, Vec2(-0.25, 0.25)), multiplyVec2(self.onePixelShift, Vec2(0.25, -0.25)) ] else: self.pixelShifts = [Vec2(0), Vec2(0)] self.currentPixelShift = PTAVecBase2f.emptyArray(1) self.lastPixelShift = PTAVecBase2f.emptyArray(1) self._setupFinalPass() self._setShaderInputs() # add update task self._attachUpdateTask()
def create(self): """ Creates this pipeline """ self.debug("Setting up render pipeline") if self.settings is None: self.error("You have to call loadSettings first!") return self.debug("Analyzing system ..") SystemAnalyzer.analyze() self.debug("Checking required Panda3D version ..") SystemAnalyzer.checkPandaVersionOutOfDate(01, 12, 2014) # Mount everything first self.mountManager.mount() # Store globals, as cython can't handle them self.debug("Setting up globals") Globals.load(self.showbase) Globals.font = loader.loadFont("Data/Font/SourceSansPro-Semibold.otf") Globals.font.setPixelsPerUnit(25) # Setting up shader loading BetterShader._DumpShaders = self.settings.dumpGeneratedShaders # We use PTA's for shader inputs, because that's faster than # using setShaderInput self.temporalProjXOffs = PTAInt.emptyArray(1) self.cameraPosition = PTAVecBase3f.emptyArray(1) self.motionBlurFactor = PTAFloat.emptyArray(1) self.lastMVP = PTALMatrix4f.emptyArray(1) self.currentMVP = PTALMatrix4f.emptyArray(1) self.currentShiftIndex = PTAInt.emptyArray(1) # Initialize variables self.camera = self.showbase.cam self.size = self._getSize() self.cullBounds = None # For the temporal reprojection it is important that the window width # is a multiple of 2 if self.settings.enableTemporalReprojection and self.size.x % 2 == 1: self.error( "The window has to have a width which is a multiple of 2 " "(Current: ", self.showbase.win.getXSize(), ")") self.error( "I'll correct that for you, but next time pass the correct " "window size!") wp = WindowProperties() wp.setSize(self.showbase.win.getXSize() + 1, self.showbase.win.getYSize()) self.showbase.win.requestProperties(wp) self.showbase.graphicsEngine.openWindows() # Get new size self.size = self._getSize() # Debug variables to disable specific features self.haveLightingPass = True # haveCombiner can only be true when haveLightingPass is enabled self.haveCombiner = True self.haveMRT = True # Not as good as I want it, so disabled. I'll work on it. self.blurEnabled = False self.debug("Window size is", self.size.x, "x", self.size.y) self.showbase.camLens.setNearFar(0.1, 50000) self.showbase.camLens.setFov(90) self.showbase.win.setClearColor(Vec4(1.0, 0.0, 1.0, 1.0)) # Create GI handler if self.settings.enableGlobalIllumination: self._setupGlobalIllumination() # Create occlusion handler self._setupOcclusion() if self.settings.displayOnscreenDebugger: self.guiManager = PipelineGuiManager(self) self.guiManager.setup() # Generate auto-configuration for shaders self._generateShaderConfiguration() # Create light manager, which handles lighting + shadows if self.haveLightingPass: self.lightManager = LightManager(self) self.patchSize = LVecBase2i(self.settings.computePatchSizeX, self.settings.computePatchSizeY) # Create separate scene graphs. The deferred graph is render self.forwardScene = NodePath("Forward-Rendering") self.transparencyScene = NodePath("Transparency-Rendering") self.transparencyScene.setBin("transparent", 30) # We need no transparency (we store other information in the alpha # channel) self.showbase.render.setAttrib( TransparencyAttrib.make(TransparencyAttrib.MNone), 100) # Now create deferred render buffers self._makeDeferredTargets() # Create the target which constructs the view-space normals and # position from world-space position if self.occlusion.requiresViewSpacePosNrm(): self._createNormalPrecomputeBuffer() if self.settings.enableGlobalIllumination: self._creatGIPrecomputeBuffer() # Setup the buffers for lighting self._createLightingPipeline() # Setup combiner for temporal reprojetion if self.haveCombiner and self.settings.enableTemporalReprojection: self._createCombiner() if self.occlusion.requiresBlurring(): self._createOcclusionBlurBuffer() self._setupAntialiasing() if self.blurEnabled: self._createDofStorage() self._createBlurBuffer() # Not sure why it has to be 0.25. But that leads to the best result aspect = float(self.size.y) / self.size.x self.onePixelShift = Vec2(0.125 / self.size.x, 0.125 / self.size.y / aspect) * self.settings.jitterAmount # Annoying that Vec2 has no multliply-operator for non-floats multiplyVec2 = lambda a, b: Vec2(a.x * b.x, a.y * b.y) if self.antialias.requiresJittering(): self.pixelShifts = [ multiplyVec2(self.onePixelShift, Vec2(-0.25, 0.25)), multiplyVec2(self.onePixelShift, Vec2(0.25, -0.25)) ] else: self.pixelShifts = [Vec2(0), Vec2(0)] self.currentPixelShift = PTAVecBase2f.emptyArray(1) self.lastPixelShift = PTAVecBase2f.emptyArray(1) self._setupFinalPass() self._setShaderInputs() # Give the gui a hint when the pipeline is done loading if self.settings.displayOnscreenDebugger: self.guiManager.onPipelineLoaded() # add update task self._attachUpdateTask()
def __init__(self, pipeline): RenderStage.__init__(self, pipeline) self.area_tex = None self.search_tex = None self.use_reprojection = True self._jitter_index = PTAInt.empty_array(1)
def create(self): """ Creates this pipeline """ self.debug("Setting up render pipeline") if self.settings is None: self.error("You have to call loadSettings first!") return # Mount everything first self.mountManager.mount() # Store globals, as cython can't handle them self.debug("Setting up globals") Globals.load(self.showbase) # Setting up shader loading BetterShader._DumpShaders = self.settings.dumpGeneratedShaders # We use PTA's for shader inputs, because that's faster than # using setShaderInput self.temporalProjXOffs = PTAInt.emptyArray(1) self.cameraPosition = PTAVecBase3f.emptyArray(1) self.motionBlurFactor = PTAFloat.emptyArray(1) self.lastMVP = PTALMatrix4f.emptyArray(1) self.currentMVP = PTALMatrix4f.emptyArray(1) # Create onscreen gui # For the temporal reprojection it is important that the window width # is a multiple of 2 if self.showbase.win.getXSize() % 2 == 1: self.error( "The window has to have a width which is a multiple of 2 " "(Current: ", self.showbase.win.getXSize(), ")") self.error( "I'll correct that for you, but next time pass the correct " "window size!") wp = WindowProperties() wp.setSize( self.showbase.win.getXSize() + 1, self.showbase.win.getYSize()) self.showbase.win.requestProperties(wp) self.showbase.graphicsEngine.openWindows() self.camera = self.showbase.cam self.size = self._getSize() self.cullBounds = None # Debug variables to disable specific features self.haveLightingPass = True # haveCombiner can only be true when haveLightingPass is enabled self.haveCombiner = True self.haveMRT = True # Not as good as I want it, so disabled. I'll work on it. self.blurEnabled = False self.debug("Window size is", self.size.x, "x", self.size.y) self.showbase.camLens.setNearFar(0.1, 50000) self.showbase.camLens.setFov(90) self.showbase.win.setClearColor(Vec4(1.0,0.0,1.0,1.0)) # Create occlusion handler self._setupOcclusion() if self.settings.displayOnscreenDebugger: self.guiManager = PipelineGuiManager(self) self.guiManager.setup() # Generate auto-configuration for shaders self._generateShaderConfiguration() # Create light manager, which handles lighting + shadows if self.haveLightingPass: self.lightManager = LightManager(self) self.patchSize = LVecBase2i( self.settings.computePatchSizeX, self.settings.computePatchSizeY) # Create separate scene graphs. The deferred graph is render self.forwardScene = NodePath("Forward-Rendering") self.transparencyScene = NodePath("Transparency-Rendering") # We need no transparency (we store other information in the alpha # channel) self.showbase.render.setAttrib( TransparencyAttrib.make(TransparencyAttrib.MNone), 100) # Now create deferred render buffers self._makeDeferredTargets() # Create the target which constructs the view-space normals and # position from world-space position if self.occlusion.requiresViewSpacePosNrm(): self._createNormalPrecomputeBuffer() # Setup the buffers for lighting self._createLightingPipeline() # Setup combiner for temporal reprojetion if self.haveCombiner: self._createCombiner() if self.occlusion.requiresBlurring(): self._createOcclusionBlurBuffer() self._setupAntialiasing() if self.blurEnabled: self._createDofStorage() self._createBlurBuffer() self._setupFinalPass() self._setShaderInputs() # add update task self._attachUpdateTask()
def __init__(self): DebugObject.__init__(self, "LightManager") self._initArrays() # create arrays to store lights & shadow sources self.lights = [] self.shadowSources = [] self.allLightsArray = ShaderStructArray(Light, 30) self.cullBounds = None self.shadowScene = render ## SHADOW ATLAS ## # todo: move to separate class # When you change this, change also SHADOW_MAP_ATLAS_SIZE in configuration.include, # and reduce the default shadow map resolution of point lights self.shadowAtlasSize = 512 self.maxShadowMaps = 24 # When you change it , change also SHAODOW_GEOMETRY_MAX_VERTICES and # SHADOW_MAX_UPDATES_PER_FRAME in configuration.include! self.maxShadowUpdatesPerFrame = 2 self.tileSize = 128 self.tileCount = self.shadowAtlasSize / self.tileSize self.tiles = [] self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray(ShadowSource, self.maxShadowMaps) # self.shadowAtlasTex = Texture("ShadowAtlas") # self.shadowAtlasTex.setup2dTexture( # self.shadowAtlasSize, self.shadowAtlasSize, Texture.TFloat, Texture.FRg16) # self.shadowAtlasTex.setMinfilter(Texture.FTLinear) # self.shadowAtlasTex.setMagfilter(Texture.FTLinear) self.debug("Init shadow atlas with tileSize =", self.tileSize, ", tileCount =", self.tileCount) for i in xrange(self.tileCount): self.tiles.append([None for j in xrange(self.tileCount)]) # create shadow compute buffer self.shadowComputeCamera = Camera("ShadowComputeCamera") self.shadowComputeCameraNode = self.shadowScene.attachNewNode( self.shadowComputeCamera) self.shadowComputeCamera.getLens().setFov(90, 90) self.shadowComputeCamera.getLens().setNearFar(10.0, 100000.0) self.shadowComputeCameraNode.setPos(0, 0, 150) self.shadowComputeCameraNode.lookAt(0, 0, 0) self.shadowComputeTarget = RenderTarget("ShadowCompute") self.shadowComputeTarget.setSize(self.shadowAtlasSize, self.shadowAtlasSize) # self.shadowComputeTarget.setLayers(self.maxShadowUpdatesPerFrame) self.shadowComputeTarget.addRenderTexture(RenderTargetType.Depth) self.shadowComputeTarget.setDepthBits(32) self.shadowComputeTarget.setSource(self.shadowComputeCameraNode, base.win) self.shadowComputeTarget.prepareSceneRender() self.shadowComputeTarget.getInternalRegion().setSort(3) self.shadowComputeTarget.getRegion().setSort(3) self.shadowComputeTarget.getInternalRegion().setNumRegions( self.maxShadowUpdatesPerFrame + 1) self.shadowComputeTarget.getInternalRegion().setDimensions( 0, (0, 1, 0, 1)) self.shadowComputeTarget.setClearDepth(False) self.depthClearer = [] for i in xrange(self.maxShadowUpdatesPerFrame): buff = self.shadowComputeTarget.getInternalBuffer() dr = buff.makeDisplayRegion() dr.setSort(2) dr.setClearDepthActive(True) dr.setClearDepth(1.0) dr.setClearColorActive(False) dr.setDimensions(0, 0, 0, 0) self.depthClearer.append(dr) self.queuedShadowUpdates = [] # Assign copy shader self._setCopyShader() # self.shadowComputeTarget.setShaderInput("atlas", self.shadowComputeTarget.getColorTexture()) # self.shadowComputeTarget.setShaderInput( # "renderResult", self.shadowComputeTarget.getDepthTexture()) # self.shadowComputeTarget.setActive(False) # Create shadow caster shader self.shadowCasterShader = BetterShader.load( "Shader/DefaultShadowCaster.vertex", "Shader/DefaultShadowCaster.fragment", "Shader/DefaultShadowCaster.geometry") self.shadowComputeCamera.setTagStateKey("ShadowPass") initialState = NodePath("ShadowCasterState") initialState.setShader(self.shadowCasterShader, 30) self.shadowComputeCamera.setInitialState( RenderState.make(ColorWriteAttrib.make(ColorWriteAttrib.C_off), DepthWriteAttrib.make(DepthWriteAttrib.M_on), 100)) self.shadowComputeCamera.setTagState("True", initialState.getState()) self.shadowScene.setTag("ShadowPass", "True") self._createDebugTexts() self.updateShadowsArray.bindTo(self.shadowScene, "updateSources") self.updateShadowsArray.bindTo(self.shadowComputeTarget, "updateSources") self.numShadowUpdatesPTA = PTAInt.emptyArray(1) # Set initial inputs for target in [self.shadowComputeTarget, self.shadowScene]: target.setShaderInput("numUpdates", self.numShadowUpdatesPTA) self.lightingComputator = None self.lightCuller = None
def __init__(self, pipeline): """ Creates a new LightManager. It expects a RenderPipeline as parameter. """ DebugObject.__init__(self, "LightManager") self.lightSlots = [None] * LightLimits.maxTotalLights self.shadowSourceSlots = [None] * LightLimits.maxShadowMaps self.queuedShadowUpdates = [] self.renderedLights = {} self.pipeline = pipeline # Create arrays to store lights & shadow sources self.allLightsArray = ShaderStructArray(Light, LightLimits.maxTotalLights) self.updateCallbacks = [] self.cullBounds = None self.numTiles = None self.lightingComputator = None self.shadowScene = Globals.render # Create atlas self.shadowAtlas = ShadowAtlas() self.shadowAtlas.setSize(self.pipeline.settings.shadowAtlasSize) self.shadowAtlas.create() self.maxShadowUpdatesPerFrame = self.pipeline.settings.maxShadowUpdatesPerFrame self.numShadowUpdatesPTA = PTAInt.emptyArray(1) self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray(ShadowSource, LightLimits.maxShadowMaps) self._initLightCulling() # Create shadow compute buffer self._createShadowPass() self._createUnshadowedLightsPass() self._createShadowedLightsPass() self._createApplyLightsPass() self._createExposurePass() if self.pipeline.settings.enableScattering: self._createScatteringPass() # Create the initial shadow state self.shadowScene.setTag("ShadowPassShader", "Default") # Register variables & arrays self.pipeline.getRenderPassManager().registerDynamicVariable( "shadowUpdateSources", self._bindUpdateSources) self.pipeline.getRenderPassManager().registerDynamicVariable( "allLights", self._bindAllLights) self.pipeline.getRenderPassManager().registerDynamicVariable( "allShadowSources", self._bindAllSources) self.pipeline.getRenderPassManager().registerStaticVariable( "numShadowUpdates", self.numShadowUpdatesPTA) self._loadIESProfiles() self._addShaderDefines() self._createDebugTexts()
def __init__(self, pipeline): """ Creates a new LightManager. It expects a RenderPipeline as parameter. """ DebugObject.__init__(self, "LightManager") self._initArrays() self.pipeline = pipeline self.settings = pipeline.getSettings() # Create arrays to store lights & shadow sources self.lights = [] self.shadowSources = [] self.queuedShadowUpdates = [] self.allLightsArray = ShaderStructArray(Light, self.maxTotalLights) self.updateCallbacks = [] self.cullBounds = None self.shadowScene = Globals.render # Create atlas self.shadowAtlas = ShadowAtlas() self.shadowAtlas.setSize(self.settings.shadowAtlasSize) self.shadowAtlas.create() self.maxShadowMaps = 24 self.maxShadowUpdatesPerFrame = self.settings.maxShadowUpdatesPerFrame self.numShadowUpdatesPTA = PTAInt.emptyArray(1) self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowMaps) # Create shadow compute buffer self._createShadowComputationBuffer() # Create the initial shadow state self.shadowComputeCamera.setTagStateKey("ShadowPassShader") # self.shadowComputeCamera.setInitialState(RenderState.make( # ColorWriteAttrib.make(ColorWriteAttrib.C_off), # ColorWriteAttrib.make(ColorWriteAttrib.C_rgb), # DepthWriteAttrib.make(DepthWriteAttrib.M_on), # CullFaceAttrib.make(CullFaceAttrib.MCullNone), # 100)) self._createTagStates() self.shadowScene.setTag("ShadowPassShader", "Default") # Create debug overlay self._createDebugTexts() # Disable buffer on start self.shadowComputeTarget.setActive(False) # Bind arrays self.updateShadowsArray.bindTo(self.shadowScene, "updateSources") self.updateShadowsArray.bindTo( self.shadowComputeTarget, "updateSources") # Set initial inputs for target in [self.shadowComputeTarget, self.shadowScene]: target.setShaderInput("numUpdates", self.numShadowUpdatesPTA) self.lightingComputator = None self.lightCuller = None self.skip = 0 self.skipRate = 0
def _create_ptas(self): self._pta_grid_pos = PTALVecBase3.empty_array(1) self._pta_grid_size = PTAFloat.empty_array(1) self._pta_grid_res = PTAInt.empty_array(1) self._pta_grid_size[0] = self._voxel_ws self._pta_grid_res[0] = self._voxel_res
def __init__(self, pipeline): """ Creates a new LightManager. It expects a RenderPipeline as parameter. """ DebugObject.__init__(self, "LightManager") self.lightSlots = [None] * LightLimits.maxTotalLights self.shadowSourceSlots = [None] * LightLimits.maxShadowMaps self.queuedShadowUpdates = [] self.renderedLights = {} self.pipeline = pipeline # Create arrays to store lights & shadow sources self.allLightsArray = ShaderStructArray(Light, LightLimits.maxTotalLights) self.updateCallbacks = [] self.cullBounds = None self.shadowScene = Globals.render # Create atlas self.shadowAtlas = ShadowAtlas() self.shadowAtlas.setSize(self.pipeline.settings.shadowAtlasSize) self.shadowAtlas.create() self.maxShadowUpdatesPerFrame = self.pipeline.settings.maxShadowUpdatesPerFrame self.numShadowUpdatesPTA = PTAInt.emptyArray(1) self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray( ShadowSource, LightLimits.maxShadowMaps) # Create shadow compute buffer self._createShadowPass() self._createUnshadowedLightsPass() self._createShadowedLightsPass() if self.pipeline.settings.enableScattering: self._createScatteringPass() self._initLightCulling() # Create the initial shadow state self.shadowScene.setTag("ShadowPassShader", "Default") # Register variables & arrays self.pipeline.getRenderPassManager().registerDynamicVariable("shadowUpdateSources", self._bindUpdateSources) self.pipeline.getRenderPassManager().registerDynamicVariable("allLights", self._bindAllLights) self.pipeline.getRenderPassManager().registerDynamicVariable("allShadowSources", self._bindAllSources) self.pipeline.getRenderPassManager().registerStaticVariable("numShadowUpdates", self.numShadowUpdatesPTA) self._loadIESProfiles() self._addShaderDefines() self.lightingComputator = None self._createDebugTexts()