| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsRenderBeast.h"
- #include "BsCCamera.h"
- #include "BsCRenderable.h"
- #include "BsMaterial.h"
- #include "BsMesh.h"
- #include "BsPass.h"
- #include "BsSamplerState.h"
- #include "BsCoreApplication.h"
- #include "BsViewport.h"
- #include "BsRenderTarget.h"
- #include "BsRenderQueue.h"
- #include "BsCoreThread.h"
- #include "BsGpuParams.h"
- #include "BsProfilerCPU.h"
- #include "BsProfilerGPU.h"
- #include "BsShader.h"
- #include "BsGpuParamBlockBuffer.h"
- #include "BsTime.h"
- #include "BsRenderableElement.h"
- #include "BsCoreObjectManager.h"
- #include "BsRenderBeastOptions.h"
- #include "BsSamplerOverrides.h"
- #include "BsLight.h"
- #include "BsGpuResourcePool.h"
- #include "BsRenderTargets.h"
- #include "BsRendererUtility.h"
- #include "BsAnimationManager.h"
- #include "BsSkeleton.h"
- #include "BsGpuBuffer.h"
- #include "BsGpuParamsSet.h"
- #include "BsRendererExtension.h"
- #include "BsReflectionCubemap.h"
- #include "BsMeshData.h"
- #include "BsLightGrid.h"
- using namespace std::placeholders;
- namespace bs { namespace ct
- {
- RenderBeast::RenderBeast()
- : mDefaultMaterial(nullptr), mTiledDeferredLightingMats(), mFlatFramebufferToTextureMat(nullptr)
- , mSkyboxMat(nullptr), mSkyboxSolidColorMat(nullptr), mGPULightData(nullptr), mLightGrid(nullptr)
- , mObjectRenderer(nullptr), mOptions(bs_shared_ptr_new<RenderBeastOptions>()), mOptionsDirty(true)
- { }
- const StringID& RenderBeast::getName() const
- {
- static StringID name = "RenderBeast";
- return name;
- }
- void RenderBeast::initialize()
- {
- Renderer::initialize();
- gCoreThread().queueCommand(std::bind(&RenderBeast::initializeCore, this), CTQF_InternalQueue);
- }
- void RenderBeast::destroy()
- {
- Renderer::destroy();
- gCoreThread().queueCommand(std::bind(&RenderBeast::destroyCore, this));
- gCoreThread().submit(true);
- }
- void RenderBeast::initializeCore()
- {
- RendererUtility::startUp();
- mCoreOptions = bs_shared_ptr_new<RenderBeastOptions>();
- mObjectRenderer = bs_new<ObjectRenderer>();
- mDefaultMaterial = bs_new<DefaultMaterial>();
- mSkyboxMat = bs_new<SkyboxMat<false>>();
- mSkyboxSolidColorMat = bs_new<SkyboxMat<true>>();
- mFlatFramebufferToTextureMat = bs_new<FlatFramebufferToTextureMat>();
- mTiledDeferredLightingMats[0] = bs_new<TTiledDeferredLightingMat<1>>();
- mTiledDeferredLightingMats[1] = bs_new<TTiledDeferredLightingMat<2>>();
- mTiledDeferredLightingMats[2] = bs_new<TTiledDeferredLightingMat<4>>();
- mTiledDeferredLightingMats[3] = bs_new<TTiledDeferredLightingMat<8>>();
- mGPULightData = bs_new<GPULightData>();
- mLightGrid = bs_new<LightGrid>();
- GpuResourcePool::startUp();
- PostProcessing::startUp();
- }
- void RenderBeast::destroyCore()
- {
- if (mObjectRenderer != nullptr)
- bs_delete(mObjectRenderer);
- for (auto& entry : mRenderables)
- bs_delete(entry);
- for (auto& entry : mCameras)
- bs_delete(entry.second);
- mRenderTargets.clear();
- mCameras.clear();
- mRenderables.clear();
- mRenderableVisibility.clear();
- PostProcessing::shutDown();
- GpuResourcePool::shutDown();
- bs_delete(mDefaultMaterial);
- bs_delete(mSkyboxMat);
- bs_delete(mSkyboxSolidColorMat);
- bs_delete(mGPULightData);
- bs_delete(mLightGrid);
- bs_delete(mFlatFramebufferToTextureMat);
- UINT32 numDeferredMats = sizeof(mTiledDeferredLightingMats) / sizeof(mTiledDeferredLightingMats[0]);
- for (UINT32 i = 0; i < numDeferredMats; i++)
- bs_delete(mTiledDeferredLightingMats[i]);
- RendererUtility::shutDown();
- assert(mSamplerOverrides.empty());
- }
- void RenderBeast::notifyRenderableAdded(Renderable* renderable)
- {
- UINT32 renderableId = (UINT32)mRenderables.size();
- renderable->setRendererId(renderableId);
- mRenderables.push_back(bs_new<RendererObject>());
- mRenderableCullInfos.push_back(CullInfo(renderable->getBounds(), renderable->getLayer()));
- mRenderableVisibility.push_back(false);
- RendererObject* rendererObject = mRenderables.back();
- rendererObject->renderable = renderable;
- rendererObject->updatePerObjectBuffer();
- SPtr<Mesh> mesh = renderable->getMesh();
- if (mesh != nullptr)
- {
- const MeshProperties& meshProps = mesh->getProperties();
- SPtr<VertexDeclaration> vertexDecl = mesh->getVertexData()->vertexDeclaration;
- for (UINT32 i = 0; i < meshProps.getNumSubMeshes(); i++)
- {
- rendererObject->elements.push_back(BeastRenderableElement());
- BeastRenderableElement& renElement = rendererObject->elements.back();
- renElement.mesh = mesh;
- renElement.subMesh = meshProps.getSubMesh(i);
- renElement.renderableId = renderableId;
- renElement.animType = renderable->getAnimType();
- renElement.animationId = renderable->getAnimationId();
- renElement.morphShapeVersion = 0;
- renElement.morphShapeBuffer = renderable->getMorphShapeBuffer();
- renElement.boneMatrixBuffer = renderable->getBoneMatrixBuffer();
- renElement.morphVertexDeclaration = renderable->getMorphVertexDeclaration();
- renElement.material = renderable->getMaterial(i);
- if (renElement.material == nullptr)
- renElement.material = renderable->getMaterial(0);
- if (renElement.material != nullptr && renElement.material->getShader() == nullptr)
- renElement.material = nullptr;
- // If no material use the default material
- if (renElement.material == nullptr)
- renElement.material = mDefaultMaterial->getMaterial();
- // Determine which technique to use
- static StringID techniqueIDLookup[4] = { StringID::NONE, RTag_Skinned, RTag_Morph, RTag_SkinnedMorph };
- static_assert((UINT32)RenderableAnimType::Count == 4, "RenderableAnimType is expected to have four sequential entries.");
-
- UINT32 techniqueIdx = -1;
- RenderableAnimType animType = renderable->getAnimType();
- if(animType != RenderableAnimType::None)
- techniqueIdx = renElement.material->findTechnique(techniqueIDLookup[(int)animType]);
- if (techniqueIdx == (UINT32)-1)
- techniqueIdx = renElement.material->getDefaultTechnique();
- renElement.techniqueIdx = techniqueIdx;
- // Validate mesh <-> shader vertex bindings
- if (renElement.material != nullptr)
- {
- UINT32 numPasses = renElement.material->getNumPasses(techniqueIdx);
- for (UINT32 j = 0; j < numPasses; j++)
- {
- SPtr<Pass> pass = renElement.material->getPass(j, techniqueIdx);
- SPtr<VertexDeclaration> shaderDecl = pass->getVertexProgram()->getInputDeclaration();
- if (!vertexDecl->isCompatible(shaderDecl))
- {
- Vector<VertexElement> missingElements = vertexDecl->getMissingElements(shaderDecl);
- // If using morph shapes ignore POSITION1 and NORMAL1 missing since we assign them from within the renderer
- if(animType == RenderableAnimType::Morph || animType == RenderableAnimType::SkinnedMorph)
- {
- auto removeIter = std::remove_if(missingElements.begin(), missingElements.end(), [](const VertexElement& x)
- {
- return (x.getSemantic() == VES_POSITION && x.getSemanticIdx() == 1) ||
- (x.getSemantic() == VES_NORMAL && x.getSemanticIdx() == 1);
- });
- missingElements.erase(removeIter, missingElements.end());
- }
- if (!missingElements.empty())
- {
- StringStream wrnStream;
- wrnStream << "Provided mesh is missing required vertex attributes to render with the provided shader. Missing elements: " << std::endl;
- for (auto& entry : missingElements)
- wrnStream << "\t" << toString(entry.getSemantic()) << entry.getSemanticIdx() << std::endl;
- LOGWRN(wrnStream.str());
- break;
- }
- }
- }
- }
- // Generate or assigned renderer specific data for the material
- renElement.params = renElement.material->createParamsSet(techniqueIdx);
- renElement.material->updateParamsSet(renElement.params, true);
- // Generate or assign sampler state overrides
- SamplerOverrideKey samplerKey(renElement.material, techniqueIdx);
- auto iterFind = mSamplerOverrides.find(samplerKey);
- if (iterFind != mSamplerOverrides.end())
- {
- renElement.samplerOverrides = iterFind->second;
- iterFind->second->refCount++;
- }
- else
- {
- SPtr<Shader> shader = renElement.material->getShader();
- MaterialSamplerOverrides* samplerOverrides = SamplerOverrideUtility::generateSamplerOverrides(shader,
- renElement.material->_getInternalParams(), renElement.params, mCoreOptions);
- mSamplerOverrides[samplerKey] = samplerOverrides;
- renElement.samplerOverrides = samplerOverrides;
- samplerOverrides->refCount++;
- }
- mObjectRenderer->initElement(*rendererObject, renElement);
- }
- }
- }
- void RenderBeast::notifyRenderableRemoved(Renderable* renderable)
- {
- UINT32 renderableId = renderable->getRendererId();
- Renderable* lastRenerable = mRenderables.back()->renderable;
- UINT32 lastRenderableId = lastRenerable->getRendererId();
- RendererObject* rendererObject = mRenderables[renderableId];
- Vector<BeastRenderableElement>& elements = rendererObject->elements;
- for (auto& element : elements)
- {
- SamplerOverrideKey samplerKey(element.material, element.techniqueIdx);
- auto iterFind = mSamplerOverrides.find(samplerKey);
- assert(iterFind != mSamplerOverrides.end());
- MaterialSamplerOverrides* samplerOverrides = iterFind->second;
- samplerOverrides->refCount--;
- if (samplerOverrides->refCount == 0)
- {
- SamplerOverrideUtility::destroySamplerOverrides(samplerOverrides);
- mSamplerOverrides.erase(iterFind);
- }
- element.samplerOverrides = nullptr;
- }
- if (renderableId != lastRenderableId)
- {
- // Swap current last element with the one we want to erase
- std::swap(mRenderables[renderableId], mRenderables[lastRenderableId]);
- std::swap(mRenderableCullInfos[renderableId], mRenderableCullInfos[lastRenderableId]);
- lastRenerable->setRendererId(renderableId);
- for (auto& element : elements)
- element.renderableId = renderableId;
- }
- // Last element is the one we want to erase
- mRenderables.erase(mRenderables.end() - 1);
- mRenderableCullInfos.erase(mRenderableCullInfos.end() - 1);
- mRenderableVisibility.erase(mRenderableVisibility.end() - 1);
- bs_delete(rendererObject);
- }
- void RenderBeast::notifyRenderableUpdated(Renderable* renderable)
- {
- UINT32 renderableId = renderable->getRendererId();
- mRenderables[renderableId]->updatePerObjectBuffer();
- mRenderableCullInfos[renderableId].bounds = renderable->getBounds();
- }
- void RenderBeast::notifyLightAdded(Light* light)
- {
- if (light->getType() == LightType::Directional)
- {
- UINT32 lightId = (UINT32)mDirectionalLights.size();
- light->setRendererId(lightId);
- mDirectionalLights.push_back(RendererLight(light));
- }
- else
- {
- if (light->getType() == LightType::Point)
- {
- UINT32 lightId = (UINT32)mRadialLights.size();
- light->setRendererId(lightId);
- mRadialLights.push_back(RendererLight(light));
- mPointLightWorldBounds.push_back(light->getBounds());
- }
- else // Spot
- {
- UINT32 lightId = (UINT32)mSpotLights.size();
- light->setRendererId(lightId);
- mSpotLights.push_back(RendererLight(light));
- mSpotLightWorldBounds.push_back(light->getBounds());
- }
- }
- }
- void RenderBeast::notifyLightUpdated(Light* light)
- {
- UINT32 lightId = light->getRendererId();
- if (light->getType() == LightType::Point)
- mPointLightWorldBounds[lightId] = light->getBounds();
- else if(light->getType() == LightType::Spot)
- mSpotLightWorldBounds[lightId] = light->getBounds();
- }
- void RenderBeast::notifyLightRemoved(Light* light)
- {
- UINT32 lightId = light->getRendererId();
- if (light->getType() == LightType::Directional)
- {
- Light* lastLight = mDirectionalLights.back().getInternal();
- UINT32 lastLightId = lastLight->getRendererId();
- if (lightId != lastLightId)
- {
- // Swap current last element with the one we want to erase
- std::swap(mDirectionalLights[lightId], mDirectionalLights[lastLightId]);
- lastLight->setRendererId(lightId);
- }
- // Last element is the one we want to erase
- mDirectionalLights.erase(mDirectionalLights.end() - 1);
- }
- else
- {
- if (light->getType() == LightType::Point)
- {
- Light* lastLight = mRadialLights.back().getInternal();
- UINT32 lastLightId = lastLight->getRendererId();
- if (lightId != lastLightId)
- {
- // Swap current last element with the one we want to erase
- std::swap(mRadialLights[lightId], mRadialLights[lastLightId]);
- std::swap(mPointLightWorldBounds[lightId], mPointLightWorldBounds[lastLightId]);
- lastLight->setRendererId(lightId);
- }
- // Last element is the one we want to erase
- mRadialLights.erase(mRadialLights.end() - 1);
- mPointLightWorldBounds.erase(mPointLightWorldBounds.end() - 1);
- }
- else // Spot
- {
- Light* lastLight = mSpotLights.back().getInternal();
- UINT32 lastLightId = lastLight->getRendererId();
- if (lightId != lastLightId)
- {
- // Swap current last element with the one we want to erase
- std::swap(mSpotLights[lightId], mSpotLights[lastLightId]);
- std::swap(mSpotLightWorldBounds[lightId], mSpotLightWorldBounds[lastLightId]);
- lastLight->setRendererId(lightId);
- }
- // Last element is the one we want to erase
- mSpotLights.erase(mSpotLights.end() - 1);
- mSpotLightWorldBounds.erase(mSpotLightWorldBounds.end() - 1);
- }
- }
- }
- void RenderBeast::notifyCameraAdded(const Camera* camera)
- {
- RendererCamera* renCamera = updateCameraData(camera);
- renCamera->updatePerViewBuffer();
- }
- void RenderBeast::notifyCameraUpdated(const Camera* camera, UINT32 updateFlag)
- {
- RendererCamera* rendererCam;
- if((updateFlag & (UINT32)CameraDirtyFlag::Everything) != 0)
- {
- rendererCam = updateCameraData(camera);
- }
- else if((updateFlag & (UINT32)CameraDirtyFlag::PostProcess) != 0)
- {
- rendererCam = mCameras[camera];
- rendererCam->setPostProcessSettings(camera->getPostProcessSettings());
- }
- else // Transform
- {
- rendererCam = mCameras[camera];
- rendererCam->setTransform(
- camera->getPosition(),
- camera->getForward(),
- camera->getViewMatrix(),
- camera->getProjectionMatrixRS(),
- camera->getWorldFrustum());
- }
- rendererCam->updatePerViewBuffer();
- }
- void RenderBeast::notifyCameraRemoved(const Camera* camera)
- {
- updateCameraData(camera, true);
- }
- SPtr<PostProcessSettings> RenderBeast::createPostProcessSettings() const
- {
- return bs_shared_ptr_new<StandardPostProcessSettings>();
- }
- RendererCamera* RenderBeast::updateCameraData(const Camera* camera, bool forceRemove)
- {
- RendererCamera* output;
- SPtr<RenderTarget> renderTarget = camera->getViewport()->getTarget();
- auto iterFind = mCameras.find(camera);
- if(forceRemove)
- {
- if(iterFind != mCameras.end())
- {
- bs_delete(iterFind->second);
- mCameras.erase(iterFind);
- }
- renderTarget = nullptr;
- output = nullptr;
- }
- else
- {
- SPtr<Viewport> viewport = camera->getViewport();
- RENDERER_VIEW_DESC viewDesc;
- viewDesc.target.clearFlags = 0;
- if (viewport->getRequiresColorClear())
- viewDesc.target.clearFlags |= FBT_COLOR;
- if (viewport->getRequiresDepthClear())
- viewDesc.target.clearFlags |= FBT_DEPTH;
- if (viewport->getRequiresStencilClear())
- viewDesc.target.clearFlags |= FBT_STENCIL;
- viewDesc.target.clearColor = viewport->getClearColor();
- viewDesc.target.clearDepthValue = viewport->getClearDepthValue();
- viewDesc.target.clearStencilValue = viewport->getClearStencilValue();
- viewDesc.target.target = viewport->getTarget();
- viewDesc.target.nrmViewRect = viewport->getNormArea();
- viewDesc.target.viewRect = Rect2I(
- viewport->getX(),
- viewport->getY(),
- (UINT32)viewport->getWidth(),
- (UINT32)viewport->getHeight());
- if (viewDesc.target.target != nullptr)
- {
- viewDesc.target.targetWidth = viewDesc.target.target->getProperties().getWidth();
- viewDesc.target.targetHeight = viewDesc.target.target->getProperties().getHeight();
- }
- else
- {
- viewDesc.target.targetWidth = 0;
- viewDesc.target.targetHeight = 0;
- }
- viewDesc.target.numSamples = camera->getMSAACount();
- viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
- viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
- viewDesc.noLighting = camera->getFlags().isSet(CameraFlag::NoLighting);
- viewDesc.triggerCallbacks = true;
- viewDesc.runPostProcessing = true;
- viewDesc.cullFrustum = camera->getWorldFrustum();
- viewDesc.visibleLayers = camera->getLayers();
- viewDesc.nearPlane = camera->getNearClipDistance();
- viewDesc.farPlane = camera->getFarClipDistance();
- viewDesc.flipView = false;
- viewDesc.viewOrigin = camera->getPosition();
- viewDesc.viewDirection = camera->getForward();
- viewDesc.projTransform = camera->getProjectionMatrixRS();
- viewDesc.viewTransform = camera->getViewMatrix();
- viewDesc.stateReduction = mCoreOptions->stateReductionMode;
- viewDesc.skyboxTexture = camera->getSkybox();
- viewDesc.sceneCamera = camera;
- if (iterFind != mCameras.end())
- {
- output = iterFind->second;
- output->setView(viewDesc);
- }
- else
- {
- output = bs_new<RendererCamera>(viewDesc);
- mCameras[camera] = output;
- }
- output->setPostProcessSettings(camera->getPostProcessSettings());
- }
- // Remove from render target list
- int rtChanged = 0; // 0 - No RT, 1 - RT found, 2 - RT changed
- for (auto iterTarget = mRenderTargets.begin(); iterTarget != mRenderTargets.end(); ++iterTarget)
- {
- RendererRenderTarget& target = *iterTarget;
- for (auto iterCam = target.cameras.begin(); iterCam != target.cameras.end(); ++iterCam)
- {
- if (camera == *iterCam)
- {
- if (renderTarget != target.target)
- {
- target.cameras.erase(iterCam);
- rtChanged = 2;
- }
- else
- rtChanged = 1;
- break;
- }
- }
- if (target.cameras.empty())
- {
- mRenderTargets.erase(iterTarget);
- break;
- }
- }
- // Register in render target list
- if (renderTarget != nullptr && (rtChanged == 0 || rtChanged == 2))
- {
- auto findIter = std::find_if(mRenderTargets.begin(), mRenderTargets.end(),
- [&](const RendererRenderTarget& x) { return x.target == renderTarget; });
- if (findIter != mRenderTargets.end())
- {
- findIter->cameras.push_back(camera);
- }
- else
- {
- mRenderTargets.push_back(RendererRenderTarget());
- RendererRenderTarget& renderTargetData = mRenderTargets.back();
- renderTargetData.target = renderTarget;
- renderTargetData.cameras.push_back(camera);
- }
- // Sort render targets based on priority
- auto cameraComparer = [&](const Camera* a, const Camera* b) { return a->getPriority() > b->getPriority(); };
- auto renderTargetInfoComparer = [&](const RendererRenderTarget& a, const RendererRenderTarget& b)
- { return a.target->getProperties().getPriority() > b.target->getProperties().getPriority(); };
- std::sort(begin(mRenderTargets), end(mRenderTargets), renderTargetInfoComparer);
- for (auto& camerasPerTarget : mRenderTargets)
- {
- Vector<const Camera*>& cameras = camerasPerTarget.cameras;
- std::sort(begin(cameras), end(cameras), cameraComparer);
- }
- }
- return output;
- }
- void RenderBeast::setOptions(const SPtr<RendererOptions>& options)
- {
- mOptions = std::static_pointer_cast<RenderBeastOptions>(options);
- mOptionsDirty = true;
- }
- SPtr<RendererOptions> RenderBeast::getOptions() const
- {
- return mOptions;
- }
- void RenderBeast::syncOptions(const RenderBeastOptions& options)
- {
- bool filteringChanged = mCoreOptions->filtering != options.filtering;
- if (options.filtering == RenderBeastFiltering::Anisotropic)
- filteringChanged |= mCoreOptions->anisotropyMax != options.anisotropyMax;
- if (filteringChanged)
- refreshSamplerOverrides(true);
- *mCoreOptions = options;
- for (auto& entry : mCameras)
- {
- RendererCamera* rendererCam = entry.second;
- rendererCam->setStateReductionMode(mCoreOptions->stateReductionMode);
- }
- }
- void RenderBeast::renderAll()
- {
- // Sync all dirty sim thread CoreObject data to core thread
- CoreObjectManager::instance().syncToCore();
- if (mOptionsDirty)
- {
- gCoreThread().queueCommand(std::bind(&RenderBeast::syncOptions, this, *mOptions));
- mOptionsDirty = false;
- }
- gCoreThread().queueCommand(std::bind(&RenderBeast::renderAllCore, this, gTime().getTime(), gTime().getFrameDelta()));
- }
- static SPtr<Texture> dbgSkyTex;
- void RenderBeast::renderAllCore(float time, float delta)
- {
- THROW_IF_NOT_CORE_THREAD;
- gProfilerGPU().beginFrame();
- gProfilerCPU().beginSample("renderAllCore");
- // Note: I'm iterating over all sampler states every frame. If this ends up being a performance
- // issue consider handling this internally in ct::Material which can only do it when sampler states
- // are actually modified after sync
- refreshSamplerOverrides();
- // Update global per-frame hardware buffers
- mObjectRenderer->setParamFrameParams(time);
- // Retrieve animation data
- AnimationManager::instance().waitUntilComplete();
- const RendererAnimationData& animData = AnimationManager::instance().getRendererData();
-
- FrameInfo frameInfo(delta, animData);
- //if (dbgSkyTex == nullptr)
- // dbgSkyTex = captureSceneCubeMap(Vector3(0, 2, 0), true, 1024, frameInfo);
- // Gather all views
- Vector<RendererCamera*> views;
- for (auto& rtInfo : mRenderTargets)
- {
- SPtr<RenderTarget> target = rtInfo.target;
- Vector<const Camera*>& cameras = rtInfo.cameras;
- UINT32 numCameras = (UINT32)cameras.size();
- for (UINT32 i = 0; i < numCameras; i++)
- {
- RendererCamera* viewInfo = mCameras[cameras[i]];
- views.push_back(viewInfo);
- }
- }
- // Render everything
- renderViews(views.data(), (UINT32)views.size(), frameInfo);
- gProfilerGPU().endFrame();
- // Present render targets with back buffers
- for (auto& rtInfo : mRenderTargets)
- {
- if(rtInfo.target->getProperties().isWindow())
- RenderAPI::instance().swapBuffers(rtInfo.target);
- }
- gProfilerCPU().endSample("renderAllCore");
- }
- void RenderBeast::renderViews(RendererCamera** views, UINT32 numViews, const FrameInfo& frameInfo)
- {
- // Generate render queues per camera
- mRenderableVisibility.assign(mRenderableVisibility.size(), false);
- for(UINT32 i = 0; i < numViews; i++)
- views[i]->determineVisible(mRenderables, mRenderableCullInfos, &mRenderableVisibility);
- // Generate a list of lights and their GPU buffers
- UINT32 numDirLights = (UINT32)mDirectionalLights.size();
- for (UINT32 i = 0; i < numDirLights; i++)
- {
- mLightDataTemp.push_back(LightData());
- mDirectionalLights[i].getParameters(mLightDataTemp.back());
- }
- UINT32 numRadialLights = (UINT32)mRadialLights.size();
- mLightVisibilityTemp.resize(numRadialLights, false);
- for (UINT32 i = 0; i < numViews; i++)
- views[i]->calculateVisibility(mPointLightWorldBounds, mLightVisibilityTemp);
- for(UINT32 i = 0; i < numRadialLights; i++)
- {
- if (!mLightVisibilityTemp[i])
- continue;
- mLightDataTemp.push_back(LightData());
- mRadialLights[i].getParameters(mLightDataTemp.back());
- }
- UINT32 numSpotLights = (UINT32)mSpotLights.size();
- mLightVisibilityTemp.resize(numSpotLights, false);
- for (UINT32 i = 0; i < numViews; i++)
- views[i]->calculateVisibility(mSpotLightWorldBounds, mLightVisibilityTemp);
- for (UINT32 i = 0; i < numSpotLights; i++)
- {
- if (!mLightVisibilityTemp[i])
- continue;
- mLightDataTemp.push_back(LightData());
- mSpotLights[i].getParameters(mLightDataTemp.back());
- }
- mGPULightData->setLights(mLightDataTemp, numDirLights, numRadialLights, numSpotLights);
- mLightDataTemp.clear();
- mLightVisibilityTemp.clear();
- // Update various buffers required by each renderable
- UINT32 numRenderables = (UINT32)mRenderables.size();
- for (UINT32 i = 0; i < numRenderables; i++)
- {
- if (!mRenderableVisibility[i])
- continue;
- // Note: Before uploading bone matrices perhaps check if they has actually been changed since last frame
- mRenderables[i]->renderable->updateAnimationBuffers(frameInfo.animData);
- // Note: Could this step be moved in notifyRenderableUpdated, so it only triggers when material actually gets
- // changed? Although it shouldn't matter much because if the internal versions keeping track of dirty params.
- for (auto& element : mRenderables[i]->elements)
- element.material->updateParamsSet(element.params);
- mRenderables[i]->perObjectParamBuffer->flushToGPU();
- }
- for (UINT32 i = 0; i < numViews; i++)
- {
- if (views[i]->isOverlay())
- renderOverlay(views[i]);
- else
- renderView(views[i], frameInfo.timeDelta);
- }
- }
- void RenderBeast::renderView(RendererCamera* viewInfo, float frameDelta)
- {
- gProfilerCPU().beginSample("Render");
- const Camera* sceneCamera = viewInfo->getSceneCamera();
- SPtr<GpuParamBlockBuffer> perCameraBuffer = viewInfo->getPerViewBuffer();
- perCameraBuffer->flushToGPU();
- Matrix4 viewProj = viewInfo->getViewProjMatrix();
- viewInfo->beginRendering(true);
- // Prepare light grid required for transparent object rendering
- mLightGrid->updateGrid(*viewInfo, *mGPULightData, viewInfo->renderWithNoLighting());
- SPtr<GpuParamBlockBuffer> gridParams;
- SPtr<GpuBuffer> gridOffsetsAndSize, gridLightIndices;
- mLightGrid->getOutputs(gridOffsetsAndSize, gridLightIndices, gridParams);
- // Assign camera and per-call data to all relevant renderables
- const VisibilityInfo& visibility = viewInfo->getVisibilityMasks();
- UINT32 numRenderables = (UINT32)mRenderables.size();
- for (UINT32 i = 0; i < numRenderables; i++)
- {
- if (!visibility.renderables[i])
- continue;
- RendererObject* rendererObject = mRenderables[i];
- rendererObject->updatePerCallBuffer(viewProj);
- for (auto& element : mRenderables[i]->elements)
- {
- if (element.perCameraBindingIdx != -1)
- element.params->setParamBlockBuffer(element.perCameraBindingIdx, perCameraBuffer, true);
- if (element.gridParamsBindingIdx != -1)
- element.params->setParamBlockBuffer(element.gridParamsBindingIdx, gridParams, true);
- element.gridOffsetsAndSizeParam.set(gridOffsetsAndSize);
- element.gridLightIndicesParam.set(gridLightIndices);
- element.lightsBufferParam.set(mGPULightData->getLightBuffer());
- }
- }
- SPtr<RenderTargets> renderTargets = viewInfo->getRenderTargets();
- renderTargets->bindGBuffer();
- // Trigger pre-base-pass callbacks
- auto iterRenderCallback = mCallbacks.begin();
- if (viewInfo->checkTriggerCallbacks())
- {
- while (iterRenderCallback != mCallbacks.end())
- {
- RendererExtension* extension = *iterRenderCallback;
- if (extension->getLocation() != RenderLocation::PreBasePass)
- break;
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- ++iterRenderCallback;
- }
- }
- // Render base pass
- const Vector<RenderQueueElement>& opaqueElements = viewInfo->getOpaqueQueue()->getSortedElements();
- for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
- {
- BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
- renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
- }
- // Trigger post-base-pass callbacks
- if (viewInfo->checkTriggerCallbacks())
- {
- while (iterRenderCallback != mCallbacks.end())
- {
- RendererExtension* extension = *iterRenderCallback;
- if (extension->getLocation() != RenderLocation::PostBasePass)
- break;
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- ++iterRenderCallback;
- }
- }
- RenderAPI& rapi = RenderAPI::instance();
- rapi.setRenderTarget(nullptr);
- // Render light pass
- ITiledDeferredLightingMat* lightingMat;
- UINT32 numSamples = viewInfo->getNumSamples();
- switch(numSamples)
- {
- case 0:
- case 1:
- lightingMat = mTiledDeferredLightingMats[0]; // No MSAA
- break;
- case 2:
- lightingMat = mTiledDeferredLightingMats[1]; // 2X MSAA
- break;
- case 4:
- lightingMat = mTiledDeferredLightingMats[2]; // 4X MSAA
- break;
- default:
- lightingMat = mTiledDeferredLightingMats[3]; // 8X MSAA or higher
- break;
- }
- lightingMat->setLights(*mGPULightData);
- lightingMat->execute(renderTargets, perCameraBuffer, viewInfo->renderWithNoLighting());
- const RenderAPIInfo& rapiInfo = RenderAPI::instance().getAPIInfo();
- bool usingFlattenedFB = numSamples > 1 && !rapiInfo.isFlagSet(RenderAPIFeatureFlag::MSAAImageStores);
- renderTargets->bindSceneColor(true);
- // If we're using flattened framebuffer for MSAA we need to copy its contents to the MSAA scene texture before
- // continuing
- if(usingFlattenedFB)
- {
- mFlatFramebufferToTextureMat->execute(renderTargets->getFlattenedSceneColorBuffer(),
- renderTargets->getSceneColor());
- }
- // Render skybox (if any)
- SPtr<Texture> skyTexture = viewInfo->getSkybox();
- if (skyTexture != nullptr && skyTexture->getProperties().getTextureType() == TEX_TYPE_CUBE_MAP)
- {
- mSkyboxMat->bind(perCameraBuffer);
- mSkyboxMat->setParams(skyTexture, Color::White);
- }
- else
- {
- Color clearColor = viewInfo->getClearColor();
- mSkyboxSolidColorMat->bind(perCameraBuffer);
- mSkyboxSolidColorMat->setParams(nullptr, clearColor);
- }
- SPtr<Mesh> mesh = gRendererUtility().getSkyBoxMesh();
- gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
- renderTargets->bindSceneColor(false);
- // Render transparent objects
- const Vector<RenderQueueElement>& transparentElements = viewInfo->getTransparentQueue()->getSortedElements();
- for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
- {
- BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
- renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
- }
- // Trigger post-light-pass callbacks
- if (viewInfo->checkTriggerCallbacks())
- {
- while (iterRenderCallback != mCallbacks.end())
- {
- RendererExtension* extension = *iterRenderCallback;
- if (extension->getLocation() != RenderLocation::PostLightPass)
- break;
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- ++iterRenderCallback;
- }
- }
- // Post-processing and final resolve
- Rect2 viewportArea = viewInfo->getViewportRect();
- if (viewInfo->checkRunPostProcessing())
- {
- // If using MSAA, resolve into non-MSAA texture before post-processing
- if(numSamples > 1)
- {
- rapi.setRenderTarget(renderTargets->getSceneColorNonMSAART());
- rapi.setViewport(viewportArea);
- SPtr<Texture> sceneColor = renderTargets->getSceneColor();
- gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewInfo->getFlipView());
- }
- // Post-processing code also takes care of writting to the final output target
- PostProcessing::instance().postProcess(viewInfo, renderTargets->getSceneColorNonMSAA(), frameDelta);
- }
- else
- {
- // Just copy from scene color to output if no post-processing
- SPtr<RenderTarget> target = viewInfo->getFinalTarget();
- rapi.setRenderTarget(target);
- rapi.setViewport(viewportArea);
- SPtr<Texture> sceneColor = renderTargets->getSceneColor();
- gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewInfo->getFlipView());
- }
- // Trigger overlay callbacks
- if (viewInfo->checkTriggerCallbacks())
- {
- while (iterRenderCallback != mCallbacks.end())
- {
- RendererExtension* extension = *iterRenderCallback;
- if (extension->getLocation() != RenderLocation::Overlay)
- break;
- if (extension->check(*sceneCamera))
- extension->render(*sceneCamera);
- ++iterRenderCallback;
- }
- }
- viewInfo->endRendering();
- gProfilerCPU().endSample("Render");
- }
- void RenderBeast::renderOverlay(RendererCamera* viewInfo)
- {
- gProfilerCPU().beginSample("RenderOverlay");
- viewInfo->getPerViewBuffer()->flushToGPU();
- viewInfo->beginRendering(false);
- const Camera* camera = viewInfo->getSceneCamera();
- SPtr<RenderTarget> target = viewInfo->getFinalTarget();
- SPtr<Viewport> viewport = camera->getViewport();
- UINT32 clearBuffers = 0;
- if (viewport->getRequiresColorClear())
- clearBuffers |= FBT_COLOR;
- if (viewport->getRequiresDepthClear())
- clearBuffers |= FBT_DEPTH;
- if (viewport->getRequiresStencilClear())
- clearBuffers |= FBT_STENCIL;
- if (clearBuffers != 0)
- {
- RenderAPI::instance().setRenderTarget(target);
- RenderAPI::instance().clearViewport(clearBuffers, viewport->getClearColor(),
- viewport->getClearDepthValue(), viewport->getClearStencilValue());
- }
- else
- RenderAPI::instance().setRenderTarget(target, false, RT_COLOR0);
- RenderAPI::instance().setViewport(viewport->getNormArea());
- // Trigger overlay callbacks
- auto iterRenderCallback = mCallbacks.begin();
- while (iterRenderCallback != mCallbacks.end())
- {
- RendererExtension* extension = *iterRenderCallback;
- if (extension->getLocation() != RenderLocation::Overlay)
- {
- ++iterRenderCallback;
- continue;
- }
- if (extension->check(*camera))
- extension->render(*camera);
- ++iterRenderCallback;
- }
- viewInfo->endRendering();
- gProfilerCPU().endSample("RenderOverlay");
- }
-
- void RenderBeast::renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass,
- const Matrix4& viewProj)
- {
- SPtr<Material> material = element.material;
- if (bindPass)
- gRendererUtility().setPass(material, passIdx, element.techniqueIdx);
- gRendererUtility().setPassParams(element.params, passIdx);
- if(element.morphVertexDeclaration == nullptr)
- gRendererUtility().draw(element.mesh, element.subMesh);
- else
- gRendererUtility().drawMorph(element.mesh, element.subMesh, element.morphShapeBuffer,
- element.morphVertexDeclaration);
- }
- SPtr<Texture> RenderBeast::captureSceneCubeMap(const Vector3& position, bool hdr, UINT32 size,
- const FrameInfo& frameInfo)
- {
- TEXTURE_DESC cubeMapDesc;
- cubeMapDesc.type = TEX_TYPE_CUBE_MAP;
- cubeMapDesc.format = hdr ? PF_FLOAT16_RGBA : PF_R8G8B8A8;
- cubeMapDesc.width = size;
- cubeMapDesc.height = size;
- cubeMapDesc.numMips = PixelUtil::getMaxMipmaps(size, size, 1, cubeMapDesc.format);
- cubeMapDesc.usage = TU_RENDERTARGET;
- SPtr<Texture> cubemap = Texture::create(cubeMapDesc);
- Matrix4 projTransform = Matrix4::projectionPerspective(Degree(90.0f), 1.0f, 0.05f, 1000.0f);
- ConvexVolume localFrustum(projTransform);
- RenderAPI::instance().convertProjectionMatrix(projTransform, projTransform);
- RENDERER_VIEW_DESC viewDesc;
- viewDesc.target.clearFlags = FBT_COLOR | FBT_DEPTH;
- viewDesc.target.clearColor = Color::Black;
- viewDesc.target.clearDepthValue = 1.0f;
- viewDesc.target.clearStencilValue = 0;
- viewDesc.target.nrmViewRect = Rect2(0, 0, 1.0f, 1.0f);
- viewDesc.target.viewRect = Rect2I(0, 0, size, size);
- viewDesc.target.targetWidth = size;
- viewDesc.target.targetHeight = size;
- viewDesc.target.numSamples = 1;
- viewDesc.isOverlay = false;
- viewDesc.isHDR = hdr;
- viewDesc.noLighting = false;
- viewDesc.triggerCallbacks = false;
- viewDesc.runPostProcessing = false;
- viewDesc.visibleLayers = 0xFFFFFFFFFFFFFFFF;
- viewDesc.nearPlane = 0.5f;
- viewDesc.farPlane = 1000.0f;
- viewDesc.flipView = RenderAPI::instance().getAPIInfo().isFlagSet(RenderAPIFeatureFlag::UVYAxisUp);
- viewDesc.viewOrigin = position;
- viewDesc.projTransform = projTransform;
- viewDesc.stateReduction = mCoreOptions->stateReductionMode;
- viewDesc.sceneCamera = nullptr;
- // Note: Find a camera to receive skybox from. Skybox should probably be a global property instead of a per-camera
- // one.
- for(auto& entry : mRenderTargets)
- {
- for(auto& camera : entry.cameras)
- {
- if (camera->getSkybox() != nullptr)
- {
- viewDesc.skyboxTexture = camera->getSkybox();
- break;
- }
- }
- }
- Matrix4 viewOffsetMat = Matrix4::translation(-position);
- RendererCamera views[6];
- for(UINT32 i = 0; i < 6; i++)
- {
- // Calculate view matrix
- Matrix3 viewRotationMat;
- Vector3 forward;
- Vector3 up = Vector3::UNIT_Y;
- switch (i)
- {
- case CF_PositiveX:
- forward = Vector3::UNIT_X;
- break;
- case CF_NegativeX:
- forward = -Vector3::UNIT_X;
- break;
- case CF_PositiveY:
- forward = Vector3::UNIT_Y;
- up = -Vector3::UNIT_Z;
- break;
- case CF_NegativeY:
- forward = Vector3::UNIT_X;
- up = Vector3::UNIT_Z;
- break;
- case CF_PositiveZ:
- forward = Vector3::UNIT_Z;
- break;
- case CF_NegativeZ:
- forward = -Vector3::UNIT_Z;
- break;
- }
- Vector3 right = Vector3::cross(up, forward);
- viewRotationMat = Matrix3(right, up, forward);
- viewDesc.viewDirection = forward;
- viewDesc.viewTransform = Matrix4(viewRotationMat) * viewOffsetMat;
- // Calculate world frustum for culling
- const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
- Matrix4 worldMatrix = viewDesc.viewTransform.transpose();
- Vector<Plane> worldPlanes(frustumPlanes.size());
- UINT32 j = 0;
- for (auto& plane : frustumPlanes)
- {
- worldPlanes[j] = worldMatrix.multiplyAffine(plane);
- j++;
- }
- viewDesc.cullFrustum = ConvexVolume(worldPlanes);
- // Set up face render target
- RENDER_TEXTURE_DESC cubeFaceRTDesc;
- cubeFaceRTDesc.colorSurfaces[0].texture = cubemap;
- cubeFaceRTDesc.colorSurfaces[0].face = i;
- cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
-
- viewDesc.target.target = RenderTexture::create(cubeFaceRTDesc);
- views[i].setView(viewDesc);
- views[i].updatePerViewBuffer();
- views[i].determineVisible(mRenderables, mRenderableCullInfos);
- }
- RendererCamera* viewPtrs[] = { &views[0], &views[1], &views[2], &views[3], &views[4], &views[5] };
- renderViews(viewPtrs, 6, frameInfo);
- ReflectionCubemap::filterCubemapForSpecular(cubemap);
- return cubemap;
- }
- void RenderBeast::refreshSamplerOverrides(bool force)
- {
- bool anyDirty = false;
- for (auto& entry : mSamplerOverrides)
- {
- SPtr<MaterialParams> materialParams = entry.first.material->_getInternalParams();
- MaterialSamplerOverrides* materialOverrides = entry.second;
- for(UINT32 i = 0; i < materialOverrides->numOverrides; i++)
- {
- SamplerOverride& override = materialOverrides->overrides[i];
- const MaterialParamsBase::ParamData* materialParamData = materialParams->getParamData(override.paramIdx);
- SPtr<SamplerState> samplerState;
- materialParams->getSamplerState(*materialParamData, samplerState);
- UINT64 hash = 0;
- if (samplerState != nullptr)
- hash = samplerState->getProperties().getHash();
- if (hash != override.originalStateHash || force)
- {
- if (samplerState != nullptr)
- override.state = SamplerOverrideUtility::generateSamplerOverride(samplerState, mCoreOptions);
- else
- override.state = SamplerOverrideUtility::generateSamplerOverride(SamplerState::getDefault(), mCoreOptions);
- override.originalStateHash = override.state->getProperties().getHash();
- materialOverrides->isDirty = true;
- }
- // Dirty flag can also be set externally, so check here even though we assign it above
- if (materialOverrides->isDirty)
- anyDirty = true;
- }
- }
- // Early exit if possible
- if (!anyDirty)
- return;
- UINT32 numRenderables = (UINT32)mRenderables.size();
- for (UINT32 i = 0; i < numRenderables; i++)
- {
- for(auto& element : mRenderables[i]->elements)
- {
- MaterialSamplerOverrides* overrides = element.samplerOverrides;
- if(overrides != nullptr && overrides->isDirty)
- {
- UINT32 numPasses = element.material->getNumPasses();
- for(UINT32 j = 0; j < numPasses; j++)
- {
- SPtr<GpuParams> params = element.params->getGpuParams(j);
- const UINT32 numStages = 6;
- for (UINT32 k = 0; k < numStages; k++)
- {
- GpuProgramType type = (GpuProgramType)k;
- SPtr<GpuParamDesc> paramDesc = params->getParamDesc(type);
- if (paramDesc == nullptr)
- continue;
- for (auto& samplerDesc : paramDesc->samplers)
- {
- UINT32 set = samplerDesc.second.set;
- UINT32 slot = samplerDesc.second.slot;
- UINT32 overrideIndex = overrides->passes[j].stateOverrides[set][slot];
- if (overrideIndex == (UINT32)-1)
- continue;
- params->setSamplerState(set, slot, overrides->overrides[overrideIndex].state);
- }
- }
- }
- }
- }
- }
- for (auto& entry : mSamplerOverrides)
- entry.second->isDirty = false;
- }
- }}
|