فهرست منبع

In renderer update per-object buffers just before rendering so that a single buffer can be shared by multiple objects
In tree view don't select an element after an edit operation if the edit operation was broken by a mouse click (which normally selects/unselects)
Duplicate now works in scene view

Marko Pintera 10 سال پیش
والد
کامیت
734b56a97d

+ 5 - 0
BansheeEditor/Include/BsGUITreeView.h

@@ -351,6 +351,11 @@ namespace BansheeEngine
 		 */
 		void onEditCanceled();
 
+		/**
+		 * @brief	Triggered when the user clicks outside of the edit box during a rename operation.
+		 */
+		void onEditFocusLost();
+
 		String mBackgroundStyle;
 		String mElementBtnStyle;
 		String mFoldoutBtnStyle;

+ 1 - 1
BansheeEditor/Include/BsGUITreeViewEditBox.h

@@ -38,7 +38,7 @@ namespace BansheeEngine
 
 		Event<void()> onInputConfirmed; /**< Triggered when the user confirms the input in the edit box. */
 		Event<void()> onInputCanceled; /**< Triggered when the user cancels the input in the edit box. */
-
+		Event<void()> onFocusLost; /**< Triggered when the user clicks outside of the editor box. */
 	private:
 		GUITreeViewEditBox(const String& styleName, const GUIDimensions& dimensions);
 

+ 14 - 2
BansheeEditor/Source/BsGUITreeView.cpp

@@ -123,6 +123,7 @@ namespace BansheeEngine
 
 		mNameEditBox->onInputConfirmed.connect(std::bind(&GUITreeView::onEditAccepted, this));
 		mNameEditBox->onInputCanceled.connect(std::bind(&GUITreeView::onEditCanceled, this));
+		mNameEditBox->onFocusLost.connect(std::bind(&GUITreeView::onEditFocusLost, this));
 
 		mDragHighlight = GUITexture::create(mDragHighlightStyle);
 		mDragSepHighlight = GUITexture::create(mDragSepHighlightStyle);
@@ -844,12 +845,24 @@ namespace BansheeEngine
 
 	void GUITreeView::onEditAccepted()
 	{
+		TreeElement* elem = mEditElement;
 		disableEdit(true);
+		selectElement(elem);
 	}
 
 	void GUITreeView::onEditCanceled()
 	{
-		if(mEditElement != nullptr)
+		if (mEditElement != nullptr)
+		{
+			TreeElement* elem = mEditElement;
+			disableEdit(false);
+			selectElement(elem);
+		}
+	}
+
+	void GUITreeView::onEditFocusLost()
+	{
+		if (mEditElement != nullptr)
 			disableEdit(false);
 	}
 
@@ -881,7 +894,6 @@ namespace BansheeEngine
 
 		mNameEditBox->setFocus(false);
 		mNameEditBox->disableRecursively();
-		selectElement(mEditElement);
 		mEditElement = nullptr;
 	}
 

+ 1 - 0
MBansheeEditor/EditorApplication.cs

@@ -100,6 +100,7 @@ namespace BansheeEditor
             inputConfig.RegisterButton(SceneWindow.MoveToolBinding, ButtonCode.W);
             inputConfig.RegisterButton(SceneWindow.RotateToolBinding, ButtonCode.E);
             inputConfig.RegisterButton(SceneWindow.ScaleToolBinding, ButtonCode.R);
+            inputConfig.RegisterButton(SceneWindow.DuplicateBinding, ButtonCode.D, ButtonModifier.Ctrl);
 
             ProjectLibrary.Refresh();
             monitor = new FolderMonitor(ProjectLibrary.ResourceFolder);

+ 54 - 4
MBansheeEditor/Scene/SceneWindow.cs

