diff --git a/models/skybox.obj b/models/skybox.obj new file mode 100644 index 0000000000000000000000000000000000000000..efca9edd0d9b4141fd45d9da514b346068dd1844 --- /dev/null +++ b/models/skybox.obj @@ -0,0 +1,38 @@ +# Blender 4.2.3 LTS +# www.blender.org +o Cube +v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -1.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +s 0 +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/4/2 7/6/2 8/7/2 +f 8/8/3 7/9/3 5/10/3 6/11/3 +f 6/12/4 2/13/4 4/5/4 8/14/4 +f 2/13/5 1/1/5 3/4/5 4/5/5 +f 6/11/6 5/10/6 1/1/6 2/13/6 diff --git a/shaders/skybox.frag b/shaders/skybox.frag new file mode 100644 index 0000000000000000000000000000000000000000..3e105bbb588eb52bb6d851b8e64a6b484fa97340 --- /dev/null +++ b/shaders/skybox.frag @@ -0,0 +1,24 @@ +#version 150 + +in vec3 position; + +out vec4 out_Color; + +uniform sampler2D sky; + +const float PI = 3.1415926535897f; + +vec2 sphere_uv(vec3 direction) +{ + float u = 0.5 + atan(direction.z, direction.x) / (2 * PI); + float v = 0.5 + asin(direction.y) / PI; + + return vec2(u, v); +} + +void main(void) +{ + out_Color = texture(sky, sphere_uv(normalize(position))); + // out_Color = vec4(0, sphere_uv(normalize(position)), 1.0); +} + diff --git a/shaders/skybox.vert b/shaders/skybox.vert new file mode 100644 index 0000000000000000000000000000000000000000..2feb43e1cc1f56a35ce9b389f0bd5c9b2eae2ec6 --- /dev/null +++ b/shaders/skybox.vert @@ -0,0 +1,18 @@ +#version 150 + +in vec3 in_Position; +in vec3 in_Normal; +in vec2 in_TexCoord; + +uniform mat4 projectionMatrix; +uniform mat4 modelToWorldToView; + +out vec3 position; + +void main(void) +{ + position = in_Position; + vec4 view_pos = vec4(mat3(modelToWorldToView) * in_Position.xyz, 1.0); + gl_Position = projectionMatrix * view_pos; +} + diff --git a/src/main.cpp b/src/main.cpp index ae8883a13c31341825c64dc0ac78000ed1027f5e..51b4f34594bf5743786b035a6508504f6688232a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #define MAIN #include "GL_utilities.h" #include "LittleOBJLoader.h" +#include "LoadTGA.h" #include "MicroGlut.h" #include "VectorUtils4.h" // uses framework OpenGL @@ -17,11 +18,13 @@ struct Object { Object() = default; - template <typename Func> - void draw(Func func) const + void use() const { glUseProgram(program); - func(program); + } + + void draw() const + { DrawModel(model, program, "in_Position", "in_Normal", "in_TexCoord"); } }; @@ -30,51 +33,143 @@ struct Scene { Object ground; Object surface; Object waterfall; + Object skybox; + + GLuint skybox_tex; + mat4 proj_matrix = perspective(70.0, 1.0, 0.2, 20.0); + vec3 pos; + float yaw; + float pitch; mat4 view_matrix = lookAtv(vec3(-5, 4, -5), vec3(0, 0, 0), vec3(0, 1, 0)); - void init() { Model* ground_model = LoadModel("models/ground.obj"); Model* surface_model = LoadModel("models/surface.obj"); Model* waterfall_model = LoadModel("models/waterfall.obj"); + Model* skybox_model = LoadModel("models/skybox.obj"); // This is not a ground logic program GLuint ground_program = loadShaders("shaders/basic.vert", "shaders/ground.frag"); GLuint surface_program = loadShaders("shaders/surface.vert", "shaders/surface.frag"); GLuint waterfall_program = loadShaders("shaders/basic.vert", "shaders/waterfall.frag"); + GLuint skybox_program = loadShaders("shaders/skybox.vert", "shaders/skybox.frag"); printError("compiled shaders"); - std::cout << "ground prog: " << ground_program << "\n"; - std::cout << "surf prog: " << surface_program << "\n"; - std::cout << "wfall prog: " << waterfall_program << "\n"; ground = Object { ground_model, ground_program }; surface = Object { surface_model, surface_program }; waterfall = Object { waterfall_model, waterfall_program }; + skybox = Object { skybox_model, skybox_program }; + + LoadTGATextureSimple("textures/sky4k.tga", &skybox_tex); + glBindTexture(GL_TEXTURE_2D, skybox_tex); + printError("bind texture"); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + printError("tex parameteri"); + } + + void do_keyboard_input() + { + vec3 fwd = vec3(sin(yaw), 0, -cos(yaw)); + vec3 right = vec3(cos(yaw), 0, sin(yaw)); + vec3 up = vec3(0, 1, 0); + float speed = 0.3; + + if (glutKeyIsDown('w')) { + pos += speed * fwd; + } + if (glutKeyIsDown('s')) { + pos -= speed * fwd; + } + if (glutKeyIsDown('d')) { + pos += speed * right; + } + if (glutKeyIsDown('a')) { + pos -= speed * right; + } + if (glutKeyIsDown('r')) { + pos += speed * up; + } + if (glutKeyIsDown('f')) { + pos -= speed * up; + } + } + + void update_view_matrix() + { + vec3 up { 0.0, 1.0, 0.0 }; + mat4 rot = Rx(pitch) * Ry(yaw); + mat4 translation = T(-pos.x, -pos.y, -pos.z); + view_matrix = rot * translation; + } + + void draw_skybox() + { + skybox.use(); + GLuint program = skybox.program; + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); + glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); + glUniform1i(glGetUniformLocation(program, "sky"), 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, skybox_tex); + + + skybox.draw(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + } + + void draw_surface() + { + surface.use(); + GLuint program = surface.program; + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); + glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); + + surface.draw(); + } + + void draw_ground() + { + ground.use(); + GLuint program = ground.program; + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); + glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); + + ground.draw(); + } + + void draw_waterfall() + { + waterfall.use(); + GLuint program = waterfall.program; + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); + glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); + + waterfall.draw(); } void draw() { - ground.draw([&](GLuint program) { - // Add uniforms, texture calls etc. here - glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); - glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); - }); - surface.draw([&](GLuint program) { - // Add uniforms, texture calls etc. here - glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); - glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); - }); - waterfall.draw([&](GLuint program) { - // Add uniforms, texture calls etc. here - glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), 1, GL_TRUE, proj_matrix.m); - glUniformMatrix4fv(glGetUniformLocation(program, "modelToWorldToView"), 1, GL_TRUE, view_matrix.m); - }); + do_keyboard_input(); + update_view_matrix(); + + draw_skybox(); + draw_surface(); + draw_ground(); + draw_waterfall(); } }; -Scene scene{}; +Scene scene {}; +int mouse_x = -1; +int mouse_y = -1; void init(void) { @@ -108,6 +203,35 @@ void display(void) glutSwapBuffers(); } +void on_mouse_move(int x, int y) +{ + const float sensitivity = 0.005f; + if (mouse_y == -1 && mouse_x == -1) { + mouse_x = x; + mouse_y = y; + + return; + } + + int dx = x - mouse_x; + int dy = y - mouse_y; + mouse_x = x; + mouse_y = y; + + scene.pitch -= dy * sensitivity; + scene.yaw += dx * sensitivity; + + scene.pitch = std::max(-1.5f, std::min(1.5f, scene.pitch)); +} + +void on_mouse_button(int button, int state, int x, int y) +{ + if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { + mouse_x = x; + mouse_y = y; + } +} + int main(int argc, char* argv[]) { glutInit(&argc, argv); @@ -118,6 +242,9 @@ int main(int argc, char* argv[]) glutDisplayFunc(display); glutRepeatingTimer(20); init(); + glutMotionFunc(on_mouse_move); + glutMouseFunc(on_mouse_button); + glutMainLoop(); exit(0); } diff --git a/textures/sky.tga b/textures/sky.tga new file mode 100644 index 0000000000000000000000000000000000000000..2cc35a2c7bd7b03f392c4e8438b82514ef51ab03 Binary files /dev/null and b/textures/sky.tga differ diff --git a/textures/sky4k.tga b/textures/sky4k.tga new file mode 100644 index 0000000000000000000000000000000000000000..898ea12aef48efe78cbe1d423dd02ef1cf29d4db Binary files /dev/null and b/textures/sky4k.tga differ