├── .gitignore ├── labeled_skybox.xcf ├── docimgs ├── shifted_net.png ├── array_format.png └── expected_net.png ├── assets └── labeled_skybox.png ├── README.tpl ├── .github └── workflows │ └── rust.yml ├── Cargo.toml ├── CONTRIBUTING.md ├── src ├── skybox.vert ├── skybox.frag └── lib.rs ├── examples └── simple.rs ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /labeled_skybox.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/bevy_skybox_cubemap/HEAD/labeled_skybox.xcf -------------------------------------------------------------------------------- /docimgs/shifted_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/bevy_skybox_cubemap/HEAD/docimgs/shifted_net.png -------------------------------------------------------------------------------- /assets/labeled_skybox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/bevy_skybox_cubemap/HEAD/assets/labeled_skybox.png -------------------------------------------------------------------------------- /docimgs/array_format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/bevy_skybox_cubemap/HEAD/docimgs/array_format.png -------------------------------------------------------------------------------- /docimgs/expected_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/bevy_skybox_cubemap/HEAD/docimgs/expected_net.png -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | [![Crates.io](https://img.shields.io/crates/v/bevy_skybox_cubemap.svg)](https://crates.io/crates/bevy_skybox_cubemap) 2 | [![Docs.rs](https://img.shields.io/docsrs/bevy_skybox_cubemap)](https://docs.rs/bevy_skybox_cubemap) 3 | {{badges}} 4 | 5 | # Bevy Skybox Cubemap 6 | 7 | {{readme}} 8 | 9 | License: {{license}} 10 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Install alsa and udev 19 | run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev 20 | - name: Build 21 | run: cargo build --verbose 22 | - name: Run tests 23 | run: cargo test --verbose 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bevy_skybox_cubemap" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Zachary Stewart "] 6 | description = "Cubemap-based Skyboxes for Bevy Engine." 7 | homepage = "https://github.com/google/bevy_skybox_cubemap" 8 | repository = "https://github.com/google/bevy_skybox_cubemap" 9 | license = "Apache-2.0" 10 | keywords = ["bevy", "skybox", "gamedev", "graphics"] 11 | categories = ["game-engines", "graphics"] 12 | exclude = [ 13 | "docimgs/", 14 | "*.xcf", 15 | ".github/", 16 | ] 17 | 18 | [badges] 19 | github = { repository = "google/bevy_skybox_cubemap", workflow = "Rust" } 20 | maintenance = { status = "passively-maintained" } 21 | 22 | [dependencies.bevy] 23 | version = "0.5.0" 24 | default-features = false 25 | features = ["render"] 26 | 27 | [dev-dependencies] 28 | bevy = "0.5.0" 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement (CLA). You (or your employer) retain the copyright to your 10 | contribution; this simply gives us permission to use and redistribute your 11 | contributions as part of the project. Head over to 12 | to see your current agreements on file or 13 | to sign a new one. 14 | 15 | You generally only need to submit a CLA once, so if you've already submitted one 16 | (even if it was for a different project), you probably don't need to do it 17 | again. 18 | 19 | ## Code Reviews 20 | 21 | All submissions, including submissions by project members, require review. We 22 | use GitHub pull requests for this purpose. Consult 23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 24 | information on using pull requests. 25 | 26 | ## Community Guidelines 27 | 28 | This project follows 29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 30 | -------------------------------------------------------------------------------- /src/skybox.vert: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #version 450 16 | layout(location = 0) in vec3 Vertex_Position; 17 | 18 | layout(set = 0, binding = 0) uniform CameraViewProj { 19 | mat4 ViewProj; 20 | }; 21 | layout(set = 0, binding = 1) uniform CameraView { 22 | mat4 View; 23 | }; 24 | layout(set = 1, binding = 0) uniform Transform { 25 | mat4 Model; 26 | }; 27 | 28 | layout(location = 0) out vec3 TexCoords; 29 | 30 | void main() { 31 | // ViewProj is Proj * inverse(View). We want to get Proj * inverse(untranslatedView). However, 32 | // the only bindings available are ProjView and View. So we first get untranslatedView by 33 | // removing the translation from the View matrix (by clearing the last column), then multiply 34 | // ProjView * View to undo the earlier Proj * inverse(View). Then we multiply by the 35 | // untranslated view to get a projection matrix that has the camera's rotation but not position. 36 | mat4 untranslatedView = View; 37 | untranslatedView[3] = vec4(0.0, 0.0, 0.0, 1.0); 38 | 39 | mat4 untranslatedProj = ViewProj * View * inverse(untranslatedView); 40 | 41 | // We allow rotating the skybox, but not translating (since we need the position to match the 42 | // zeroed camera position). To do that, remove the translation from the model matrix. 43 | mat4 untranslatedModel = Model; 44 | untranslatedModel[3] = vec4(0.0, 0.0, 0.0, 1.0); 45 | 46 | vec4 pos = untranslatedProj * untranslatedModel * vec4(Vertex_Position, 1.0); 47 | // Use w as z to force the point as far back a possible for depth testing purposes. This makes 48 | // sure it never draws in front of anything else. 49 | gl_Position = pos.xyww; 50 | 51 | // Since we're sampling a cubemap, texcoords is just the vertex coordinate. 52 | TexCoords = Vertex_Position; 53 | } 54 | -------------------------------------------------------------------------------- /src/skybox.frag: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #version 450 16 | layout(location = 0) in vec3 TexCoords; 17 | 18 | layout(set = 2, binding = 0) uniform SkyboxMaterial_color { 19 | vec4 color; 20 | }; 21 | #ifdef SKYBOXMATERIAL_TEXTURE 22 | layout(set = 2, binding = 1) uniform texture2DArray SkyboxMaterial_texture; 23 | layout(set = 2, binding = 2) uniform sampler SkyboxMaterial_texture_sampler; 24 | #endif 25 | 26 | layout(location = 0) out vec4 o_Target; 27 | 28 | // This is a handwritten cubemap sampler. We should use the shader language's builtin cubemap 29 | // sampling, but that doesn't work right now because Bevy has a bug binding cubemaps currently. 30 | // So instead we just write our own cubemap sampler and use an array texture, which does work 31 | // correctly. 32 | // TODO: Just use a normal cubemap once those work in bevy. 33 | vec3 sampleCubeHacky(const vec3 ray) { 34 | vec3 rayAbs = abs(ray); 35 | float maxAdjust; 36 | float faceIndex; 37 | vec2 uv; 38 | if (rayAbs.z >= rayAbs.x && rayAbs.z >= rayAbs.y) { 39 | faceIndex = ray.z < 0.0 ? 5.0 : 4.0; 40 | maxAdjust = 0.5 / rayAbs.z; 41 | uv = vec2(ray.x * -sign(ray.z), -ray.y); 42 | } else if (rayAbs.y >= rayAbs.x) { 43 | faceIndex = ray.y < 0.0 ? 3.0 : 2.0; 44 | maxAdjust = 0.5 / ray.y; 45 | uv = vec2(ray.x * sign(ray.y), -ray.z); 46 | } else { 47 | faceIndex = ray.x < 0.0 ? 1.0 : 0.0; 48 | maxAdjust = 0.5 / ray.x; 49 | uv = vec2(ray.z, ray.y * -sign(ray.x)); 50 | } 51 | return vec3(uv * maxAdjust + 0.5, faceIndex); 52 | } 53 | 54 | void main() { 55 | #ifdef SKYBOXMATERIAL_TEXTURE 56 | vec3 uvIndex = sampleCubeHacky(TexCoords); 57 | o_Target = texture( 58 | sampler2DArray(SkyboxMaterial_texture, SkyboxMaterial_texture_sampler), 59 | uvIndex 60 | ) * color; 61 | 62 | // This is how this should work. 63 | // o_Target = texture( 64 | // samplerCube(SkyboxMaterial_texture, SkyboxMaterial_texture_sampler), 65 | // TexCoords 66 | // ) * color; 67 | #else 68 | o_Target = color; 69 | #endif 70 | } 71 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use bevy::prelude::*; 16 | use bevy::render::camera::{Camera, PerspectiveProjection}; 17 | use bevy_skybox_cubemap::{SkyboxBundle, SkyboxMaterial, SkyboxPlugin, SkyboxTextureConversion}; 18 | 19 | fn main() { 20 | App::build() 21 | .insert_resource(ClearColor(Color::PINK)) 22 | .insert_resource(Msaa { samples: 4 }) 23 | .add_plugins(DefaultPlugins) 24 | .add_plugin(SkyboxPlugin) 25 | .add_startup_system(setup.system()) 26 | .add_system(spin_camera.system()) 27 | .run(); 28 | } 29 | 30 | fn spin_camera( 31 | time: Res