| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsLightRendering.h"
- #include "Material/BsMaterial.h"
- #include "Material/BsShader.h"
- #include "BsRenderBeast.h"
- #include "RenderAPI/BsGpuParams.h"
- #include "Material/BsGpuParamsSet.h"
- #include "RenderAPI/BsGpuBuffer.h"
- #include "Renderer/BsLight.h"
- #include "Renderer/BsRendererUtility.h"
- #include "BsStandardDeferredLighting.h"
- namespace bs { namespace ct
- {
- static const UINT32 BUFFER_INCREMENT = 16 * sizeof(LightData);
- TiledLightingParamDef gTiledLightingParamDef;
- RendererLight::RendererLight(Light* light)
- :internal(light)
- { }
- void RendererLight::getParameters(LightData& output) const
- {
- Radian spotAngle = Math::clamp(internal->getSpotAngle() * 0.5f, Degree(0), Degree(89));
- Radian spotFalloffAngle = Math::clamp(internal->getSpotFalloffAngle() * 0.5f, Degree(0), (Degree)spotAngle);
- Color color = internal->getColor();
- const Transform& tfrm = internal->getTransform();
- output.position = tfrm.getPosition();
- output.attRadius = internal->getBounds().getRadius();
- output.srcRadius = internal->getSourceRadius();
- output.direction = -tfrm.getRotation().zAxis();
- output.luminance = internal->getLuminance();
- output.spotAngles.x = spotAngle.valueRadians();
- output.spotAngles.y = Math::cos(output.spotAngles.x);
- output.spotAngles.z = 1.0f / std::max(Math::cos(spotFalloffAngle) - output.spotAngles.y, 0.001f);
- output.attRadiusSqrdInv = 1.0f / (output.attRadius * output.attRadius);
- output.color = Vector3(color.r, color.g, color.b);
- // If directional lights, convert angular radius in degrees to radians
- if (internal->getType() == LightType::Directional)
- output.srcRadius *= Math::DEG2RAD;
- output.shiftedLightPosition = getShiftedLightPosition();
- }
- void RendererLight::getParameters(SPtr<GpuParamBlockBuffer>& buffer) const
- {
- LightData lightData;
- getParameters(lightData);
- float type = 0.0f;
- switch (internal->getType())
- {
- case LightType::Directional:
- type = 0;
- break;
- case LightType::Radial:
- type = 0.3f;
- break;
- case LightType::Spot:
- type = 0.8f;
- break;
- default:
- break;
- }
- gPerLightParamDef.gLightPositionAndSrcRadius.set(buffer, Vector4(lightData.position, lightData.srcRadius));
- gPerLightParamDef.gLightColorAndLuminance.set(buffer, Vector4(lightData.color, lightData.luminance));
- gPerLightParamDef.gLightSpotAnglesAndSqrdInvAttRadius.set(buffer, Vector4(lightData.spotAngles, lightData.attRadiusSqrdInv));
- gPerLightParamDef.gLightDirectionAndAttRadius.set(buffer, Vector4(lightData.direction, lightData.attRadius));
- gPerLightParamDef.gShiftedLightPositionAndType.set(buffer, Vector4(lightData.shiftedLightPosition, type));
- Vector4 lightGeometry;
- lightGeometry.x = internal->getType() == LightType::Spot ? (float)Light::LIGHT_CONE_NUM_SIDES : 0;
- lightGeometry.y = (float)Light::LIGHT_CONE_NUM_SLICES;
- lightGeometry.z = internal->getBounds().getRadius();
- float extraRadius = lightData.srcRadius / Math::tan(lightData.spotAngles.x * 0.5f);
- float coneRadius = Math::sin(lightData.spotAngles.x) * (internal->getAttenuationRadius() + extraRadius);
- lightGeometry.w = coneRadius;
- gPerLightParamDef.gLightGeometry.set(buffer, lightGeometry);
- const Transform& tfrm = internal->getTransform();
- Quaternion lightRotation(BsIdentity);
- lightRotation.lookRotation(-tfrm.getRotation().zAxis());
- Matrix4 transform = Matrix4::TRS(lightData.shiftedLightPosition, lightRotation, Vector3::ONE);
- gPerLightParamDef.gMatConeTransform.set(buffer, transform);
- }
- Vector3 RendererLight::getShiftedLightPosition() const
- {
- const Transform& tfrm = internal->getTransform();
- Vector3 direction = -tfrm.getRotation().zAxis();
- // Create position for fake attenuation for area spot lights (with disc center)
- if (internal->getType() == LightType::Spot)
- return tfrm.getPosition() - direction * (internal->getSourceRadius() / Math::tan(internal->getSpotAngle() * 0.5f));
- else
- return tfrm.getPosition();
- }
- GBufferParams::GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet)
- : mMaterial(material), mParamsSet(paramsSet)
- {
- mGBufferA = material->getParamTexture("gGBufferATex");
- mGBufferB = material->getParamTexture("gGBufferBTex");
- mGBufferC = material->getParamTexture("gGBufferCTex");
- mGBufferDepth = material->getParamTexture("gDepthBufferTex");
- SAMPLER_STATE_DESC desc;
- desc.minFilter = FO_POINT;
- desc.magFilter = FO_POINT;
- desc.mipFilter = FO_POINT;
- SPtr<SamplerState> ss = SamplerState::create(desc);
- material->setSamplerState("gDepthBufferSamp", ss);
- }
- void GBufferParams::bind(const GBufferTextures& gbuffer)
- {
- mGBufferA.set(gbuffer.albedo);
- mGBufferB.set(gbuffer.normals);
- mGBufferC.set(gbuffer.roughMetal);
- mGBufferDepth.set(gbuffer.depth);
- mMaterial->updateParamsSet(mParamsSet);
- }
- VisibleLightData::VisibleLightData()
- :mNumLights{}, mNumShadowedLights{}
- { }
- void VisibleLightData::update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup)
- {
- const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
- for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
- mVisibleLights[i].clear();
- // Generate a list of lights and their GPU buffers
- UINT32 numDirLights = (UINT32)sceneInfo.directionalLights.size();
- for (UINT32 i = 0; i < numDirLights; i++)
- mVisibleLights[(UINT32)LightType::Directional].push_back(&sceneInfo.directionalLights[i]);
- UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
- for(UINT32 i = 0; i < numRadialLights; i++)
- {
- if (!visibility.radialLights[i])
- continue;
- mVisibleLights[(UINT32)LightType::Radial].push_back(&sceneInfo.radialLights[i]);
- }
- UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
- for (UINT32 i = 0; i < numSpotLights; i++)
- {
- if (!visibility.spotLights[i])
- continue;
- mVisibleLights[(UINT32)LightType::Spot].push_back(&sceneInfo.spotLights[i]);
- }
- for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
- mNumLights[i] = (UINT32)mVisibleLights[i].size();
- // Partition all visible lights so that unshadowed ones come first
- auto partition = [](Vector<const RendererLight*>& entries)
- {
- UINT32 numUnshadowed = 0;
- int first = 0;
- for (UINT32 i = 0; i < (UINT32)entries.size(); ++i)
- {
- if(entries[i]->internal->getCastsShadow())
- {
- first = i;
- break;
- }
- else
- ++numUnshadowed;
- }
- for(UINT32 i = first + 1; i < (UINT32)entries.size(); ++i)
- {
- if(!entries[i]->internal->getCastsShadow())
- {
- std::swap(entries[i], entries[first]);
- ++first;
- ++numUnshadowed;
- }
- }
- return numUnshadowed;
- };
- for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
- mNumShadowedLights[i] = mNumLights[i] - partition(mVisibleLights[i]);
- // Generate light data to initialize the GPU buffer with
- for(auto& lightsPerType : mVisibleLights)
- {
- for(auto& entry : lightsPerType)
- {
- mLightDataTemp.push_back(LightData());
- entry->getParameters(mLightDataTemp.back());
- }
- }
- UINT32 size = (UINT32)mLightDataTemp.size() * sizeof(LightData);
- UINT32 curBufferSize;
- if (mLightBuffer != nullptr)
- curBufferSize = mLightBuffer->getSize();
- else
- curBufferSize = 0;
- if (size > curBufferSize || curBufferSize == 0)
- {
- // Allocate at least one block even if no lights, to avoid issues with null buffers
- UINT32 bufferSize = std::max(1, Math::ceilToInt(size / (float)BUFFER_INCREMENT)) * BUFFER_INCREMENT;
- GPU_BUFFER_DESC bufferDesc;
- bufferDesc.type = GBT_STRUCTURED;
- bufferDesc.elementCount = bufferSize / sizeof(LightData);
- bufferDesc.elementSize = sizeof(LightData);
- bufferDesc.format = BF_UNKNOWN;
- mLightBuffer = GpuBuffer::create(bufferDesc);
- }
- if (size > 0)
- mLightBuffer->writeData(0, size, mLightDataTemp.data(), BWT_DISCARD);
- mLightDataTemp.clear();
- }
- const UINT32 TiledDeferredLightingMat::TILE_SIZE = 16;
- ShaderVariation TiledDeferredLightingMat::VAR_1MSAA = ShaderVariation({
- ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
- ShaderVariation::Param("MSAA_COUNT", 1)
- });
- ShaderVariation TiledDeferredLightingMat::VAR_2MSAA = ShaderVariation({
- ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
- ShaderVariation::Param("MSAA_COUNT", 2)
- });
- ShaderVariation TiledDeferredLightingMat::VAR_4MSAA = ShaderVariation({
- ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
- ShaderVariation::Param("MSAA_COUNT", 4)
- });
- ShaderVariation TiledDeferredLightingMat::VAR_8MSAA = ShaderVariation({
- ShaderVariation::Param("TILE_SIZE", TILE_SIZE),
- ShaderVariation::Param("MSAA_COUNT", 8)
- });
- TiledDeferredLightingMat::TiledDeferredLightingMat()
- :mGBufferParams(mMaterial, mParamsSet)
- {
- mSampleCount = mVariation.getUInt("MSAA_COUNT");
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->getBufferParam(GPT_COMPUTE_PROGRAM, "gLights", mLightBufferParam);
- if (params->hasLoadStoreTexture(GPT_COMPUTE_PROGRAM, "gOutput"))
- params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputTextureParam);
- if (params->hasBuffer(GPT_COMPUTE_PROGRAM, "gOutput"))
- params->getBufferParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputBufferParam);
- if (mSampleCount > 1)
- params->getTextureParam(GPT_COMPUTE_PROGRAM, "gMSAACoverage", mMSAACoverageTexParam);
- mParamBuffer = gTiledLightingParamDef.createBuffer();
- params->setParamBlockBuffer("Params", mParamBuffer);
- }
- void TiledDeferredLightingMat::_initVariations(ShaderVariations& variations)
- {
- variations.add(VAR_1MSAA);
- variations.add(VAR_2MSAA);
- variations.add(VAR_4MSAA);
- variations.add(VAR_8MSAA);
- }
- void TiledDeferredLightingMat::execute(const RendererView& view, const VisibleLightData& lightData,
- const GBufferTextures& gbuffer, const SPtr<Texture>& lightAccumTex, const SPtr<GpuBuffer>& lightAccumBuffer,
- const SPtr<Texture>& msaaCoverage)
- {
- const RendererViewProperties& viewProps = view.getProperties();
- const RenderSettings& settings = view.getRenderSettings();
- mLightBufferParam.set(lightData.getLightBuffer());
- UINT32 width = viewProps.viewRect.width;
- UINT32 height = viewProps.viewRect.height;
- Vector2I framebufferSize;
- framebufferSize[0] = width;
- framebufferSize[1] = height;
- gTiledLightingParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
- if (!settings.enableLighting)
- {
- Vector4I lightCounts;
- lightCounts[0] = 0;
- lightCounts[1] = 0;
- lightCounts[2] = 0;
- lightCounts[3] = 0;
- Vector2I lightStrides;
- lightStrides[0] = 0;
- lightStrides[1] = 0;
- gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
- gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
- }
- else
- {
- Vector4I unshadowedLightCounts;
- unshadowedLightCounts[0] = lightData.getNumUnshadowedLights(LightType::Directional);
- unshadowedLightCounts[1] = lightData.getNumUnshadowedLights(LightType::Radial);
- unshadowedLightCounts[2] = lightData.getNumUnshadowedLights(LightType::Spot);
- unshadowedLightCounts[3] = unshadowedLightCounts[0] + unshadowedLightCounts[1] + unshadowedLightCounts[2];
- Vector4I lightCounts;
- lightCounts[0] = lightData.getNumLights(LightType::Directional);
- lightCounts[1] = lightData.getNumLights(LightType::Radial);
- lightCounts[2] = lightData.getNumLights(LightType::Spot);
- lightCounts[3] = lightCounts[0] + lightCounts[1] + lightCounts[2];
- Vector2I lightStrides;
- lightStrides[0] = lightCounts[0];
- lightStrides[1] = lightStrides[0] + lightCounts[1];
- if(!settings.enableShadows)
- gTiledLightingParamDef.gLightCounts.set(mParamBuffer, lightCounts);
- else
- gTiledLightingParamDef.gLightCounts.set(mParamBuffer, unshadowedLightCounts);
- gTiledLightingParamDef.gLightStrides.set(mParamBuffer, lightStrides);
- }
- mParamBuffer->flushToGPU();
- mGBufferParams.bind(gbuffer);
- mParamsSet->getGpuParams()->setParamBlockBuffer("PerCamera", view.getPerViewBuffer());
- if (mSampleCount > 1)
- {
- mOutputBufferParam.set(lightAccumBuffer);
- mMSAACoverageTexParam.set(msaaCoverage);
- }
- else
- mOutputTextureParam.set(lightAccumTex);
- UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
- UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
- gRendererUtility().setComputePass(mMaterial, 0);
- gRendererUtility().setPassParams(mParamsSet);
- RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
- }
- TiledDeferredLightingMat* TiledDeferredLightingMat::getVariation(UINT32 msaaCount)
- {
- switch(msaaCount)
- {
- case 1:
- return get(VAR_1MSAA);
- case 2:
- return get(VAR_2MSAA);
- case 4:
- return get(VAR_4MSAA);
- case 8:
- default:
- return get(VAR_8MSAA);
- }
- }
- FlatFramebufferToTextureParamDef gFlatFramebufferToTextureParamDef;
- FlatFramebufferToTextureMat::FlatFramebufferToTextureMat()
- {
- SPtr<GpuParams> params = mParamsSet->getGpuParams();
- params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gInput", mInputParam);
- mParamBuffer = gTiledLightingParamDef.createBuffer();
- params->setParamBlockBuffer("Params", mParamBuffer);
- }
- void FlatFramebufferToTextureMat::_initVariations(ShaderVariations& variations)
- {
- // Do nothing
- }
- void FlatFramebufferToTextureMat::execute(const SPtr<GpuBuffer>& flatFramebuffer, const SPtr<Texture>& target)
- {
- const TextureProperties& props = target->getProperties();
- Vector2I framebufferSize;
- framebufferSize[0] = props.getWidth();
- framebufferSize[1] = props.getHeight();
- gFlatFramebufferToTextureParamDef.gFramebufferSize.set(mParamBuffer, framebufferSize);
- gFlatFramebufferToTextureParamDef.gSampleCount.set(mParamBuffer, props.getNumSamples());
- mParamBuffer->flushToGPU();
- mInputParam.set(flatFramebuffer);
- gRendererUtility().setPass(mMaterial, 0);
- gRendererUtility().setPassParams(mParamsSet);
- Rect2 area(0.0f, 0.0f, (float)props.getWidth(), (float)props.getHeight());
- gRendererUtility().drawScreenQuad(area);
- }
- }}
|