@@ -11,10 +11,11 @@ namespace BansheeEditor
     internal sealed class SceneWindow : EditorWindow
     {
         internal const string ToggleProfilerOverlayBinding = "ToggleProfilerOverlay";
-        internal const string ViewToolBinding = "ViewTool";
-        internal const string MoveToolBinding = "MoveTool";
-        internal const string RotateToolBinding = "RotateTool";
-        internal const string ScaleToolBinding = "ScaleTool";
+        internal const string ViewToolBinding = "EdViewTool";
+        internal const string MoveToolBinding = "EdMoveTool";
+        internal const string RotateToolBinding = "EdRotateTool";
+        internal const string ScaleToolBinding = "EdScaleTool";
+        internal const string DuplicateBinding = "EdDuplicate";
 
         private const int HeaderHeight = 20;
         private const float DefaultPlacementDepth = 5.0f;
@@ -48,6 +49,8 @@ namespace BansheeEditor
 
         private int editorSettingsHash = int.MaxValue;
 
+        private VirtualButton duplicateKey;
+
         // Tool shortcuts
         private VirtualButton viewToolKey;
         private VirtualButton moveToolKey;
@@ -146,6 +149,7 @@ namespace BansheeEditor
             moveToolKey = new VirtualButton(MoveToolBinding);
             rotateToolKey = new VirtualButton(RotateToolBinding);
             scaleToolKey = new VirtualButton(ScaleToolBinding);
+            duplicateKey = new VirtualButton(DuplicateBinding);
 
             UpdateRenderTexture(Width, Height - HeaderHeight);
             UpdateProfilerOverlay();
@@ -196,6 +200,23 @@ namespace BansheeEditor
 
                 if (VirtualInput.IsButtonUp(scaleToolKey))
                     EditorApplication.ActiveSceneTool = SceneViewTool.Scale;
+
+                if (VirtualInput.IsButtonUp(duplicateKey))
+                {
+                    SceneObject[] selectedObjects = Selection.sceneObjects;
+                    CleanDuplicates(ref selectedObjects);
+
+                    if (selectedObjects.Length > 0)
+                    {
+                        String message;
+		                if (selectedObjects.Length == 1)
+			                message = "Duplicated " + selectedObjects[0].Name;
+		                else
+			                message = "Duplicated " + selectedObjects.Length + " elements";
+
+                        UndoRedo.CloneSO(selectedObjects, message);
+                    }
+                }
             }
 
             // Refresh GUI buttons if needed (in case someones changes the values from script)
@@ -504,5 +525,34 @@ namespace BansheeEditor
             if (profilerCamera != null)
                 profilerCamera.Target = renderTexture;
 	    }
+
+        private void CleanDuplicates(ref SceneObject[] objects)
+	    {
+		    List<SceneObject> cleanList = new List<SceneObject>();
+		    for (int i = 0; i < objects.Length; i++)
+		    {
+			    bool foundParent = false;
+                for (int j = 0; j < objects.Length; j++)
+                {
+                    SceneObject elem = objects[i];
+
+                    while (elem != null && elem != objects[j])
+                        elem = objects[i].Parent;
+
+                    bool isChildOf =  elem == objects[j];
+
+				    if (i != j && isChildOf)
+				    {
+					    foundParent = true;
+					    break;
+				    }
+			    }
+
+			    if (!foundParent)
+				    cleanList.Add(objects[i]);
+		    }
+
+		    objects = cleanList.ToArray();
+	    }
     }
 }

+ 1 - 2
RenderBeast/Include/BsLitTexRenderableController.h

