Default shader and mesh

This commit is contained in:
Chewico 2026-02-06 03:25:04 +01:00
parent 2d15ff8c07
commit 818941460f
12 changed files with 412 additions and 40 deletions

View File

@ -77,21 +77,8 @@ namespace Deer {
static Scope<GPUMesh> buildResource(const BaseDataType& baseData); static Scope<GPUMesh> buildResource(const BaseDataType& baseData);
}; };
namespace MeshManager { namespace Builtin {
uint16_t loadModel(const Path&); Resource<GPUMesh> cube();
uint16_t loadModel(const MeshData&, const Path&); Resource<GPUMesh> sphere();
VertexArray& getModel(uint16_t model_id); } // namespace Builtin
const Path& getModelName(uint16_t model_id);
void unloadAllModels();
} // namespace MeshManager
namespace DataStore {
void saveModel(const MeshData&, const Path& name);
void loadModel(MeshData&, const Path& name);
void saveBinModel(const MeshData&, const Path& name);
void createExampleMeshData();
} // namespace DataStore
} // namespace Deer } // namespace Deer

View File

@ -37,4 +37,9 @@ namespace Deer {
namespace DataStore { namespace DataStore {
void loadShader(ShaderData& data, const Path& name); void loadShader(ShaderData& data, const Path& name);
} // namespace DataStore } // namespace DataStore
namespace Builtin {
Resource<Shader> simpleShader();
}
} // namespace Deer } // namespace Deer

View File

@ -0,0 +1,125 @@
#include "DeerRender/Mesh.h"
namespace Deer {
namespace Builtin {
// Vertex positions (duplicated per face for correct normals)
VertexPosition cubeVertexPositions[] = {
// Front (+Z)
VertexPosition(-0.5f, -0.5f, 0.5f),
VertexPosition(0.5f, -0.5f, 0.5f),
VertexPosition(0.5f, 0.5f, 0.5f),
VertexPosition(-0.5f, 0.5f, 0.5f),
// Back (-Z)
VertexPosition(0.5f, -0.5f, -0.5f),
VertexPosition(-0.5f, -0.5f, -0.5f),
VertexPosition(-0.5f, 0.5f, -0.5f),
VertexPosition(0.5f, 0.5f, -0.5f),
// Left (-X)
VertexPosition(-0.5f, -0.5f, -0.5f),
VertexPosition(-0.5f, -0.5f, 0.5f),
VertexPosition(-0.5f, 0.5f, 0.5f),
VertexPosition(-0.5f, 0.5f, -0.5f),
// Right (+X)
VertexPosition(0.5f, -0.5f, 0.5f),
VertexPosition(0.5f, -0.5f, -0.5f),
VertexPosition(0.5f, 0.5f, -0.5f),
VertexPosition(0.5f, 0.5f, 0.5f),
// Top (+Y)
VertexPosition(-0.5f, 0.5f, 0.5f),
VertexPosition(0.5f, 0.5f, 0.5f),
VertexPosition(0.5f, 0.5f, -0.5f),
VertexPosition(-0.5f, 0.5f, -0.5f),
// Bottom (-Y)
VertexPosition(-0.5f, -0.5f, -0.5f),
VertexPosition(0.5f, -0.5f, -0.5f),
VertexPosition(0.5f, -0.5f, 0.5f),
VertexPosition(-0.5f, -0.5f, 0.5f),
};
// Normals per vertex
VertexNormal cubeVertexNormals[] = {
// Front (+Z)
VertexNormal(0, 0, 64),
VertexNormal(0, 0, 64),
VertexNormal(0, 0, 64),
VertexNormal(0, 0, 64),
// Back (-Z)
VertexNormal(0, 0, -64),
VertexNormal(0, 0, -64),
VertexNormal(0, 0, -64),
VertexNormal(0, 0, -64),
// Left (-X)
VertexNormal(-64, 0, 0),
VertexNormal(-64, 0, 0),
VertexNormal(-64, 0, 0),
VertexNormal(-64, 0, 0),
// Right (+X)
VertexNormal(64, 0, 0),
VertexNormal(64, 0, 0),
VertexNormal(64, 0, 0),
VertexNormal(64, 0, 0),
// Top (+Y)
VertexNormal(0, 64, 0),
VertexNormal(0, 64, 0),
VertexNormal(0, 64, 0),
VertexNormal(0, 64, 0),
// Bottom (-Y)
VertexNormal(0, -64, 0),
VertexNormal(0, -64, 0),
VertexNormal(0, -64, 0),
VertexNormal(0, -64, 0),
};
uint32_t cubeIndices[] = {
// Front
0, 1, 2, 0, 2, 3,
// Back
4, 5, 6, 4, 6, 7,
// Left
8, 9, 10, 8, 10, 11,
// Right
12, 13, 14, 12, 14, 15,
// Top
16, 17, 18, 16, 18, 19,
// Bottom
20, 21, 22, 20, 22, 23};
} // namespace Builtin
Resource<GPUMesh> Builtin::cube() {
Resource<GPUMesh> cubeMesh = ResourceManager<GPUMesh>::getResource("Builtin:Cube");
if (cubeMesh.isValid())
return cubeMesh;
MeshData meshData;
meshData.createVertices(24); // 4 vertices per face * 6 faces
meshData.createIndices(36); // 6 indices per face * 6 faces
// Fill positions
for (size_t i = 0; i < 24; i++)
meshData.getVertexPosition()[i] = cubeVertexPositions[i];
// Fill normals
for (size_t i = 0; i < 24; i++) {
meshData.getVertexNormal()[i] = cubeVertexNormals[i];
}
// Fill indices
for (size_t i = 0; i < 36; i++)
meshData.getIndexData()[i] = cubeIndices[i];
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, "Builtin:Cube");
}
} // namespace Deer

