From 3c884ed3f0844c6d63f94337fb15353a85a0ea48 Mon Sep 17 00:00:00 2001 From: Piotr Date: Sat, 26 Sep 2020 18:38:39 +0200 Subject: [PATCH] Skybox --- resources/shaders/skybox.fs | 11 +++++ resources/shaders/skybox.vs | 14 ++++++ src/example_client.rs | 23 +++++---- src/gaia/mod.rs | 1 + src/gaia/sky.rs | 95 +++++++++++++++++++++++++++++++++++++ src/gaia/utils.rs | 64 +++++++++++++++++++++++++ 6 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 resources/shaders/skybox.fs create mode 100644 resources/shaders/skybox.vs create mode 100644 src/gaia/sky.rs diff --git a/resources/shaders/skybox.fs b/resources/shaders/skybox.fs new file mode 100644 index 0000000..2205847 --- /dev/null +++ b/resources/shaders/skybox.fs @@ -0,0 +1,11 @@ +#version 330 core +out vec4 FragColor; + +in vec3 TexCoords; + +uniform samplerCube skybox; + +void main() +{ + FragColor = texture(skybox, TexCoords); +} diff --git a/resources/shaders/skybox.vs b/resources/shaders/skybox.vs new file mode 100644 index 0000000..f3e48d6 --- /dev/null +++ b/resources/shaders/skybox.vs @@ -0,0 +1,14 @@ +#version 330 core +layout (location = 0) in vec3 aPos; + +out vec3 TexCoords; + +uniform mat4 projection; +uniform mat4 view; + +void main() +{ + TexCoords = aPos; + vec4 pos = projection * view * vec4(aPos, 1.0); + gl_Position = pos.xyww; +} diff --git a/src/example_client.rs b/src/example_client.rs index 40a1066..d3c404c 100644 --- a/src/example_client.rs +++ b/src/example_client.rs @@ -4,6 +4,7 @@ use crate::gaia::client::Client; use crate::gaia::components::{ModelComponent, Transform}; use crate::gaia::consts; use crate::gaia::engine::Engine; +use crate::gaia::sky::Sky; use crate::gaia::*; use cgmath::{perspective, vec3, Deg, Matrix4, Point3}; use imgui_glfw_rs::glfw; @@ -12,6 +13,7 @@ pub struct ExampleClient { models: Vec, camera: Camera, shader: shader::Shader, + sky: Sky, show_object_info: bool, show_camera_info: bool, object_info_id: i32, @@ -19,6 +21,10 @@ pub struct ExampleClient { impl ExampleClient { pub fn create() -> ExampleClient { + let sky; + unsafe { + sky = Sky::new(); + } ExampleClient { object_info_id: 0, show_camera_info: true, @@ -37,6 +43,7 @@ impl ExampleClient { "resources/shaders/model_loading.vs", "resources/shaders/model_loading.fs", ), + sky: sky, } } } @@ -60,10 +67,7 @@ impl Client for ExampleClient { scale: vec3(2.5, 2.5, 2.5), ..Transform::default() }, - model: cache.get_model_ext( - "resources/objects/tree/tree_6_d.obj", - Some("tree_e.png") - ), + model: cache.get_model_ext("resources/objects/tree/tree_6_d.obj", Some("tree_e.png")), }; let tree2 = ModelComponent { transform: Transform { @@ -71,10 +75,7 @@ impl Client for ExampleClient { scale: vec3(2.5, 2.5, 2.5), ..Transform::default() }, - model: cache.get_model_ext( - "resources/objects/tree/tree_6_c.obj", - Some("tree_e.png") - ), + model: cache.get_model_ext("resources/objects/tree/tree_6_c.obj", Some("tree_e.png")), }; let tree3 = ModelComponent { transform: Transform { @@ -82,10 +83,7 @@ impl Client for ExampleClient { scale: vec3(2.5, 2.5, 2.5), ..Transform::default() }, - model: cache.get_model_ext( - "resources/objects/tree/tree_6_c.obj", - Some("tree_e.png") - ), + model: cache.get_model_ext("resources/objects/tree/tree_6_c.obj", Some("tree_e.png")), }; self.models = vec![tree, tree2, tree3, ground, robot]; } @@ -107,6 +105,7 @@ impl Client for ExampleClient { for model in self.models.iter() { model.draw(&self.shader); } + self.sky.draw(view, projection); } fn update(&mut self, _engine: &mut Engine) {} diff --git a/src/gaia/mod.rs b/src/gaia/mod.rs index a1432be..be2ac52 100644 --- a/src/gaia/mod.rs +++ b/src/gaia/mod.rs @@ -10,4 +10,5 @@ pub mod engine; pub mod mesh; pub mod model; pub mod shader; +pub mod sky; pub mod utils; diff --git a/src/gaia/sky.rs b/src/gaia/sky.rs new file mode 100644 index 0000000..3425a59 --- /dev/null +++ b/src/gaia/sky.rs @@ -0,0 +1,95 @@ +use crate::gaia::camera::*; +use crate::gaia::shader::*; +use crate::gaia::utils::*; +use cgmath::Matrix4; +use gl::types::*; +use std::mem; +use std::os::raw::c_void; +use std::ptr; + +pub struct Sky { + shader: Shader, + texture_id: u32, + vao: u32, + vbo: u32, +} + +impl Drop for Sky { + fn drop(&mut self) { + unsafe { + gl::DeleteVertexArrays(1, &self.vao); + gl::DeleteBuffers(1, &self.vbo); + } + } +} + +impl Sky { + pub unsafe fn new() -> Sky { + let shader = + Shader::from_file("resources/shaders/skybox.vs", "resources/shaders/skybox.fs"); + + let skybox_vertices: [f32; 108] = [ + // positions + -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, + -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, + -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, + -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, + ]; + + // skybox VAO + let (mut skybox_vao, mut skybox_vbo) = (0, 0); + gl::GenVertexArrays(1, &mut skybox_vao); + gl::GenBuffers(1, &mut skybox_vbo); + gl::BindVertexArray(skybox_vao); + gl::BindBuffer(gl::ARRAY_BUFFER, skybox_vbo); + gl::BufferData( + gl::ARRAY_BUFFER, + (skybox_vertices.len() * mem::size_of::()) as GLsizeiptr, + &skybox_vertices[0] as *const f32 as *const c_void, + gl::STATIC_DRAW, + ); + gl::EnableVertexAttribArray(0); + let stride = 3 * mem::size_of::() as GLsizei; + gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null()); + + let faces = [ + "resources/textures/skybox/right.jpg", + "resources/textures/skybox/left.jpg", + "resources/textures/skybox/top.jpg", + "resources/textures/skybox/bottom.jpg", + "resources/textures/skybox/back.jpg", + "resources/textures/skybox/front.jpg", + ]; + let cubemap_texture = load_cubemap(&faces); + shader.use_program(); + shader.setInt(c_str!("skybox"), 0); + + Sky { + shader: shader, + texture_id: cubemap_texture, + vao: skybox_vao, + vbo: skybox_vbo, + } + } + + pub unsafe fn draw(&mut self, mut view: Matrix4, projection: Matrix4) { + gl::DepthFunc(gl::LEQUAL); // change depth function so depth test passes when values are equal to depth buffer's content + self.shader.use_program(); + // remove translation from the view matrix + view.w[0] = 0.0; + view.w[1] = 0.0; + view.w[2] = 0.0; + self.shader.set_mat4(c_str!("view"), &view); + self.shader.set_mat4(c_str!("projection"), &projection); + // skybox cube + gl::BindVertexArray(self.vao); + gl::ActiveTexture(gl::TEXTURE0); + gl::BindTexture(gl::TEXTURE_CUBE_MAP, self.texture_id); + gl::DrawArrays(gl::TRIANGLES, 0, 36); + gl::BindVertexArray(0); + gl::DepthFunc(gl::LESS); // set depth function back to default + } +} diff --git a/src/gaia/utils.rs b/src/gaia/utils.rs index bda2ee2..320c5d4 100644 --- a/src/gaia/utils.rs +++ b/src/gaia/utils.rs @@ -61,3 +61,67 @@ pub unsafe fn load_texture_from_dir(filename: &str, directory: &str) -> u32 { load_texture(&fullpath, format) } + +/// loads a cubemap texture from 6 individual texture faces +/// order: +/// +X (right) +/// -X (left) +/// +Y (top) +/// -Y (bottom) +/// +Z (front) +/// -Z (back) +/// ------------------------------------------------------- +pub unsafe fn load_cubemap(faces: &[&str]) -> u32 { + let mut texture_id = 0; + gl::GenTextures(1, &mut texture_id); + gl::BindTexture(gl::TEXTURE_CUBE_MAP, texture_id); + + for (i, face) in faces.iter().enumerate() { + let (data, dim) = { + let img: ImagePtr = io::read_u8(face).unwrap(); + let img_data = img.data().to_vec(); + let (x, y, _) = img.shape(); + + (img_data, (x as i32, y as i32)) + }; + gl::TexImage2D( + gl::TEXTURE_CUBE_MAP_POSITIVE_X + i as u32, + 0, + gl::RGB as i32, + dim.0, + dim.1, + 0, + gl::RGB, + gl::UNSIGNED_BYTE, + &data[0] as *const u8 as *const c_void, + ); + } + + gl::TexParameteri( + gl::TEXTURE_CUBE_MAP, + gl::TEXTURE_MIN_FILTER, + gl::LINEAR as i32, + ); + gl::TexParameteri( + gl::TEXTURE_CUBE_MAP, + gl::TEXTURE_MAG_FILTER, + gl::LINEAR as i32, + ); + gl::TexParameteri( + gl::TEXTURE_CUBE_MAP, + gl::TEXTURE_WRAP_S, + gl::CLAMP_TO_EDGE as i32, + ); + gl::TexParameteri( + gl::TEXTURE_CUBE_MAP, + gl::TEXTURE_WRAP_T, + gl::CLAMP_TO_EDGE as i32, + ); + gl::TexParameteri( + gl::TEXTURE_CUBE_MAP, + gl::TEXTURE_WRAP_R, + gl::CLAMP_TO_EDGE as i32, + ); + + texture_id +}