From: Richard Date: Tue, 13 Dec 2022 17:09:21 +0000 (+0000) Subject: Equirectangular projection support for Skybox X-Git-Tag: dali_2.2.6~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-demo.git;a=commitdiff_plain;h=refs%2Fchanges%2F98%2F285498%2F3 Equirectangular projection support for Skybox Change-Id: Idc94667e91f62508531745ed3c037561da4130b8 --- diff --git a/examples/rendering-skybox/rendering-skybox.cpp b/examples/rendering-skybox/rendering-skybox.cpp index c0083b9..d6bf994 100644 --- a/examples/rendering-skybox/rendering-skybox.cpp +++ b/examples/rendering-skybox/rendering-skybox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ #include "generated/rendering-skybox-cube-frag.h" #include "generated/rendering-skybox-cube-vert.h" +#include "generated/rendering-skybox-equirectangular-frag.h" #include "generated/rendering-skybox-frag.h" #include "generated/rendering-skybox-vert.h" #include "look-camera.h" @@ -40,6 +41,15 @@ const unsigned int SKYBOX_FACE_COUNT = 6; const unsigned int SKYBOX_FACE_WIDTH = 2048; const unsigned int SKYBOX_FACE_HEIGHT = 2048; +/** + * @brief The skybox types supported by the application. + */ +enum class SkyboxType +{ + CUBEMAP, ///< Skybox in cubemap + EQUIRECTANGULAR ///< Skybox in equirectangular projection +}; + /* * Credit to Joey do Vries for the following cubemap images * Take from git://github.com/JoeyDeVries/LearnOpenGL.git @@ -55,6 +65,13 @@ const char* SKYBOX_FACES[SKYBOX_FACE_COUNT] = DEMO_IMAGE_DIR "lake_back.jpg", DEMO_IMAGE_DIR "lake_front.jpg"}; +/* + * Take from Wikimedia Commons, the free media repository + * https://commons.wikimedia.org + * The image is licensed under the terms of the CC BY-SA 4.0 license: + * https://creativecommons.org/licenses/by-sa/4.0 + */ +const char* EQUIRECTANGULAR_TEXTURE_URL = DEMO_IMAGE_DIR "veste_oberhaus_spherical_panoramic.jpg"; } // namespace // This example shows how to create a skybox @@ -65,7 +82,8 @@ class TexturedCubeController : public ConnectionTracker { public: TexturedCubeController(Application& application) - : mApplication(application) + : mApplication(application), + mCurrentSkyboxType(SkyboxType::CUBEMAP) { // Connect to the Application's Init signal mApplication.InitSignal().Connect(this, &TexturedCubeController::Create); @@ -101,13 +119,18 @@ public: // The depth test is enabled, the shader sets 1.0, which is the maximum depth and // the depth function is set to LESS or EQUAL so the fragment shader will run only // in those pixels that any other object has written on them. - DisplaySkybox(); + DisplaySkybox(mCurrentSkyboxType); // Step 6. Play animation to rotate the cube PlayAnimation(); // Respond to key events window.KeyEventSignal().Connect(this, &TexturedCubeController::OnKeyEvent); + + // Create a tap gesture detector to detect double tap + mDoubleTapGesture = TapGestureDetector::New(2); + mDoubleTapGesture.Attach(window.GetRootLayer()); + mDoubleTapGesture.DetectedSignal().Connect(this, &TexturedCubeController::OnDoubleTap); } /** @@ -127,6 +150,20 @@ public: } } + void OnDoubleTap(Actor /*actor*/, const TapGesture& /*gesture*/) + { + if(mCurrentSkyboxType == SkyboxType::CUBEMAP) + { + mCurrentSkyboxType = SkyboxType::EQUIRECTANGULAR; + } + else + { + mCurrentSkyboxType = SkyboxType::CUBEMAP; + } + + DisplaySkybox(mCurrentSkyboxType); + } + /** * @brief Setup a perspective camera pointing in the negative Z direction */ @@ -148,8 +185,9 @@ public: */ void CreateShaders() { - mShaderCube = Shader::New(SHADER_RENDERING_SKYBOX_CUBE_VERT, SHADER_RENDERING_SKYBOX_CUBE_FRAG); - mShaderSkybox = Shader::New(SHADER_RENDERING_SKYBOX_VERT, SHADER_RENDERING_SKYBOX_FRAG); + mShaderCube = Shader::New(SHADER_RENDERING_SKYBOX_CUBE_VERT, SHADER_RENDERING_SKYBOX_CUBE_FRAG); + mShaderSkybox = Shader::New(SHADER_RENDERING_SKYBOX_VERT, SHADER_RENDERING_SKYBOX_FRAG); + mShaderSkyboxEquirectangular = Shader::New(SHADER_RENDERING_SKYBOX_VERT, SHADER_RENDERING_SKYBOX_EQUIRECTANGULAR_FRAG); } /** @@ -330,21 +368,41 @@ public: /** * Display a skybox surrounding the camera */ - void DisplaySkybox() + void DisplaySkybox(SkyboxType type) { - // Load skybox faces from file - Texture texture = Texture::New(TextureType::TEXTURE_CUBE, Pixel::RGBA8888, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT); - for(unsigned int i = 0; i < SKYBOX_FACE_COUNT; i++) + mSkyboxTextures.Reset(); + mSkyboxRenderer.Reset(); + mSkyboxActor.Reset(); + + Texture texture; + + if(type == SkyboxType::CUBEMAP) + { + // Load skybox faces from file + texture = Texture::New(TextureType::TEXTURE_CUBE, Pixel::RGBA8888, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT); + for(unsigned int i = 0; i < SKYBOX_FACE_COUNT; i++) + { + PixelData pixels = SyncImageLoader::Load(SKYBOX_FACES[i]); + texture.Upload(pixels, CubeMapLayer::POSITIVE_X + i, 0, 0, 0, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT); + } + + mSkyboxRenderer = Renderer::New(mSkyboxGeometry, mShaderSkybox); + } + else { - PixelData pixels = SyncImageLoader::Load(SKYBOX_FACES[i]); - texture.Upload(pixels, CubeMapLayer::POSITIVE_X + i, 0, 0, 0, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT); + // Load equirectangular image from file + PixelData pixels = SyncImageLoader::Load(EQUIRECTANGULAR_TEXTURE_URL); + + texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight()); + texture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight()); + + mSkyboxRenderer = Renderer::New(mSkyboxGeometry, mShaderSkyboxEquirectangular); } // create TextureSet mSkyboxTextures = TextureSet::New(); mSkyboxTextures.SetTexture(0, texture); - mSkyboxRenderer = Renderer::New(mSkyboxGeometry, mShaderSkybox); mSkyboxRenderer.SetTextures(mSkyboxTextures); mSkyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f); @@ -385,6 +443,7 @@ private: Shader mShaderCube; Shader mShaderSkybox; + Shader mShaderSkyboxEquirectangular; Geometry mGeometry; TextureSet mTextureSet; @@ -396,6 +455,9 @@ private: TextureSet mSkyboxTextures; Renderer mSkyboxRenderer; Actor mSkyboxActor; + + TapGestureDetector mDoubleTapGesture; + SkyboxType mCurrentSkyboxType; }; int DALI_EXPORT_API main(int argc, char** argv) diff --git a/examples/rendering-skybox/shaders/rendering-skybox-equirectangular.frag b/examples/rendering-skybox/shaders/rendering-skybox-equirectangular.frag new file mode 100644 index 0000000..e38d7e8 --- /dev/null +++ b/examples/rendering-skybox/shaders/rendering-skybox-equirectangular.frag @@ -0,0 +1,35 @@ +// Fragment shader for a skybox in equirectangular projection +precision mediump float; + +uniform sampler2D uSkyBoxEquirectangularTexture; + +varying vec3 vTexCoord; + +// Take the sample direction as interpolated from the cube's local position, +// and use this direction vector and the spherical to cartesian coordinate +// conversion to sample the equirectangular map as if it's a cube map. + +const float M_1_PI = 0.3183; // The reciprocal of pi in radians +const float M_1_2PI = 0.1591; // The reciprocal of 2*pi in radians + +const vec2 inverseAtan = vec2(M_1_2PI, M_1_PI); + +vec2 SampleEquirectangularMapAsCubeMap(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= inverseAtan; + uv += 0.5; + return uv; +} + +void main() +{ + // Project the equirectangular map to a cube's faces + vec2 uv = SampleEquirectangularMapAsCubeMap(normalize(vTexCoord)); + + // Flip the texture UVs vertically + vec2 uvFlippped = vec2(uv.x, 1.0 - uv.y); + + vec4 texColor = texture2D( uSkyBoxEquirectangularTexture, uvFlippped ); + gl_FragColor = texColor; +} diff --git a/resources/images/veste_oberhaus_spherical_panoramic.jpg b/resources/images/veste_oberhaus_spherical_panoramic.jpg new file mode 100644 index 0000000..b0781b5 Binary files /dev/null and b/resources/images/veste_oberhaus_spherical_panoramic.jpg differ