Added GLTF submodule and start of ModelLoader

This commit is contained in:
Simon Lübeß
2021-08-06 12:22:46 +02:00
parent 5c0ee3bae0
commit 80e0bae347
8 changed files with 505 additions and 4 deletions
+3
View File
@@ -16,3 +16,6 @@
[submodule "GlitchyEngine/vendor/freetype"] [submodule "GlitchyEngine/vendor/freetype"]
path = GlitchyEngine/vendor/freetype path = GlitchyEngine/vendor/freetype
url = https://github.com/aharabada/FreeType-beef.git url = https://github.com/aharabada/FreeType-beef.git
[submodule "GlitchyEngine/vendor/gltf"]
path = GlitchyEngine/vendor/gltf
url = https://github.com/aharabada/cgltf-beef.git
+1 -1
View File
@@ -1,5 +1,5 @@
FileVersion = 1 FileVersion = 1
Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, ImGui = {Path = "GlitchyEngine/vendor/imgui-beef/ImGui"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplWin32"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplDX11"}, DirectXTK = {Path = "GlitchyEngine/vendor/DirectXTK/DirectXTK-beef"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}} Projects = {Sandbox = {Path = "Sandbox"}, GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, ImGui = {Path = "GlitchyEngine/vendor/imgui-beef/ImGui"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplWin32"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui-beef/ImGuiImplDX11"}, DirectXTK = {Path = "GlitchyEngine/vendor/DirectXTK/DirectXTK-beef"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}}
[Workspace] [Workspace]
StartupProject = "Sandbox" StartupProject = "Sandbox"
+1 -1
View File
@@ -1,5 +1,5 @@
FileVersion = 1 FileVersion = 1
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", ImGui = "*", ImGuiImplWin32 = "*", ImGuiImplDX11 = "*", DirectXTK = "*", FreeType = "*"} Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", ImGui = "*", ImGuiImplWin32 = "*", ImGuiImplDX11 = "*", DirectXTK = "*", FreeType = "*", cgltf-beef = "*"}
[Project] [Project]
Name = "GlitchyEngine" Name = "GlitchyEngine"
+217
View File
@@ -0,0 +1,217 @@
using System;
using System.Collections;
using cgltf;
using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
namespace GlitchyEngine.Content
{
public static class ModelLoader
{
public static void LoadModel(String filename, GraphicsContext context, Effect validationEffect, List<(Matrix Transform, GeometryBinding Model)> output)
{
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
Log.EngineLogger.Assert(result == .Success, "Failed to load model.");
result = CGLTF.LoadBuffers(options, data, filename);
Log.EngineLogger.Assert(result == .Success, "Failed to load buffers");
for(var node in data.Nodes)
{
if(node.Mesh != null)
{
Matrix transform = ?;
CGLTF.NodeTransformWorld(&node, (float*)&transform);
for(var primitive in node.Mesh.Primitives)
{
GeometryBinding binding = ModelLoader.PrimitiveToGeoBinding(context, primitive, validationEffect);
output.Add((transform, binding));
}
}
}
/* TODO make awesome stuff */
CGLTF.Free(data);
}
public static GeometryBinding PrimitiveToGeoBinding(GraphicsContext context, CGLTF.Primitive primitive, Effect validationEffect)
{
GeometryBinding binding = new GeometryBinding(context);
// primitive topology
switch(primitive.Type)
{
case .Points:
binding.SetPrimitiveTopology(.PointList);
case .Lines:
binding.SetPrimitiveTopology(.LineList);
case .LineStrip:
binding.SetPrimitiveTopology(.LineStrip);
case .Triangles:
binding.SetPrimitiveTopology(.TriangleList);
case .TriangleStrip:
binding.SetPrimitiveTopology(.TriangleStrip);
default:
Log.EngineLogger.Assert(false, scope $"{primitive.Type} not supported.");
}
// indices
{
CGLTF.Accessor* indices = primitive.Indices;
if(indices != null)
{
bool is16bit = indices.ComponentType == .R_16u || indices.ComponentType == .R_16;
IndexBuffer ib = new IndexBuffer(context, (.)indices.Count, .Immutable, .None, is16bit ? .Index16Bit : .Index32Bit);
uint8* bufferData = (uint8*)indices.BufferView.Buffer.Data;
bufferData += indices.BufferView.Offset;
ib.SetData<uint8>(bufferData, (.)indices.BufferView.Size);
binding.SetIndexBuffer(ib);
ib.ReleaseRef();
}
}
// vertices
{
List<VertexElement> elements = scope .(primitive.Attributes.Length);
Dictionary<CGLTF.BufferView*, VertexBuffer> buffers = scope .();
List<VertexBufferBinding> bindings = scope .();
for(var attribute in primitive.Attributes)
{
// Get Input Element format
Format format = FormatFromVectorComponent(attribute.Data.Type, attribute.Data.ComponentType);
Log.EngineLogger.AssertDebug(format != .Unknown, "Vertex element format must not be \"Unknown.\"");
VertexBuffer vertexBuffer = null;
// Get vertex buffer
{
CGLTF.BufferView* bufferView = attribute.Data.BufferView;
// if buffer doesn't exist -> create
if(!buffers.TryGetValue(bufferView, out vertexBuffer))
{
vertexBuffer = new VertexBuffer(context, 1, (uint32)bufferView.Size, .Immutable)..ReleaseRefNoDelete();
uint8* bufferData = (uint8*)bufferView.Buffer.Data;
bufferData += bufferView.Offset;
vertexBuffer.SetData(bufferData, (.)bufferView.Size);
buffers.Add(attribute.Data.BufferView, vertexBuffer);
}
Log.EngineLogger.AssertDebug(vertexBuffer != null);
}
VertexBufferBinding bufferBinding = .(vertexBuffer, (.)attribute.Data.Stride, (.)attribute.Data.Offset);
// get slot of bufferBinding
int bindingSlot = bindings.IndexOf(bufferBinding);
// binding has no slot -> add to list
if(bindingSlot == -1)
{
bindingSlot = bindings.Count;
bindings.Add(bufferBinding);
binding.SetVertexBufferSlot(bufferBinding, (.)bindingSlot);
}
VertexElement element = .(format, new String(attribute.Name), true, (.)attribute.Index, (.)bindingSlot);
elements.Add(element);
}
VertexElement[] vertexElements = new VertexElement[elements.Count];
for(int i < elements.Count)
{
vertexElements[i] = elements[i];
}
// TODO: validate vertex layout somewhere else
VertexLayout layout = new VertexLayout(context, vertexElements, true, validationEffect.VertexShader);
binding.SetVertexLayout(layout..ReleaseRefNoDelete());
}
return binding;
}
/**
* Converts the vector and component type to the corresponding Format.
*/
static Format FormatFromVectorComponent(CGLTF.Type vectorType, CGLTF.ComponentType componentType)
{
switch((vectorType, componentType))
{
case (.Scalar, .R_8):
return .R8_SInt;
case (.Scalar, .R_8u):
return .R8_UInt;
case (.Scalar, .R_16):
return .R16_SInt;
case (.Scalar, .R_16u):
return .R16_UInt;
case (.Scalar, .R_32u):
return .R32_UInt;
case (.Scalar, .R_32f):
return .R32_Float;
case (.Vec2, .R_8):
return .R8G8_SInt;
case (.Vec2, .R_8u):
return .R8G8_UInt;
case (.Vec2, .R_16):
return .R16G16_SInt;
case (.Vec2, .R_16u):
return .R16G16_UInt;
case (.Vec2, .R_32u):
return .R32G32_UInt;
case (.Vec2, .R_32f):
return .R32G32_Float;
//case (.Vec3, .R_8):
//case (.Vec3, .R_8u):
//case (.Vec3, .R_16):
//case (.Vec3, .R_16u):
case (.Vec3, .R_32u):
return .R32G32B32_UInt;
case (.Vec3, .R_32f):
return .R32G32B32_Float;
case (.Vec4, .R_8):
return .R8G8B8A8_SInt;
case (.Vec4, .R_8u):
return .R8G8B8A8_UInt;
case (.Vec4, .R_16):
return .R16G16B16A16_SInt;
case (.Vec4, .R_16u):
return .R16G16B16A16_UInt;
case (.Vec4, .R_32u):
return .R32G32B32A32_UInt;
case (.Vec4, .R_32f):
return .R32G32B32A32_Float;
case (.Mat4, .R_32f):
return .R32G32B32A32_Float;
default:
Log.EngineLogger.Assert(false, scope $"Unhandled vector - componenttype combination. ({vectorType}, {componentType})");
}
return .Unknown;
}
}
}
+142
View File
@@ -0,0 +1,142 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0.0,
0.0,
1.0
],
"metallicFactor": 0.0
},
"name": "Red"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
}
],
"buffers": [
{
"byteLength": 648,
"uri": "Box0.bin"
}
]
}
Binary file not shown.
+54
View File
@@ -0,0 +1,54 @@
cbuffer SceneConstants
{
float4x4 ViewProjection = float4x4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
cbuffer ObjectConstants
{
float4x4 Transform;
}
cbuffer Constants
{
float4 BaseColor;
float3 LightDir;
}
struct VS_IN
{
float3 Position : POSITION;
float3 Normal : NORMAL;
};
struct PS_IN
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL;
};
PS_IN VS(VS_IN input)
{
PS_IN output;
float4 worldPosition = mul(Transform, float4(input.Position, 1));
output.Position = mul(ViewProjection, worldPosition);
output.Normal = mul((float3x3)Transform, input.Normal);
return output;
}
float4 PS(PS_IN input) : SV_TARGET
{
input.Normal = normalize(input.Normal);
float shading = dot(LightDir, input.Normal);
shading = clamp(shading, 0.0f, 1.0f);
return BaseColor * shading;
}
#effect[VS=VS,PS=PS]
+87 -2
View File
@@ -8,6 +8,8 @@ using ImGui;
using GlitchyEngine.Renderer; using GlitchyEngine.Renderer;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.World; using GlitchyEngine.World;
using System.Collections;
using GlitchyEngine.Content;
namespace Sandbox namespace Sandbox
{ {
@@ -55,8 +57,10 @@ namespace Sandbox
GeometryBinding _quadGeometryBinding ~ _?.ReleaseRef(); GeometryBinding _quadGeometryBinding ~ _?.ReleaseRef();
RasterizerState _rasterizerState ~ _?.ReleaseRef(); RasterizerState _rasterizerState ~ _?.ReleaseRef();
RasterizerState _rasterizerStateClockWise ~ _?.ReleaseRef();
GraphicsContext _context ~ _?.ReleaseRef(); GraphicsContext _context ~ _?.ReleaseRef();
DepthStencilTarget _depthTarget ~ _?.ReleaseRef();
Texture2D _texture ~ _?.ReleaseRef(); Texture2D _texture ~ _?.ReleaseRef();
Texture2D _ge_logo ~ _?.ReleaseRef(); Texture2D _ge_logo ~ _?.ReleaseRef();
@@ -85,8 +89,12 @@ namespace Sandbox
_effectLibrary.LoadNoRefInc("content\\Shaders\\basicShader.hlsl"); _effectLibrary.LoadNoRefInc("content\\Shaders\\basicShader.hlsl");
_effectLibrary.LoadNoRefInc("content\\Shaders\\testShader.hlsl");
var textureEffect = _effectLibrary.Load("content\\Shaders\\textureShader.hlsl"); var textureEffect = _effectLibrary.Load("content\\Shaders\\textureShader.hlsl");
_depthTarget = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height);
// Create Input Layout // Create Input Layout
VertexLayout vertexLayout = new VertexLayout(_context, VertexColorTexture.VertexElements, false, textureEffect.VertexShader); VertexLayout vertexLayout = new VertexLayout(_context, VertexColorTexture.VertexElements, false, textureEffect.VertexShader);
@@ -163,6 +171,9 @@ namespace Sandbox
RasterizerStateDescription rsDesc = .(.Solid, .Back, true); RasterizerStateDescription rsDesc = .(.Solid, .Back, true);
_rasterizerState = new RasterizerState(_context, rsDesc); _rasterizerState = new RasterizerState(_context, rsDesc);
rsDesc.FrontCounterClockwise = false;
_rasterizerStateClockWise = new RasterizerState(_context, rsDesc);
_texture = new Texture2D(_context, "content/Textures/Checkerboard.dds"); _texture = new Texture2D(_context, "content/Textures/Checkerboard.dds");
_ge_logo = new Texture2D(_context, "content/Textures/GE_Logo.dds"); _ge_logo = new Texture2D(_context, "content/Textures/GE_Logo.dds");
@@ -190,6 +201,53 @@ namespace Sandbox
_cameraController = new .(Application.Get().Window.Context.SwapChain.BackbufferViewport.Width / _cameraController = new .(Application.Get().Window.Context.SwapChain.BackbufferViewport.Width /
Application.Get().Window.Context.SwapChain.BackbufferViewport.Height); Application.Get().Window.Context.SwapChain.BackbufferViewport.Height);
_cameraController.CameraPosition = .(0, 0, -5); _cameraController.CameraPosition = .(0, 0, -5);
TestLoadModel();
}
//GeometryBinding _modelTest ~ _?.ReleaseRef();
List<(Matrix Transform, GeometryBinding Model)> _modelTest = new .() ~ UnloadModelTest!();
mixin UnloadModelTest()
{
for(var entry in _modelTest)
{
entry.Model?.ReleaseRef();
}
delete _modelTest;
}
void TestLoadModel()
{
var testEffect = _effectLibrary.Get("testShader");
ModelLoader.LoadModel("content\\Models\\box.gltf", _context, testEffect, _modelTest);
testEffect.ReleaseRef();
/*
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, "content\\Models\\box.gltf", out data);
CGLTF.LoadBuffers(options, data, "content\\Models\\box.gltf");
Log.EngineLogger.Assert(result == .Success, "Failed to load model");
var mesh = data.Meshes[0];
var primitive = mesh.Primitives[0];
var testEffect = _effectLibrary.Get("testShader");
_modelTest = ModelLoader.PrimitiveToGeoBinding(_context, primitive, testEffect);
testEffect.ReleaseRef();
/* TODO make awesome stuff */
CGLTF.Free(data);
*/
} }
void InitEcs() void InitEcs()
@@ -217,13 +275,13 @@ namespace Sandbox
_cameraController.Update(gameTime); _cameraController.Update(gameTime);
RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f)); RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f));
_depthTarget.Clear(1.0f, 0, .Depth);
// Draw test geometry // Draw test geometry
_context.SetRenderTarget(null); _context.SetRenderTarget(null);
_depthTarget.Bind();
_context.BindRenderTargets(); _context.BindRenderTargets();
_context.SetRasterizerState(_rasterizerState);
_context.SetViewport(_context.SwapChain.BackbufferViewport); _context.SetViewport(_context.SwapChain.BackbufferViewport);
Renderer.BeginScene(_cameraController.Camera); Renderer.BeginScene(_cameraController.Camera);
@@ -233,6 +291,24 @@ namespace Sandbox
var basicEffect = _effectLibrary.Get("basicShader"); var basicEffect = _effectLibrary.Get("basicShader");
var textureEffect = _effectLibrary.Get("textureShader"); var textureEffect = _effectLibrary.Get("textureShader");
// Model test
{
_context.SetRasterizerState(_rasterizerStateClockWise);
var testEffect = _effectLibrary.Get("testShader");
testEffect.Variables["BaseColor"].SetData(Color.White);
testEffect.Variables["LightDir"].SetData(Vector3(-1, 1, -0.5f).Normalized());
for(var entry in _modelTest)
{
Renderer.Submit(entry.Model, testEffect, entry.Transform);
}
testEffect.ReleaseRef();
}
_context.SetRasterizerState(_rasterizerState);
for(var entity in _world.Enumerate(typeof(TransformComponent))) for(var entity in _world.Enumerate(typeof(TransformComponent)))
{ {
var transform = _world.GetComponent<TransformComponent>(entity); var transform = _world.GetComponent<TransformComponent>(entity);
@@ -281,6 +357,7 @@ namespace Sandbox
EventDispatcher dispatcher = EventDispatcher(event); EventDispatcher dispatcher = EventDispatcher(event);
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e)); dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
dispatcher.Dispatch<WindowResizeEvent>(scope (e) => OnWindowResize(e));
} }
private bool OnImGuiRender(ImGuiRenderEvent e) private bool OnImGuiRender(ImGuiRenderEvent e)
@@ -295,6 +372,14 @@ namespace Sandbox
return false; return false;
} }
private bool OnWindowResize(WindowResizeEvent e)
{
_depthTarget.ReleaseRef();
_depthTarget = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height);
return false;
}
} }
class SandboxApp : Application class SandboxApp : Application