예제 #1
0
    def __init__(self, N, sourceTex, normalizationFactor):
        """ Creates a new fft instance. The source texture has to specified
        from the begining, as the shaderAttributes are pregenerated for
        performance reasons """
        DebugObject.__init__(self, "GPU-FFT")

        self.size = N
        self.log2Size = int(math.log(N, 2))
        self.normalizationFactor = normalizationFactor

        # Create a ping and a pong texture, because we can't write to the
        # same texture while reading to it (that would lead to unexpected
        # behaviour, we could solve that by using an appropriate thread size,
        # but it works fine so far)
        self.pingTexture = Texture("FFTPing")
        self.pingTexture.setup2dTexture(self.size, self.size, Texture.TFloat,
                                        Texture.FRgba32)
        self.pongTexture = Texture("FFTPong")
        self.pongTexture.setup2dTexture(self.size, self.size, Texture.TFloat,
                                        Texture.FRgba32)
        self.sourceTex = sourceTex

        for tex in [self.pingTexture, self.pongTexture, sourceTex]:
            tex.setMinfilter(Texture.FTNearest)
            tex.setMagfilter(Texture.FTNearest)
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)

        # Pregenerate weights & indices for the shaders
        self._computeWeighting()

        # Pre generate the shaders, we have 2 passes: Horizontal and Vertical
        # which both execute log2(N) times with varying radii
        self.horizontalFFTShader = Shader.loadCompute(
            Shader.SLGLSL, "Shader/WaterFFT/HorizontalFFT.compute")
        self.horizontalFFT = NodePath("HorizontalFFT")
        self.horizontalFFT.setShader(self.horizontalFFTShader)
        self.horizontalFFT.setShaderInput("precomputedWeights",
                                          self.weightsLookupTex)
        self.horizontalFFT.setShaderInput("N", LVecBase2i(self.size))

        self.verticalFFTShader = Shader.loadCompute(
            Shader.SLGLSL, "Shader/WaterFFT/VerticalFFT.compute")
        self.verticalFFT = NodePath("VerticalFFT")
        self.verticalFFT.setShader(self.verticalFFTShader)
        self.verticalFFT.setShaderInput("precomputedWeights",
                                        self.weightsLookupTex)
        self.verticalFFT.setShaderInput("N", LVecBase2i(self.size))

        # Create a texture where the result is stored
        self.resultTexture = Texture("Result")
        self.resultTexture.setup2dTexture(self.size, self.size, Texture.TFloat,
                                          Texture.FRgba16)
        self.resultTexture.setMinfilter(Texture.FTLinear)
        self.resultTexture.setMagfilter(Texture.FTLinear)

        # Prepare the shader attributes, so we don't have to regenerate them
        # every frame -> That is VERY slow (3ms per fft instance)
        self._prepareAttributes()
예제 #2
0
    def __init__(self, N, sourceTex, normalizationFactor):
        """ Creates a new fft instance. The source texture has to specified
        from the begining, as the shaderAttributes are pregenerated for
        performance reasons """
        DebugObject.__init__(self, "GPU-FFT")

        self.size = N
        self.log2Size = int(math.log(N, 2))
        self.normalizationFactor = normalizationFactor

        # Create a ping and a pong texture, because we can't write to the
        # same texture while reading to it (that would lead to unexpected
        # behaviour, we could solve that by using an appropriate thread size,
        # but it works fine so far)
        self.pingTexture = Texture("FFTPing")
        self.pingTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba32)
        self.pongTexture = Texture("FFTPong")
        self.pongTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba32)
        self.sourceTex = sourceTex

        for tex in [self.pingTexture, self.pongTexture, sourceTex]:
            tex.setMinfilter(Texture.FTNearest)
            tex.setMagfilter(Texture.FTNearest)
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)

        # Pregenerate weights & indices for the shaders
        self._computeWeighting()

        # Pre generate the shaders, we have 2 passes: Horizontal and Vertical
        # which both execute log2(N) times with varying radii
        self.horizontalFFTShader = Shader.loadCompute(Shader.SLGLSL,
            "Shader/Water/HorizontalFFT.compute")
        self.horizontalFFT = NodePath("HorizontalFFT")
        self.horizontalFFT.setShader(self.horizontalFFTShader)
        self.horizontalFFT.setShaderInput(
            "precomputedWeights", self.weightsLookupTex)
        self.horizontalFFT.setShaderInput("N", LVecBase2i(self.size))

        self.verticalFFTShader = Shader.loadCompute(Shader.SLGLSL,
            "Shader/Water/VerticalFFT.compute")
        self.verticalFFT = NodePath("VerticalFFT")
        self.verticalFFT.setShader(self.verticalFFTShader)
        self.verticalFFT.setShaderInput(
            "precomputedWeights", self.weightsLookupTex)
        self.verticalFFT.setShaderInput("N", LVecBase2i(self.size))

        # Create a texture where the result is stored
        self.resultTexture = Texture("Result")
        self.resultTexture.setup2dTexture(
            self.size, self.size, Texture.TFloat, Texture.FRgba16)
        self.resultTexture.setMinfilter(Texture.FTLinear)
        self.resultTexture.setMagfilter(Texture.FTLinear)

        # Prepare the shader attributes, so we don't have to regenerate them
        # every frame -> That is VERY slow (3ms per fft instance)
        self._prepareAttributes()
