Skip to content

Commit e60734b

Browse files
committed
Rendering: Working on high level PBR renderer (initial IBL shaders as well)
1 parent bd712c7 commit e60734b

33 files changed

+992
-690
lines changed

Alimer.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
</Folder>
2222
<Folder Name="/assets/shaders/">
2323
<File Path="assets/Shaders/Alimer.hlsli" />
24+
<File Path="assets/Shaders/IBL.slang" />
2425
<File Path="assets/Shaders/Math.hlsli" />
2526
<File Path="assets/Shaders/PBR.slang" />
2627
<File Path="assets/Shaders/ShaderTypes.h" />

assets/Shaders/IBL.slang

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "Alimer.hlsli"
2+
#include "ShaderTypes.h"
3+
#include "VertexInputOutput.hlsli"
4+
5+
enum class BRDF : uint {
6+
Lambert,
7+
TrowbridgeReitz,
8+
};
9+
10+
static float3 CubeDirectionFromFaceAndUV(in int face, in float2 uv)
11+
{
12+
float3 dir;
13+
switch (face)
14+
{
15+
case 0:
16+
dir = float3(1.0f, uv.y, -uv.x);
17+
break;
18+
case 1:
19+
dir = float3(-1.0f, uv.y, uv.x);
20+
break;
21+
case 2:
22+
dir = float3(uv.x, -1.0f, uv.y);
23+
break;
24+
case 3:
25+
dir = float3(uv.x, 1.0f, -uv.y);
26+
break;
27+
case 4:
28+
dir = float3(uv.x, uv.y, 1.0f);
29+
break;
30+
case 5:
31+
dir = float3(-uv.x, uv.y, -1.0f);
32+
break;
33+
}
34+
35+
return normalize(dir);
36+
}
37+
38+
static float2 EquirectUVFromCubeDirection(float3 v)
39+
{
40+
const float2 scales = float2(0.1591549f, 0.3183099f);
41+
const float2 biases = float2(0.5f, 0.5f);
42+
// Assumes +Z is forward. For -X forward, use atan2(v.z, v.x) below instead.
43+
float2 uv = float2(atan2(-v.x, v.z), asin(v.y)) * scales + biases;
44+
return uv;
45+
}
46+
47+
// Material (space 0)
48+
Texture2D<float4> inputTexture : register(t0);
49+
RWTexture2DArray<float4> outputTexture : register(u0);
50+
// SamplerState defaultSampler : register(s0);
51+
52+
[shader("compute")]
53+
[numthreads(32, 32, 1)]
54+
// Utility kernel for converting from an equirectangular environment map (LDR or HDR) to a cube map
55+
void CubeFromEquirectangular(uint3 ThreadID: SV_DispatchThreadID)
56+
{
57+
const SamplerState equirectSampler = SamplerLinearClamp;
58+
const uint2 coords = ThreadID.xy;
59+
const int face = ThreadID.z;
60+
61+
float outputWidth, outputHeight, outputDepth;
62+
outputTexture.GetDimensions(outputWidth, outputHeight, outputDepth);
63+
64+
const float cubeSize = outputWidth;
65+
const float2 cubeUV = ((float2(ThreadID.xy) / (cubeSize - 1)) * 2 - 1);
66+
const float3 dir = CubeDirectionFromFaceAndUV(face, cubeUV);
67+
const float2 rectUV = EquirectUVFromCubeDirection(dir);
68+
float4 color = inputTexture.SampleLevel(equirectSampler, rectUV, 0);
69+
outputTexture[uint3(coords, face)] = color;
70+
}

assets/Shaders/PBR.slang

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,29 @@
22
#include "VertexInputOutput.hlsli"
33
#include "ShaderTypes.h"
44