View File

@ -0,0 +1,76 @@
#include "DeerRender/Mesh.h"
#include <cmath>
namespace Deer {
namespace Builtin {
// Sphere parameters
constexpr int SPHERE_SEGMENTS = 32; // longitude
constexpr int SPHERE_RINGS = 16; // latitude
} // namespace Builtin
Resource<GPUMesh> Builtin::sphere() {
Resource<GPUMesh> sphereMesh = ResourceManager<GPUMesh>::getResource("Builtin:Sphere");
if (sphereMesh.isValid())
return sphereMesh;
MeshData meshData;
const int vertexCount = (SPHERE_RINGS + 1) * (SPHERE_SEGMENTS + 1);
const int indexCount = SPHERE_RINGS * SPHERE_SEGMENTS * 6;
meshData.createVertices(vertexCount);
meshData.createIndices(indexCount);
VertexPosition* positions = meshData.getVertexPosition();
VertexNormal* normals = meshData.getVertexNormal();
uint32_t* indices = meshData.getIndexData();
// Generate vertices
int v = 0;
for (int y = 0; y <= SPHERE_RINGS; y++) {
float theta = y * M_PI / SPHERE_RINGS; // 0..pi
float sinTheta = sinf(theta);
float cosTheta = cosf(theta);
for (int x = 0; x <= SPHERE_SEGMENTS; x++) {
float phi = x * 2.0f * M_PI / SPHERE_SEGMENTS; // 0..2pi
float sinPhi = sinf(phi);
float cosPhi = cosf(phi);
float px = cosPhi * sinTheta * 0.5f; // scale to radius 0.5
float py = cosTheta * 0.5f;
float pz = sinPhi * sinTheta * 0.5f;
positions[v] = VertexPosition(px, py, pz);
// Normal is just position normalized and scaled to int8_t range
normals[v] = VertexNormal(
static_cast<int8_t>(px * 127.0f),
static_cast<int8_t>(py * 127.0f),
static_cast<int8_t>(pz * 127.0f));
v++;
}
}
// Generate indices
int idx = 0;
for (int y = 0; y < SPHERE_RINGS; y++) {
for (int x = 0; x < SPHERE_SEGMENTS; x++) {
int a = y * (SPHERE_SEGMENTS + 1) + x;
int b = a + SPHERE_SEGMENTS + 1;
indices[idx++] = a;
indices[idx++] = a + 1;
indices[idx++] = b;
indices[idx++] = b;
indices[idx++] = a + 1;
indices[idx++] = b + 1;
}
}
return ResourceManager<GPUMesh>::loadResourceFromData(meshData, "Builtin:Sphere");
}
} // namespace Deer