예제 #3
0
    def _createInitialGrid(self):
        """ Creates the initial cloud grid """
        shader = Shader.loadCompute(Shader.SLGLSL, "Shader/Clouds/InitialGrid.compute")
        dummy = NodePath("dummy")
        dummy.setShader(shader)
        dummy.setShaderInput("cloudGrid", self.voxelGrid)
        sattr = dummy.getAttrib(ShaderAttrib)
        Globals.base.graphicsEngine.dispatch_compute(
            (self.cloudResolution / 8, self.cloudResolution / 8, self.cloudResolutionH / 8), sattr, Globals.base.win.getGsg())

        shader = Shader.loadCompute(Shader.SLGLSL, "Shader/Clouds/CloudNoise.compute")
        dummy = NodePath("dummy")
        dummy.setShader(shader)
        dummy.setShaderInput("noiseGrid", self.cloudNoise)
        sattr = dummy.getAttrib(ShaderAttrib)
        Globals.base.graphicsEngine.dispatch_compute(
            (64 / 8, 64 / 8, 64 / 8), sattr, Globals.base.win.getGsg())
예제 #4
0
    def _createInitialGrid(self):
        """ Creates the initial cloud grid """
        shader = Shader.loadCompute(Shader.SLGLSL,
                                    "Shader/Clouds/InitialGrid.compute")
        dummy = NodePath("dummy")
        dummy.setShader(shader)
        dummy.setShaderInput("cloudGrid", self.voxelGrid)
        sattr = dummy.getAttrib(ShaderAttrib)
        Globals.base.graphicsEngine.dispatch_compute(
            (self.cloudResolution / 8, self.cloudResolution / 8,
             self.cloudResolutionH / 8), sattr, Globals.base.win.getGsg())

        shader = Shader.loadCompute(Shader.SLGLSL,
                                    "Shader/Clouds/CloudNoise.compute")
        dummy = NodePath("dummy")
        dummy.setShader(shader)
        dummy.setShaderInput("noiseGrid", self.cloudNoise)
        sattr = dummy.getAttrib(ShaderAttrib)
        Globals.base.graphicsEngine.dispatch_compute((64 / 8, 64 / 8, 64 / 8),
                                                     sattr,
                                                     Globals.base.win.getGsg())
