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 _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, pos=Vec2(0), rightAligned=False, color=Vec3(0, 0, 0), size=0.04, parent=None): if parent is None: parent = Globals.base.aspect2d self.parent = parent self._loadCharset() self._prepareFontTextures() self._makeFontShader() self._makeSquare() self.data = PTAFloat.empty_array(100) self.lastText = "" self.size = 16.0 / base.win.getYSize() * 2.0 self.square.setShaderInput("displData", self.data) self.rightAligned = rightAligned self.pos = pos self.posOffset = Vec2(0) self.color = PTALVecBase3f.emptyArray(1) self.color[0] = color self.posPTA = PTALVecBase2f.emptyArray(1) self.square.setShaderInput("pos", self.posPTA) self._updateInputs()
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__(self, pos=Vec2(0), rightAligned=False, color=Vec3(0, 0, 0), size=0.04): self._loadCharset() self._prepareFontTextures() self._makeFontShader() self._makeSquare() self.data = PTAFloat.empty_array(100) self.lastText = "" self.size = size self.square.setShaderInput("displData", self.data) self.rightAligned = rightAligned self.pos = pos self.posOffset = Vec2(0) self.color = color self.posPTA = PTALVecBase2f.emptyArray(1) self.square.setShaderInput("pos", self.posPTA) self._updateInputs()
def _generatePTAs(self): self.debug("Generating PTAs ..") for settingName, settingValue in self.settings.items(): if type(settingValue) == float: self.settingsPTA[settingName] = PTAFloat.emptyArray(1) self.settingsPTA[settingName][0] = settingValue elif type(settingValue) == Vec3: self.settingsPTA[settingName] = PTALVecBase3f.emptyArray(1) self.settingsPTA[settingName][0] = settingValue elif type(settingValue) == bool: # no pta bool yet self.settingsPTA[settingName] = settingValue else: self.warn("Unkown type:", settingName, type(settingValue))
def _generatePTAs(self): """ Converts all settings to pta arrays, this is faster than using setShaderInput for every uniform """ for settingName, settingValue in self.settings.iteritems(): if type(settingValue) == float: self.settingsPTA[settingName] = PTAFloat.emptyArray(1) self.settingsPTA[settingName][0] = settingValue elif type(settingValue) == Vec3: self.settingsPTA[settingName] = PTALVecBase3f.emptyArray(1) self.settingsPTA[settingName][0] = settingValue elif type(settingValue) == bool: self.settingsPTA[settingName] = settingValue else: self.warn("Unkown type:", settingName, type(settingValue))
def __init__(self, pos=Vec2(0), rightAligned=False, color=Vec3(0,0,0), size=0.04): self._loadCharset() self._prepareFontTextures() self._makeFontShader() self._makeSquare() self.data = PTAFloat.empty_array(100) self.lastText = "" self.size = size self.square.setShaderInput("displData", self.data) self.rightAligned = rightAligned self.pos = pos self.posOffset = Vec2(0) self.color = color self._updateInputs()
def __init__(self, pipeline): DebugObject.__init__(self, "GlobalIllumnination") self.pipeline = pipeline self.qualityLevel = self.pipeline.settings.giQualityLevel if self.qualityLevel not in self.QualityLevels: self.fatal("Unsupported gi quality level:" + self.qualityLevel) self.qualityLevelIndex = self.QualityLevels.index(self.qualityLevel) # Grid size in world space units self.voxelGridSize = self.pipeline.settings.giVoxelGridSize # Grid resolution in pixels self.voxelGridResolution = [32, 64, 128, 192][self.qualityLevelIndex] # Has to be a multiple of 2 self.distributionSteps = [16, 30, 60, 90][self.qualityLevelIndex] self.slideCount = int(self.voxelGridResolution / 8) self.slideVertCount = self.voxelGridResolution / self.slideCount self.bounds = BoundingBox() self.renderCount = 0 # Create the task manager self.taskManager = DistributedTaskManager() self.gridPosLive = PTALVecBase3f.emptyArray(1) self.gridPosTemp = PTALVecBase3f.emptyArray(1) # Store ready state self.readyStateFlag = PTAFloat.emptyArray(1) self.readyStateFlag[0] = 0 self.frameIndex = 0 self.steps = []
def _list_to_pta(self, list_values): """ Converts a list to a PTAFloat """ pta = PTAFloat.empty_array(len(list_values)) for i, val in enumerate(list_values): pta[i] = val return pta
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 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_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): DebugObject.__init__(self, "WaterManager") self.options = OceanOptions() self.options.size = 512 self.options.windDir.normalize() self.options.waveAmplitude *= 1e-7 self.displacementTex = Texture("Displacement") self.displacementTex.setup2dTexture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.normalTex = Texture("Normal") self.normalTex.setup2dTexture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.combineShader = Shader.loadCompute(Shader.SLGLSL, "Shader/WaterFFT/Combine.compute") self.ptaTime = PTAFloat.emptyArray(1) # Create a gaussian random texture, as shaders aren't well suited # for that setRandomSeed(523) self.randomStorage = PNMImage(self.options.size, self.options.size, 4) self.randomStorage.setMaxval((2 ** 16) - 1) for x in xrange(self.options.size): for y in xrange(self.options.size): rand1 = self._getGaussianRandom() / 10.0 + 0.5 rand2 = self._getGaussianRandom() / 10.0 + 0.5 self.randomStorage.setXel(x, y, float(rand1), float(rand2), 0) self.randomStorage.setAlpha(x, y, 1.0) self.randomStorageTex = Texture("RandomStorage") self.randomStorageTex.load(self.randomStorage) self.randomStorageTex.setFormat(Texture.FRgba16) self.randomStorageTex.setMinfilter(Texture.FTNearest) self.randomStorageTex.setMagfilter(Texture.FTNearest) # Create the texture wwhere the intial height (H0 + Omega0) is stored. self.texInitialHeight = Texture("InitialHeight") self.texInitialHeight.setup2dTexture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.texInitialHeight.setMinfilter(Texture.FTNearest) self.texInitialHeight.setMagfilter(Texture.FTNearest) # Create the shader which populates the initial height texture self.shaderInitialHeight = Shader.loadCompute(Shader.SLGLSL, "Shader/WaterFFT/InitialHeight.compute") self.nodeInitialHeight = NodePath("initialHeight") self.nodeInitialHeight.setShader(self.shaderInitialHeight) self.nodeInitialHeight.setShaderInput("dest", self.texInitialHeight) self.nodeInitialHeight.setShaderInput( "N", LVecBase2i(self.options.size)) self.nodeInitialHeight.setShaderInput( "patchLength", self.options.patchLength) self.nodeInitialHeight.setShaderInput("windDir", self.options.windDir) self.nodeInitialHeight.setShaderInput( "windSpeed", self.options.windSpeed) self.nodeInitialHeight.setShaderInput( "waveAmplitude", self.options.waveAmplitude) self.nodeInitialHeight.setShaderInput( "windDependency", self.options.windDependency) self.nodeInitialHeight.setShaderInput( "randomTex", self.randomStorageTex) self.attrInitialHeight = self.nodeInitialHeight.getAttrib(ShaderAttrib) self.heightTextures = [] for i in xrange(3): tex = Texture("Height") tex.setup2dTexture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) tex.setMinfilter(Texture.FTNearest) tex.setMagfilter(Texture.FTNearest) tex.setWrapU(Texture.WMClamp) tex.setWrapV(Texture.WMClamp) self.heightTextures.append(tex) # Also create the shader which updates the spectrum self.shaderUpdate = Shader.loadCompute(Shader.SLGLSL, "Shader/WaterFFT/Update.compute") self.nodeUpdate = NodePath("update") self.nodeUpdate.setShader(self.shaderUpdate) self.nodeUpdate.setShaderInput("outH0x", self.heightTextures[0]) self.nodeUpdate.setShaderInput("outH0y", self.heightTextures[1]) self.nodeUpdate.setShaderInput("outH0z", self.heightTextures[2]) self.nodeUpdate.setShaderInput("initialHeight", self.texInitialHeight) self.nodeUpdate.setShaderInput("N", LVecBase2i(self.options.size)) self.nodeUpdate.setShaderInput("time", self.ptaTime) self.attrUpdate = self.nodeUpdate.getAttrib(ShaderAttrib) # Create 3 FFTs self.fftX = GPUFFT(self.options.size, self.heightTextures[0], self.options.normalizationFactor) self.fftY = GPUFFT(self.options.size, self.heightTextures[1], self.options.normalizationFactor) self.fftZ = GPUFFT(self.options.size, self.heightTextures[2], self.options.normalizationFactor) self.combineNode = NodePath("Combine") self.combineNode.setShader(self.combineShader) self.combineNode.setShaderInput( "displacementX", self.fftX.getResultTexture()) self.combineNode.setShaderInput( "displacementY", self.fftY.getResultTexture()) self.combineNode.setShaderInput( "displacementZ", self.fftZ.getResultTexture()) self.combineNode.setShaderInput("normalDest", self.normalTex) self.combineNode.setShaderInput( "displacementDest", self.displacementTex) self.combineNode.setShaderInput( "N", LVecBase2i(self.options.size)) self.combineNode.setShaderInput( "choppyScale", self.options.choppyScale) self.combineNode.setShaderInput( "gridLength", self.options.patchLength) # Store only the shader attrib as this is way faster self.attrCombine = self.combineNode.getAttrib(ShaderAttrib)
def __init__(self): DebugObject.__init__(self, "WaterManager") self.options = OceanOptions() self.options.size = 512 self.options.windDir.normalize() self.options.waveAmplitude *= 1e-7 self.displacementTex = Texture("Displacement") self.displacementTex.setup2dTexture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.normalTex = Texture("Normal") self.normalTex.setup2dTexture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.combineShader = BetterShader.loadCompute( "Shader/Water/Combine.compute") self.ptaTime = PTAFloat.emptyArray(1) # Create a gaussian random texture, as shaders aren't well suited # for that setRandomSeed(523) self.randomStorage = PNMImage(self.options.size, self.options.size, 4) self.randomStorage.setMaxval((2**16) - 1) for x in xrange(self.options.size): for y in xrange(self.options.size): rand1 = self._getGaussianRandom() / 10.0 + 0.5 rand2 = self._getGaussianRandom() / 10.0 + 0.5 self.randomStorage.setXel(x, y, LVecBase3d(rand1, rand2, 0)) self.randomStorage.setAlpha(x, y, 1.0) self.randomStorageTex = Texture("RandomStorage") self.randomStorageTex.load(self.randomStorage) self.randomStorageTex.setFormat(Texture.FRgba16) self.randomStorageTex.setMinfilter(Texture.FTNearest) self.randomStorageTex.setMagfilter(Texture.FTNearest) # Create the texture wwhere the intial height (H0 + Omega0) is stored. self.texInitialHeight = Texture("InitialHeight") self.texInitialHeight.setup2dTexture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.texInitialHeight.setMinfilter(Texture.FTNearest) self.texInitialHeight.setMagfilter(Texture.FTNearest) # Create the shader which populates the initial height texture self.shaderInitialHeight = BetterShader.loadCompute( "Shader/Water/InitialHeight.compute") self.nodeInitialHeight = NodePath("initialHeight") self.nodeInitialHeight.setShader(self.shaderInitialHeight) self.nodeInitialHeight.setShaderInput("dest", self.texInitialHeight) self.nodeInitialHeight.setShaderInput("N", LVecBase2i(self.options.size)) self.nodeInitialHeight.setShaderInput("patchLength", self.options.patchLength) self.nodeInitialHeight.setShaderInput("windDir", self.options.windDir) self.nodeInitialHeight.setShaderInput("windSpeed", self.options.windSpeed) self.nodeInitialHeight.setShaderInput("waveAmplitude", self.options.waveAmplitude) self.nodeInitialHeight.setShaderInput("windDependency", self.options.windDependency) self.nodeInitialHeight.setShaderInput("randomTex", self.randomStorageTex) self.attrInitialHeight = self.nodeInitialHeight.getAttrib(ShaderAttrib) self.heightTextures = [] for i in xrange(3): tex = Texture("Height") tex.setup2dTexture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) tex.setMinfilter(Texture.FTNearest) tex.setMagfilter(Texture.FTNearest) tex.setWrapU(Texture.WMClamp) tex.setWrapV(Texture.WMClamp) self.heightTextures.append(tex) # Also create the shader which updates the spectrum self.shaderUpdate = BetterShader.loadCompute( "Shader/Water/Update.compute") self.nodeUpdate = NodePath("update") self.nodeUpdate.setShader(self.shaderUpdate) self.nodeUpdate.setShaderInput("outH0x", self.heightTextures[0]) self.nodeUpdate.setShaderInput("outH0y", self.heightTextures[1]) self.nodeUpdate.setShaderInput("outH0z", self.heightTextures[2]) self.nodeUpdate.setShaderInput("initialHeight", self.texInitialHeight) self.nodeUpdate.setShaderInput("N", LVecBase2i(self.options.size)) self.nodeUpdate.setShaderInput("time", self.ptaTime) self.attrUpdate = self.nodeUpdate.getAttrib(ShaderAttrib) # Create 3 FFTs self.fftX = GPUFFT(self.options.size, self.heightTextures[0], self.options.normalizationFactor) self.fftY = GPUFFT(self.options.size, self.heightTextures[1], self.options.normalizationFactor) self.fftZ = GPUFFT(self.options.size, self.heightTextures[2], self.options.normalizationFactor) self.combineNode = NodePath("Combine") self.combineNode.setShader(self.combineShader) self.combineNode.setShaderInput("displacementX", self.fftX.getResultTexture()) self.combineNode.setShaderInput("displacementY", self.fftY.getResultTexture()) self.combineNode.setShaderInput("displacementZ", self.fftZ.getResultTexture()) self.combineNode.setShaderInput("normalDest", self.normalTex) self.combineNode.setShaderInput("displacementDest", self.displacementTex) self.combineNode.setShaderInput("N", LVecBase2i(self.options.size)) self.combineNode.setShaderInput("choppyScale", self.options.choppyScale) self.combineNode.setShaderInput("gridLength", self.options.patchLength) # Store only the shader attrib as this is way faster self.attrCombine = self.combineNode.getAttrib(ShaderAttrib)
def __init__(self, water_options): self.options = water_options self.options.size = 512 self.options.wind_dir.normalize() self.options.wave_amplitude *= 1e-7 self.displacement_tex = Texture("Displacement") self.displacement_tex.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.normal_tex = Texture("Normal") self.normal_tex.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.combine_shader = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/combine.compute") self.pta_time = PTAFloat.emptyArray(1) # Create a gaussian random texture, as shaders aren't well suited # for that setRandomSeed(523) self.random_storage = PNMImage(self.options.size, self.options.size, 4) self.random_storage.setMaxval((2 ** 16) - 1) for x in range(self.options.size): for y in range(self.options.size): rand1 = self._get_gaussian_random() / 10.0 + 0.5 rand2 = self._get_gaussian_random() / 10.0 + 0.5 self.random_storage.setXel(x, y, float(rand1), float(rand2), 0) self.random_storage.setAlpha(x, y, 1.0) self.random_storage_tex = Texture("RandomStorage") self.random_storage_tex.load(self.random_storage) self.random_storage_tex.set_format(Texture.FRgba16) self.random_storage_tex.set_minfilter(Texture.FTNearest) self.random_storage_tex.set_magfilter(Texture.FTNearest) # Create the texture wwhere the intial height (H0 + Omega0) is stored. self.tex_initial_height = Texture("InitialHeight") self.tex_initial_height.setup_2d_texture( self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) self.tex_initial_height.set_minfilter(Texture.FTNearest) self.tex_initial_height.set_magfilter(Texture.FTNearest) # Create the shader which populates the initial height texture self.shader_initial_height = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/initial_height.compute") self.node_initial_height = NodePath("initialHeight") self.node_initial_height.set_shader(self.shader_initial_height) self.node_initial_height.set_shader_input("dest", self.tex_initial_height) self.node_initial_height.set_shader_input( "N", LVecBase2i(self.options.size)) self.node_initial_height.set_shader_input( "patchLength", self.options.patch_length) self.node_initial_height.set_shader_input("windDir", self.options.wind_dir) self.node_initial_height.set_shader_input( "windSpeed", self.options.wind_speed) self.node_initial_height.set_shader_input( "waveAmplitude", self.options.wave_amplitude) self.node_initial_height.set_shader_input( "windDependency", self.options.wind_dependency) self.node_initial_height.set_shader_input( "randomTex", self.random_storage_tex) self.attr_initial_height = self.node_initial_height.get_attrib(ShaderAttrib) self.height_textures = [] for i in range(3): tex = Texture("Height") tex.setup_2d_texture(self.options.size, self.options.size, Texture.TFloat, Texture.FRgba16) tex.set_minfilter(Texture.FTNearest) tex.set_magfilter(Texture.FTNearest) tex.set_wrap_u(Texture.WMClamp) tex.set_wrap_v(Texture.WMClamp) self.height_textures.append(tex) # Also create the shader which updates the spectrum self.shader_update = Shader.load_compute(Shader.SLGLSL, "/$$rp/rpcore/water/shader/update.compute") self.node_update = NodePath("update") self.node_update.set_shader(self.shader_update) self.node_update.set_shader_input("outH0x", self.height_textures[0]) self.node_update.set_shader_input("outH0y", self.height_textures[1]) self.node_update.set_shader_input("outH0z", self.height_textures[2]) self.node_update.set_shader_input("initialHeight", self.tex_initial_height) self.node_update.set_shader_input("N", LVecBase2i(self.options.size)) self.node_update.set_shader_input("time", self.pta_time) self.attr_update = self.node_update.get_attrib(ShaderAttrib) # Create 3 FFTs self.fftX = GPUFFT(self.options.size, self.height_textures[0], self.options.normalization_factor) self.fftY = GPUFFT(self.options.size, self.height_textures[1], self.options.normalization_factor) self.fftZ = GPUFFT(self.options.size, self.height_textures[2], self.options.normalization_factor) self.combine_node = NodePath("Combine") self.combine_node.set_shader(self.combine_shader) self.combine_node.set_shader_input( "displacementX", self.fftX.get_result_texture()) self.combine_node.set_shader_input( "displacementY", self.fftY.get_result_texture()) self.combine_node.set_shader_input( "displacementZ", self.fftZ.get_result_texture()) self.combine_node.set_shader_input("normalDest", self.normal_tex) self.combine_node.set_shader_input( "displacementDest", self.displacement_tex) self.combine_node.set_shader_input( "N", LVecBase2i(self.options.size)) self.combine_node.set_shader_input( "choppyScale", self.options.choppy_scale) self.combine_node.set_shader_input( "gridLength", self.options.patch_length) # Store only the shader attrib as this is way faster self.attr_combine = self.combine_node.get_attrib(ShaderAttrib)
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()