@@ -23,8 +23,6 @@ namespace BansheeEngine
 		 */
 		struct PerObjectData
 		{
-			SPtr<GpuParamBlockBufferCore> perObjectParamBuffer;
-
 			GpuParamMat4Core wvpParam;
 
 			Vector<RenderableElement::BufferBindInfo> perObjectBuffers;
@@ -83,6 +81,7 @@ namespace BansheeEngine
 		SPtr<GpuParamBlockBufferCore> staticParamBuffer;
 		SPtr<GpuParamBlockBufferCore> perFrameParamBuffer;
 		SPtr<GpuParamBlockBufferCore> perCameraParamBuffer;
+		SPtr<GpuParamBlockBufferCore> perObjectParamBuffer;
 
 		SPtr<GpuParamsCore> staticParams;
 		SPtr<GpuParamsCore> perFrameParams;

+ 17 - 10
RenderBeast/Include/BsRenderBeast.h

@@ -8,6 +8,8 @@
 
 namespace BansheeEngine
 {
+	class BeastRenderableElement;
+
 	/**
 	 * Semantics that may be used for signaling the renderer
 	 * for what is a certain shader parameter used for.
@@ -16,6 +18,16 @@ namespace BansheeEngine
 	static StringID RPS_Time = "Time";
 	static StringID RPS_LightDir = "LightDir";
 
+	/**
+	 * @brief	Data used by the renderer when rendering renderable handlers.
+	 */
+	struct RenderableData
+	{
+		RenderableHandlerCore* renderable;
+		Vector<BeastRenderableElement> elements;
+		RenderableController* controller;
+	};
+
 	/**
 	 * @copydoc	RenderableElement
 	 *
@@ -30,6 +42,11 @@ namespace BansheeEngine
 		 *			properties on a global scale (e.g. filtering most commonly).
 		 */
 		MaterialSamplerOverrides* samplerOverrides;
+
+		/**
+		 * @brief	Id of the owner renderable.
+		 */
+		UINT32 renderableId;
 	};
 
 	/**
@@ -57,16 +74,6 @@ namespace BansheeEngine
 			RenderQueuePtr renderQueue;
 		};
 
-		/**
-		 * @brief	Data used by the renderer when rendering renderable handlers.
-		 */
-		struct RenderableData
-		{
-			RenderableHandlerCore* renderable;
-			Vector<BeastRenderableElement> elements;
-			RenderableController* controller;
-		};
-
 		/**
 		 * @brief	Data used by the renderer for lights.
 		 */

+ 3 - 8
RenderBeast/Source/BsLitTexRenderableController.cpp

@@ -136,6 +136,7 @@ namespace BansheeEngine
 		staticParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(staticParamBlockDesc.blockSize * sizeof(UINT32));
 		perFrameParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perFrameParamBlockDesc.blockSize * sizeof(UINT32));
 		perCameraParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perCameraParamBlockDesc.blockSize * sizeof(UINT32));
+		perObjectParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perObjectParamBlockDesc.blockSize * sizeof(UINT32));
 
 		staticParams->setParamBlockBuffer(staticParamBlockDesc.slot, staticParamBuffer);
 		perFrameParams->setParamBlockBuffer(perFrameParamBlockDesc.slot, perFrameParamBuffer);
@@ -255,10 +256,7 @@ namespace BansheeEngine
 					{
 						if (findIter->second.blockSize == perObjectParamBlockDesc.blockSize)
 						{
-							if (rendererData->perObjectParamBuffer == nullptr)
-								rendererData->perObjectParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perObjectParamBlockDesc.blockSize * sizeof(UINT32));
-
-							rendererData->perObjectBuffers.push_back(RenderableElement::BufferBindInfo(i, j, findIter->second.slot, rendererData->perObjectParamBuffer));
+							rendererData->perObjectBuffers.push_back(RenderableElement::BufferBindInfo(i, j, findIter->second.slot, perObjectParamBuffer));
 
 							if (rendererData->wvpParam == nullptr && wvpParamName != "")
 							{
@@ -285,7 +283,7 @@ namespace BansheeEngine
 		{
 			SPtr<GpuParamsCore> params = element.material->getPassParameters(perObjectBuffer.passIdx)->getParamByIdx(perObjectBuffer.paramsIdx);
 
-			params->setParamBlockBuffer(perObjectBuffer.slotIdx, rendererData->perObjectParamBuffer);
+			params->setParamBlockBuffer(perObjectBuffer.slotIdx, perObjectParamBuffer);
 		}
 	}
 
@@ -308,9 +306,6 @@ namespace BansheeEngine
 		PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element.rendererData);
 
 		rendererData->wvpParam.set(wvpMatrix);
-
-		if (rendererData->perObjectParamBuffer != nullptr)
-			rendererData->perObjectParamBuffer->flushToGPU();
 	}
 
 	SPtr<ShaderCore> LitTexRenderableController::createDefaultShader()

+ 39 - 29
RenderBeast/Source/BsRenderBeast.cpp

@@ -117,6 +117,7 @@ namespace BansheeEngine
 
 				renElement.mesh = mesh;
 				renElement.subMesh = meshProps.getSubMesh(i);
+				renElement.renderableId = renderableId;
 
 				renElement.material = renderable->getMaterial(i);
 				if (renElement.material == nullptr)
@@ -450,32 +451,6 @@ namespace BansheeEngine
 			if ((renderable->getLayer() & cameraLayers) == 0)
 				continue;
 