5+
struct SurfaceInfo
6+
{
7+
// Fill these yourself:
8+
float3 worldPos; // world space position
9+
float3 V; // normalized vector from the shading location to the eye
10+
float3 N; // surface normal in the world space
11+
12+
float roughness;
13+
float metalness;
14+
float3 specularColor;
15+
float3 diffuseColor;
16+
17+
float ao;
18+
float alpha;
19+
float3 emissive;
20+
float4 transmission;
21+
22+
// Calculated properties
23+
float NdotV;
24+
float3 R;
25+
float3 F0;
26+
};
27+
528
// Material (space 0)
629
ConstantBuffer<PBRMaterialData> material : register(b0);
730
Texture2D<float4> baseColorTexture : register(t0);
@@ -10,10 +33,19 @@ SamplerState baseColorSampler : register(s0);
1033
[shader("pixel")]
1134
float4 fragmentMain(in VertexOutput input, in bool isFrontFace: SV_IsFrontFace) : SV_TARGET
1235
{
13-
// Vulkan has issues with static samplers
36+
const float4 baseColorMap = baseColorTexture.Sample(baseColorSampler, input.TexCoord0);
37+
1438
// float4 baseColor = material.baseColorFactor * baseColorTexture.Sample(SamplerLinearClamp, input.TexCoord0);
15-
float4 baseColor = material.baseColorFactor * baseColorTexture.Sample(baseColorSampler, input.TexCoord0);
39+
float4 baseColor = material.baseColorFactor * baseColorMap;
1640
baseColor.rgb *= input.Color;
41+
// clip(baseColor.a - material.GetAlphaCutoff());
42+
43+
SurfaceInfo surface;
44+
surface.worldPos = input.WorldPosition;
45+
surface.V = normalize(view.cameraPosition.xyz - surface.worldPos);
46+
47+
// Should we normalize here?
48+
float3x3 TBN = float3x3(input.Tangent, input.Bitangent, input.Normal);
1749

1850
return baseColor;
1951
}

assets/Shaders/ShaderTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct ALIGNMENT PerViewData
5050
float3 cameraPosition;
5151
};
5252