예제 #5
0
    def enable(self):
        if not self.isSupported():
            # HDR/auto exposure is implemented using compute
            # shaders, which are only supported by more modern
            # graphics cards and requires at least OpenGL 4.3.
            return

        self.sceneTex = Texture('hdrSceneTex')
        self.sceneTex.setup2dTexture(self.Size, self.Size, Texture.TFloat, Texture.FRgba32)
        self.sceneTex.setWrapU(SamplerState.WMClamp)
        self.sceneTex.setWrapV(SamplerState.WMClamp)
        self.sceneTex.clearImage()
        
        self.__setupSceneQuad()

        # Build luminance histogram bucket ranges.
        self.ptaBucketRange = PTALVecBase2f.emptyArray(self.NumBuckets)
        for i in xrange(self.NumBuckets):
            # Use even distribution
            bmin = float(i) / float(self.NumBuckets)
            bmax = float(i + 1) / float(self.NumBuckets)

            # Use a distribution with slightly more bins in the low range.
            if bmin > 0.0:
                bmin = math.pow(bmin, 1.5)
            if bmax > 0.0:
                bmax = math.pow(bmax, 1.5)

            self.ptaBucketRange.setElement(i, Vec2(bmin, bmax))

        self.histogramTex = Texture('histogram')
        self.histogramTex.setup1dTexture(self.NumBuckets, Texture.TInt, Texture.FR32i)
        self.histogramTex.setClearColor(Vec4(0))
        self.histogramTex.clearImage()
        self.histogramCompute = base.computeRoot.attachNewNode(ComputeNode('histogramCompute'))
        self.histogramCompute.node().addDispatch(self.Size / 8, self.Size / 8, self.Size / 16)
        self.histogramCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/build_histogram.compute.glsl"), 1)
        self.histogramCompute.setShaderInput("scene_texture", self.sceneTex)
        self.histogramCompute.setShaderInput("histogram_texture", self.histogramTex)
        self.histogramCompute.setShaderInput("bucketrange", self.ptaBucketRange)
        self.histogramCompute.setBin("fixed", 0)

        self.exposureTex = Texture('exposure')
        self.exposureTex.setup1dTexture(1, Texture.TFloat, Texture.FR16)
        self.exposureTex.setClearColor(Vec4(0.0))
        self.exposureTex.clearImage()
        self.exposureCompute = base.computeRoot.attachNewNode(ComputeNode('exposureCompute'))
        self.exposureCompute.node().addDispatch(1, 1, 1)
        self.exposureCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/calc_luminance.compute.glsl"), 1)
        self.exposureCompute.setShaderInput("histogram_texture", self.histogramTex)
        self.exposureCompute.setShaderInput("avg_lum_texture", self.exposureTex)
        self.exposureCompute.setShaderInput("bucketrange", self.ptaBucketRange)
        self.exposureCompute.setShaderInput("exposure_minmax", Vec2(1.0, 2.0))
        self.exposureCompute.setShaderInput("adaption_rate_brightdark", Vec2(0.6, 0.6))
        self.exposureCompute.setShaderInput("exposure_scale", base.config.GetFloat("hdr-tonemapscale", 1.75))
        self.exposureCompute.setShaderInput("config_minAvgLum", base.config.GetFloat("hdr-min-avglum", 3.0))
        self.exposureCompute.setShaderInput("config_perctBrightPixels", base.config.GetFloat("hdr-percent-bright-pixels", 2.0))
        self.exposureCompute.setShaderInput("config_perctTarget", base.config.GetFloat("hdr-percent-target", 60.0))
        self.exposureCompute.setBin("fixed", 1)
        
        base.filters.setExposure(self.exposureTex)

        taskMgr.add(self.__update, "hdrUpdate", sort = -10000000)

        if base.config.GetBool("hdr-debug-histogram", False):
            self.debugTex = Texture('histogramDebugTex')
            self.debugTex.setup2dTexture(self.NumBuckets, 1, Texture.TFloat, Texture.FRgba32)
            self.debugTex.setMagfilter(SamplerState.FTNearest)
            self.debugTex.setClearColor(Vec4(0.3, 0.3, 0.5, 1.0))
            self.debugTex.clearImage()
            self.debugCompute = base.computeRoot.attachNewNode(ComputeNode('debugHistogramCompute'))
            self.debugCompute.node().addDispatch(1, 1, 1)
            self.debugCompute.setShader(Shader.loadCompute(Shader.SLGLSL, "phase_14/models/shaders/debug_histogram.compute.glsl"), 1)
            self.debugCompute.setShaderInput("histogram_texture", self.histogramTex)
            self.debugCompute.setShaderInput("debug_texture", self.debugTex)
            self.debugCompute.setBin("fixed", 2)
            self.debugImg = OnscreenImage(image = self.debugTex, scale = 0.3, pos = (-0.6, -0.7, -0.7))
예제 #6
0
    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)
예제 #7
0
    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)