| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsRenderBeastIBLUtility.h"
- #include "Image/BsTexture.h"
- #include "Material/BsGpuParamsSet.h"
- #include "Renderer/BsRendererUtility.h"
- #include "RenderAPI/BsGpuBuffer.h"
- #include "BsRenderBeast.h"
- namespace bs { namespace ct
- {
- ReflectionCubeDownsampleParamDef gReflectionCubeDownsampleParamDef;
- ReflectionCubeDownsampleMat::ReflectionCubeDownsampleMat()
- {
- mParamBuffer = gReflectionCubeDownsampleParamDef.createBuffer();
- SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
- gpuParams->setParamBlockBuffer("Input", mParamBuffer);
- gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
- }
- void ReflectionCubeDownsampleMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void ReflectionCubeDownsampleMat::execute(
- const SPtr<Texture>& source,
- UINT32 face,
- UINT32 mip,
- const SPtr<RenderTarget>& target)
- {
- RenderAPI& rapi = RenderAPI::instance();
- const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
- gReflectionCubeDownsampleParamDef.gCubeFace.set(mParamBuffer, face);
- if(rapiInfo.isFlagSet(RenderAPIFeatureFlag::TextureViews))
- {
- mInputTexture.set(source, TextureSurface(mip, 1, 0, 6));
- gReflectionCubeDownsampleParamDef.gMipLevel.set(mParamBuffer, 0);
- }
- else
- {
- mInputTexture.set(source);
- gReflectionCubeDownsampleParamDef.gMipLevel.set(mParamBuffer, mip);
- }
- rapi.setRenderTarget(target);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- }
- const UINT32 ReflectionCubeImportanceSampleMat::NUM_SAMPLES = 1024;
- ReflectionCubeImportanceSampleParamDef gReflectionCubeImportanceSampleParamDef;
- ReflectionCubeImportanceSampleMat::ReflectionCubeImportanceSampleMat()
- {
- mParamBuffer = gReflectionCubeImportanceSampleParamDef.createBuffer();
- SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
- gpuParams->setParamBlockBuffer("Input", mParamBuffer);
- gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
- }
- void ReflectionCubeImportanceSampleMat::_initVariations(ShaderVariations& variations)
- {
- ShaderVariation variation({
- ShaderVariation::Param("NUM_SAMPLES", NUM_SAMPLES)
- });
- variations.add(variation);
- }
- void ReflectionCubeImportanceSampleMat::execute(const SPtr<Texture>& source, UINT32 face, UINT32 mip,
- const SPtr<RenderTarget>& target)
- {
- mInputTexture.set(source);
- gReflectionCubeImportanceSampleParamDef.gCubeFace.set(mParamBuffer, face);
- gReflectionCubeImportanceSampleParamDef.gMipLevel.set(mParamBuffer, mip);
- gReflectionCubeImportanceSampleParamDef.gNumMips.set(mParamBuffer, source->getProperties().getNumMipmaps() + 1);
- float width = (float)source->getProperties().getWidth();
- float height = (float)source->getProperties().getHeight();
- // First part of the equation for determining mip level to sample from.
- // See http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
- float mipFactor = 0.5f * std::log2(width * height / NUM_SAMPLES);
- gReflectionCubeImportanceSampleParamDef.gPrecomputedMipFactor.set(mParamBuffer, mipFactor);
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(target);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- }
- IrradianceComputeSHParamDef gIrradianceComputeSHParamDef;
- // TILE_WIDTH * TILE_HEIGHT must be pow2 because of parallel reduction algorithm
- const static UINT32 TILE_WIDTH = 8;
- const static UINT32 TILE_HEIGHT = 8;
- // For very small textures this should be reduced so number of launched threads can properly utilize GPU cores
- const static UINT32 PIXELS_PER_THREAD = 4;
- ShaderVariation IrradianceComputeSHMat::VAR_Order3 = ShaderVariation({
- ShaderVariation::Param("TILE_WIDTH", TILE_WIDTH),
- ShaderVariation::Param("TILE_HEIGHT", TILE_HEIGHT),
- ShaderVariation::Param("PIXELS_PER_THREAD", PIXELS_PER_THREAD),
- ShaderVariation::Param("SH_ORDER", 3),
- });
- ShaderVariation IrradianceComputeSHMat::VAR_Order5 = ShaderVariation({
- ShaderVariation::Param("TILE_WIDTH", TILE_WIDTH),
- ShaderVariation::Param("TILE_HEIGHT", TILE_HEIGHT),
- ShaderVariation::Param("PIXELS_PER_THREAD", PIXELS_PER_THREAD),
- ShaderVariation::Param("SH_ORDER", 5),
- });
- IrradianceComputeSHMat::IrradianceComputeSHMat()
- {
- mParamBuffer = gIrradianceComputeSHParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getTextureParam(GPT_COMPUTE_PROGRAM, "gInputTex", mInputTexture);
- params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBuffer);
- }
- void IrradianceComputeSHMat::_initVariations(ShaderVariations& variations)
- {
- variations.add(VAR_Order3);
- variations.add(VAR_Order5);
- }
- void IrradianceComputeSHMat::execute(const SPtr<Texture>& source, UINT32 face, const SPtr<GpuBuffer>& output)
- {
- auto& props = source->getProperties();
- UINT32 faceSize = props.getWidth();
- assert(faceSize == props.getHeight());
- Vector2I dispatchSize;
- dispatchSize.x = Math::divideAndRoundUp(faceSize, TILE_WIDTH * PIXELS_PER_THREAD);
- dispatchSize.y = Math::divideAndRoundUp(faceSize, TILE_HEIGHT * PIXELS_PER_THREAD);
- mInputTexture.set(source);
- gIrradianceComputeSHParamDef.gCubeFace.set(mParamBuffer, face);
- gIrradianceComputeSHParamDef.gFaceSize.set(mParamBuffer, source->getProperties().getWidth());
- gIrradianceComputeSHParamDef.gDispatchSize.set(mParamBuffer, dispatchSize);
- mOutputBuffer.set(output);
- RenderAPI& rapi = RenderAPI::instance();
- gRendererUtility().setComputePass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- rapi.dispatchCompute(dispatchSize.x, dispatchSize.y);
- }
- SPtr<GpuBuffer> IrradianceComputeSHMat::createOutputBuffer(const SPtr<Texture>& source, UINT32& numCoeffSets)
- {
- auto& props = source->getProperties();
- UINT32 faceSize = props.getWidth();
- assert(faceSize == props.getHeight());
- Vector2I dispatchSize;
- dispatchSize.x = Math::divideAndRoundUp(faceSize, TILE_WIDTH * PIXELS_PER_THREAD);
- dispatchSize.y = Math::divideAndRoundUp(faceSize, TILE_HEIGHT * PIXELS_PER_THREAD);
- numCoeffSets = dispatchSize.x * dispatchSize.y * 6;
- GPU_BUFFER_DESC bufferDesc;
- bufferDesc.type = GBT_STRUCTURED;
- bufferDesc.elementCount = numCoeffSets;
- bufferDesc.format = BF_UNKNOWN;
- bufferDesc.randomGpuWrite = true;
- if(mVariation.getInt("SH_ORDER") == 3)
- bufferDesc.elementSize = sizeof(SHCoeffsAndWeight3);
- else
- bufferDesc.elementSize = sizeof(SHCoeffsAndWeight5);
- return GpuBuffer::create(bufferDesc);
- }
- IrradianceComputeSHMat* IrradianceComputeSHMat::getVariation(int order)
- {
- if (order == 3)
- return get(VAR_Order3);
- return get(VAR_Order5);
- }
- IrradianceComputeSHFragParamDef gIrradianceComputeSHFragParamDef;
- IrradianceComputeSHFragMat::IrradianceComputeSHFragMat()
- {
- mParamBuffer = gIrradianceComputeSHFragParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
- }
- void IrradianceComputeSHFragMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void IrradianceComputeSHFragMat::execute(const SPtr<Texture>& source, UINT32 face, UINT32 coefficientIdx,
- const SPtr<RenderTarget>& output)
- {
- // Set parameters
- mInputTexture.set(source);
- gIrradianceComputeSHFragParamDef.gCubeFace.set(mParamBuffer, face);
- gIrradianceComputeSHFragParamDef.gFaceSize.set(mParamBuffer, source->getProperties().getWidth());
- gIrradianceComputeSHFragParamDef.gCoeffIdx.set(mParamBuffer, coefficientIdx);
- // Render
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(output);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- rapi.setRenderTarget(nullptr);
- }
- POOLED_RENDER_TEXTURE_DESC IrradianceComputeSHFragMat::getOutputDesc(const SPtr<Texture>& input)
- {
- auto& props = input->getProperties();
- return POOLED_RENDER_TEXTURE_DESC::createCube(PF_RGBA16F, props.getWidth(), props.getHeight(), TU_RENDERTARGET);
- }
- IrradianceAccumulateSHParamDef gIrradianceAccumulateSHParamDef;
- IrradianceAccumulateSHMat::IrradianceAccumulateSHMat()
- {
- mParamBuffer = gIrradianceAccumulateSHParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
- }
- void IrradianceAccumulateSHMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void IrradianceAccumulateSHMat::execute(const SPtr<Texture>& source, UINT32 face, UINT32 sourceMip,
- const SPtr<RenderTarget>& output)
- {
- // Set parameters
- mInputTexture.set(source);
- auto& props = source->getProperties();
- Vector2 halfPixel(0.5f / props.getWidth(), 0.5f / props.getHeight());
- gIrradianceAccumulateSHParamDef.gCubeFace.set(mParamBuffer, face);
- gIrradianceAccumulateSHParamDef.gCubeMip.set(mParamBuffer, sourceMip);
- gIrradianceAccumulateSHParamDef.gHalfPixel.set(mParamBuffer, halfPixel);
- // Render
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(output);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- rapi.setRenderTarget(nullptr);
- }
- POOLED_RENDER_TEXTURE_DESC IrradianceAccumulateSHMat::getOutputDesc(const SPtr<Texture>& input)
- {
- auto& props = input->getProperties();
- // Assuming it's a cubemap
- UINT32 size = std::max(1U, (UINT32)(props.getWidth() * 0.5f));
- return POOLED_RENDER_TEXTURE_DESC::createCube(PF_RGBA16F, size, size, TU_RENDERTARGET);
- }
- IrradianceAccumulateCubeSHMat::IrradianceAccumulateCubeSHMat()
- {
- mParamBuffer = gIrradianceAccumulateSHParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
- }
- void IrradianceAccumulateCubeSHMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void IrradianceAccumulateCubeSHMat::execute(const SPtr<Texture>& source, UINT32 sourceMip, const Vector2I& outputOffset,
- UINT32 coefficientIdx, const SPtr<RenderTarget>& output)
- {
- // Set parameters
- mInputTexture.set(source);
- auto& props = source->getProperties();
- Vector2 halfPixel(0.5f / props.getWidth(), 0.5f / props.getHeight());
- gIrradianceAccumulateSHParamDef.gCubeFace.set(mParamBuffer, 0);
- gIrradianceAccumulateSHParamDef.gCubeMip.set(mParamBuffer, sourceMip);
- gIrradianceAccumulateSHParamDef.gHalfPixel.set(mParamBuffer, halfPixel);
- auto& rtProps = output->getProperties();
- // Render to just one pixel corresponding to the coefficient
- Rect2 viewRect;
- viewRect.x = (outputOffset.x + coefficientIdx) / (float)rtProps.width;
- viewRect.y = outputOffset.y / (float)rtProps.height;
- viewRect.width = 1.0f / rtProps.width;
- viewRect.height = 1.0f / rtProps.height;
- // Render
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(output);
- rapi.setViewport(viewRect);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- rapi.setRenderTarget(nullptr);
- rapi.setViewport(Rect2(0, 0, 1, 1));
- }
- POOLED_RENDER_TEXTURE_DESC IrradianceAccumulateCubeSHMat::getOutputDesc()
- {
- return POOLED_RENDER_TEXTURE_DESC::create2D(PF_RGBA32F, 9, 1, TU_RENDERTARGET);
- }
- IrradianceReduceSHParamDef gIrradianceReduceSHParamDef;
- ShaderVariation IrradianceReduceSHMat::VAR_Order3 = ShaderVariation({
- ShaderVariation::Param("SH_ORDER", 3),
- });
- ShaderVariation IrradianceReduceSHMat::VAR_Order5 = ShaderVariation({
- ShaderVariation::Param("SH_ORDER", 5),
- });
- IrradianceReduceSHMat::IrradianceReduceSHMat()
- {
- mParamBuffer = gIrradianceReduceSHParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getBufferParam(GPT_COMPUTE_PROGRAM, "gInput", mInputBuffer);
- params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTexture);
- }
- void IrradianceReduceSHMat::_initVariations(ShaderVariations& variations)
- {
- variations.add(VAR_Order3);
- variations.add(VAR_Order5);
- }
- void IrradianceReduceSHMat::execute(const SPtr<GpuBuffer>& source, UINT32 numCoeffSets,
- const SPtr<Texture>& output, UINT32 outputIdx)
- {
- UINT32 shOrder = (UINT32)mVariation.getInt("SH_ORDER");
- Vector2I outputCoords = IBLUtility::getSHCoeffXYFromIdx(outputIdx, shOrder);
- gIrradianceReduceSHParamDef.gOutputIdx.set(mParamBuffer, outputCoords);
- gIrradianceReduceSHParamDef.gNumEntries.set(mParamBuffer, numCoeffSets);
- mInputBuffer.set(source);
- mOutputTexture.set(output);
- RenderAPI& rapi = RenderAPI::instance();
- gRendererUtility().setComputePass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- rapi.dispatchCompute(1);
- }
- SPtr<Texture> IrradianceReduceSHMat::createOutputTexture(UINT32 numCoeffSets)
- {
- UINT32 shOrder = (UINT32)mVariation.getInt("SH_ORDER");
- Vector2I size = IBLUtility::getSHCoeffTextureSize(numCoeffSets, shOrder);
- TEXTURE_DESC textureDesc;
- textureDesc.width = (UINT32)size.x;
- textureDesc.height = (UINT32)size.y;
- textureDesc.format = PF_RGBA32F;
- textureDesc.usage = TU_STATIC | TU_LOADSTORE;
- return Texture::create(textureDesc);
- }
- IrradianceReduceSHMat* IrradianceReduceSHMat::getVariation(int order)
- {
- if (order == 3)
- return get(VAR_Order3);
- return get(VAR_Order5);
- }
- IrradianceProjectSHParamDef gIrradianceProjectSHParamDef;
- IrradianceProjectSHMat::IrradianceProjectSHMat()
- {
- mParamBuffer = gIrradianceProjectSHParamDef.createBuffer();
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->setParamBlockBuffer("Params", mParamBuffer);
- params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSHCoeffs", mInputTexture);
- }
- void IrradianceProjectSHMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void IrradianceProjectSHMat::execute(const SPtr<Texture>& shCoeffs, UINT32 face, const SPtr<RenderTarget>& target)
- {
- gIrradianceProjectSHParamDef.gCubeFace.set(mParamBuffer, face);
- mInputTexture.set(shCoeffs);
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(target);
- gRendererUtility().setPass(mMaterial);
- gRendererUtility().setPassParams(mParamsSet);
- gRendererUtility().drawScreenQuad();
- }
- void RenderBeastIBLUtility::filterCubemapForSpecular(const SPtr<Texture>& cubemap, const SPtr<Texture>& scratch) const
- {
- auto& props = cubemap->getProperties();
- SPtr<Texture> scratchCubemap = scratch;
- if (scratchCubemap == nullptr)
- {
- TEXTURE_DESC cubemapDesc;
- cubemapDesc.type = TEX_TYPE_CUBE_MAP;
- cubemapDesc.format = props.getFormat();
- cubemapDesc.width = props.getWidth();
- cubemapDesc.height = props.getHeight();
- cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format);
- cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
- scratchCubemap = Texture::create(cubemapDesc);
- }
- // We sample the cubemaps using importance sampling to generate roughness
- UINT32 numMips = props.getNumMipmaps();
- // Before importance sampling the cubemaps we first create box filtered versions for each mip level. This helps fix
- // the aliasing artifacts that would otherwise be noticeable on importance sampled cubemaps. The aliasing happens
- // because:
- // 1. We use the same random samples for all pixels, which appears to duplicate reflections instead of creating
- // noise, which is usually more acceptable
- // 2. Even if we were to use fully random samples we would need a lot to avoid noticeable noise, which isn't
- // practical
- // Copy base mip level to scratch cubemap
- for (UINT32 face = 0; face < 6; face++)
- {
- TEXTURE_COPY_DESC copyDesc;
- copyDesc.srcFace = face;
- copyDesc.dstFace = face;
- cubemap->copy(scratchCubemap, copyDesc);
- }
- // Fill out remaining scratch mip levels by downsampling
- for (UINT32 mip = 1; mip < numMips; mip++)
- {
- UINT32 sourceMip = mip - 1;
- downsampleCubemap(scratchCubemap, sourceMip, scratchCubemap, mip);
- }
- // Importance sample
- for (UINT32 mip = 1; mip < numMips; mip++)
- {
- for (UINT32 face = 0; face < 6; face++)
- {
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = cubemap;
- cubeFaceRTDesc.colorSurfaces[0].face = face;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
- cubeFaceRTDesc.colorSurfaces[0].mipLevel = mip;
- SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
- ReflectionCubeImportanceSampleMat* material = ReflectionCubeImportanceSampleMat::get();
- material->execute(scratchCubemap, face, mip, target);
- }
- }
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(nullptr);
- }
- bool supportsComputeSH()
- {
- return gRenderBeast()->getFeatureSet() == RenderBeastFeatureSet::Desktop;
- }
- void RenderBeastIBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output) const
- {
- SPtr<Texture> coeffTexture;
- if(supportsComputeSH())
- {
- IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(5);
- IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(5);
- UINT32 numCoeffSets;
- SPtr<GpuBuffer> coeffSetBuffer = shCompute->createOutputBuffer(cubemap, numCoeffSets);
- for (UINT32 face = 0; face < 6; face++)
- shCompute->execute(cubemap, face, coeffSetBuffer);
- coeffTexture = shReduce->createOutputTexture(1);
- shReduce->execute(coeffSetBuffer, numCoeffSets, coeffTexture, 0);
- }
- else
- {
- GpuResourcePool& resPool = GpuResourcePool::instance();
- SPtr<PooledRenderTexture> finalCoeffs = resPool.get(IrradianceAccumulateCubeSHMat::getOutputDesc());
- filterCubemapForIrradianceNonCompute(cubemap, 0, finalCoeffs->renderTexture);
- coeffTexture = finalCoeffs->texture;
- }
- IrradianceProjectSHMat* shProject = IrradianceProjectSHMat::get();
- for (UINT32 face = 0; face < 6; face++)
- {
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = output;
- cubeFaceRTDesc.colorSurfaces[0].face = face;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
- cubeFaceRTDesc.colorSurfaces[0].mipLevel = 0;
- SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
- shProject->execute(coeffTexture, face, target);
- }
- }
-
- void RenderBeastIBLUtility::filterCubemapForIrradiance(const SPtr<Texture>& cubemap, const SPtr<Texture>& output,
- UINT32 outputIdx) const
- {
- if(supportsComputeSH())
- {
- IrradianceComputeSHMat* shCompute = IrradianceComputeSHMat::getVariation(3);
- IrradianceReduceSHMat* shReduce = IrradianceReduceSHMat::getVariation(3);
- UINT32 numCoeffSets;
- SPtr<GpuBuffer> coeffSetBuffer = shCompute->createOutputBuffer(cubemap, numCoeffSets);
- for (UINT32 face = 0; face < 6; face++)
- shCompute->execute(cubemap, face, coeffSetBuffer);
- shReduce->execute(coeffSetBuffer, numCoeffSets, output, outputIdx);
- }
- else
- {
- RENDER_TEXTURE_DESC rtDesc;
- rtDesc.colorSurfaces[0].texture = output;
- SPtr<RenderTexture> target = RenderTexture::create(rtDesc);
- filterCubemapForIrradianceNonCompute(cubemap, outputIdx, target);
- }
- }
- void RenderBeastIBLUtility::scaleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst,
- UINT32 dstMip) const
- {
- auto& srcProps = src->getProperties();
- auto& dstProps = dst->getProperties();
- SPtr<Texture> scratchTex = src;
- int sizeSrcLog2 = (int)log2((float)srcProps.getWidth());
- int sizeDstLog2 = (int)log2((float)dstProps.getWidth());
- int sizeLog2Diff = sizeSrcLog2 - sizeDstLog2;
- // If size difference is greater than one mip-level and we're downscaling, we need to generate intermediate mip
- // levels
- if(sizeLog2Diff > 1)
- {
- UINT32 mipSize = (UINT32)exp2((float)(sizeSrcLog2 - 1));
- UINT32 numDownsamples = sizeLog2Diff - 1;
- TEXTURE_DESC cubemapDesc;
- cubemapDesc.type = TEX_TYPE_CUBE_MAP;
- cubemapDesc.format = srcProps.getFormat();
- cubemapDesc.width = mipSize;
- cubemapDesc.height = mipSize;
- cubemapDesc.numMips = numDownsamples - 1;
- cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET;
- scratchTex = Texture::create(cubemapDesc);
- downsampleCubemap(src, srcMip, scratchTex, 0);
- for(UINT32 i = 0; i < cubemapDesc.numMips; i++)
- downsampleCubemap(scratchTex, i, scratchTex, i + 1);
- srcMip = cubemapDesc.numMips;
- }
- // Same size so just copy
- if(sizeSrcLog2 == sizeDstLog2)
- {
- for (UINT32 face = 0; face < 6; face++)
- {
- TEXTURE_COPY_DESC copyDesc;
- copyDesc.srcFace = face;
- copyDesc.srcMip = srcMip;
- copyDesc.dstFace = face;
- copyDesc.dstMip = dstMip;
- src->copy(dst, copyDesc);
- }
- }
- else
- downsampleCubemap(scratchTex, srcMip, dst, dstMip);
- }
- void RenderBeastIBLUtility::downsampleCubemap(const SPtr<Texture>& src, UINT32 srcMip, const SPtr<Texture>& dst,
- UINT32 dstMip)
- {
- for (UINT32 face = 0; face < 6; face++)
- {
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = dst;
- cubeFaceRTDesc.colorSurfaces[0].face = face;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
- cubeFaceRTDesc.colorSurfaces[0].mipLevel = dstMip;
- SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
- ReflectionCubeDownsampleMat* material = ReflectionCubeDownsampleMat::get();
- material->execute(src, face, srcMip, target);
- }
- }
- void RenderBeastIBLUtility::filterCubemapForIrradianceNonCompute(const SPtr<Texture>& cubemap, UINT32 outputIdx,
- const SPtr<RenderTexture>& output)
- {
- static const UINT32 NUM_COEFFS = 9;
- GpuResourcePool& resPool = GpuResourcePool::instance();
- IrradianceComputeSHFragMat* shCompute = IrradianceComputeSHFragMat::get();
- IrradianceAccumulateSHMat* shAccum = IrradianceAccumulateSHMat::get();
- IrradianceAccumulateCubeSHMat* shAccumCube = IrradianceAccumulateCubeSHMat::get();
- for(UINT32 coeff = 0; coeff < NUM_COEFFS; ++coeff)
- {
- SPtr<PooledRenderTexture> coeffsTex = resPool.get(shCompute->getOutputDesc(cubemap));
-
- // Generate SH coefficients and weights per-texel
- for(UINT32 face = 0; face < 6; face++)
- {
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = coeffsTex->texture;
- cubeFaceRTDesc.colorSurfaces[0].face = face;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
- cubeFaceRTDesc.colorSurfaces[0].mipLevel = 0;
- SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
- shCompute->execute(cubemap, face, coeff, target);
- }
- // Downsample, summing up coefficients and weights all the way down to 1x1
- auto& sourceProps = cubemap->getProperties();
- UINT32 numMips = PixelUtil::getMaxMipmaps(sourceProps.getWidth(), sourceProps.getHeight(), 1,
- sourceProps.getFormat());
- SPtr<PooledRenderTexture> downsampleInput = coeffsTex;
- coeffsTex = nullptr;
- for(UINT32 mip = 0; mip < numMips; mip++)
- {
- SPtr<PooledRenderTexture> accumCoeffsTex = resPool.get(shAccum->getOutputDesc(downsampleInput->texture));
- for(UINT32 face = 0; face < 6; face++)
- {
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = accumCoeffsTex->texture;
- cubeFaceRTDesc.colorSurfaces[0].face = face;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
- cubeFaceRTDesc.colorSurfaces[0].mipLevel = 0;
- SPtr<RenderTarget> target = RenderTexture::create(cubeFaceRTDesc);
- shAccum->execute(downsampleInput->texture, face, 0, target);
- }
- downsampleInput = accumCoeffsTex;
- }
- // Sum up all the faces and write the coefficient to the final texture
- Vector2I outputOffset = getSHCoeffXYFromIdx(outputIdx, 3);
- shAccumCube->execute(downsampleInput->texture, 0, outputOffset, coeff, output);
- }
- }
- }}
|