View File

@ -10,6 +10,7 @@
namespace Deer { namespace Deer {
class FrameBuffer; class FrameBuffer;
class GPUMesh;
namespace Scripting { namespace Scripting {
template <typename T> template <typename T>
@ -47,6 +48,5 @@ namespace Deer {
bool frameBuffer_isValid(Resource<FrameBuffer>&); bool frameBuffer_isValid(Resource<FrameBuffer>&);
void frameBuffer_resize(int, int, Resource<FrameBuffer>&); void frameBuffer_resize(int, int, Resource<FrameBuffer>&);
Resource<FrameBuffer> createFrameBuffer(std::string& name, int sixeX, int sizeY); Resource<FrameBuffer> createFrameBuffer(std::string& name, int sixeX, int sizeY);
} // namespace Scripting } // namespace Scripting
} // namespace Deer } // namespace Deer

View File

@ -49,6 +49,10 @@ namespace Deer {
scriptEngine->SetDefaultNamespace("Resource"); scriptEngine->SetDefaultNamespace("Resource");
REGISTER_GLOBAL_FUNC(scriptEngine, "FrameBuffer createFrameBuffer(string&in name, int sizeX, int sizeY)", createFrameBuffer); REGISTER_GLOBAL_FUNC(scriptEngine, "FrameBuffer createFrameBuffer(string&in name, int sizeX, int sizeY)", createFrameBuffer);
scriptEngine->SetDefaultNamespace("Builtin");
REGISTER_GLOBAL_FUNC(scriptEngine, "GPUMesh cube()", Builtin::cube);
REGISTER_GLOBAL_FUNC(scriptEngine, "GPUMesh sphere()", Builtin::sphere);
REGISTER_GLOBAL_FUNC(scriptEngine, "Shader simpleShader()", Builtin::simpleShader);
scriptEngine->SetDefaultNamespace(""); scriptEngine->SetDefaultNamespace("");
} }
/* /*

View File

@ -0,0 +1,105 @@
#include "DeerRender/Shader.h"
namespace Deer {
namespace Builtin {
const char* vertexSimpleShader = R"(
#version 410 core
// Vertex attributes
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_UV;
// Outputs to fragment shader
out vec3 normalWS;
out vec3 normalVS;
out vec3 positionVS;
// Uniforms
uniform mat4 u_worldMatrix;
uniform mat4 u_viewMatrix;
void main()
{
gl_Position = u_viewMatrix * u_worldMatrix * vec4(v_position, 1.0);
positionVS = gl_Position.xyz;
mat3 normalMatrix = transpose(inverse(mat3(u_worldMatrix)));
normalWS = normalize(normalMatrix * v_normal);
mat3 normalMatrixView = transpose(inverse(mat3(u_viewMatrix * u_worldMatrix)));
normalVS = normalize(normalMatrixView * v_normal);
}
)";
const char* fragmentSimpleShader = R"(
#version 410 core
// Fragment outputs
layout(location = 0) out vec4 fragColor;
layout(location = 1) out int objectID;
// Inputs from vertex shader
in vec3 normalWS;
in vec3 normalVS;
in vec3 positionVS;
// Uniforms
uniform int u_objectID;
void main()
{
// Directional light
vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0));
// Base light intensity
float light = clamp(dot(normalWS, lightDir) * 0.8 + 0.2, 0.0, 1.0);
// Gradient from purple (dark) to cyan (lit)
vec3 gradientColor = mix(
vec3(0.9412, 0.4471, 0.7137),
vec3(1.0, 0.9725, 0.5255),
light
);
// Rim/fresnel effect
float rim = 0.5 - dot(normalWS, normalize(lightDir)) * 0.5;
float rimValue = rim * rim * rim * rim;
vec3 rimColor = vec3(1.0, 0.8, 0.5) * (rim * rim * rim * rim);
vec3 mixedColor = mix(
gradientColor,
vec3(1, 1, 1) ,
rimValue
);
//float fresnel = dot(, vec3(0, 0, -1));
//fresnel = fresnel * fresnel;
float fresnel = 1 + dot(normalize(positionVS), normalize(normalVS));
fresnel = fresnel * fresnel * fresnel * fresnel;
// Combine everything
fragColor = vec4(mixedColor + vec3(fresnel, fresnel, fresnel), 1.0);
// Object ID output
objectID = u_objectID;
}
)";
} // namespace Builtin
Resource<Shader> Builtin::simpleShader() {
Resource<Shader> shader = ResourceManager<Shader>::getResource("Builtin:SimpleShader");
if (shader.isValid())
return shader;
ShaderData shaderData;
shaderData.fragmentShader = fragmentSimpleShader;
shaderData.vertexShader = vertexSimpleShader;
return ResourceManager<Shader>::loadResourceFromData(shaderData, "Builtin:SimpleShader");
}
} // namespace Deer

View File

@ -105,8 +105,6 @@ namespace Deer {
StudioPanel::render(); StudioPanel::render();
ImGui::ShowDemoWindow();
ImGui::End(); ImGui::End();
Engine::endRender(); Engine::endRender();

View File

@ -16,7 +16,7 @@ class CameraComponentRender {
float nearZ = cameraComponent.nearZ; float nearZ = cameraComponent.nearZ;
float farZ = cameraComponent.farZ; float farZ = cameraComponent.farZ;
fov = ImGui::magicSlider("FOV", fov, 0.1f); fov = ImGui::magicSlider("Fov", fov, 0.1f);
if (fov > 180.0f) fov = 180.0f; if (fov > 180.0f) fov = 180.0f;
if (fov < 1.0f) fov = 1.0f; if (fov < 1.0f) fov = 1.0f;

View File

@ -70,7 +70,6 @@ class EntityNodeUI {
} }
void renderInteraction() { void renderInteraction() {
// Drag and drop // Drag and drop
ImGui::dragDropSource("ENTITY", any(entity), entity.name); ImGui::dragDropSource("ENTITY", any(entity), entity.name);
ImGui::dragDropTarget("ENTITY", ReciverFunction(this.entityDrop)); ImGui::dragDropTarget("ENTITY", ReciverFunction(this.entityDrop));
@ -114,6 +113,9 @@ class EntityNodeUI {
entity.createChild("node"); entity.createChild("node");
rootPanel.onInit(); rootPanel.onInit();
} }
ImGui::separator();
ImGui::subMenu("3d Object", SimpleFunction(this.render3dObjectMenu));
} else { } else {
if (ImGui::menuItem("Add child")) { if (ImGui::menuItem("Add child")) {
entity.createChild("node"); entity.createChild("node");
@ -129,6 +131,33 @@ class EntityNodeUI {
entity.destroy(); entity.destroy();
rootPanel.onInit(); rootPanel.onInit();
} }
ImGui::separator();
ImGui::subMenu("3d Object", SimpleFunction(this.render3dObjectMenu));
}
}
void render3dObjectMenu() {
if (ImGui::menuItem("Cube")) {
Entity child = entity.createChild("node");
MeshComponent childMesh = child.addComponent<MeshComponent>();
childMesh.meshResource = Builtin::cube();
ShaderComponent childShader = child.addComponent<ShaderComponent>();
childShader.shader = Builtin::simpleShader();
rootPanel.onInit();
}
if (ImGui::menuItem("Sphere")) {
Entity child = entity.createChild("node");
MeshComponent childMesh = child.addComponent<MeshComponent>();
childMesh.meshResource = Builtin::sphere();
ShaderComponent childShader = child.addComponent<ShaderComponent>();
childShader.shader = Builtin::simpleShader();
rootPanel.onInit();
} }
} }
@ -181,7 +210,6 @@ class TreePanel : Panel {
} }
void onImGui() { void onImGui() {
if (infoChanged) { if (infoChanged) {
Entity root = World::getRoot(); Entity root = World::getRoot();
@rootNode = @EntityNodeUI(root, this); @rootNode = @EntityNodeUI(root, this);
@ -189,6 +217,10 @@ class TreePanel : Panel {
infoChanged = false; infoChanged = false;
} }
rootNode.render(); ImGui::contextMenuPopup("POP_ROOT", SimpleFunction(rootNode.renderContextMenu));
for (uint i = 0; i < rootNode.children.length(); i++) {
if (rootNode.children[i].entity.exists) rootNode.children[i].render();
}
} }
} }

View File

@ -1,43 +1,83 @@
#type vertex #type vertex
#version 410 core #version 410 core
// Vertex attributes
layout(location = 0) in vec3 v_position; layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal; layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_UV; layout(location = 2) in vec2 v_UV;
out vec3 normal; // Outputs to fragment shader
out vec2 uv; out vec3 normalWS;
out vec3 normalVS;
out vec3 positionVS;
uniform mat4 u_viewMatrix; // Uniforms
uniform mat4 u_worldMatrix; uniform mat4 u_worldMatrix;
uniform mat4 u_viewMatrix;
void main() void main()
{ {
uv = v_UV;
normal = mat3(u_worldMatrix) * v_normal; // transform normals into world space
gl_Position = u_viewMatrix * u_worldMatrix * vec4(v_position, 1.0); gl_Position = u_viewMatrix * u_worldMatrix * vec4(v_position, 1.0);
positionVS = gl_Position.xyz;
mat3 normalMatrix = transpose(inverse(mat3(u_worldMatrix)));
normalWS = normalize(normalMatrix * v_normal);
mat3 normalMatrixView = transpose(inverse(mat3(u_viewMatrix * u_worldMatrix)));
normalVS = normalize(normalMatrixView * v_normal);
} }
#type fragment #type fragment
#version 410 core #version 410 core
// Fragment outputs
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
layout(location = 1) out int objectID; layout(location = 1) out int objectID;
in vec3 normal; // Inputs from vertex shader
in vec2 uv; in vec3 normalWS;
in vec3 normalVS;
in vec3 positionVS;
uniform sampler2D u_Texture; // Uniforms
uniform int u_objectID; uniform int u_objectID;
void main() void main()
{ {
vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0)) * 0.2f + 0.8f; // Directional light
float light = clamp(dot(normalize(normal), lightDir), 0.1, 1.0); vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0));
fragColor = vec4(light, light, light, 1); // Base light intensity
// fragColor = vec4(uv.r, uv.g, 0, 1); float light = clamp(dot(normalWS, lightDir) * 0.8 + 0.2, 0.0, 1.0);
// Gradient from purple (dark) to cyan (lit)
vec3 gradientColor = mix(
vec3(0.9412, 0.4471, 0.7137),
vec3(1.0, 0.9725, 0.5255),
light
);
// Rim/fresnel effect
float rim = 0.5 - dot(normalWS, normalize(lightDir)) * 0.5;
float rimValue = rim * rim * rim * rim;
vec3 rimColor = vec3(1.0, 0.8, 0.5) * (rim * rim * rim * rim);
vec3 mixedColor = mix(
gradientColor,
vec3(1, 1, 1) ,
rimValue
);
//float fresnel = dot(, vec3(0, 0, -1));
//fresnel = fresnel * fresnel;
float fresnel = 1 + dot(normalize(positionVS), normalize(normalVS));
fresnel = fresnel * fresnel * fresnel * fresnel;
// Combine everything
fragColor = vec4(mixedColor + vec3(fresnel, fresnel, fresnel), 1.0);
// Object ID output
objectID = u_objectID; objectID = u_objectID;
} }

View File

@ -67,7 +67,7 @@ DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=2560,1345 Split=Y
DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=2560,926 Split=X DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=2560,926 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1230,1336 Split=X Selected=0x16E3C1E7 DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1230,1336 Split=X Selected=0x16E3C1E7
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=569,572 CentralNode=1 Selected=0x16E3C1E7 DockNode ID=0x00000005 Parent=0x00000001 SizeRef=569,572 CentralNode=1 Selected=0x16E3C1E7
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=1299,572 Selected=0x5E5F7166 DockNode ID=0x00000006 Parent=0x00000001 SizeRef=1299,572 Selected=0x0F5FFC8C
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=688,1336 Selected=0x9876A79B DockNode ID=0x00000002 Parent=0x00000003 SizeRef=688,1336 Selected=0x9876A79B
DockNode ID=0x00000004 Parent=0x0AC2E849 SizeRef=2560,418 Selected=0x018A0F9B DockNode ID=0x00000004 Parent=0x0AC2E849 SizeRef=2560,418 Selected=0x018A0F9B