-			// Update buffers
-			for (auto& renderElem : renderableData.elements)
-			{
-				if (controller != nullptr)
-					controller->bindPerObjectBuffers(renderElem);
-
-				if (renderableType == RenType_LitTextured)
-				{
-					Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
-					mLitTexHandler->updatePerObjectBuffers(renderElem, worldViewProjMatrix);
-				}
-
-				UINT32 numPasses = renderElem.material->getNumPasses();
-				for (UINT32 i = 0; i < numPasses; i++)
-				{
-					SPtr<PassParametersCore> passParams = renderElem.material->getPassParameters(i);
-
-					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
-					{
-						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
-						if (params != nullptr)
-							params->updateHardwareBuffers();
-					}
-				}
-			}
-
 			// Do frustum culling
 			// TODO - This is bound to be a bottleneck at some point. When it is ensure that intersect
 			// methods use vector operations, as it is trivial to update them.
@@ -502,9 +477,44 @@ namespace BansheeEngine
 		{
 			SPtr<MaterialCore> material = iter->material;
 
-			BeastRenderableElement* renderable = static_cast<BeastRenderableElement*>(iter->renderElem);
-			if (renderable != nullptr && renderable->samplerOverrides != nullptr)
-				setPass(material, iter->passIdx, &renderable->samplerOverrides->passes[iter->passIdx]);
+			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+			if (renderElem != nullptr)
+			{
+				UINT32 rendererId = renderElem->renderableId;
+				const RenderableData& renderableData = mRenderables[rendererId];
+
+				RenderableHandlerCore* renderable = renderableData.renderable;
+				RenderableController* controller = renderableData.controller;
+				UINT32 renderableType = renderable->getRenderableType();
+				
+				if (controller != nullptr)
+					controller->bindPerObjectBuffers(*renderElem);
+
+				if (renderableType == RenType_LitTextured)
+				{
+					Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
+					mLitTexHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+				}
+
+				UINT32 numPasses = renderElem->material->getNumPasses();
+				for (UINT32 i = 0; i < numPasses; i++)
+				{
+					SPtr<PassParametersCore> passParams = renderElem->material->getPassParameters(i);
+
+					for (UINT32 j = 0; j < PassParametersCore::NUM_PARAMS; j++)
+					{
+						SPtr<GpuParamsCore> params = passParams->getParamByIdx(j);
+						if (params != nullptr)
+							params->updateHardwareBuffers();
+					}
+				}
+				
+				if (renderElem != nullptr && renderElem->samplerOverrides != nullptr)
+					setPass(material, iter->passIdx, &renderElem->samplerOverrides->passes[iter->passIdx]);
+				else
+					setPass(material, iter->passIdx, nullptr);
+
+			}
 			else
 				setPass(material, iter->passIdx, nullptr);
 

+ 5 - 19
TODO.txt

@@ -55,25 +55,9 @@ Code quality improvements:
 Polish
 
  - Duplicating a mesh doesn't properly render the mesh
-  - It seems to be due to renderables sharing materials. I generate a separate per-object buffer per each
-    renderable (but maybe I shouldn't? Just generate the one and update it before rendering) and then assign
-	it to the same MaterialCore which means whichever one was applied last was the one that sticks.
-
-Maybe:
-Make current material not a resource
-Store material in Renderable by value (so its copied when cloning happens)
- - TODO - Does cloning even properly clone Renderable or do they point to the same RenderableHandler? (If not, switching RTTI to non-ptr might be okay)
-  - Same issue will be with CameraHandler and LightInternal
-
-Add a new MaterialPrefab type that is a resource
- - Internally it stores a Material and it can be instantiated (copied) for use on Renderable
-POTENTIALLY - When serializing Renderable don't serialize a handle to the resource but the material directly. Then cloning it will ensure it has an unique instance.
-  - Same would go for assignment of material to Renderable, it would need to be cloned
-  - A pointer to the original resource could still be held
-BE AWARE - That in Unity when accessed from inspector materials aren't instantiated (they all share parameters)
- - However sometimes it will be useful to modify the materials without cloning & reassigning them (i.e. I'd still like to keep the original reference)
-  - But I think this will only happen at runtime, and it's probably fine to lose the original reference
-   - or maybe I don't lose the original reference but just don't persist (i.e. serialize) the instantiated ones
+  - RenderableHandler, CameraHandler, LightInternal needs to be serialized by value to avoid issues when cloning them
+  - Per-object parameters should be updated just before object rendering
+  - (Later) Material will need a clone() method, in both C++ and C#, for when the user needs to customize a specific object instance
 
 Ribek use:
  - Camera, Renderable, Material, Texture inspector
@@ -125,6 +109,7 @@ Other polish:
    - Likely use a user-provided callback to trigger when populating the menus
  - CmdRecordSO records an SO and all its children but it should only record a single SO
    - Also it doesn't record a diff, but instead the whole object
+ - Ctrl+D should perform duplicate in scene view as well
 
 Stage 2 polish:
  - Inject an icon into an .exe (Win32 specific)
@@ -152,6 +137,7 @@ Finalizing:
  - Splash screen
  - Settings/Preferences window
  - Documentation
+ - Need to generate a proper merge of dev and preview branches
  - (Optionally) GUI tabbing to switch between elements
 
 ----------------------------------------------------------------------

+ 60 - 57
TODOExperimentation.txt

@@ -1,29 +1,52 @@
--------------------------
+------------------------- STUDY --------------------------------
 Study shadow rendering implementations
 Study how is transparency handled (is it order independant?)
 Figure out what is skylight
 Determine how is light bleeding handled (if at all)
 
-Think about/set up deferred buffers per camera (don't activate them just yet)
+---------------------- IMPLEMENTATION ---------------------------
+
 RenderTexturePool needs support for cube and 3D textures
 Lights need getLightMesh() method
+ - Need cone to use when rendering spot light, sphere otherwise
+Load up and set up a test-bed with Ribek's scene
+Quantize buffer sizes so they're divideable by 8 when requesting them from RenderTexturePool
 
-Think about how to start with deferred
+Keep a list of all renderables per camera depending on their layer
+ - This would be an optimization so I don't need to filter them every frame
+ - I'd need to update this list when renderable is added/removed, when camera is added/removed and when layer is changed (camera's or renderable's)
 
+Before any rendering is done generate separate render queues for all elements
+ - Iterate over all elements valid for the camera and perform frustum culling
+ - Initially this would be different queues for transparent & opaque, but later there might be more types
+ - Store these queues per-camera
+ - Do the same for lights (separate them by type most likely)
 
-Test all APIs with new changes regarding depth buffer creation on windows
-Load up and set up a test-bed with Ribek's scene
-Issue with state caching: State caching doesn't work when deserializing
-Need cone to use when rendering spot light
-Quantize buffer sizes so they're divideable by 8 when requesting them from RenderTexturePool
+Generate different RenderableController for each set of elements
+ - Will likely want to rename current LitTexRenderableController to OpaqueSomething
+ - Each controller would be connected to its own render queue (generated in above step)
+ - Renderable controller should probably be notified when rendering starts/ends so it may bind gbuffer and/or other resoures.
+
+Create a class RenderTargets
+ - ::create(CameraPtr)
+ - ::bind (calls RenderTargetPool::get() and sets the render targets)
+ - ::unbind (calls RenderTargetPool::free)
+ - Holds references to PooledRenderTarget
 
+Store RenderTargets per camera
+ - Only create it if camera is rendering some renderables
+ - If none are rendered clear the reference to free the targets
 
-Create a basic GBuffer - albedo, normal, depth
- - Using HDR formats where needed
- - Will need some kind of a pool that handles multiple viewports (each with its own gbuffer) and viewport resizing
+I sort rendering based on render targets so I don't need to rebind them
+ - I should do something similar with GBuffers
+ - First sort by GBuffers, then sort by output render targets
+ - This means I'll need to find out what kind of gbuffers cameras need before rendering the camera
+   - Move the renderable by layer filtering in renderAll, or do it when renderers are updated (as described above)
+   - Don't actually allocate targets at this point to avoid allocating a lot of memory at once.
 
-Implement deferred rendering (just basic lambert shading for now, only point light)
- - Then convert to tiled rendering (will likely need normal deferred too as a fallback - and to be able to toggle and compare)
+--------------------------- DESIGN ---------------------------
+
+Issue with state caching: State caching doesn't work when deserializing
 
 How will cameras interact with the renderer? The cameras currently available shouldn't have depth buffers
  - Need to modify RenderWindow so it doesn't create depth buffers
@@ -33,75 +56,55 @@ How will cameras interact with the renderer? The cameras currently available sho
    - Print out a warning and ignore it?
    - Or resolve the gbuffer into it? Probably this, as I want to be able to read the depth buffer from script code if needed
      - This still isn't perfect as I'd have duplicate buffers when using non-MSAA buffer that require no resolve
+ - Similar issue when a multisampled buffer is used for the camera
 
-Render:
- - Iterate over all cameras and create their render queues, record whether a camera requires a gbuffer or not
-    - How will "render()" callback signify whether they want a gbuffer or something else? 
-     - Assume they need it? Probably - although it would be nice to be able to customize the render targets
-	   of the render() calls. But I should probably think about that if it ever comes up, and implement it simply for now.
-	 - Potentially restrict cameras to only non-multisampled RGBA8 targets. Then later we can add a special
-	   mechanism for reading the depth buffer from sim thread(as well as reading other gbuffers)
-	    - But I don't think this should be needed (It will probably be enough to signal to the rendering
-		  thread to bind any one of those buffers, as we're only likely to use them from shaders. And shaders
-		  can then even render them out to an outside target if needed.)
-		- ALTHOUGH I do want to be able to set up custom render targets for the camera. So that custom scripts
-		  and shaders can be executed as needed, possibly outputting multiple targets of various formats.
- - Sort cameras based on render targets and priority as we do now, additionally sort by whether they require gbuffer or not
- - Add new class RendererTargets
-   - beginSceneRendering
-   - endSceneRendering
-   - resolve(RenderTarget)
-  - Add new class RenderTargetPool
-   - RTHandle handle = find(format, width, height, depth)
-   - RTHandle keeps a shared ptr so that all cameras that use it can hold (once it runs out the render targets are freed)
-
- - Separate GUI rendering into a separate part to be rendered after gbuffer is resolved?
+Separate GUI rendering into a separate part to be rendered after gbuffer is resolved?
 
 Will likely need an easy way to determine supported feature set (likely just depending on shader model)
 Consider encapsulating shaders together with methods for setting their parameters (and possibly retrieving output)
  - So that external code doesn't need to know about its internal and do less work
-
--------------
-
-Implement gamma correct rendering, HDR, tone mapping
- - Will likely need a simple framework for rendering full-screen effects
-   (e.g. I will need to downsample scene to determine brightness here, but will
-    also need that framework for all post-processing)
-
--------------
+ - This would contain a reference to the shader and its parameters
+ - It would then have a SetParameters method (custom per each shader) which updates its params in a simple manner
+ - (Later) Possibly allow them to return a feature level and/or platform they're to be used on
+ - (Later) It might be important to be easily able to use different versions of the shader (e.g. different defines)
+   - This might require handling compilation on this class, instead on resource load (But then again I could potentially
+     have the shader in an include file and then specific shader files for each define version)
+
+--------------------------- LONG TERM ------------------------
+
+Deferred:
+ - Create a tile deferred renderer
+ - Support for point, directional and spot lights
+ - Basic lambert shading initially
+  - Create brand new default shaders
+ - HDR, tone mapping and gamma correct (toggle-able)
+   - Will likely need a simple framework for rendering full-screen effects
+     (e.g. I will need to downsample scene to determine brightness here, but will
+      also need that framework for all post-processing)
 
 Implement shadows
  - Start with hard shadows
  - Move to PCF soft shadows (see if there's anything better)
  - Then cascaded maps
 
--------------
-
 Later: 
- - Finish up all light types
  - Reflection probes
  - Proper PBR materials with reflection
  - Post-processing system - FXAA, SSAO, Color correction, Depth of field (Bokeh)
  - Forward rendering for transparent objects
- - Need a way to toggle texture filtering mode for all textures (Some kind of an override?)
-
------------------
-
-SECOND STAGE(S)
  - Occlusion
  - GI
  - Volumetric lighting
  - SSR
  - Depth pre-pass - Make sure this can be toggled on and off as needed
  - HDR skybox, skylight stuff
-
------------------
-
-THIRD STAGE(S)
  - Skin & vegetation shaders
  - Tesselation/displacement/parallax
  - Water
  - Fog
  - Motion blur
  - Per object shadows
- - Extend camera with shutter speed (motion blur), aperture size and focal distance (depth of field), exposure (HDR)
+ - Extend camera with shutter speed (motion blur), aperture size and focal distance (depth of field), exposure (HDR)
+--------------------------- TEST -----------------------------
+
+Test all APIs with new changes regarding depth buffer creation on windows