diff --git a/.gitignore b/.gitignore index 24f15cc..9549556 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build -include/SDL3 assets/StylizedNature/OBJ assets/StylizedNature/FBX assets/StylizedNature/FBX (Unity) diff --git a/.ignore b/.ignore index de735a6..032d927 100644 --- a/.ignore +++ b/.ignore @@ -3,3 +3,4 @@ SDL external build +assets diff --git a/assets.cpp b/assets.cpp index 3e56d77..9511649 100644 --- a/assets.cpp +++ b/assets.cpp @@ -1,4 +1,4 @@ -const u64 IMAGE_MAX = 1024; +const u64 MODEL_MAX = 2048; #include @@ -42,9 +42,11 @@ struct Mesh struct Material { - TextureID textures[MMI_Max]; - PipelineID pipeline_id; - BufferID buffer_id; + TextureID textures[MMI_Max]; + ShaderModelState shader_state; + PipelineID pipeline_id; + BufferID buffer_id; + BufferID shader_state_buffer_id; }; struct Model @@ -55,6 +57,8 @@ struct Model Array materials; }; +Model g_models[MODEL_MAX]; + Array OpenFile(String8 file_path) { @@ -233,8 +237,8 @@ LoadImage(cgltf_image *asset_image, String8 texture_path) } else { - u8 buffer[512]; - String8 file_path = SPrintf(buffer, "%s%s", texture_path.ptr, uri_path.ptr); + u8 buffer[512]; + String8 file_path = SPrintf(buffer, "%s%s", texture_path.ptr, uri_path.ptr); Array image_file = OpenFile(file_path); image_buffer = LoadImage(image_file.ptr, (i32)image_file.length); @@ -303,7 +307,8 @@ LoadImageToTexture(cgltf_image *asset_image, String8 texture_path) return texture_id; } -TextureID FindTexture(cgltf_texture *texture, cgltf_data *data, Model *model) +TextureID +FindTexture(cgltf_texture *texture, cgltf_data *data, Model *model) { TextureID result = g_renderer.default_texture; @@ -312,6 +317,7 @@ TextureID FindTexture(cgltf_texture *texture, cgltf_data *data, Model *model) if(texture == data->textures+i) { result = model->textures[i]; + break; } } @@ -444,7 +450,8 @@ LoadGLTF(Arena* arena, Model* model_result, String8 file_name) for(u64 i = 0; i < data->materials_count; i += 1) { - MaterialSet material_set; + MaterialSet material_set = {}; + ShaderModelState shader_state = {}; TextureID *textures = model.materials[i].textures; cgltf_material *material = data->materials+i; @@ -455,6 +462,7 @@ LoadGLTF(Arena* arena, Model* model_result, String8 file_name) if(pbr_mr->base_color_texture.texture) { textures[MMI_Albedo] = FindTexture(pbr_mr->base_color_texture.texture, data, &model); + shader_state.albedo_texture = true; } memcpy(material_set.maps[MMI_Albedo].color.v, pbr_mr->base_color_factor, sizeof(f32)*4); @@ -468,16 +476,20 @@ LoadGLTF(Arena* arena, Model* model_result, String8 file_name) material_set.maps[MMI_Metallic].value = pbr_mr->metallic_factor; material_set.maps[MMI_Roughness].value = pbr_mr->roughness_factor; + + shader_state.metallic_roughness_texture = true; } if(material->normal_texture.texture) { textures[MMI_Normal] = FindTexture(material->normal_texture.texture, data, &model); + shader_state.normal_texture = true; } if(material->occlusion_texture.texture) { textures[MMI_Occlusion] = FindTexture(material->occlusion_texture.texture, data, &model); + shader_state.occlusion_texture = true; } if(material->emissive_texture.texture) @@ -486,10 +498,13 @@ LoadGLTF(Arena* arena, Model* model_result, String8 file_name) memcpy(material_set.maps[MMI_Emission].color.v, material->emissive_factor, sizeof(f32)*3); material_set.maps[MMI_Emission].color.a = 1.0; + shader_state.emission_texture = true; } } - model.materials[i].buffer_id = CreateBuffer(&material_set); + model.materials[i].buffer_id = CreateBuffer(&material_set); + model.materials[i].shader_state = shader_state; + model.materials[i].shader_state_buffer_id = CreateBuffer(&shader_state); } u64 mesh_index = 0, point_index = 0; diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv new file mode 100644 index 0000000..0dec751 Binary files /dev/null and b/assets/shaders/pbr.frag.spv differ diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv new file mode 100644 index 0000000..9f34656 Binary files /dev/null and b/assets/shaders/pbr.vert.spv differ diff --git a/main.cpp b/main.cpp index 6736c57..bc67468 100644 --- a/main.cpp +++ b/main.cpp @@ -40,6 +40,8 @@ typedef double f64; typedef uintptr_t uintptr; typedef intptr_t intptr; +typedef uint32_t b32; + #ifdef __linux__ typedef ssize_t isize; typedef size_t usize; @@ -265,6 +267,35 @@ typedef GLuint PipelineID; typedef GLuint ShaderID; typedef GLuint BufferID; +enum PipelineFeature +{ + PF_Albedo = 1<<0, + PF_Normal = 1<<1, + PF_Metallic = 1<<2, + PF_Roughness = 1<<3, + PF_Occlusion = 1<<4, + PF_Emission = 1<<5, + PF_Height = 1<<6, + PF_Cubemap = 1<<7, + PF_Irradiance = 1<<8, + PF_Prefilter = 1<<9, + PF_BRDF = 1<<10, +}; + +const PipelineFeature PIPELINE_FEATURES[] = { + PF_Albedo, + PF_Normal, + PF_Metallic, + PF_Roughness, + PF_Occlusion, + PF_Emission, + PF_Height, + PF_Cubemap, + PF_Irradiance, + PF_Prefilter, + PF_BRDF, +}; + struct ImageBuffer { Array data; @@ -315,6 +346,25 @@ struct ShaderGlobals Mat4 model_matrix; }; +struct ShaderModelState +{ + b32 albedo_texture; + b32 normal_texture; + b32 metallic_roughness_texture; + b32 occlusion_texture; + b32 emission_texture; + b32 height_texture; + b32 cubemap_texture; + b32 irradiance_texture; + b32 prefilter_texture; + b32 brdf_texture; +}; + +struct ShaderInstanceState +{ + Mat4 model_matrix; +}; + struct Renderer { SDL_Window* window; @@ -355,14 +405,14 @@ CreateModelBuffers() } ShaderID -CreateShader(GLenum type, char *src) +CreateShader(GLenum type, Array src) { ShaderID shader_id = glCreateShader(type); if(shader_id) { GLint success; - glShaderSource(shader_id, 1, (const char **)&src, NULL); + glShaderSource(shader_id, src.length, src.ptr, NULL); glCompileShader(shader_id); glGetShaderiv(shader_id, GL_COMPILE_STATUS, &success); @@ -386,13 +436,26 @@ CreateShader(GLenum type, char *src) } PipelineID -CreatePipeline(Array vertex_shader_src, Array frag_shader_src) +CreatePipeline(Array shader_src) { PipelineID pipeline_id; GLint success; - ShaderID vertex_shader_id = CreateShader(GL_VERTEX_SHADER, (char *)vertex_shader_src.ptr); - ShaderID fragment_shader_id = CreateShader(GL_FRAGMENT_SHADER, (char *)frag_shader_src.ptr); + const char *vertex_src[] = { "#version 460\n", "#define VERTEX_SHADER 1\n", (const char *)shader_src.ptr }; + const char *fragment_src[] = { "#version 460\n", (const char *)shader_src.ptr }; + + Array vertex_src_array = { + .ptr = vertex_src, + .length = Length(vertex_src), + }; + + Array fragment_src_array = { + .ptr = fragment_src, + .length = Length(fragment_src), + }; + + ShaderID vertex_shader_id = CreateShader(GL_VERTEX_SHADER, vertex_src_array); + ShaderID fragment_shader_id = CreateShader(GL_FRAGMENT_SHADER, fragment_src_array); if(vertex_shader_id && fragment_shader_id) { pipeline_id = glCreateProgram(); @@ -570,14 +633,12 @@ Init(Renderer *renderer) SDL_SetWindowPosition(renderer->window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_ShowWindow(renderer->window); - Array vertex_src = OpenFile(String8Lit("./shaders/vert.glsl")); - Array fragment_src = OpenFile(String8Lit("./shaders/frag.glsl")); - if(vertex_src.ptr && fragment_src.ptr) + Array shader_src = OpenFile(String8Lit("./shaders/pbr.glsl")); + if(shader_src) { - renderer->pipeline_id = CreatePipeline(vertex_src, fragment_src); + renderer->pipeline_id = CreatePipeline(shader_src); - Free(&vertex_src); - Free(&fragment_src); + Free(&shader_src); } InitCheckError(!renderer->pipeline_id, "Unable to create pipeline"); @@ -599,9 +660,12 @@ Init(Renderer *renderer) glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + renderer->globals.projection = IdentityMatrix(); - renderer->globals.view = LookAt(Vec3(0.0f), Vec3(0.0f, 5.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f)); - renderer->globals.model_matrix = Translate(IdentityMatrix(), Vec3(0.0f, 0.0f, -3.0f)); + renderer->globals.view = LookAt(Vec3(0.0f, 5.0f, 0.0f), Vec3(0.0f, 30.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f)); + renderer->globals.model_matrix = Translate(IdentityMatrix(), Vec3(0.0f, 0.0f, 20.0f)); renderer->globals_buffer_id = CreateBuffer(&renderer->globals); glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_renderer.globals_buffer_id); @@ -631,6 +695,9 @@ main(int argc, char** argv) } } + Mat4 model_matrix = IdentityMatrix(); + BufferID model_matrix_buffer_id = CreateBuffer(&model_matrix); + while(running) { BeginScratch(); @@ -684,6 +751,10 @@ main(int argc, char** argv) glUniform1i(g_renderer.texture_locations[j], j); glBindTexture(GL_TEXTURE_2D, material->textures[j]); } + + glBindBufferBase(GL_UNIFORM_BUFFER, 1, material->shader_state_buffer_id); + glBindBufferBase(GL_UNIFORM_BUFFER, 2, model_matrix_buffer_id); + glBindBufferBase(GL_UNIFORM_BUFFER, 3, material->buffer_id); glDrawElements(GL_TRIANGLES, tree_model.meshes[i].index_length, GL_UNSIGNED_INT, (void *)(u64)(tree_model.meshes[i].index_start*sizeof(u32))); diff --git a/shaders/frag.glsl b/shaders/frag.glsl index ffb8e17..2e60f78 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -1,6 +1,6 @@ #version 460 -precision highp float; +precision mediump float; #define AlbedoTexture u_texture0 #define NormalTexture u_texture1 diff --git a/shaders/pbr.glsl b/shaders/pbr.glsl new file mode 100644 index 0000000..244449e --- /dev/null +++ b/shaders/pbr.glsl @@ -0,0 +1,141 @@ +precision mediump float; + +#define f32 float +#define f64 double +#define u32 uint +#define i32 int +#define b32 bool + +#ifdef VERTEX_SHADER +# define varying_param out + +layout(location = 0) in vec4 a_color; +layout(location = 1) in vec4 a_tangent; +layout(location = 2) in vec3 a_pos; +layout(location = 3) in vec3 a_normal; +layout(location = 4) in vec2 a_uv0; +layout(location = 5) in vec2 a_uv1; + +#else +# define varying_param in + +layout(location = 0) out vec4 FragColor; + +#define AlbedoTexture u_texture0 +#define NormalTexture u_texture1 +#define MetallicTexture u_texture2 +#define RoughnessTexture u_texture3 +#define OcclusionTexture u_texture4 +#define EmissionTexture u_texture5 +#define HeightTexture u_texture6 +#define CubemapTexture u_texture7 +#define IrradianceTexture u_texture8 +#define PrefilterTexture u_texture9 +#define BRDFTexture u_texture10 + +uniform sampler2D u_texture0; +uniform sampler2D u_texture1; +uniform sampler2D u_texture2; +uniform sampler2D u_texture3; +uniform sampler2D u_texture4; +uniform sampler2D u_texture5; +uniform sampler2D u_texture6; +uniform sampler2D u_texture7; +uniform sampler2D u_texture8; +uniform sampler2D u_texture9; +uniform sampler2D u_texture10; + +#endif + +#define MMI_Albedo 0 +#define MMI_Normal 1 +#define MMI_Metallic 2 +#define MMI_Roughness 3 +#define MMI_Occlusion 4 +#define MMI_Emission 5 +#define MMI_Height 6 +#define MMI_Cubemap 7 +#define MMI_Irradiance 8 +#define MMI_Prefilter 9 +#define MMI_BRDF 10 +#define MMI_MAX 11 + +#define AlbedoMaterial material_maps[MMI_Albedo] +#define NormalMaterial material_maps[MMI_Normal] +#define MetallicMaterial material_maps[MMI_Metallic] +#define RoughnessMaterial material_maps[MMI_Roughness] +#define OcclusionMaterial material_maps[MMI_Occlusion] +#define EmissionMaterial material_maps[MMI_Emission] +#define HeightMaterial material_maps[MMI_Height] +#define CubemapMaterial material_maps[MMI_Cubemap] +#define IrradianceMaterial material_maps[MMI_Irradiance] +#define PrefilterMaterial material_maps[MMI_Prefilter] +#define BRDFMaterial material_maps[MMI_BRDF] + +#define VertexMain main +#define FragmentMain main + +struct MaterialMap +{ + vec4 color; + f32 value; +}; + +layout(location = 0) varying_param vec2 v_uv0; +layout(location = 1) varying_param vec2 v_uv1; + +layout(std140, binding = 0) uniform Globals +{ + mat4 projection; + mat4 view; +}; + +layout(std140, binding = 1) uniform ModelState +{ + bool albedo_texture; + bool normal_texture; + bool metallic_roughness_texture; + bool occlusion_texture; + bool emission_texture; + bool height_texture; + bool cubemap_texture; + bool irradiance_texture; + bool prefilter_texture; + bool brdf_texture; +}; + +layout(std140, binding = 2) uniform InstanceState +{ + mat4 model_matrix; +}; + +layout(std140, binding = 3) uniform Materials +{ + MaterialMap material_maps[MMI_MAX]; +}; + +#ifdef VERTEX_SHADER + +void +VertexMain() +{ + gl_Position = projection * model_matrix * vec4(a_pos, 1.0); + v_uv0 = a_uv0; +} + +#else + +void +FragmentMain() +{ + if(albedo_texture) + { + FragColor = texture(AlbedoTexture, v_uv0); + } + else + { + FragColor = AlbedoMaterial.color; + } +} + +#endif