From 26fb1fcafa552c600a70b2680c868f7355b138e4 Mon Sep 17 00:00:00 2001 From: omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 12 Jun 2024 00:16:51 +1000 Subject: wip: uvsphere mesh gen and pbr shader first pass --- assets/shaders/pbr_params.frag | 85 +++++++++++++++++++++++++++++++++++++ examples/primitives/ex_primitives.c | 53 +++++++++++++++++++++++ src/maths/primitives.c | 64 ++++++++++++++++++++++++++-- src/maths/primitives.h | 2 +- src/renderer/render_types.h | 12 ++++-- src/resources/gltf.c | 2 +- xmake.lua | 7 +++ 7 files changed, 217 insertions(+), 8 deletions(-) create mode 100644 assets/shaders/pbr_params.frag create mode 100644 examples/primitives/ex_primitives.c diff --git a/assets/shaders/pbr_params.frag b/assets/shaders/pbr_params.frag new file mode 100644 index 0000000..06e0f7e --- /dev/null +++ b/assets/shaders/pbr_params.frag @@ -0,0 +1,85 @@ +#version 410 + +out vec4 FragColor; + +in vec3 WorldPos; +in vec3 Normal; +in vec2 TexCoords; + +struct PointLight { + vec3 position; + vec3 color; +}; + +// --- Uniforms +uniform vec3 viewPos; +// Lights data +#define NUM_POINT_LIGHTS 4 +uniform PointLight pointLights[NUM_POINT_LIGHTS]; +// Material properties +uniform vec3 albedo; +uniform float metallic; +uniform float roughness; +uniform float ao; + +// Forward declarations +vec3 fresnelSchlick(float cosTheta, vec3 F0); +float DistributionGGX(vec3 N, vec3 H, float roughness); +float GeometrySchlickGGX(float NdotV, float roughness); +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness); + +void main() { + vec3 norm = normalize(Normal); + vec3 viewDir = normalize(viewPos - WorldPos); + + vec3 radiance = vec3(0.0); // denoted L in the radiance equation + for (int i = 0; i < 4; i++) { + vec3 lightVec = normalize(pointLights[i].position - WorldPos); + vec3 halfway = normalize(Normal + lightVec); + float distance = length(pointLights[i].position - WorldPos); + float attenuation = 1.0 / (distance * distance); + vec3 radiance = pointLights[i].color * attenuation; + + vec3 F0 = vec3(0.04); + F0 = mix(F0, albedo, metallic); + vec3 F = fresnelSchlick(max(dot(halfway, lightVec), 0.0), F0); + } +} + +/* The below are from https://learnopengl.com/PBR/Lighting */ + +vec3 fresnelSchlick(float cosTheta, vec3 F0) { + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); +} +float DistributionGGX(vec3 N, vec3 H, float roughness) { + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return num / denom; +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return num / denom; +} +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} \ No newline at end of file diff --git a/examples/primitives/ex_primitives.c b/examples/primitives/ex_primitives.c new file mode 100644 index 0000000..c208734 --- /dev/null +++ b/examples/primitives/ex_primitives.c @@ -0,0 +1,53 @@ +#include + +#include "buf.h" +#include "camera.h" +#include "core.h" +#include "file.h" +#include "log.h" +#include "maths.h" +#include "maths_types.h" +#include "mem.h" +#include "primitives.h" +#include "ral.h" +#include "ral_types.h" +#include "render.h" +#include "render_types.h" + +extern core g_core; + +int main() { + core_bringup(); + arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + + vec3 camera_pos = vec3(2., 2., 2.); + vec3 camera_front = vec3_normalise(vec3_negate(camera_pos)); + camera cam = camera_create(camera_pos, camera_front, VEC3_Y, deg_to_rad(45.0)); + + // Geometry + // geo_create_cuboid(f32x3(1, 1, 1)); + geometry_data sphere_data = geo_create_uvsphere(2.0, 8, 8); + mesh sphere = mesh_create(&sphere_data, false); + + // Texture + texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false); + texture_handle texture = texture_data_upload(tex_data, true); + + static f32 theta = 0.0; + + // Main loop + while (!should_exit(&g_core)) { + input_update(&g_core.input); + + render_frame_begin(&g_core.renderer); + + mat4 model = mat4_ident(); + draw_mesh(&sphere, &model, &cam); + + render_frame_end(&g_core.renderer); + } + + renderer_shutdown(&g_core.renderer); + + return 0; +} diff --git a/src/maths/primitives.c b/src/maths/primitives.c index c0af140..3931b93 100644 --- a/src/maths/primitives.c +++ b/src/maths/primitives.c @@ -112,7 +112,7 @@ geometry_data geo_create_cuboid(f32x3 extents) { .vertices = vertices, .has_indices = true, .indices = indices, // FIXME: make darray methods that return stack allocated struct - .colour = vec3(0, 0, 0), + .colour = (rgba){ 0, 0, 0, 1 } }; return geo; @@ -133,6 +133,64 @@ geometry_data geo_create_cuboid(f32x3 extents) { // --- Spheres -geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines) { - // TODO +vec3 spherical_to_cartesian_coords(f32 rho, f32 theta, f32 phi) { + f32 x = rho * sin(phi) * cos(theta); + f32 y = rho * sin(phi) * sin(theta); + f32 z = rho * cos(phi); + return vec3(x, y, z); +} + +geometry_data geo_create_uvsphere(f32 radius, u32 north_south_lines, u32 east_west_lines) { + assert(east_west_lines >= 3); // sphere will be degenerate and look gacked without at least 3 + assert(north_south_lines >= 3); + + vertex_darray* vertices = vertex_darray_new(2 + (east_west_lines - 1) * north_south_lines); + + // Create a UV sphere with spherical coordinates + // a point P on the unit sphere can be represented P(r, theta, phi) + // for each vertex we must convert that to a cartesian R3 coordinate + + // Top point + vertex top = { .static_3d = { .position = vec3(0, 0, radius), + .normal = vec3(0, 0, radius), + .tex_coords = vec2(0, 0) } }; + + // parallels + for (u32 i = 0; i < (east_west_lines - 1); i++) { + // phi should range from 0 to pi + f32 phi = PI * ((i + 1) / east_west_lines); + + // meridians + for (u32 j = 0; j < east_west_lines; j++) { + // theta should range from 0 to 2PI + f32 theta = TAU * (j / north_south_lines); + vec3 position = spherical_to_cartesian_coords(radius, theta, phi); + f32 d = vec3_len(position); + assert(d == radius); // all points on the sphere should be 'radius' away from the origin + vertex v = { .static_3d = { + .position = position, + .normal = position, // normal vector on sphere is same as position + .tex_coords = vec2(0, 0) // TODO + } }; + vertex_darray_push(vertices, v); + } + } + + // Bottom point + vertex bot = { .static_3d = { .position = vec3(0, 0, -radius), + .normal = vec3(0, 0, -radius), + .tex_coords = vec2(0, 0) } }; + + // TODO: generate indices for for each flat quad on the UV sphere and triangles + // where they meet the north and south poles + u32_darray* indices = u32_darray_new(1); + + geometry_data geo = { + .format = VERTEX_STATIC_3D, + .vertices = vertices, + .has_indices = true, + .indices = indices, + .colour = RED_800, + }; + return geo; } diff --git a/src/maths/primitives.h b/src/maths/primitives.h index 3e0cc5f..be2c6ff 100644 --- a/src/maths/primitives.h +++ b/src/maths/primitives.h @@ -9,5 +9,5 @@ geometry_data geo_create_plane(f32x2 extents); geometry_data geo_create_cuboid(f32x3 extents); geometry_data geo_create_cylinder(f32 radius, f32 height, u32 resolution); -geometry_data geo_create_uvsphere(f32 radius, f32 north_south_lines, f32 east_west_lines); +geometry_data geo_create_uvsphere(f32 radius, u32 north_south_lines, u32 east_west_lines); geometry_data geo_create_icosphere(f32 radius, f32 n_subdivisions); \ No newline at end of file diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index b8ed512..1485ae4 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -13,6 +13,7 @@ #include "defines.h" #include "ral.h" #include "ral_types.h" +#include "colours.h" #if defined(CEL_PLATFORM_WINDOWS) // #include "backend_dx11.h" #endif @@ -31,7 +32,7 @@ typedef struct geometry_data { vertex_darray* vertices; // TODO: make it not a pointer bool has_indices; u32_darray* indices; - vec3 colour; /** Optional: set vertex colours */ + rgba colour; /** Optional: set vertex colours */ } geometry_data; // 'Upload' a geometry_data (to GPU) -> get back a mesh @@ -65,9 +66,10 @@ typedef struct texture_data { typedef enum material_kind { MAT_BLINN_PHONG, MAT_PBR, + MAT_PBR_PARAMS, // uses float values to represent a surface uniformly MAT_COUNT } material_kind; -static const char* material_kind_names[] = { "Blinn Phong", "PBR", "Count (This should be an error)"}; +static const char* material_kind_names[] = { "Blinn Phong", "PBR (Textures)", "PBR (Params)", "Count (This should be an error)"}; typedef struct blinn_phong_material { char name[256]; @@ -85,7 +87,10 @@ typedef struct blinn_phong_material { // typedef blinn_phong_material material; typedef struct pbr_parameters { - + vec3 albedo; + f32 metallic; + f32 roughness; + f32 ao; } pbr_parameters; typedef struct pbr_material { @@ -101,6 +106,7 @@ typedef struct material { material_kind kind; union { blinn_phong_material blinn_phong; + pbr_parameters pbr_params; pbr_material pbr; } mat_data; char* name; diff --git a/src/resources/gltf.c b/src/resources/gltf.c index dcb3d96..46ad4f3 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -380,7 +380,7 @@ bool model_load_gltf_str(const char *file_string, const char *filepath, str8 rel geometry_data *geometry = malloc(sizeof(geometry_data)); geometry->format = VERTEX_STATIC_3D; - geometry->colour = vec3(1, 1, 1); + geometry->colour = (rgba){ 1, 1, 1, 1 }; geometry->vertices = geo_vertices; geometry->indices = geo_indices; geometry->has_indices = has_indices; diff --git a/xmake.lua b/xmake.lua index 598b7a3..55af4f2 100644 --- a/xmake.lua +++ b/xmake.lua @@ -188,6 +188,13 @@ target("cube") add_files("examples/cube/ex_cube.c") set_rundir("$(projectdir)") +target("primitives") + set_kind("binary") + set_group("examples") + add_deps("core_static") + add_files("examples/primitives/ex_primitives.c") + set_rundir("$(projectdir)") + -- target("std") -- set_kind("binary") -- set_group("examples") -- cgit v1.2.3-70-g09d2