diff --git a/.gitignore b/.gitignore index 259148f..9793c1a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,8 @@ *.exe *.out *.app + +# Custom +.idea/* +build/* +bindings/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0186de4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.0) +project(Task-2-3Dobject CXX) + +set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}) +set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) +set(CMAKE_CXX_STANDARD 17) + +# CONFIG option is important so that CMake doesnt search for modules into the default modules directory +find_package(imgui CONFIG) +find_package(glfw CONFIG) +find_package(glew CONFIG) +find_package(fmt CONFIG) +find_package(glm CONFIG) +find_package(stb CONFIG) +find_package(assimp CONFIG) + +add_executable( + Task-2-3Dobject + + src/main.cpp + src/initials.h + src/buffers.h + + src/utils/shader.cpp + src/utils/camera.h + src/utils/model.h + src/utils/mesh.h + + bindings/imgui_impl_glfw.cpp + bindings/imgui_impl_opengl3.cpp + + assets/skybox/skybox.vs + assets/skybox/skybox.fs + assets/nanosuit/nanosuit.vs + assets/nanosuit/nanosuit.fs +) + +add_custom_command( + TARGET Task-2-3Dobject + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/assets ${PROJECT_BINARY_DIR}/assets +) + +target_compile_definitions( + Task-2-3Dobject + PUBLIC + IMGUI_IMPL_OPENGL_LOADER_GLEW +) + +target_link_libraries( + Task-2-3Dobject + imgui::imgui + GLEW::glew_s + glfw::glfw + fmt::fmt + glm::glm + stb::stb + assimp::assimp +) diff --git a/README.md b/README.md index 985e0a8..78d0305 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -# ComputerGraphics-OpenGL \ No newline at end of file +# 3D объект + +### Условие +- загрузка и отрисовка 3D модели формата obj с текстурами +- отражения и преломления environment'а (cubemap/sphere map) +- навигация камеры воркуг объекта. + - в качестве образца берем логику навигации отсюда https://threejs.org/examples/#webgl_geometry_teapot + - камера всегда смотрит в центр сцены (условно, lookat=(0, 0, 0)) + - mouse drag перемещает камеру по сфере с центром в lookat + - mouse zoom - приближает/отдаляет камеру (меняет радиус сферы) + +## Запуск +Собираем проект: +1) Windows `build.bat` +2) Linux `build.sh` + +Далее запускаем `build/Task-2-3Dobject` + +## Примеры +- *With Fresnel coefficient* +![](screenshots/nanosuit_2.gif) + +- *Without Fresnel coefficient* +![](screenshots/nanosuit.gif) + +- *Without Fresnel coefficient* +![](screenshots/aircraft.gif) diff --git a/assets/aircraft/piper_pa18.mtl b/assets/aircraft/piper_pa18.mtl new file mode 100644 index 0000000..813fa90 --- /dev/null +++ b/assets/aircraft/piper_pa18.mtl @@ -0,0 +1,111 @@ +# Blender MTL File: 'piper_pa18.blend' +# Material Count: 10 + +newmtl base +Ns 96.078431 +Ka 0.300000 0.300000 0.300000 +Kd 0.683972 0.355875 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 5 +map_Kd textures/piper_diffuse.jpg +map_Bump textures/piper_bump.jpg + +newmtl base_NONE +Ns 96.078431 +Ka 0.300000 0.300000 0.300000 +Kd 0.683972 0.355875 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 5 +map_Bump textures/piper_bump.jpg +map_Kd textures/piper_diffuse.jpg + +newmtl glass +Ns 96.078431 +Ka 0.080000 0.080000 0.080000 +Kd 0.683972 0.683972 0.683972 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.300000 +d 0.100000 +illum 7 +map_Kd textures/piper_diffuse.jpg + +newmtl glass_NONE +Ns 96.078431 +Ka 0.080000 0.080000 0.080000 +Kd 0.683972 0.683972 0.683972 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.300000 +d 0.100000 +illum 7 + +newmtl internals_alu +Ns 96.078431 +Ka 0.500000 0.500000 0.500000 +Kd 0.336015 0.336015 0.336015 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 5 +map_Kd textures/piper_diffuse.jpg + +newmtl internals_alu_NONE +Ns 96.078431 +Ka 0.500000 0.500000 0.500000 +Kd 0.336015 0.336015 0.336015 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 5 + +newmtl internals_b +Ns 96.078431 +Ka 0.100000 0.100000 0.100000 +Kd 0.007214 0.007214 0.007214 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 3 + +newmtl mirror +Ns 96.078431 +Ka 0.080000 0.080000 0.080000 +Kd 0.560000 0.560000 0.560000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 0.200000 +illum 5 + +newmtl prop +Ns 96.078431 +Ka 0.100000 0.100000 0.100000 +Kd 0.011735 0.011735 0.011735 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 5 +map_Kd textures/piper_diffuse.jpg + +newmtl tires +Ns 96.078431 +Ka 1.000000 1.000000 1.000000 +Kd 0.005754 0.005754 0.005754 +Ks 0.300000 0.300000 0.300000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 +map_Kd textures/piper_diffuse.jpg +map_Ks textures/piper_refl.jpg diff --git a/assets/aircraft/textures/piper_bump.jpg b/assets/aircraft/textures/piper_bump.jpg new file mode 100644 index 0000000..7828b52 Binary files /dev/null and b/assets/aircraft/textures/piper_bump.jpg differ diff --git a/assets/aircraft/textures/piper_diffuse.jpg b/assets/aircraft/textures/piper_diffuse.jpg new file mode 100644 index 0000000..c3edd50 Binary files /dev/null and b/assets/aircraft/textures/piper_diffuse.jpg differ diff --git a/assets/aircraft/textures/piper_refl.jpg b/assets/aircraft/textures/piper_refl.jpg new file mode 100644 index 0000000..4afe297 Binary files /dev/null and b/assets/aircraft/textures/piper_refl.jpg differ diff --git a/assets/nanosuit/nanosuit.fs b/assets/nanosuit/nanosuit.fs new file mode 100644 index 0000000..e591f80 --- /dev/null +++ b/assets/nanosuit/nanosuit.fs @@ -0,0 +1,40 @@ +#version 330 core + +out vec4 FragColor; + +in vec3 normal; +in vec3 position; +in vec2 texture_coords; + +uniform sampler2D texture_diffuse1; +uniform sampler2D texture_specular1; +uniform vec3 camera_pos; +uniform samplerCube skybox; + +uniform float coefficient_texture; +uniform float coefficient_reflection; +uniform float coefficient_refraction; +uniform float fresnel_alpha; +uniform float frag_color_mix; + +void main() +{ + // Texture + vec4 texel_diffuse = texture2D(texture_diffuse1, texture_coords); + vec4 texel_specular = texture2D(texture_specular1, texture_coords); + vec4 result_texture = mix(texel_diffuse, texel_specular, coefficient_texture); + + // Reflect, Refract, Fresnel + float angle = -dot(normalize(position - camera_pos), normalize(normal)); + vec3 reflection = reflect(normalize(position - camera_pos), normalize(normal)); + vec3 refraction = refract(normalize(position - camera_pos), normalize(normal), coefficient_refraction); + float coefficient_fresnel = pow(1 - angle, fresnel_alpha) * (1 - coefficient_reflection) + coefficient_reflection; + + vec4 R = mix( + vec4(texture(skybox, refraction).rgb, 1.0), + vec4(texture(skybox, reflection).rgb, 1.0), + coefficient_fresnel + ); + + FragColor = mix(R, result_texture, frag_color_mix); +} diff --git a/assets/nanosuit/nanosuit.vs b/assets/nanosuit/nanosuit.vs new file mode 100644 index 0000000..21dc5e2 --- /dev/null +++ b/assets/nanosuit/nanosuit.vs @@ -0,0 +1,21 @@ +#version 330 core + +layout (location = 0) in vec3 in_pos; +layout (location = 1) in vec3 in_normal; +layout (location = 2) in vec2 in_texture_coord; + +out vec2 texture_coords; +out vec3 normal; +out vec3 position; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() { + texture_coords = in_texture_coord; + normal = mat3(transpose(inverse(model))) * in_normal; + position = vec3(model * vec4(in_pos, 1.0)); + + gl_Position = projection * view * model * vec4(in_pos, 1.0); +} diff --git a/assets/nanosuit/scene.bin b/assets/nanosuit/scene.bin new file mode 100644 index 0000000..531d4e0 Binary files /dev/null and b/assets/nanosuit/scene.bin differ diff --git a/assets/nanosuit/scene.gltf b/assets/nanosuit/scene.gltf new file mode 100644 index 0000000..1b66a43 --- /dev/null +++ b/assets/nanosuit/scene.gltf @@ -0,0 +1,1522 @@ +{ + "accessors": [ + { + "bufferView": 2, + "componentType": 5126, + "count": 1889, + "max": [ + 0.79831701517105103, + 15.412224769592285, + 0.72109508514404297 + ], + "min": [ + -0.77879029512405396, + 12.646074295043945, + -1.110875129699707 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 22668, + "componentType": 5126, + "count": 1889, + "max": [ + 1, + 1, + 0.99973982572555542 + ], + "min": [ + -0.99992507696151733, + -0.99957412481307983, + -0.99310559034347534 + ], + "type": "VEC3" + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99809950590133667, + 0.9961281418800354, + 0.99129021167755127, + 1 + ], + "min": [ + -0.99809962511062622, + -0.99996346235275269, + -1, + -1 + ], + "type": "VEC4" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 15112, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 30224, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 45336, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 60448, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 75560, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 90672, + "componentType": 5126, + "count": 1889, + "max": [ + 0.99169921875, + 0.99820137023925781 + ], + "min": [ + 0.004611968994140625, + 0.0107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "componentType": 5125, + "count": 7248, + "max": [ + 1888 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 45336, + "componentType": 5126, + "count": 82, + "max": [ + 0.64372682571411133, + 14.536141395568848, + 0.67394542694091797 + ], + "min": [ + -0.62420028448104858, + 13.98453426361084, + 0.20199108123779297 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 46320, + "componentType": 5126, + "count": 82, + "max": [ + 0.92128890752792358, + -0.034667652100324631, + 0.98050642013549805 + ], + "min": [ + -0.92189621925354004, + -0.29724445939064026, + 0.38588279485702515 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 105784, + "componentType": 5126, + "count": 82, + "max": [ + 0.97509765625, + 0.9795074462890625 + ], + "min": [ + 0.046417236328125, + 0.10107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 106440, + "componentType": 5126, + "count": 82, + "max": [ + 0.97509765625, + 0.9795074462890625 + ], + "min": [ + 0.046417236328125, + 0.10107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 107096, + "componentType": 5126, + "count": 82, + "max": [ + 0.97509765625, + 0.9795074462890625 + ], + "min": [ + 0.046417236328125, + 0.10107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 107752, + "componentType": 5126, + "count": 82, + "max": [ + 0.97509765625, + 0.9795074462890625 + ], + "min": [ + 0.046417236328125, + 0.10107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 108408, + "componentType": 5126, + "count": 82, + "max": [ + 0.97509765625, + 0.9795074462890625 + ], + "min": [ + 0.046417236328125, + 0.10107421875 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 28992, + "componentType": 5125, + "count": 234, + "max": [ + 81 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 47304, + "componentType": 5126, + "count": 2112, + "max": [ + 1.8108295202255249, + 13.960199356079102, + 1.2154834270477295 + ], + "min": [ + -1.8071557283401489, + 8.3305644989013672, + -1.7196972370147705 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 72648, + "componentType": 5126, + "count": 2112, + "max": [ + 0.99834072589874268, + 0.99877780675888062, + 0.99862062931060791 + ], + "min": [ + -0.99839991331100464, + -0.99352020025253296, + -0.99999499320983887 + ], + "type": "VEC3" + }, + { + "bufferView": 3, + "byteOffset": 30224, + "componentType": 5126, + "count": 2112, + "max": [ + 0.99998980760574341, + 0.9968450665473938, + 0.9931786060333252, + 1 + ], + "min": [ + -0.99998307228088379, + -0.99606835842132568, + -0.98481595516204834, + -1 + ], + "type": "VEC4" + }, + { + "bufferView": 1, + "byteOffset": 109064, + "componentType": 5126, + "count": 2112, + "max": [ + 2.978515625, + 0.99612808227539062 + ], + "min": [ + 0.006595611572265625, + 0.0068359375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 125960, + "componentType": 5126, + "count": 2112, + "max": [ + 2.978515625, + 0.99612808227539062 + ], + "min": [ + 0.006595611572265625, + 0.0068359375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 142856, + "componentType": 5126, + "count": 2112, + "max": [ + 2.978515625, + 0.99612808227539062 + ], + "min": [ + 0.006595611572265625, + 0.0068359375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 159752, + "componentType": 5126, + "count": 2112, + "max": [ + 2.978515625, + 0.99612808227539062 + ], + "min": [ + 0.006595611572265625, + 0.0068359375 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 29928, + "componentType": 5125, + "count": 8316, + "max": [ + 2111 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 97992, + "componentType": 5126, + "count": 1718, + "max": [ + 3.9108269214630127, + 12.986776351928711, + 1.1816089153289795 + ], + "min": [ + -3.9071896076202393, + 8.7199258804321289, + -1.4715893268585205 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 118608, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99732846021652222, + 0.99593204259872437, + 0.99813145399093628 + ], + "min": [ + -0.99732840061187744, + -0.99995952844619751, + -0.99866753816604614 + ], + "type": "VEC3" + }, + { + "bufferView": 3, + "byteOffset": 64016, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99875408411026001, + 0.99937969446182251, + 0.9996681809425354, + 1 + ], + "min": [ + -0.99837386608123779, + -0.98311781883239746, + -0.99966263771057129, + -1 + ], + "type": "VEC4" + }, + { + "bufferView": 1, + "byteOffset": 176648, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99951171875, + 0.99313735961914062 + ], + "min": [ + 0.004817962646484375, + 0.005859375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 190392, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99951171875, + 0.99313735961914062 + ], + "min": [ + 0.004817962646484375, + 0.005859375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 204136, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99951171875, + 0.99313735961914062 + ], + "min": [ + 0.004817962646484375, + 0.005859375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 217880, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99951171875, + 0.99313735961914062 + ], + "min": [ + 0.004817962646484375, + 0.005859375 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 231624, + "componentType": 5126, + "count": 1718, + "max": [ + 0.99951171875, + 0.99313735961914062 + ], + "min": [ + 0.004817962646484375, + 0.005859375 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 63192, + "componentType": 5125, + "count": 6804, + "max": [ + 1717 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 139224, + "componentType": 5126, + "count": 5926, + "max": [ + 3.9942905902862549, + 9.0687427520751953, + 1.7199372053146362 + ], + "min": [ + -3.9944617748260498, + 7.3449630737304688, + 0.42309093475341797 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 210336, + "componentType": 5126, + "count": 5926, + "max": [ + 0.99972575902938843, + 0.99902230501174927, + 0.99998867511749268 + ], + "min": [ + -0.99996984004974365, + -1, + -0.99870645999908447 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 245368, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 292776, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 340184, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 387592, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 435000, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 482408, + "componentType": 5126, + "count": 5926, + "max": [ + 0.998046875, + 0.9991002082824707 + ], + "min": [ + -0.00603485107421875, + 0.00341796875 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 90408, + "componentType": 5125, + "count": 19350, + "max": [ + 5925 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 281448, + "componentType": 5126, + "count": 3556, + "max": [ + 2.3562133312225342, + 9.2147579193115234, + 1.2145678997039795 + ], + "min": [ + -2.3544621467590332, + 4.4817454181611538e-05, + -1.3846142292022705 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 324120, + "componentType": 5126, + "count": 3556, + "max": [ + 0.99944913387298584, + 0.99555438756942749, + 0.99938863515853882 + ], + "min": [ + -0.99950683116912842, + -0.99995815753936768, + -0.99885451793670654 + ], + "type": "VEC3" + }, + { + "bufferView": 3, + "byteOffset": 91504, + "componentType": 5126, + "count": 3556, + "max": [ + 0.99955165386199951, + 0.98040479421615601, + 0.99927216768264771, + 1 + ], + "min": [ + -0.99953776597976685, + -0.97048556804656982, + -0.99965673685073853, + -1 + ], + "type": "VEC4" + }, + { + "bufferView": 1, + "byteOffset": 529816, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 558264, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 586712, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 615160, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 643608, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 1, + "byteOffset": 672056, + "componentType": 5126, + "count": 3556, + "max": [ + 2.6796875, + 0.99720001220703125 + ], + "min": [ + 0.006500244140625, + 0.00634765625 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 167808, + "componentType": 5125, + "count": 15222, + "max": [ + 3555 + ], + "min": [ + 0 + ], + "type": "SCALAR" + } + ], + "asset": { + "extras": { + "author": "ivangeta79 (https://sketchfab.com/ivangeta79)", + "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)", + "source": "https://sketchfab.com/3d-models/crysis-nano-suit-2-ca311b94a0c249a1abc6697d105253e5", + "title": "Crysis Nano Suit 2" + }, + "generator": "Sketchfab-8.4.0", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 228696, + "byteOffset": 0, + "name": "floatBufferViews", + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 700504, + "byteOffset": 228696, + "byteStride": 8, + "name": "floatBufferViews", + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 366792, + "byteOffset": 929200, + "byteStride": 12, + "name": "floatBufferViews", + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 148400, + "byteOffset": 1295992, + "byteStride": 16, + "name": "floatBufferViews", + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 1444392, + "uri": "scene.bin" + } + ], + "extensionsRequired": [ + "KHR_materials_pbrSpecularGlossiness" + ], + "extensionsUsed": [ + "KHR_materials_pbrSpecularGlossiness" + ], + "images": [ + { + "uri": "textures/Helmet_diffuse.png" + }, + { + "uri": "textures/Helmet_normal.png" + }, + { + "uri": "textures/Glass_diffuse.png" + }, + { + "uri": "textures/Body_diffuse.png" + }, + { + "uri": "textures/Body_specularGlossiness.png" + }, + { + "uri": "textures/Body_normal.png" + }, + { + "uri": "textures/material_diffuse.png" + }, + { + "uri": "textures/material_specularGlossiness.png" + }, + { + "uri": "textures/material_normal.png" + }, + { + "uri": "textures/Hand_diffuse.png" + }, + { + "uri": "textures/Hand_specularGlossiness.png" + }, + { + "uri": "textures/material_5_diffuse.png" + }, + { + "uri": "textures/material_5_specularGlossiness.png" + }, + { + "uri": "textures/material_5_normal.png" + } + ], + "materials": [ + { + "doubleSided": true, + "emissiveFactor": [ + 0, + 0, + 0 + ], + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 0, + "texCoord": 0 + }, + "glossinessFactor": 0.29999999999999999, + "specularFactor": [ + 0.050000000000000003, + 0.050000000000000003, + 0.050000000000000003 + ], + "specularGlossinessTexture": { + "index": 0, + "texCoord": 0 + } + } + }, + "name": "Helmet", + "normalTexture": { + "index": 1, + "scale": 0.62590910015684187, + "texCoord": 0 + } + }, + { + "doubleSided": true, + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 2, + "texCoord": 0 + }, + "glossinessFactor": 0.66833334258108423, + "specularFactor": [ + 0.019848494096235795, + 0.019848494096235795, + 0.019848494096235795 + ] + } + }, + "name": "Glass" + }, + { + "doubleSided": true, + "emissiveFactor": [ + 0, + 0, + 0 + ], + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 3, + "texCoord": 0 + }, + "glossinessFactor": 0.29999999999999999, + "specularFactor": [ + 1, + 1, + 1 + ], + "specularGlossinessTexture": { + "index": 4, + "texCoord": 0 + } + } + }, + "name": "Body", + "normalTexture": { + "index": 5, + "scale": 1, + "texCoord": 0 + } + }, + { + "doubleSided": true, + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 6, + "texCoord": 0 + }, + "glossinessFactor": 0.29999999999999999, + "specularFactor": [ + 1, + 1, + 1 + ], + "specularGlossinessTexture": { + "index": 7, + "texCoord": 0 + } + } + }, + "name": "material", + "normalTexture": { + "index": 8, + "scale": 1, + "texCoord": 0 + } + }, + { + "doubleSided": true, + "emissiveFactor": [ + 0, + 0, + 0 + ], + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 9, + "texCoord": 0 + }, + "glossinessFactor": 0.29999999999999999, + "specularFactor": [ + 1, + 1, + 1 + ], + "specularGlossinessTexture": { + "index": 10, + "texCoord": 0 + } + } + }, + "name": "Hand" + }, + { + "doubleSided": true, + "emissiveFactor": [ + 0, + 0, + 0 + ], + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseFactor": [ + 1, + 1, + 1, + 1 + ], + "diffuseTexture": { + "index": 11, + "texCoord": 0 + }, + "glossinessFactor": 0.29999999999999999, + "specularFactor": [ + 1, + 1, + 1 + ], + "specularGlossinessTexture": { + "index": 12, + "texCoord": 0 + } + } + }, + "name": "material_5", + "normalTexture": { + "index": 13, + "scale": 1, + "texCoord": 0 + } + } + ], + "meshes": [ + { + "name": "nanosuit_2_Helmet_0", + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 0, + "TANGENT": 2, + "TEXCOORD_0": 3, + "TEXCOORD_1": 4, + "TEXCOORD_2": 5, + "TEXCOORD_3": 6, + "TEXCOORD_4": 7, + "TEXCOORD_5": 8, + "TEXCOORD_6": 9 + }, + "indices": 10, + "material": 0, + "mode": 4 + } + ] + }, + { + "name": "nanosuit_2_Glass_0", + "primitives": [ + { + "attributes": { + "NORMAL": 12, + "POSITION": 11, + "TEXCOORD_0": 13, + "TEXCOORD_1": 14, + "TEXCOORD_2": 15, + "TEXCOORD_3": 16, + "TEXCOORD_4": 17 + }, + "indices": 18, + "material": 1, + "mode": 4 + } + ] + }, + { + "name": "nanosuit_2_Body_0", + "primitives": [ + { + "attributes": { + "NORMAL": 20, + "POSITION": 19, + "TANGENT": 21, + "TEXCOORD_0": 22, + "TEXCOORD_1": 23, + "TEXCOORD_2": 24, + "TEXCOORD_3": 25 + }, + "indices": 26, + "material": 2, + "mode": 4 + } + ] + }, + { + "name": "nanosuit_2_Arm_0", + "primitives": [ + { + "attributes": { + "NORMAL": 28, + "POSITION": 27, + "TANGENT": 29, + "TEXCOORD_0": 30, + "TEXCOORD_1": 31, + "TEXCOORD_2": 32, + "TEXCOORD_3": 33, + "TEXCOORD_4": 34 + }, + "indices": 35, + "material": 3, + "mode": 4 + } + ] + }, + { + "name": "nanosuit_2_Hand_0", + "primitives": [ + { + "attributes": { + "NORMAL": 37, + "POSITION": 36, + "TEXCOORD_0": 38, + "TEXCOORD_1": 39, + "TEXCOORD_2": 40, + "TEXCOORD_3": 41, + "TEXCOORD_4": 42, + "TEXCOORD_5": 43 + }, + "indices": 44, + "material": 4, + "mode": 4 + } + ] + }, + { + "name": "nanosuit_2_Leg_0", + "primitives": [ + { + "attributes": { + "NORMAL": 46, + "POSITION": 45, + "TANGENT": 47, + "TEXCOORD_0": 48, + "TEXCOORD_1": 49, + "TEXCOORD_2": 50, + "TEXCOORD_3": 51, + "TEXCOORD_4": 52, + "TEXCOORD_5": 53 + }, + "indices": 54, + "material": 5, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "name": "RootNode (gltf orientation matrix)", + "rotation": [ + -0.70710678118654746, + -0, + -0, + 0.70710678118654757 + ] + }, + { + "children": [ + 2 + ], + "name": "RootNode (model correction matrix)" + }, + { + "children": [ + 3 + ], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + -1, + 0, + 0, + 0, + 0, + 0, + 1 + ], + "name": "scene.fbx" + }, + { + "children": [ + 4, + 11, + 14 + ], + "name": "RootNode" + }, + { + "children": [ + 5, + 6, + 7, + 8, + 9, + 10 + ], + "name": "nanosuit_2" + }, + { + "mesh": 0, + "name": "nanosuit_2_Helmet_0" + }, + { + "mesh": 1, + "name": "nanosuit_2_Glass_0" + }, + { + "mesh": 2, + "name": "nanosuit_2_Body_0" + }, + { + "mesh": 3, + "name": "nanosuit_2_Arm_0" + }, + { + "mesh": 4, + "name": "nanosuit_2_Hand_0" + }, + { + "mesh": 5, + "name": "nanosuit_2_Leg_0" + }, + { + "children": [ + 12 + ], + "matrix": [ + 0.77472349941488439, + 0.60341370366002378, + 0.18893226746548278, + 0, + -0.33087434214396449, + 0.13225617137725576, + 0.93436099813906437, + 0, + 0.53881877209796103, + -0.78638426190248945, + 0.3021160761477657, + 0, + -2, + 2, + 2, + 1 + ], + "name": "Light" + }, + { + "children": [ + 13 + ], + "matrix": [ + 1, + 0, + 0, + 0, + 0, + 2.2204460492503131e-16, + 1, + 0, + 0, + -1, + 2.2204460492503131e-16, + 0, + 0, + 0, + 0, + 1 + ], + "name": "" + }, + { + "name": "" + }, + { + "children": [ + 15 + ], + "matrix": [ + 2.2204460492503131e-16, + 0, + -1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 2.2204460492503131e-16, + 0, + -8.5592269897460938e-05, + 7.7061347961425781, + 41.175117492675781, + 1 + ], + "name": "Camera" + }, + { + "name": "" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9987, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "scene": 0, + "scenes": [ + { + "name": "OSG_Scene", + "nodes": [ + 0 + ] + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + }, + { + "sampler": 0, + "source": 1 + }, + { + "sampler": 0, + "source": 2 + }, + { + "sampler": 0, + "source": 3 + }, + { + "sampler": 0, + "source": 4 + }, + { + "sampler": 0, + "source": 5 + }, + { + "sampler": 0, + "source": 6 + }, + { + "sampler": 0, + "source": 7 + }, + { + "sampler": 0, + "source": 8 + }, + { + "sampler": 0, + "source": 9 + }, + { + "sampler": 0, + "source": 10 + }, + { + "sampler": 0, + "source": 11 + }, + { + "sampler": 0, + "source": 12 + }, + { + "sampler": 0, + "source": 13 + } + ] +} + diff --git a/assets/nanosuit/textures/Body_diffuse.png b/assets/nanosuit/textures/Body_diffuse.png new file mode 100644 index 0000000..7512098 Binary files /dev/null and b/assets/nanosuit/textures/Body_diffuse.png differ diff --git a/assets/nanosuit/textures/Body_normal.png b/assets/nanosuit/textures/Body_normal.png new file mode 100644 index 0000000..17673d7 Binary files /dev/null and b/assets/nanosuit/textures/Body_normal.png differ diff --git a/assets/nanosuit/textures/Body_specularGlossiness.png b/assets/nanosuit/textures/Body_specularGlossiness.png new file mode 100644 index 0000000..0ed4e29 Binary files /dev/null and b/assets/nanosuit/textures/Body_specularGlossiness.png differ diff --git a/assets/nanosuit/textures/Glass_diffuse.png b/assets/nanosuit/textures/Glass_diffuse.png new file mode 100644 index 0000000..2a9dce4 Binary files /dev/null and b/assets/nanosuit/textures/Glass_diffuse.png differ diff --git a/assets/nanosuit/textures/Hand_diffuse.png b/assets/nanosuit/textures/Hand_diffuse.png new file mode 100644 index 0000000..656a01a Binary files /dev/null and b/assets/nanosuit/textures/Hand_diffuse.png differ diff --git a/assets/nanosuit/textures/Hand_specularGlossiness.png b/assets/nanosuit/textures/Hand_specularGlossiness.png new file mode 100644 index 0000000..53dd2c3 Binary files /dev/null and b/assets/nanosuit/textures/Hand_specularGlossiness.png differ diff --git a/assets/nanosuit/textures/Helmet_diffuse.png b/assets/nanosuit/textures/Helmet_diffuse.png new file mode 100644 index 0000000..6727e84 Binary files /dev/null and b/assets/nanosuit/textures/Helmet_diffuse.png differ diff --git a/assets/nanosuit/textures/Helmet_normal.png b/assets/nanosuit/textures/Helmet_normal.png new file mode 100644 index 0000000..a29541f Binary files /dev/null and b/assets/nanosuit/textures/Helmet_normal.png differ diff --git a/assets/nanosuit/textures/material_5_diffuse.png b/assets/nanosuit/textures/material_5_diffuse.png new file mode 100644 index 0000000..74ede7f Binary files /dev/null and b/assets/nanosuit/textures/material_5_diffuse.png differ diff --git a/assets/nanosuit/textures/material_5_normal.png b/assets/nanosuit/textures/material_5_normal.png new file mode 100644 index 0000000..0b1d434 Binary files /dev/null and b/assets/nanosuit/textures/material_5_normal.png differ diff --git a/assets/nanosuit/textures/material_5_specularGlossiness.png b/assets/nanosuit/textures/material_5_specularGlossiness.png new file mode 100644 index 0000000..a0e3ef0 Binary files /dev/null and b/assets/nanosuit/textures/material_5_specularGlossiness.png differ diff --git a/assets/nanosuit/textures/material_diffuse.png b/assets/nanosuit/textures/material_diffuse.png new file mode 100644 index 0000000..c5fc201 Binary files /dev/null and b/assets/nanosuit/textures/material_diffuse.png differ diff --git a/assets/nanosuit/textures/material_normal.png b/assets/nanosuit/textures/material_normal.png new file mode 100644 index 0000000..d0261ac Binary files /dev/null and b/assets/nanosuit/textures/material_normal.png differ diff --git a/assets/nanosuit/textures/material_specularGlossiness.png b/assets/nanosuit/textures/material_specularGlossiness.png new file mode 100644 index 0000000..c383b7d Binary files /dev/null and b/assets/nanosuit/textures/material_specularGlossiness.png differ diff --git a/assets/skybox/skybox.fs b/assets/skybox/skybox.fs new file mode 100644 index 0000000..d4be392 --- /dev/null +++ b/assets/skybox/skybox.fs @@ -0,0 +1,11 @@ +#version 330 core + +out vec4 FragColor; + +in vec3 tex_coords; + +uniform samplerCube skybox; + +void main() { + FragColor = texture(skybox, tex_coords); +} diff --git a/assets/skybox/skybox.vs b/assets/skybox/skybox.vs new file mode 100644 index 0000000..9a8fcc0 --- /dev/null +++ b/assets/skybox/skybox.vs @@ -0,0 +1,14 @@ +#version 330 core + +layout (location = 0) in vec3 in_pos; + +out vec3 tex_coords; + +uniform mat4 projection; +uniform mat4 view; + +void main() { + tex_coords = in_pos; + vec4 pos = projection * view * vec4(in_pos, 1.0); + gl_Position = pos.xyww; +} diff --git a/assets/skybox/textures/simple/back.jpg b/assets/skybox/textures/simple/back.jpg new file mode 100644 index 0000000..470a679 Binary files /dev/null and b/assets/skybox/textures/simple/back.jpg differ diff --git a/assets/skybox/textures/simple/bottom.jpg b/assets/skybox/textures/simple/bottom.jpg new file mode 100644 index 0000000..893f394 Binary files /dev/null and b/assets/skybox/textures/simple/bottom.jpg differ diff --git a/assets/skybox/textures/simple/front.jpg b/assets/skybox/textures/simple/front.jpg new file mode 100644 index 0000000..4e17b77 Binary files /dev/null and b/assets/skybox/textures/simple/front.jpg differ diff --git a/assets/skybox/textures/simple/left.jpg b/assets/skybox/textures/simple/left.jpg new file mode 100644 index 0000000..5750b91 Binary files /dev/null and b/assets/skybox/textures/simple/left.jpg differ diff --git a/assets/skybox/textures/simple/right.jpg b/assets/skybox/textures/simple/right.jpg new file mode 100644 index 0000000..8963037 Binary files /dev/null and b/assets/skybox/textures/simple/right.jpg differ diff --git a/assets/skybox/textures/simple/top.jpg b/assets/skybox/textures/simple/top.jpg new file mode 100644 index 0000000..4db3c2a Binary files /dev/null and b/assets/skybox/textures/simple/top.jpg differ diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..3898417 --- /dev/null +++ b/build.bat @@ -0,0 +1,9 @@ +@ECHO ON + +RMDIR /Q /S build +MKDIR build +PUSHD build + +conan install .. +cmake .. -G "Visual Studio 15 2017 Win64" +cmake --build . --config Release diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..a09a066 --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e +set -x + +rm -rf build +mkdir build +pushd build + +export CONAN_SYSREQUIRES_MODE=enabled +conan install .. +cmake .. -DCMAKE_BUILD_TYPE=Release +cmake --build . diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..8e1460f --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,21 @@ +[requires] +imgui/1.74 +glfw/3.3.2 +glew/2.1.0 +fmt/7.0.3 +glm/0.9.9.8 +stb/20200203 +assimp/5.0.1 + +[generators] +cmake_find_package_multi + +[options] +glew:shared=False +fmt:header_only=True + +[imports] +./res/bindings, imgui_impl_glfw.cpp -> ../bindings +./res/bindings, imgui_impl_opengl3.cpp -> ../bindings +./res/bindings, imgui_impl_glfw.h -> ../bindings +./res/bindings, imgui_impl_opengl3.h -> ../bindings diff --git a/screenshots/aircraft.gif b/screenshots/aircraft.gif new file mode 100644 index 0000000..adc686b Binary files /dev/null and b/screenshots/aircraft.gif differ diff --git a/screenshots/nanosuit.gif b/screenshots/nanosuit.gif new file mode 100644 index 0000000..629fcea Binary files /dev/null and b/screenshots/nanosuit.gif differ diff --git a/screenshots/nanosuit_2.gif b/screenshots/nanosuit_2.gif new file mode 100644 index 0000000..df84206 Binary files /dev/null and b/screenshots/nanosuit_2.gif differ diff --git a/src/buffers.h b/src/buffers.h new file mode 100644 index 0000000..595c2f3 --- /dev/null +++ b/src/buffers.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +const GLuint WINDOW_WIDTH = 800; +const GLuint WINDOW_HEIGHT = 600; +const GLfloat RATIO = GLfloat(WINDOW_WIDTH) / GLfloat(WINDOW_HEIGHT); + +std::vector cube_textures = { + "assets/skybox/textures/simple/right.jpg", + "assets/skybox/textures/simple/left.jpg", + "assets/skybox/textures/simple/top.jpg", + "assets/skybox/textures/simple/bottom.jpg", + "assets/skybox/textures/simple/front.jpg", + "assets/skybox/textures/simple/back.jpg" +}; + +GLfloat skybox_vertices[] = { + -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, + + -1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f +}; diff --git a/src/initials.h b/src/initials.h new file mode 100644 index 0000000..694257c --- /dev/null +++ b/src/initials.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "buffers.h" +#include "../bindings/imgui_impl_glfw.h" +#include "../bindings/imgui_impl_opengl3.h" + + +// Camera +Camera camera(glm::vec3(0.0f, 0.0f, 0.5f)); + +void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +void scroll_callback(GLFWwindow *window, double offset_x, double offset_y) { + camera.process_mouse_scroll(offset_y); +} + +void init_buffers(GLuint &skyboxVBO, GLuint &skyboxVAO) { + glGenVertexArrays(1, &skyboxVAO); + glGenBuffers(1, &skyboxVBO); + glBindVertexArray(skyboxVAO); + glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(skybox_vertices), &skybox_vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) nullptr); +} + +ImGuiIO init_ImGui(GLFWwindow *window) { + const char *glsl_version = "#version 330"; + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO &io = ImGui::GetIO(); + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init(glsl_version); + ImGui::StyleColorsDark(); + + return io; +} + +GLFWwindow *init_opengl() { + glfwInit(); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + glfwWindowHint(GLFW_SAMPLES, 4); + + GLFWwindow *window = glfwCreateWindow( + WINDOW_WIDTH, + WINDOW_HEIGHT, + "Task-2-3Dobject", + nullptr, + nullptr + ); + + if (window == nullptr) { + glfwTerminate(); + throw std::runtime_error("Failed to create GLFW window"); + } + + glfwMakeContextCurrent(window); + + glfwSetKeyCallback(window, key_callback); + glfwSetScrollCallback(window, scroll_callback); + + glewExperimental = GL_TRUE; + if (glewInit() != GLEW_OK) { + throw std::runtime_error("Failed to initialize GLEW"); + } + + int frame_width, frame_height; + glfwGetFramebufferSize(window, &frame_width, &frame_height); + glViewport(0, 0, frame_width, frame_height); + glEnable(GL_DEPTH_TEST); + + return window; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..572fd32 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,122 @@ +#include "utils/shader.h" +#include "utils/camera.h" +#include "utils/model.h" +#include "initials.h" + + +int main() { + GLFWwindow *window = init_opengl(); + ImGuiIO io = init_ImGui(window); + + // Buffers + GLuint skybox_vbo, skybox_vao; + init_buffers(skybox_vbo, skybox_vao); + + // Cubemap + GLuint cubemap_texture = Model::load_cubemap(cube_textures); + + // Shader + Shader nanosuit_shader("assets/nanosuit/nanosuit.vs", "assets/nanosuit/nanosuit.fs"); + Shader skybox_shader("assets/skybox/skybox.vs", "assets/skybox/skybox.fs"); + + skybox_shader.use(); + skybox_shader.set_uniform("skybox", 0); + + // Model + Model nanosuit_model("assets/nanosuit/scene.gltf"); +// Model nanosuit_model("assets/aircraft/piper_pa18.obj"); + + // Uniforms + static float coefficient_texture; + static float coefficient_reflection; + static float coefficient_refraction; + static float fresnel_alpha; + static float frag_color_mix = 0.5; + + while (!glfwWindowShouldClose(window)) { + // Check and call events + glfwPollEvents(); + + // Settings + int frame_width, frame_height; + glfwGetFramebufferSize(window, &frame_width, &frame_height); + glViewport(0, 0, frame_width, frame_height); + glClear(GLuint(GL_COLOR_BUFFER_BIT) | GLuint(GL_DEPTH_BUFFER_BIT)); + + // Mouse event + if (!ImGui::IsAnyWindowFocused()) { + auto[delta_x, delta_y] = ImGui::GetMouseDragDelta(); + ImGui::ResetMouseDragDelta(); + + glfwGetFramebufferSize(window, &frame_width, &frame_height); + camera.process_mouse_movement(delta_x / float(frame_width), + delta_y / float(frame_height)); + } + + // ImGui + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + + ImGui::NewFrame(); + ImGui::Begin("Settings"); + ImGui::SliderFloat("Texture", &coefficient_texture, 0.0f, 1.0f); + ImGui::SliderFloat("Reflection", &coefficient_reflection, 0.0f, 1.0f); + ImGui::SliderFloat("Refraction", &coefficient_refraction, 0.0f, 1.0f); + ImGui::SliderFloat("Fresnel alpha", &fresnel_alpha, 0.0f, 2.0f); + ImGui::SliderFloat("Frag color mix", &frag_color_mix, 0.0f, 1.0f); + ImGui::End(); + + nanosuit_shader.use(); + nanosuit_shader.set_uniform("coefficient_texture", coefficient_texture); + nanosuit_shader.set_uniform("coefficient_reflection", coefficient_reflection); + nanosuit_shader.set_uniform("coefficient_refraction", coefficient_refraction); + nanosuit_shader.set_uniform("fresnel_alpha", fresnel_alpha); + nanosuit_shader.set_uniform("frag_color_mix", frag_color_mix); + + // Init MVP + auto model = glm::identity(); + model = glm::translate(model, glm::vec3(0.0f, -2.0f, 0.0f)); + model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5)); + + glm::mat4 view = camera.view(); + glm::mat4 projection = glm::perspective(glm::radians(45.0f), RATIO, 0.1f, 100.0f); + + nanosuit_shader.set_uniform("model", glm::value_ptr(model)); + nanosuit_shader.set_uniform("view", glm::value_ptr(view)); + nanosuit_shader.set_uniform("projection", glm::value_ptr(projection)); + nanosuit_shader.set_uniform("camera_pos", camera.position()); + + nanosuit_model.draw(nanosuit_shader); + + // Skybox + glDepthFunc(GL_LEQUAL); + skybox_shader.use(); + view = glm::mat4(glm::mat3(camera.view())); + skybox_shader.set_uniform("view", glm::value_ptr(view)); + skybox_shader.set_uniform("projection", glm::value_ptr(projection)); + + // Skybox cube + glBindVertexArray(skybox_vao); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap_texture); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); + glDepthFunc(GL_LESS); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + glfwSwapBuffers(window); + } + + glDeleteVertexArrays(1, &skybox_vao); + glDeleteBuffers(1, &skybox_vbo); + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); + glfwTerminate(); + + return 0; +} diff --git a/src/utils/camera.h b/src/utils/camera.h new file mode 100644 index 0000000..1a724bb --- /dev/null +++ b/src/utils/camera.h @@ -0,0 +1,69 @@ +#pragma once + +#include + +#include +#include +#include + + +class Camera { +public: + explicit Camera(glm::vec3 position) { + position_ = position; + } + + [[nodiscard]] + glm::mat4 view() const { + return glm::lookAt( + position(), + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 1.0f, 0.0f) + ); + } + + void process_mouse_movement(GLfloat offset_x, GLfloat offset_y) { + yaw_ += offset_x * MOUSE_SENSITIVITY; + pitch_ += offset_y * MOUSE_SENSITIVITY; + + if (pitch_ > 89.0f) pitch_ = 89.0f; + if (pitch_ < -89.0f) pitch_ = -89.0f; + } + + void process_mouse_scroll(GLfloat offset_y) { + if (offset_y < 0) zoom_ *= 1.2; + else zoom_ /= 1.2; + } + + [[nodiscard]] + glm::vec3 position() const { + glm::vec3 pos = position_ * zoom_; + + auto rotate = glm::rotate( + glm::identity(), + glm::radians(yaw_), + glm::vec3(0.0f, 1.0f, 0.0f) + ); + pos = glm::vec3(rotate * glm::vec4(pos, 1.0f)); + + auto inverse = glm::vec3(rotate * glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)); + rotate = glm::rotate( + glm::identity(), + glm::radians(pitch_), + inverse + ); + + return pos = glm::vec3(rotate * glm::vec4(pos, 1.0f)); + } + +private: + const GLfloat MOUSE_SENSITIVITY = 45.0f; + +private: + glm::vec3 position_{}; + + GLfloat pitch_ = 0.0f; + GLfloat yaw_ = 0.0f; + + GLfloat zoom_ = 45.0f; +}; diff --git a/src/utils/mesh.h b/src/utils/mesh.h new file mode 100644 index 0000000..e647e3a --- /dev/null +++ b/src/utils/mesh.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "shader.h" + + +struct Vertex { + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texture_coords; + glm::vec3 tangent; + glm::vec3 bitangent; +}; + +struct Texture { + GLuint id; + std::string type; + std::string path; +}; + +class Mesh { +private: + GLuint vbo_{}, vao_{}, ebo_{}; + std::vector vertices_; + std::vector indices_; + std::vector textures_; + +public: + Mesh(std::vector vertices, std::vector indices, std::vector textures) + : vertices_(std::move(vertices)), + indices_(std::move(indices)), + textures_(std::move(textures)) { + setup_mesh(); + } + + void draw(Shader &shader) { + GLint diffuse_counter = 1; + GLint specular_counter = 1; + GLint normal_counter = 1; + GLint height_counter = 1; + for (GLint i = 0; i < textures_.size(); ++i) { + glActiveTexture(GL_TEXTURE0 + i + 1); + + std::string number; + std::string name = textures_[i].type; + if (name == "texture_diffuse") number = std::to_string(diffuse_counter++); + else if (name == "texture_specular") number = std::to_string(specular_counter++); + else if (name == "texture_normal") number = std::to_string(normal_counter++); + else if (name == "texture_height") number = std::to_string(height_counter++); + + shader.set_uniform(name + number, i + 1); + glBindTexture(GL_TEXTURE_2D, textures_[i].id); + } + + glBindVertexArray(vao_); + glDrawElements(GL_TRIANGLES, indices_.size(), GL_UNSIGNED_INT, nullptr); + glBindVertexArray(0); + + glActiveTexture(GL_TEXTURE0); + } + +private: + void setup_mesh() { + glGenVertexArrays(1, &vao_); + glGenBuffers(1, &vbo_); + glGenBuffers(1, &ebo_); + + glBindVertexArray(vao_); + glBindBuffer(GL_ARRAY_BUFFER, vbo_); + glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), &vertices_[0], GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(GLuint), &indices_[0], GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), static_cast(nullptr)); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, normal))); + + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, texture_coords))); + + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, tangent))); + + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), + reinterpret_cast(offsetof(Vertex, bitangent))); + + glBindVertexArray(0); + } +}; diff --git a/src/utils/model.h b/src/utils/model.h new file mode 100644 index 0000000..de6612d --- /dev/null +++ b/src/utils/model.h @@ -0,0 +1,238 @@ +#pragma once +#define STB_IMAGE_IMPLEMENTATION + +#include +#include +#include +#include +#include +#include + +#include "mesh.h" +#include "shader.h" + +#include +#include +#include +#include +#include +#include + + +class Model { +private: + std::vector textures_loaded_; + std::vector meshes_; + std::string directory_; + +public: + explicit Model(const std::string &path) { + load_model(path); + } + + void draw(Shader &shader) { + for (auto &mesh : meshes_) mesh.draw(shader); + } + +private: + void load_model(std::string const &path) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | + aiProcess_GenSmoothNormals | + aiProcess_FlipUVs | + aiProcess_CalcTangentSpace); + + if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { + std::cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl; + return; + } + + directory_ = path.substr(0, path.find_last_of('/')); + + process_node(scene->mRootNode, scene); + } + + void process_node(aiNode *node, const aiScene *scene) { + for (GLuint i = 0; i < node->mNumMeshes; ++i) { + aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; + meshes_.push_back(process_mesh(mesh, scene)); + } + + for (GLuint i = 0; i < node->mNumChildren; i++) { + process_node(node->mChildren[i], scene); + } + } + + Mesh process_mesh(aiMesh *mesh, const aiScene *scene) { + std::vector vertices; + std::vector indices; + std::vector textures; + + for (GLuint i = 0; i < mesh->mNumVertices; ++i) { + Vertex vertex{}; + glm::vec3 vector = glm::vec3( + mesh->mVertices[i].x, + mesh->mVertices[i].y, + mesh->mVertices[i].z + ); + + // Positions + vertex.position = vector; + + // Normals + if (mesh->HasNormals()) { + vector.x = mesh->mNormals[i].x; + vector.y = mesh->mNormals[i].y; + vector.z = mesh->mNormals[i].z; + vertex.normal = vector; + } + + // Texture coordinates + if (mesh->mTextureCoords[0]) { + glm::vec2 vec; + vec.x = mesh->mTextureCoords[0][i].x; + vec.y = mesh->mTextureCoords[0][i].y; + vertex.texture_coords = vec; + + vector.x = mesh->mTangents[i].x; + vector.y = mesh->mTangents[i].y; + vector.z = mesh->mTangents[i].z; + vertex.tangent = vector; + + vector.x = mesh->mBitangents[i].x; + vector.y = mesh->mBitangents[i].y; + vector.z = mesh->mBitangents[i].z; + vertex.bitangent = vector; + } else { + vertex.texture_coords = glm::vec2(0.0f, 0.0f); + } + + vertices.push_back(vertex); + } + + for (GLuint i = 0; i < mesh->mNumFaces; ++i) { + aiFace face = mesh->mFaces[i]; + for (GLuint j = 0; j < face.mNumIndices; ++j) { + indices.push_back(face.mIndices[j]); + } + } + + aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex]; + + // 1. Diffuse maps + std::vector diffuse_maps = load_material_textures(material, + aiTextureType_DIFFUSE, + "texture_diffuse"); + textures.insert(textures.end(), diffuse_maps.begin(), diffuse_maps.end()); + + // 2. Specular maps + std::vector specular_maps = load_material_textures(material, + aiTextureType_SPECULAR, + "texture_specular"); + textures.insert(textures.end(), specular_maps.begin(), specular_maps.end()); + + // 3. Normal maps + std::vector normal_maps = load_material_textures(material, + aiTextureType_HEIGHT, + "texture_normal"); + textures.insert(textures.end(), normal_maps.begin(), normal_maps.end()); + + // 4. Height maps + std::vector height_maps = load_material_textures(material, + aiTextureType_AMBIENT, + "texture_height"); + textures.insert(textures.end(), height_maps.begin(), height_maps.end()); + + return Mesh(vertices, indices, textures); + } + + std::vector + load_material_textures(aiMaterial *material, aiTextureType texture_type, const std::string &type_name) { + std::vector textures; + for (GLuint i = 0; i < material->GetTextureCount(texture_type); ++i) { + aiString path; + material->GetTexture(texture_type, i, &path); + + bool is_loaded = false; + for (auto &texture_path : textures_loaded_) { + if (std::strcmp(texture_path.path.data(), path.C_Str()) == 0) { + textures.push_back(texture_path); + is_loaded = true; + break; + } + } + + if (!is_loaded) { + Texture texture; + texture.id = load_texture_from_file(path.C_Str(), directory_); + texture.type = type_name; + texture.path = path.C_Str(); + textures.push_back(texture); + textures_loaded_.push_back(texture); + } + } + + return textures; + } + +public: + static GLuint load_texture_from_file(const char *path, const std::string &dir) { + std::string filename = std::string(path); + filename = dir + '/' + filename; + + GLuint textureID; + glGenTextures(1, &textureID); + + GLint width, height, nrComponents; + GLubyte *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); + if (data) { + GLenum format; + if (nrComponents == 1) format = GL_RED; + else if (nrComponents == 3) format = GL_RGB; + else if (nrComponents == 4) format = GL_RGBA; + + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + stbi_image_free(data); + } else { + std::cout << "Texture failed to load at path: " << path << std::endl; + stbi_image_free(data); + } + + return textureID; + } + + static GLuint load_cubemap(const std::vector &maps) { + GLuint textureID; + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); + + int width, height, nrComponents; + for (GLuint i = 0; i < maps.size(); i++) { + GLubyte *data = stbi_load(maps[i].c_str(), &width, &height, &nrComponents, 0); + if (data) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, + 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + stbi_image_free(data); + } else { + std::cout << "Cubemap texture failed to load at path: " << maps[i] << std::endl; + stbi_image_free(data); + } + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + return textureID; + } +}; diff --git a/src/utils/shader.cpp b/src/utils/shader.cpp new file mode 100644 index 0000000..239dde8 --- /dev/null +++ b/src/utils/shader.cpp @@ -0,0 +1,125 @@ +#include "shader.h" + +#include +#include +#include + +namespace { + std::string read_shader_code(const std::string &filename) { + std::stringstream file_stream; + try { + std::ifstream file(filename.c_str()); + file_stream << file.rdbuf(); + file.close(); + } + catch (std::exception const &e) { + std::cerr << "Error reading shader file: " << e.what() << std::endl; + } + return file_stream.str(); + } +} + +Shader::Shader(const std::string &vertex_filepath, const std::string &fragment_filepath) { + const auto vertex_code = read_shader_code(vertex_filepath); + const auto fragment_code = read_shader_code(fragment_filepath); + compile(vertex_code, fragment_code); + link(); +} + +Shader::~Shader() = default; + +void Shader::compile(const std::string &vertex_code, const std::string &fragment_code) { + const char *vcode = vertex_code.c_str(); + vertex_id_ = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_id_, 1, &vcode, nullptr); + glCompileShader(vertex_id_); + + const char *fcode = fragment_code.c_str(); + fragment_id_ = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_id_, 1, &fcode, nullptr); + glCompileShader(fragment_id_); + check_compile_error(); +} + +void Shader::link() { + program_id_ = glCreateProgram(); + glAttachShader(program_id_, vertex_id_); + glAttachShader(program_id_, fragment_id_); + glLinkProgram(program_id_); + check_linking_error(); + glDeleteShader(vertex_id_); + glDeleteShader(fragment_id_); +} + +void Shader::use() const { + glUseProgram(program_id_); +} + +template<> +void Shader::set_uniform(const std::string &name, int val) { + glUniform1i(glGetUniformLocation(program_id_, name.c_str()), val); +} + +template<> +void Shader::set_uniform(const std::string &name, bool val) { + glUniform1i(glGetUniformLocation(program_id_, name.c_str()), val); +} + +template<> +void Shader::set_uniform(const std::string &name, float val) { + glUniform1f(glGetUniformLocation(program_id_, name.c_str()), val); +} + +template<> +void Shader::set_uniform(const std::string &name, float val1, float val2) { + glUniform2f(glGetUniformLocation(program_id_, name.c_str()), val1, val2); +} + +template<> +void Shader::set_uniform(const std::string &name, float val1, float val2, float val3) { + glUniform3f(glGetUniformLocation(program_id_, name.c_str()), val1, val2, val3); +} + +template<> +void Shader::set_uniform(const std::string &name, float *val) { + glUniformMatrix4fv(glGetUniformLocation(program_id_, name.c_str()), 1, GL_FALSE, val); +} + +template<> +void Shader::set_uniform(const std::string &name, glm::vec3 vec) { + set_uniform(name, vec.x, vec.y, vec.z); +} + +void Shader::check_compile_error() const { + int success; + char infoLog[1024]; + glGetShaderiv(vertex_id_, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex_id_, 1024, nullptr, infoLog); + std::cerr << "Error compiling Vertex Shader:\n" << infoLog << std::endl; + } + glGetShaderiv(fragment_id_, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragment_id_, 1024, nullptr, infoLog); + std::cerr << "Error compiling Fragment Shader:\n" << infoLog << std::endl; + } +} + +void Shader::check_linking_error() const { + int success; + char infoLog[1024]; + glGetProgramiv(program_id_, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(program_id_, 1024, nullptr, infoLog); + std::cerr << "Error Linking Shader Program:\n" << infoLog << std::endl; + } +} + +template +void Shader::set_uniform(const std::string &name, T val) {} + +template +void Shader::set_uniform(const std::string &name, T val1, T val2) {} + +template +void Shader::set_uniform(const std::string &name, T val1, T val2, T val3) {} diff --git a/src/utils/shader.h b/src/utils/shader.h new file mode 100644 index 0000000..e479c59 --- /dev/null +++ b/src/utils/shader.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include +#include + +class Shader { +public: + Shader(const std::string &vertex_filepath, const std::string &fragment_filepath); + ~Shader(); + + void use() const; + + template + void set_uniform(const std::string &name, T val); + + template + void set_uniform(const std::string &name, T val1, T val2); + + template + void set_uniform(const std::string &name, T val1, T val2, T val3); + +private: + void check_compile_error() const; + void check_linking_error() const; + void compile(const std::string &vertex_code, const std::string &fragment_code); + void link(); + +private: + GLuint vertex_id_{}; + GLuint fragment_id_{}; + GLuint program_id_{}; +};