From 1b2530749ea3dc4937cdd7aa37e5a144e6d10183 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sun, 12 Nov 2017 20:14:15 -0800 Subject: Updated to version 2.1 --- .../GhostCubeScene/src/Android/AndroidMain.cpp | 58 ++++++ unityplugin/GhostCubeScene/src/GhostCubeScene.cpp | 215 +++++++++++++++++++++ unityplugin/GhostCubeScene/src/GhostCubeScene.h | 58 ++++++ .../src/GhostCubeSceneResTrsnHelper.cpp | 62 ++++++ .../src/GhostCubeSceneResTrsnHelper.h | 38 ++++ 5 files changed, 431 insertions(+) create mode 100644 unityplugin/GhostCubeScene/src/Android/AndroidMain.cpp create mode 100644 unityplugin/GhostCubeScene/src/GhostCubeScene.cpp create mode 100644 unityplugin/GhostCubeScene/src/GhostCubeScene.h create mode 100644 unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.cpp create mode 100644 unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.h (limited to 'unityplugin/GhostCubeScene/src') diff --git a/unityplugin/GhostCubeScene/src/Android/AndroidMain.cpp b/unityplugin/GhostCubeScene/src/Android/AndroidMain.cpp new file mode 100644 index 0000000..e2e659c --- /dev/null +++ b/unityplugin/GhostCubeScene/src/Android/AndroidMain.cpp @@ -0,0 +1,58 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +// This header must be included, otherwise the linker will somehow fail to find android_main() +#include +#include +#include "IUnityInterface.h" + +extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetMatrixFromUnity + (float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); + +extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTexturesFromUnity(void* renderTargetHandle, void *depthBufferHandle); + +// Actual implementation of the android_main() +void android_main_impl( struct android_app* state ); + + +void *LoadPluginFunction(const char *name) +{ + static std::unordered_map functions_map = + { + {"SetMatrixFromUnity", reinterpret_cast(SetMatrixFromUnity) }, + {"SetTexturesFromUnity", reinterpret_cast(SetTexturesFromUnity) } + }; + auto it = functions_map.find(name); + return it != functions_map.end() ? it->second : nullptr; +} + +// When a native library is being loaded, JNI loader looks for the android_main function. +// If the entry does not export that function, it will fail to load. So we have to define +// android_main() in every android native application +void android_main( android_app* state ) +{ + android_main_impl(state); +} diff --git a/unityplugin/GhostCubeScene/src/GhostCubeScene.cpp b/unityplugin/GhostCubeScene/src/GhostCubeScene.cpp new file mode 100644 index 0000000..2fb3a97 --- /dev/null +++ b/unityplugin/GhostCubeScene/src/GhostCubeScene.cpp @@ -0,0 +1,215 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "GhostCubeScene.h" +#include "BasicMath.h" +#include +#include "BasicShaderSourceStreamFactory.h" +#include "GraphicsUtilities.h" +#include "MapHelper.h" +#include "CommonlyUsedStates.h" + +#if defined(PLATFORM_WIN32) || defined(PLATFORM_UNIVERSAL_WINDOWS) +# define D3D12_SUPPORTED 1 +#else +# define D3D12_SUPPORTED 0 +#endif + +#if D3D12_SUPPORTED +# include "GhostCubeSceneResTrsnHelper.h" +#endif + +using namespace Diligent; + +UnitySceneBase* CreateScene() +{ + return new GhostCubeScene; +} + + +void GhostCubeScene::OnPluginLoad(TLoadPluginFunction LoadPluginFunctionCallback) +{ + SetMatrixFromUnity = reinterpret_cast( LoadPluginFunctionCallback("SetMatrixFromUnity") ); + VERIFY_EXPR(SetMatrixFromUnity != nullptr); + + SetTexturesFromUnity = reinterpret_cast( LoadPluginFunctionCallback("SetTexturesFromUnity") ); + VERIFY_EXPR(SetTexturesFromUnity != nullptr); +} + +void GhostCubeScene::OnPluginUnload() +{ +} + +void GhostCubeScene::OnGraphicsInitialized() +{ + auto pDevice = m_DiligentGraphics->GetDevice(); + TextureDesc TexDesc; + TexDesc.Name = "Mirror render target"; + TexDesc.Type = RESOURCE_DIM_TEX_2D; + TexDesc.Width = 1024; + TexDesc.Height = 1024; + TexDesc.Format = TEX_FORMAT_RGBA8_UNORM_SRGB; + TexDesc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE; + TexDesc.ClearValue.Color[0] = 0.f; + TexDesc.ClearValue.Color[1] = 0.2f; + TexDesc.ClearValue.Color[2] = 0.5f; + TexDesc.ClearValue.Color[3] = 1.0f; + pDevice->CreateTexture(TexDesc, TextureData(), &m_pRenderTarget); + + TexDesc.Name = "Mirror depth buffer"; + TexDesc.Format = TEX_FORMAT_D32_FLOAT; + TexDesc.BindFlags = BIND_DEPTH_STENCIL | BIND_SHADER_RESOURCE; + TexDesc.ClearValue.DepthStencil.Depth = 0.f; + pDevice->CreateTexture(TexDesc, TextureData(), &m_pDepthBuffer); + + auto deviceType = pDevice->GetDeviceCaps().DevType; + { + const auto &SCDesc = m_DiligentGraphics->GetSwapChain()->GetDesc(); + auto UseReverseZ = m_DiligentGraphics->UsesReverseZ(); + + PipelineStateDesc PSODesc; + PSODesc.IsComputePipeline = false; + PSODesc.Name = "Render sample cube PSO"; + PSODesc.GraphicsPipeline.NumRenderTargets = 1; + + PSODesc.GraphicsPipeline.RTVFormats[0] = SCDesc.ColorBufferFormat == TEX_FORMAT_RGBA8_UNORM ? TEX_FORMAT_RGBA8_UNORM_SRGB : SCDesc.ColorBufferFormat; + PSODesc.GraphicsPipeline.DSVFormat = SCDesc.DepthBufferFormat; + PSODesc.GraphicsPipeline.PrimitiveTopologyType = PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + PSODesc.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_BACK; + PSODesc.GraphicsPipeline.DepthStencilDesc.DepthFunc = UseReverseZ ? COMPARISON_FUNC_GREATER_EQUAL : COMPARISON_FUNC_LESS_EQUAL; + + ShaderCreationAttribs CreationAttribs; + BasicShaderSourceStreamFactory BasicSSSFactory("shaders"); + CreationAttribs.pShaderSourceStreamFactory = &BasicSSSFactory; + CreationAttribs.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; + CreationAttribs.Desc.DefaultVariableType = SHADER_VARIABLE_TYPE_STATIC; + + CreateUniformBuffer(pDevice, sizeof(float4x4), "Mirror VS constants CB", &m_pMirrorVSConstants); + + RefCntAutoPtr pVS; + { + CreationAttribs.Desc.ShaderType = SHADER_TYPE_VERTEX; + CreationAttribs.EntryPoint = "main"; + CreationAttribs.Desc.Name = "Mirror VS"; + CreationAttribs.FilePath = "Mirror.vsh"; + pDevice->CreateShader(CreationAttribs, &pVS); + pVS->GetShaderVariable("Constants")->Set(m_pMirrorVSConstants); + } + + + RefCntAutoPtr pPS; + { + CreationAttribs.Desc.ShaderType = SHADER_TYPE_PIXEL; + CreationAttribs.EntryPoint = "main"; + CreationAttribs.Desc.Name = "Mirror PS"; + CreationAttribs.FilePath = "Mirror.psh"; + StaticSamplerDesc StaticSamplers[] = + { + {"g_tex2Reflection", Sam_Aniso4xClamp} + }; + CreationAttribs.Desc.StaticSamplers = StaticSamplers; + CreationAttribs.Desc.NumStaticSamplers = _countof(StaticSamplers); + pDevice->CreateShader(CreationAttribs, &pPS); + pPS->GetShaderVariable("g_tex2Reflection")->Set(m_pRenderTarget->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)); + } + + PSODesc.GraphicsPipeline.pVS = pVS; + PSODesc.GraphicsPipeline.pPS = pPS; + pDevice->CreatePipelineState(PSODesc, &m_pMirrorPSO); + } +#if D3D12_SUPPORTED + m_pStateTransitionHandler.reset(new GhostCubeSceneResTrsnHelper(*this)); +#endif +} + +void GhostCubeScene::Render(UnityRenderingEvent RenderEventFunc, double CurrTime, double ElapsedTime) +{ + auto pDevice = m_DiligentGraphics->GetDevice(); + auto pCtx = m_DiligentGraphics->GetContext(); + auto DevType = pDevice->GetDeviceCaps().DevType; + bool IsDX = DevType == DeviceType::D3D11 || DevType == DeviceType::D3D12; + auto ReverseZ = m_DiligentGraphics->UsesReverseZ(); + + // In OpenGL, render targets must be bound to the pipeline to be cleared + ITextureView *pRTVs[] = { m_pRenderTarget->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET) }; + ITextureView *pDSV = m_pDepthBuffer->GetDefaultView(TEXTURE_VIEW_DEPTH_STENCIL); + pCtx->SetRenderTargets(1, pRTVs, pDSV); + const float ClearColor[] = { 0.f, 0.2f, 0.5f, 1.0f }; + pCtx->ClearRenderTarget(pRTVs[0], ClearColor); + pCtx->ClearDepthStencil(pDSV, CLEAR_DEPTH_FLAG, ReverseZ ? 0.f : 1.f, 0); + + if (DevType == DeviceType::D3D12) + { + // D3D12 context must be flushed so that the commands are submitted before the + // commands issued by the plugin + pCtx->Flush(); + } + + + // Render ghost cube into the mirror texture + { + // Create fake reflection matrix + float4x4 CubeWorldView = scaleMatrix(1,2,1) * rotationY( -static_cast(CurrTime) * 2.0f) * rotationX(-PI_F*0.3f) * translationMatrix(0.f, 0.0f, 10.0f); + float NearPlane = 0.3f; + float FarPlane = 1000.f; + if (ReverseZ) + std::swap(NearPlane, FarPlane); + float aspectRatio = 1.0f; + float4x4 ReflectionCameraProj = Projection(PI_F / 4.f, aspectRatio, NearPlane, FarPlane, IsDX); + auto wvp = CubeWorldView * ReflectionCameraProj; + float ReverseZ = IsDX ? -1.f : +1.f; + SetMatrixFromUnity(wvp._m00, ReverseZ * wvp._m01, wvp._m02, wvp._m03, + wvp._m10, ReverseZ * wvp._m11, wvp._m12, wvp._m13, + wvp._m20, ReverseZ * wvp._m21, wvp._m22, wvp._m23, + wvp._m30, ReverseZ * wvp._m31, wvp._m32, wvp._m33); + + SetTexturesFromUnity(m_pRenderTarget->GetNativeHandle(), m_pDepthBuffer->GetNativeHandle()); + + // Call the plugin + RenderEventFunc(0); + } + + // We need to invalidate the context state since the plugin has used d3d11 context + pCtx->InvalidateState(); + pCtx->SetRenderTargets(0, nullptr, nullptr); + pCtx->SetPipelineState(m_pMirrorPSO); + pCtx->CommitShaderResources(nullptr, COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES); + + { + float4x4 MirrorWorldView = scaleMatrix(5,5,5) * rotationX(PI_F*0.6f) * translationMatrix(0.f, -3.0f, 10.0f); + float NearPlane = 0.3f; + float FarPlane = 1000.f; + if (ReverseZ) + std::swap(NearPlane, FarPlane); + float AspectRatio = static_cast(m_WindowWidth) / static_cast(std::max(m_WindowHeight, 1)); + float4x4 MainCameraProj = Projection(PI_F / 3.f, AspectRatio, NearPlane, FarPlane, IsDX); + auto wvp = MirrorWorldView * MainCameraProj; + MapHelper CBConstants(pCtx, m_pMirrorVSConstants, MAP_WRITE, MAP_FLAG_DISCARD); + *CBConstants = transposeMatrix(wvp); + } + + DrawAttribs DrawAttrs; + DrawAttrs.NumVertices = 4; + DrawAttrs.Topology = PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + pCtx->Draw(DrawAttrs); +} diff --git a/unityplugin/GhostCubeScene/src/GhostCubeScene.h b/unityplugin/GhostCubeScene/src/GhostCubeScene.h new file mode 100644 index 0000000..546acaf --- /dev/null +++ b/unityplugin/GhostCubeScene/src/GhostCubeScene.h @@ -0,0 +1,58 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "UnitySceneBase.h" +#include "IUnityInterface.h" + +using TSetMatrixFromUnity = void (UNITY_INTERFACE_API *) (float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); +using TSetTexturesFromUnity = void (UNITY_INTERFACE_API *)(void* renderTargetHandle, void *depthBufferHandle); + +class GhostCubeScene : public UnitySceneBase +{ +public: + virtual void OnPluginLoad(TLoadPluginFunction LoadPluginFunctionCallback)override final; + + virtual void OnPluginUnload()override final; + + virtual void OnGraphicsInitialized()override final; + + virtual void Render(UnityRenderingEvent RenderEventFunc, double CurrTime, double ElapsedTime)override final; + + virtual const char* GetSceneName()override final { return "Ghost Cube Scene"; } + + virtual const char* GetPluginName()override final { return "GhostCubePlugin"; } + +private: + friend class GhostCubeSceneResTrsnHelper; + + TSetMatrixFromUnity SetMatrixFromUnity; + TSetTexturesFromUnity SetTexturesFromUnity; + + Diligent::RefCntAutoPtr m_pRenderTarget; + Diligent::RefCntAutoPtr m_pDepthBuffer; + Diligent::RefCntAutoPtr m_pMirrorVSConstants; + Diligent::RefCntAutoPtr m_pMirrorPSO; +}; \ No newline at end of file diff --git a/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.cpp b/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.cpp new file mode 100644 index 0000000..504a633 --- /dev/null +++ b/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.cpp @@ -0,0 +1,62 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ +#include + +#include "GhostCubeSceneResTrsnHelper.h" +#include "GhostCubeScene.h" +#include "IUnityGraphicsD3D12.h" +#include "TextureD3D12.h" +#include "DeviceContextD3D12.h" +#include "ValidatedCast.h" + + +using namespace Diligent; + +void GhostCubeSceneResTrsnHelper::TransitionResources(int stateCount, UnityGraphicsD3D12ResourceState* states) +{ + if (stateCount == 0) + return; + + auto *pCtx = ValidatedCast(m_TheScene.m_DiligentGraphics->GetContext()); + for (int i = 0; i < stateCount; ++i) + { + auto &ResState = states[i]; + ITextureD3D12 *pMirrorRT = ValidatedCast(m_TheScene.m_pRenderTarget.RawPtr()); + ITextureD3D12 *pMirrorDepth = ValidatedCast(m_TheScene.m_pDepthBuffer.RawPtr()); + ITextureD3D12 *pResToTransition = nullptr; + if (ResState.resource == pMirrorRT->GetD3D12Texture()) + pResToTransition = pMirrorRT; + else if(ResState.resource == pMirrorDepth->GetD3D12Texture()) + pResToTransition = pMirrorDepth; + else + { + UNEXPECTED("Unexpected resource to transition") + } + if (pResToTransition) + { + pCtx->TransitionTextureState(pResToTransition, ResState.expected); + pResToTransition->SetD3D12ResourceState(ResState.current); + } + } + pCtx->Flush(); +} diff --git a/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.h b/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.h new file mode 100644 index 0000000..794c2de --- /dev/null +++ b/unityplugin/GhostCubeScene/src/GhostCubeSceneResTrsnHelper.h @@ -0,0 +1,38 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "ResourceStateTransitionHandler.h" + +class GhostCubeScene; +class GhostCubeSceneResTrsnHelper : public IResourceStateTransitionHandler +{ +public: + GhostCubeSceneResTrsnHelper(GhostCubeScene& TheScene) : + m_TheScene(TheScene) + {} + virtual ~GhostCubeSceneResTrsnHelper()override {} + virtual void TransitionResources(int stateCount, UnityGraphicsD3D12ResourceState* states)override final; + +private: + GhostCubeScene& m_TheScene; +}; -- cgit v1.2.3