diff --git a/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png new file mode 100644 index 000000000..9716d3124 Binary files /dev/null and b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png differ diff --git a/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png.meta b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png.meta new file mode 100644 index 000000000..d40385c4f --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_linear.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: fc1ba24d4a4141d4d9e9ae0a0d3ecd0a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 0 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: -1 + mipBias: -100 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 0 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png new file mode 100644 index 000000000..9716d3124 Binary files /dev/null and b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png differ diff --git a/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png.meta b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png.meta new file mode 100644 index 000000000..2f875a10b --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Tests/4x4_gray_import_as_srgb.png.meta @@ -0,0 +1,116 @@ +fileFormatVersion: 2 +guid: 0f7acf68f1798ae48a5505519abac457 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 1 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 0 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs b/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs new file mode 100644 index 000000000..3fbb330f4 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs @@ -0,0 +1,74 @@ +using System; +using NUnit.Framework; +using UnityEditor; +using UnityEngine; + +namespace VRMShaders +{ + public sealed class TextureColorSpaceSpecificationTests + { + private static readonly string AssetPath = "Assets/VRMShaders/GLTF/IO/Tests"; + private static readonly Texture2D SrgbGrayTex = AssetDatabase.LoadAssetAtPath($"{AssetPath}/4x4_gray_import_as_srgb.png"); + private static readonly Texture2D LinearGrayTex = AssetDatabase.LoadAssetAtPath($"{AssetPath}/4x4_gray_import_as_linear.png"); + private static readonly Color32 JustGray = new Color32(127, 127, 127, 255); + private static readonly Color32 SrgbGrayInSrgb = JustGray; + private static readonly Color32 SrgbGrayInLinear = ((Color) SrgbGrayInSrgb).linear; + private static readonly Color32 LinearGrayInLinear = JustGray; + private static readonly Color32 LinearGrayInSrgb = ((Color) LinearGrayInLinear).gamma; + + [Test] + public void InputAssetsRawImage() + { + Assert.AreEqual(SrgbGrayInSrgb, GetFirstPixelInTexture2D(SrgbGrayTex)); + + // Image color space is sRGB even through Texture color space was Linear. + Assert.AreEqual(SrgbGrayInSrgb, GetFirstPixelInTexture2D(LinearGrayTex)); + } + + [Test] + public void CopyToSrgbRenderTexture() + { + var srgbRt = RenderTexture.GetTemporary(4, 4, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + + Graphics.Blit(SrgbGrayTex, srgbRt); + Assert.AreEqual(SrgbGrayInSrgb, GetFirstPixelInRenderTexture(srgbRt)); + + Graphics.Blit(LinearGrayTex, srgbRt); + Assert.AreEqual(LinearGrayInSrgb, GetFirstPixelInRenderTexture(srgbRt)); + + RenderTexture.ReleaseTemporary(srgbRt); + } + + [Test] + public void CopyToLinearRenderTexture() + { + var linearRt = RenderTexture.GetTemporary(4, 4, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); + + Graphics.Blit(SrgbGrayTex, linearRt); + Assert.AreEqual(SrgbGrayInLinear, GetFirstPixelInRenderTexture(linearRt)); + + Graphics.Blit(LinearGrayTex, linearRt); + Assert.AreEqual(LinearGrayInLinear, GetFirstPixelInRenderTexture(linearRt)); + + RenderTexture.ReleaseTemporary(linearRt); + } + + private Color32 GetFirstPixelInTexture2D(Texture2D tex) + { + return tex.GetPixels32()[0]; + } + + private Color32 GetFirstPixelInRenderTexture(RenderTexture rt) + { + // This function copies memory values and just read, so Texture2D's color space is not important. + var srgbTex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, mipChain: false, linear: false); + RenderTexture.active = rt; + srgbTex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); + srgbTex.Apply(); + RenderTexture.active = null; + var pixel = GetFirstPixelInTexture2D(srgbTex); + UnityEngine.Object.DestroyImmediate(srgbTex); + return pixel; + } + } +} diff --git a/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs.meta b/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs.meta new file mode 100644 index 000000000..a430c5519 --- /dev/null +++ b/Assets/VRMShaders/GLTF/IO/Tests/TextureColorSpaceSpecificationTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 19082be49cd24881a2f53c13de83ac70 +timeCreated: 1621413009 \ No newline at end of file