53+
/* TODO: pack and use half*/
5354
struct ALIGNMENT PBRMaterialData
5455
{
5556
float4 baseColorFactor;

assets/Shaders/VertexCommon.slang

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ VertexOutput vertexMain(in VertexInput input,
2727
output.Normal = normalize(mul(float4(input.Normal, 0.0f), worldMatrix)).xyz;
2828

2929
// World-space tangent and bitangent
30-
//output.Tangent = normalize(mul(draw.worldMatrix, float4(input.Tangent.xyz, 0.0f))).xyz;
31-
//output.Bitangent = cross(output.Normal, output.Tangent) * input.Tangent.w;
30+
output.Tangent = normalize(mul(float4(input.Tangent.xyz, 0.0f), worldMatrix)).xyz;
31+
output.Bitangent = cross(output.Normal, output.Tangent) * input.Tangent.w;
3232

3333
// Pass along the texture coordinates
3434
output.TexCoord0 = input.TexCoord0;

assets/Shaders/VertexInputOutput.hlsli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
struct VertexInput {
1212
float3 Position : POSITION;
1313
float3 Normal : NORMAL;
14+
float4 Tangent : TANGENT;
1415
float2 TexCoord0 : TEXCOORD0;
15-
//float4 Tangent : TANGENT;
1616
//float2 TexCoord1 : TEXCOORD1;
1717

1818
#if USE_VERTEX_COLOR
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "Alimer.hlsli"
2+
#include "VertexInputOutput.hlsli"
3+
#include "ShaderTypes.h"
4+
5+
// Material (space 0)
6+
ConstantBuffer<PBRMaterialData> material : register(b0);
7+
Texture2D<float4> baseColorTexture : register(t0);
8+
SamplerState baseColorSampler : register(s0);
9+
10+
[shader("pixel")]
11+
float4 fragmentMain(in VertexOutput input, in bool isFrontFace: SV_IsFrontFace) : SV_TARGET
12+
{
13+
SurfaceInfo surface;
14+
surface.worldPos = input.WorldPosition;
15+
surface.V = normalize(view.cameraPosition.xyz - surface.worldPos);
16+
17+
const float4 baseColorMap = baseColorTexture.Sample(baseColorSampler, input.TexCoord0);
18+
19+
// float4 baseColor = material.baseColorFactor * baseColorTexture.Sample(SamplerLinearClamp, input.TexCoord0);
20+
float4 baseColor = material.baseColorFactor * baseColorMap;
21+
baseColor.rgb *= input.Color;
22+
23+
return baseColor;
24+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) Amer Koleci and Contributors.
2+
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
3+
4+
using System.ComponentModel;
5+
using System.Numerics;
6+
using Alimer.Assets.Graphics;
7+
using Alimer.Engine;
8+
using Alimer.Graphics;
9+
using Alimer.Physics;
10+
using Alimer.Rendering;
11+
12+
namespace Alimer.Samples;
13+
14+
[Description("Engine - Scene PBR Renderer")]
15+
public sealed class ScenePBRRendererSample : SampleBase
16+
{
17+
private readonly Entity _cameraEntity;
18+
private readonly Entity _damagedHelmetEntity;
19+
20+
public ScenePBRRendererSample(IServiceRegistry services)
21+
: base("Engine - Scene Cube")
22+
{
23+
Services = services;
24+
GraphicsDevice = services.GetService<GraphicsDevice>();
25+
Scene = services.GetService<SceneSystem>();
26+
Entity root = new();
27+
28+
// Camera
29+
_cameraEntity = new();
30+
CameraComponent camera = _cameraEntity.AddComponent<CameraComponent>();
31+
camera.Entity!.Transform.Position = new Vector3(0.0f, 0.0f, 25.0f);
32+
root.Children.Add(_cameraEntity);
33+
34+
// GLTF mesh
35+
PhysicallyBasedMaterial sharedMaterial = new()
36+
{
37+
BaseColorFactor = Colors.White,
38+
};
39+
40+
string meshesPath = Path.Combine(AppContext.BaseDirectory, "Assets", "Meshes");
41+
42+
MeshImporter meshImporter = new();
43+
MeshMetadata meshMetadata = new()
44+
{
45+
FileFullPath = Path.Combine(meshesPath, "DamagedHelmet.glb")
46+
};
47+
MeshAsset meshAsset = meshImporter.Import(meshMetadata).Result;
48+
49+
Span<VertexPositionNormalTangentTexture> vertices = stackalloc VertexPositionNormalTangentTexture[meshAsset.Data!.VertexCount];
50+
for (int i = 0; i < meshAsset.Data.VertexCount; i++)
51+
{
52+
vertices[i] = new VertexPositionNormalTangentTexture(
53+
meshAsset.Data.Positions[i],
54+
meshAsset.Data.Normals[i],
55+
meshAsset.Data.Tangents[i],
56+
meshAsset.Data.Texcoords[i]
57+
);
58+
}
59+
60+
Mesh damagedHelmetMesh = new(vertices.Length, VertexPositionNormalTangentTexture.VertexAttributes, meshAsset.Data.Indices!.Length, IndexFormat.Uint32);
61+
damagedHelmetMesh.SetVertices(vertices);
62+
damagedHelmetMesh.SetIndices(meshAsset.Data.Indices!.AsSpan());
63+
damagedHelmetMesh.RecalculateBounds();
64+
damagedHelmetMesh.CreateGpuData(GraphicsDevice);
65+
_= ToDispose(damagedHelmetMesh);
66+
67+
{
68+
_damagedHelmetEntity = new("Damaged Helmet", new Vector3(0.0f, 2.0f, 0.0f));
69+
70+
MeshComponent meshComponent = new(damagedHelmetMesh);
71+
meshComponent.Materials.Add(sharedMaterial);
72+
_damagedHelmetEntity.AddComponent(meshComponent);
73+
root.Children.Add(_damagedHelmetEntity);
74+
}
75+
76+
Scene.RootEntity = root;
77+
}
78+
79+
public IServiceRegistry Services { get; }
80+
public GraphicsDevice GraphicsDevice { get; }
81+
public SceneSystem Scene { get; }
82+
83+
public override void Update(GameTime time)
84+
{
85+
float deltaTime = (float)time.Elapsed.TotalSeconds;
86+
_damagedHelmetEntity.Transform.Rotate(10 * deltaTime, 20 * deltaTime, 30 * deltaTime);
87+
}
88+
89+
public override void Draw(CommandBuffer context, Texture swapChainTexture)
90+
{
91+
//_cubeEntity.GetComponent<RigidBodyComponent>().LinearVelocity = new Vector3(100, -100.0f, 0.0f);
92+
}
93+
}

samples/Alimer.Samples/Graphics/DrawIndexedQuadSample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public override void Draw(CommandBuffer context, Texture swapChainTexture)
6464

6565
RenderPassEncoder renderPassEncoder = context.BeginRenderPass(backBufferRenderPass);
6666
renderPassEncoder.SetVertexBuffer(0, _vertexBuffer);
67-
renderPassEncoder.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16);
67+
renderPassEncoder.SetIndexBuffer(_indexBuffer, IndexFormat.Uint16);
6868
renderPassEncoder.SetPipeline(_renderPipeline!);
6969
renderPassEncoder.DrawIndexed(6);
7070
renderPassEncoder.EndEncoding();

samples/Alimer.Samples/Graphics/DrawMeshSample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public override void Draw(CommandBuffer context, Texture swapChainTexture)
132132
//context.SetPushConstants(0, worldViewProjection);
133133

134134
renderPassEncoder.SetVertexBuffer(0, _vertexBuffer);
135-
renderPassEncoder.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16);
135+
renderPassEncoder.SetIndexBuffer(_indexBuffer, IndexFormat.Uint16);
136136
renderPassEncoder.DrawIndexed(_indexCount);
137137
renderPassEncoder.EndEncoding();
138138
}

0 commit comments

Comments
 (0)