diff --git a/Assets/Plugins/Android/AppInfo.java b/Assets/Plugins/Android/AppInfo.java index 1f7b12c..422eaa5 100644 --- a/Assets/Plugins/Android/AppInfo.java +++ b/Assets/Plugins/Android/AppInfo.java @@ -273,7 +273,7 @@ public class AppInfo extends UnityPlayerActivity { } } - public static DecodedBitmap loadRawImage(String imagePath, int maxWidth, int maxHeight) { + public static DecodedBitmap loadRawImage(String imagePath, int maxPixels) { Log.v(TAG, "Decoding image at " + imagePath); try { @@ -290,8 +290,7 @@ public class AppInfo extends UnityPlayerActivity { // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width smaller than the requested height and width. options.inSampleSize = 1; - while ((height / options.inSampleSize) >= maxHeight - || (width / options.inSampleSize) >= maxWidth) { + while (height / options.inSampleSize * width / options.inSampleSize > maxPixels) { options.inSampleSize *= 2; } Log.v(TAG, "Image sample size: " + options.inSampleSize); diff --git a/Assets/Scripts/SkyboxHandler.cs b/Assets/Scripts/SkyboxHandler.cs index d20bfd0..d4975b0 100644 --- a/Assets/Scripts/SkyboxHandler.cs +++ b/Assets/Scripts/SkyboxHandler.cs @@ -11,10 +11,10 @@ namespace QuestAppLauncher { public class SkyboxHandler : MonoBehaviour { - // Max width and height of skybox image. + // Max pixles of skybox image for both equirectangular and cubemap images. + // We calculate this to be: 2048px x 2048px x 6 faces (for cubemap). // Anything larger we'll scale down. We restrict it primarily due to memory constraints. - const int MaxWidth = 4096; - const int MaxHeight = 4096; + const int MaxPixels = 2048 * 2048 * 6; // Skybox selected callback public Action OnSkyboxSelected; @@ -155,7 +155,7 @@ namespace QuestAppLauncher using (AndroidJavaObject currentActivity = unity.GetStatic("currentActivity")) { // Call Android plugin to load the raw image. - var jo = currentActivity.CallStatic("loadRawImage", MakeAbsoluteSkymapPath(skyboxPath), MaxHeight, MaxWidth); + var jo = currentActivity.CallStatic("loadRawImage", MakeAbsoluteSkymapPath(skyboxPath), MaxPixels); if (null == jo) { return null; @@ -223,13 +223,23 @@ namespace QuestAppLauncher Material material; if (4 * texture.height == 3 * texture.width) { - // Texture is a cube map (4:3 aspect ratio). + // Texture is a horizontal cross cube map (4:3 aspect ratio). // Load cubemap shader. Also rotate x-axis by 180 degrees to compensate for platform-specific rendering differences // (see https://docs.unity3d.com/Manual/SL-PlatformDifferences.html). - Debug.LogFormat("Setting cubemap skybox"); + Debug.LogFormat("Setting horizontal-cross cubemap skybox"); material = new Material(Shader.Find("skybox/cube")); material.SetFloat("_RotationX", 180); - material.SetTexture("_Tex", CubemapFromTexture2D(texture)); + material.SetTexture("_Tex", CubemapFromHorizCrossTexture2D(texture)); + } + else if (6 * texture.height == texture.width) + { + // Texture is a horizontal cube map (6:1 aspect ratio). + // Load cubemap shader. Also rotate x-axis by 180 degrees to compensate for platform-specific rendering differences + // (see https://docs.unity3d.com/Manual/SL-PlatformDifferences.html). + Debug.LogFormat("Setting horizontal cubemap skybox"); + material = new Material(Shader.Find("skybox/cube")); + material.SetFloat("_RotationX", 180); + material.SetTexture("_Tex", CubemapFromHorizTexture2D(texture)); } else { @@ -251,11 +261,15 @@ namespace QuestAppLauncher } /// - /// Gets cubemap from a 2D texture (which represents 6-sided cube) + /// Gets cubemap from a 2D texture that represents 6-sided cube as a horizontal cross: + /// [ ] [ +y ] [ ] + /// [ -x ] [ +z ] [ +x ] + /// [ ] [ -y ] [ ] + /// Note: This is less memory efficient than horizontal representation below. /// /// /// - private static Cubemap CubemapFromTexture2D(Texture2D texture) + private static Cubemap CubemapFromHorizCrossTexture2D(Texture2D texture) { int cubedim = texture.width / 4; Cubemap cube = new Cubemap(cubedim, TextureFormat.ARGB32, false); @@ -269,6 +283,27 @@ namespace QuestAppLauncher return cube; } + /// + /// Gets cubemap from a 2D texture that represents 6-sided cube as a horizontal layout: + /// [ +x ] [ -x ] [ +y ] [ -y ] [ +z ] [ -z ] + /// Note: This is the recommended representation of cube map as it is more efficient in terms of memory. + /// + /// + /// + private static Cubemap CubemapFromHorizTexture2D(Texture2D texture) + { + int cubedim = texture.width / 4; + Cubemap cube = new Cubemap(cubedim, TextureFormat.ARGB32, false); + cube.SetPixels(texture.GetPixels(0, 0, cubedim, cubedim), CubemapFace.PositiveX); + cube.SetPixels(texture.GetPixels(cubedim, 0, cubedim, cubedim), CubemapFace.NegativeX); + cube.SetPixels(texture.GetPixels(2 * cubedim, 0, cubedim, cubedim), CubemapFace.PositiveY); + cube.SetPixels(texture.GetPixels(3 * cubedim, 0, cubedim, cubedim), CubemapFace.NegativeY); + cube.SetPixels(texture.GetPixels(4 * cubedim, 0, cubedim, cubedim), CubemapFace.PositiveZ); + cube.SetPixels(texture.GetPixels(5 * cubedim, 0, cubedim, cubedim), CubemapFace.NegativeZ); + cube.Apply(); + return cube; + } + public void SetDefaultSkybox() { Debug.LogFormat("Setting default skybox");