New skyboxrenderer + moved meshrenderer inside engine and out from main to clean that up
This commit is contained in:
@@ -231,3 +231,62 @@ graph LR
|
||||
1. **Cubemap source** — **Procedural gradient skybox** chosen because asset loading infrastructure is not yet established.
|
||||
2. **Sampler heap** — Evaluate what exists. However, with a procedural skybox, we won't need a sampler for Phase 3! (The sky color can be procedurally generated from the reconstructed view direction).
|
||||
3. **Specular** — **Blinn-Phong** specular, structured in an agnostic way so PBR (physically based rendering) parameters can be plugged in later.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Forward Rendered Entity Lights
|
||||
|
||||
A simple, fast forward renderer using a Global Structured Buffer for entity-based point lights.
|
||||
|
||||
### Approach: Bindless Global Lights Buffer
|
||||
|
||||
Instead of passing each light via PushConstants, we pass a `StructuredBuffer<PointLight>` index and iterate over the active lights in the fragment shader.
|
||||
|
||||
### New C++ Components
|
||||
|
||||
```cpp
|
||||
struct PointLight
|
||||
{
|
||||
Vector3 Position;
|
||||
float Radius;
|
||||
Vector3 Color;
|
||||
float Intensity;
|
||||
};
|
||||
```
|
||||
|
||||
1. **Lights Buffer Allocation**: Allocate a `StructuredBuffer` large enough for all potential lights (e.g., max 1024).
|
||||
2. **Buffer Upload**: Loop through the active game entity lights every frame and upload them using the TransferBuffer system.
|
||||
3. **PushData Update**:
|
||||
- `uint32 LightsBufferIndex`
|
||||
- `uint32 ActiveLightCount`
|
||||
|
||||
### Shader Design
|
||||
|
||||
**Fragment Shader Expansion** loop over all `ActiveLightCount` to compute the attenuation and diffuse, then accumulate.
|
||||
|
||||
```hlsl
|
||||
StructuredBuffer<PointLight> lights = ResourceDescriptorHeap[LightsBufferIndex];
|
||||
|
||||
float3 totalDiffuse = Color.rgb * LightColor * NdotL; // Include Directional Sun
|
||||
|
||||
for (uint i = 0; i < ActiveLightCount; ++i)
|
||||
{
|
||||
PointLight light = lights[i];
|
||||
|
||||
float3 lightVector = light.Position - WorldPosition;
|
||||
float distance = length(lightVector);
|
||||
|
||||
if (distance > light.Radius) continue;
|
||||
|
||||
float3 L = lightVector / distance;
|
||||
float NdotL = saturate(dot(N, L));
|
||||
|
||||
float attenuation = 1.0 - saturate(distance / light.Radius);
|
||||
attenuation *= attenuation; // inverse square-ish
|
||||
|
||||
totalDiffuse += Color.rgb * light.Color * light.Intensity * NdotL * attenuation;
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Passing `WorldPosition` to the Fragment shader from the Vertex shader is required for positional lighting.
|
||||
|
||||
Binary file not shown.
BIN
Assets/compiled/Skybox.frag.dxil
Normal file
BIN
Assets/compiled/Skybox.frag.dxil
Normal file
Binary file not shown.
BIN
Assets/compiled/Skybox.vert.dxil
Normal file
BIN
Assets/compiled/Skybox.vert.dxil
Normal file
Binary file not shown.
@@ -13,8 +13,8 @@ Output main(uint vertexIndex : SV_VertexID)
|
||||
// Retrieve the vertex buffer using SM6.6 bindless syntax
|
||||
ByteAddressBuffer buffer = ResourceDescriptorHeap[BufferIndex];
|
||||
|
||||
// TextureIndex is used as vertex offset for consolidated buffer (depth-tested at 0, overlay at halfMax)
|
||||
uint actualVertexIndex = vertexIndex + TextureIndex;
|
||||
// VertexOffset is used as vertex offset for consolidated buffer (depth-tested at 0, overlay at halfMax)
|
||||
uint actualVertexIndex = vertexIndex + VertexOffset;
|
||||
|
||||
// Vertex layout: float3 Position (12 bytes) + float4 Color (16 bytes) = 28 bytes stride
|
||||
uint stride = 28;
|
||||
|
||||
26
Assets/source/Skybox.frag.hlsl
Normal file
26
Assets/source/Skybox.frag.hlsl
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "RootConstants.hlsl"
|
||||
|
||||
float4 main(float3 ViewDir : TEXCOORD0) : SV_Target0
|
||||
{
|
||||
float3 dir = normalize(ViewDir);
|
||||
|
||||
// Simple Procedural Gradient Skybox Colors
|
||||
float3 skyZenithColor = float3(0.05f, 0.15f, 0.45f); // Deep blue top
|
||||
float3 skyHorizonColor = float3(0.4f, 0.6f, 0.9f); // Light blue horizon
|
||||
float3 groundColor = float3(0.1f, 0.1f, 0.15f); // Dark ground
|
||||
|
||||
float t = dir.z; // -1 to 1 based on vertical alignment
|
||||
|
||||
float3 finalColor = groundColor;
|
||||
|
||||
if (t > 0.0f) {
|
||||
// Blend from horizon to zenith
|
||||
finalColor = lerp(skyHorizonColor, skyZenithColor, t);
|
||||
} else {
|
||||
// Ground - quick blend from horizon to ground
|
||||
finalColor = lerp(skyHorizonColor, groundColor, saturate(-t * 2.0f));
|
||||
}
|
||||
|
||||
// Combine with overall ambient lighting scale
|
||||
return float4(finalColor, 1.0f);
|
||||
}
|
||||
74
Assets/source/Skybox.vert.hlsl
Normal file
74
Assets/source/Skybox.vert.hlsl
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "RootConstants.hlsl"
|
||||
|
||||
struct Output
|
||||
{
|
||||
float3 ViewDir : TEXCOORD0;
|
||||
float4 Position : SV_Position;
|
||||
};
|
||||
|
||||
float4x4 Inverse(float4x4 m)
|
||||
{
|
||||
float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0];
|
||||
float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1];
|
||||
float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2];
|
||||
float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3];
|
||||
|
||||
float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
|
||||
float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
|
||||
float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
|
||||
float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
|
||||
|
||||
float det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
|
||||
float idet = 1.0f / det;
|
||||
|
||||
float4x4 ret;
|
||||
ret[0][0] = t11 * idet;
|
||||
ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet;
|
||||
ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet;
|
||||
ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet;
|
||||
|
||||
ret[1][0] = t12 * idet;
|
||||
ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet;
|
||||
ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet;
|
||||
ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet;
|
||||
|
||||
ret[2][0] = t13 * idet;
|
||||
ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet;
|
||||
ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet;
|
||||
ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet;
|
||||
|
||||
ret[3][0] = t14 * idet;
|
||||
ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet;
|
||||
ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet;
|
||||
ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Output main(uint vertexID : SV_VertexID)
|
||||
{
|
||||
Output output;
|
||||
|
||||
// Fullscreen triangle properties
|
||||
// vertexID 0 -> uv(0,0) -> pos(-1, 1)
|
||||
// vertexID 1 -> uv(2,0) -> pos( 3, 1)
|
||||
// vertexID 2 -> uv(0,2) -> pos(-1, -3)
|
||||
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
|
||||
|
||||
// Map uv to clip space position.
|
||||
// Z is set to 1.0 (far plane in reverse-Z or standard depth)
|
||||
// Assuming standard Z projection ranges from 0 to 1, we use 1.0 for the far plane.
|
||||
// Depending on reverse-z, this might need to be 0.0, but let's stick to standard 1.0
|
||||
// depth for skyboxes.
|
||||
float4 clipPos = float4(uv * 2.0 - 1.0, 1.0, 1.0);
|
||||
clipPos.y = -clipPos.y; // Flip Y for D3D
|
||||
|
||||
output.Position = clipPos;
|
||||
|
||||
// Reconstruct view direction from clip space
|
||||
float4x4 inverseVP = Inverse(ViewProjection);
|
||||
float4 worldPos = mul(inverseVP, clipPos);
|
||||
output.ViewDir = worldPos.xyz / worldPos.w;
|
||||
|
||||
return output;
|
||||
}
|
||||
@@ -133,4 +133,46 @@ namespace Juliet
|
||||
result.m[3][3] = 0.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline Matrix MatrixInverse(const Matrix& m)
|
||||
{
|
||||
Matrix out = {};
|
||||
|
||||
float m00 = m.m[0][0], m01 = m.m[0][1], m02 = m.m[0][2], m03 = m.m[0][3];
|
||||
float m10 = m.m[1][0], m11 = m.m[1][1], m12 = m.m[1][2], m13 = m.m[1][3];
|
||||
float m20 = m.m[2][0], m21 = m.m[2][1], m22 = m.m[2][2], m23 = m.m[2][3];
|
||||
float m30 = m.m[3][0], m31 = m.m[3][1], m32 = m.m[3][2], m33 = m.m[3][3];
|
||||
|
||||
out.m[0][0] = m11 * m22 * m33 - m11 * m23 * m32 - m21 * m12 * m33 + m21 * m13 * m32 + m31 * m12 * m23 - m31 * m13 * m22;
|
||||
out.m[1][0] = -m10 * m22 * m33 + m10 * m23 * m32 + m20 * m12 * m33 - m20 * m13 * m32 - m30 * m12 * m23 + m30 * m13 * m22;
|
||||
out.m[2][0] = m10 * m21 * m33 - m10 * m23 * m31 - m20 * m11 * m33 + m20 * m13 * m31 + m30 * m11 * m23 - m30 * m13 * m21;
|
||||
out.m[3][0] = -m10 * m21 * m32 + m10 * m22 * m31 + m20 * m11 * m32 - m20 * m12 * m31 - m30 * m11 * m22 + m30 * m12 * m21;
|
||||
|
||||
out.m[0][1] = -m01 * m22 * m33 + m01 * m23 * m32 + m21 * m02 * m33 - m21 * m03 * m32 - m31 * m02 * m23 + m31 * m03 * m22;
|
||||
out.m[1][1] = m00 * m22 * m33 - m00 * m23 * m32 - m20 * m02 * m33 + m20 * m03 * m32 + m30 * m02 * m23 - m30 * m03 * m22;
|
||||
out.m[2][1] = -m00 * m21 * m33 + m00 * m23 * m31 + m20 * m01 * m33 - m20 * m03 * m31 - m30 * m01 * m23 + m30 * m03 * m21;
|
||||
out.m[3][1] = m00 * m21 * m32 - m00 * m22 * m31 - m20 * m01 * m32 + m20 * m02 * m31 + m30 * m01 * m22 - m30 * m02 * m21;
|
||||
|
||||
out.m[0][2] = m01 * m12 * m33 - m01 * m13 * m32 - m11 * m02 * m33 + m11 * m03 * m32 + m31 * m02 * m13 - m31 * m03 * m12;
|
||||
out.m[1][2] = -m00 * m12 * m33 + m00 * m13 * m32 + m10 * m02 * m33 - m10 * m03 * m32 - m30 * m02 * m13 + m30 * m03 * m12;
|
||||
out.m[2][2] = m00 * m11 * m33 - m00 * m13 * m31 - m10 * m01 * m33 + m10 * m03 * m31 + m30 * m01 * m13 - m30 * m03 * m11;
|
||||
out.m[3][2] = -m00 * m11 * m32 + m00 * m12 * m31 + m10 * m01 * m32 - m10 * m02 * m31 - m30 * m01 * m12 + m30 * m02 * m11;
|
||||
|
||||
out.m[0][3] = -m01 * m12 * m23 + m01 * m13 * m22 + m11 * m02 * m23 - m11 * m03 * m22 - m21 * m02 * m13 + m21 * m03 * m12;
|
||||
out.m[1][3] = m00 * m12 * m23 - m00 * m13 * m22 - m10 * m02 * m23 + m10 * m03 * m22 + m20 * m02 * m13 - m20 * m03 * m12;
|
||||
out.m[2][3] = -m00 * m11 * m23 + m00 * m13 * m21 + m10 * m01 * m23 - m10 * m03 * m21 - m20 * m01 * m13 + m20 * m03 * m11;
|
||||
out.m[3][3] = m00 * m11 * m22 - m00 * m12 * m21 - m10 * m01 * m22 + m10 * m02 * m21 + m20 * m01 * m12 - m20 * m02 * m11;
|
||||
|
||||
float det = m00 * out.m[0][0] + m01 * out.m[1][0] + m02 * out.m[2][0] + m03 * out.m[3][0];
|
||||
|
||||
if (det != 0.0f)
|
||||
{
|
||||
float invDet = 1.0f / det;
|
||||
for (int r = 0; r < 4; ++r)
|
||||
for (int c = 0; c < 4; ++c)
|
||||
out.m[r][c] *= invDet;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -8,13 +8,14 @@ namespace Juliet
|
||||
|
||||
struct Engine
|
||||
{
|
||||
IApplication* Application = nullptr;
|
||||
IApplication* Application = nullptr;
|
||||
Arena* PlatformArena = nullptr;
|
||||
};
|
||||
|
||||
void InitializeEngine(JulietInit_Flags flags);
|
||||
void ShutdownEngine();
|
||||
|
||||
void LoadApplication(IApplication& app);
|
||||
void LoadApplication(IApplication& app, Arena* arena);
|
||||
void UnloadApplication();
|
||||
|
||||
void RunEngine();
|
||||
|
||||
29
Juliet/include/Graphics/SkyboxRenderer.h
Normal file
29
Juliet/include/Graphics/SkyboxRenderer.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Math/Matrix.h>
|
||||
#include <Juliet.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
struct RenderPass;
|
||||
struct CommandList;
|
||||
struct Window;
|
||||
struct GraphicsPipeline;
|
||||
struct GraphicsDevice;
|
||||
|
||||
struct SkyboxRenderer
|
||||
{
|
||||
GraphicsDevice* Device;
|
||||
GraphicsPipeline* Pipeline;
|
||||
};
|
||||
|
||||
[[nodiscard]] JULIET_API bool InitializeSkyboxRenderer(NonNullPtr<GraphicsDevice> device,
|
||||
NonNullPtr<Window> window);
|
||||
JULIET_API void ShutdownSkyboxRenderer();
|
||||
JULIET_API void RenderSkybox(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection);
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
JULIET_API void ReloadSkyboxShaders();
|
||||
#endif
|
||||
|
||||
} // namespace Juliet
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <Graphics/DebugDisplay.h>
|
||||
#include <Graphics/Graphics.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Graphics/MeshRenderer.h>
|
||||
#include <Graphics/SkyboxRenderer.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
@@ -37,6 +39,11 @@ namespace Juliet
|
||||
if (device)
|
||||
{
|
||||
DebugDisplay_Initialize(device);
|
||||
if (Window* window = EngineInstance.Application->GetPlatformWindow())
|
||||
{
|
||||
InitializeMeshRenderer(EngineInstance.PlatformArena, device, window);
|
||||
InitializeSkyboxRenderer(device, window);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
@@ -73,6 +80,8 @@ namespace Juliet
|
||||
if (device)
|
||||
{
|
||||
DebugDisplay_Shutdown(device);
|
||||
ShutdownSkyboxRenderer();
|
||||
ShutdownMeshRenderer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +130,9 @@ namespace Juliet
|
||||
// Debug display flush (inside render pass)
|
||||
Camera debugCamera = EngineInstance.Application->GetDebugCamera();
|
||||
DebugDisplay_Flush(cmdList, pass, debugCamera);
|
||||
|
||||
// Note: The MeshRenderer and SkyboxRenderer draw calls are still inside Application->OnRender
|
||||
// They shouldn't be moved here directly without an interface since they require PushData.
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
// ImGui rendering (always last before EndRenderPass)
|
||||
@@ -155,9 +167,10 @@ namespace Juliet
|
||||
ShutdownLogManager();
|
||||
}
|
||||
|
||||
void LoadApplication(IApplication& app)
|
||||
void LoadApplication(IApplication& app, Arena* platformArena)
|
||||
{
|
||||
EngineInstance.Application = &app;
|
||||
EngineInstance.Application = &app;
|
||||
EngineInstance.PlatformArena = platformArena;
|
||||
EngineInstance.Application->Init();
|
||||
|
||||
// Systems depending on Window/GraphicsDevice
|
||||
|
||||
102
Juliet/src/Graphics/SkyboxRenderer.cpp
Normal file
102
Juliet/src/Graphics/SkyboxRenderer.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <Graphics/SkyboxRenderer.h>
|
||||
|
||||
#include <Core/HAL/Filesystem/Filesystem.h>
|
||||
#include <Core/Logging/LogManager.h>
|
||||
#include <Core/Logging/LogTypes.h>
|
||||
#include <Graphics/GraphicsDevice.h>
|
||||
#include <Graphics/PushConstants.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
namespace
|
||||
{
|
||||
SkyboxRenderer g_SkyboxRenderer;
|
||||
} // namespace
|
||||
|
||||
bool InitializeSkyboxRenderer(NonNullPtr<GraphicsDevice> device, NonNullPtr<Window> window)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
GraphicsDevice* graphicsDevice = g_SkyboxRenderer.Device = device.Get();
|
||||
|
||||
String skyboxVSEntry = WrapString("main");
|
||||
ShaderCreateInfo skyboxVSCI = {};
|
||||
skyboxVSCI.EntryPoint = skyboxVSEntry;
|
||||
skyboxVSCI.Stage = ShaderStage::Vertex;
|
||||
String vsPath = GetAssetPath(WrapString("Skybox.vert.dxil"));
|
||||
Shader* skyboxVS = CreateShader(graphicsDevice, vsPath, skyboxVSCI);
|
||||
|
||||
String skyboxFSEntry = WrapString("main");
|
||||
ShaderCreateInfo skyboxFSCI = {};
|
||||
skyboxFSCI.EntryPoint = skyboxFSEntry;
|
||||
skyboxFSCI.Stage = ShaderStage::Fragment;
|
||||
String fsPath = GetAssetPath(WrapString("Skybox.frag.dxil"));
|
||||
Shader* skyboxFS = CreateShader(graphicsDevice, fsPath, skyboxFSCI);
|
||||
|
||||
ColorTargetDescription colorTargetDesc = {};
|
||||
colorTargetDesc.Format = GetSwapChainTextureFormat(graphicsDevice, window);
|
||||
|
||||
GraphicsPipelineCreateInfo skyboxPipelineCI = {};
|
||||
skyboxPipelineCI.VertexShader = skyboxVS;
|
||||
skyboxPipelineCI.FragmentShader = skyboxFS;
|
||||
skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList;
|
||||
skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc;
|
||||
skyboxPipelineCI.TargetInfo.NumColorTargets = 1;
|
||||
skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT;
|
||||
skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true;
|
||||
skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid;
|
||||
skyboxPipelineCI.RasterizerState.CullMode = CullMode::None;
|
||||
skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
|
||||
skyboxPipelineCI.DepthStencilState.EnableDepthTest = true;
|
||||
skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false;
|
||||
skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual;
|
||||
|
||||
g_SkyboxRenderer.Pipeline = CreateGraphicsPipeline(graphicsDevice, skyboxPipelineCI);
|
||||
if (g_SkyboxRenderer.Pipeline == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Failed to create skybox pipeline!");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (skyboxVS) DestroyShader(graphicsDevice, skyboxVS);
|
||||
if (skyboxFS) DestroyShader(graphicsDevice, skyboxFS);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShutdownSkyboxRenderer()
|
||||
{
|
||||
if (g_SkyboxRenderer.Pipeline)
|
||||
{
|
||||
DestroyGraphicsPipeline(g_SkyboxRenderer.Device, g_SkyboxRenderer.Pipeline);
|
||||
g_SkyboxRenderer.Pipeline = nullptr;
|
||||
}
|
||||
|
||||
g_SkyboxRenderer = {};
|
||||
}
|
||||
|
||||
void RenderSkybox(NonNullPtr<RenderPass> pass, NonNullPtr<CommandList> cmdList, const Matrix& viewProjection)
|
||||
{
|
||||
if (!g_SkyboxRenderer.Pipeline)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PushData pushData = {};
|
||||
pushData.ViewProjection = viewProjection;
|
||||
pushData.Model = MatrixIdentity();
|
||||
|
||||
BindGraphicsPipeline(pass, g_SkyboxRenderer.Pipeline);
|
||||
SetPushConstants(cmdList, ShaderStage::Vertex, 0, sizeof(pushData) / 4, &pushData);
|
||||
SetPushConstants(cmdList, ShaderStage::Fragment, 0, sizeof(pushData) / 4, &pushData);
|
||||
DrawPrimitives(pass, 3, 1, 0, 0);
|
||||
}
|
||||
|
||||
#if ALLOW_SHADER_HOT_RELOAD
|
||||
void ReloadSkyboxShaders()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Juliet
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <Graphics/MeshRenderer.h>
|
||||
#include <Graphics/RenderPass.h>
|
||||
#include <Graphics/VertexData.h>
|
||||
#include <Juliet.h>
|
||||
#include <Graphics/SkyboxRenderer.h>
|
||||
|
||||
#ifdef JULIET_ENABLE_IMGUI
|
||||
#include <imgui.h>
|
||||
@@ -135,6 +135,50 @@ void JulietApplication::Init()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create Skybox Pipeline
|
||||
String skyboxVSEntry = WrapString("main");
|
||||
ShaderCreateInfo skyboxVSCI = {};
|
||||
skyboxVSCI.EntryPoint = skyboxVSEntry;
|
||||
skyboxVSCI.Stage = ShaderStage::Vertex;
|
||||
String vsPath = GetAssetPath(WrapString("Skybox.vert.dxil"));
|
||||
Shader* skyboxVS = CreateShader(GraphicsDevice, vsPath, skyboxVSCI);
|
||||
|
||||
String skyboxFSEntry = WrapString("main");
|
||||
ShaderCreateInfo skyboxFSCI = {};
|
||||
skyboxFSCI.EntryPoint = skyboxFSEntry;
|
||||
skyboxFSCI.Stage = ShaderStage::Fragment;
|
||||
String fsPath = GetAssetPath(WrapString("Skybox.frag.dxil"));
|
||||
Shader* skyboxFS = CreateShader(GraphicsDevice, fsPath, skyboxFSCI);
|
||||
|
||||
ColorTargetDescription colorTargetDesc = {};
|
||||
colorTargetDesc.Format = GetSwapChainTextureFormat(GraphicsDevice, MainWindow);
|
||||
|
||||
GraphicsPipelineCreateInfo skyboxPipelineCI = {};
|
||||
skyboxPipelineCI.VertexShader = skyboxVS;
|
||||
skyboxPipelineCI.FragmentShader = skyboxFS;
|
||||
skyboxPipelineCI.PrimitiveType = PrimitiveType::TriangleList;
|
||||
skyboxPipelineCI.TargetInfo.ColorTargetDescriptions = &colorTargetDesc;
|
||||
skyboxPipelineCI.TargetInfo.NumColorTargets = 1;
|
||||
skyboxPipelineCI.TargetInfo.DepthStencilFormat = TextureFormat::D32_FLOAT;
|
||||
skyboxPipelineCI.TargetInfo.HasDepthStencilTarget = true;
|
||||
skyboxPipelineCI.RasterizerState.FillMode = FillMode::Solid;
|
||||
skyboxPipelineCI.RasterizerState.CullMode = CullMode::None;
|
||||
skyboxPipelineCI.RasterizerState.FrontFace = FrontFace::Clockwise;
|
||||
skyboxPipelineCI.DepthStencilState.EnableDepthTest = true;
|
||||
skyboxPipelineCI.DepthStencilState.EnableDepthWrite = false;
|
||||
skyboxPipelineCI.DepthStencilState.CompareOperation = CompareOperation::LessOrEqual;
|
||||
|
||||
SkyboxPipeline = CreateGraphicsPipeline(GraphicsDevice, skyboxPipelineCI);
|
||||
if (SkyboxPipeline == nullptr)
|
||||
{
|
||||
LogError(LogCategory::Graphics, "Failed to create skybox pipeline!");
|
||||
Running = false;
|
||||
}
|
||||
|
||||
if (skyboxVS) DestroyShader(GraphicsDevice, skyboxVS);
|
||||
if (skyboxFS) DestroyShader(GraphicsDevice, skyboxFS);
|
||||
|
||||
}
|
||||
|
||||
GameCode.Functions = reinterpret_cast<void**>(&Game);
|
||||
@@ -324,6 +368,7 @@ void JulietApplication::OnRender(RenderPass* pass, CommandList* cmd)
|
||||
pushData.LightColor = { 1.0f, 0.95f, 0.8f };
|
||||
pushData.AmbientIntensity = 0.2f;
|
||||
|
||||
RenderSkybox(pass, cmd, pushData.ViewProjection);
|
||||
RenderMeshes(pass, cmd, pushData);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class JulietApplication : public Juliet::IApplication
|
||||
Juliet::HotReloadCode GameCode = {};
|
||||
Juliet::GraphicsPipeline* GraphicsPipeline = {};
|
||||
Juliet::Texture* DepthBuffer = {};
|
||||
Juliet::GraphicsPipeline* SkyboxPipeline = {};
|
||||
Juliet::Arena* GameArena = nullptr;
|
||||
Juliet::Arena* GameScratchArena = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user