Пример #1
0
        public static void CompositeMips(Texture2D target, AlloyCustomImportObject source,
                                         AlloyTextureColorCache[] mapCache, AlloyTextureColorCache normalCache, int mipLevel)
        {
            // Basically a 1:1 port of the original shader
            // The only point of major difference is the filtering method used; which is a fraction simpler.

            // This was disabled, since it appears GetPixels results don't appear to be affected by Unity's messing with Linear inputs; the same way they do at runtime. Re-enable if you like.

            int w = Mathf.Max(2, target.width >> mipLevel);
            int h = Mathf.Max(2, target.height >> mipLevel);

            var colors = new Color[w * h];


            float rangeX = (1.0f / (mipLevel + 1)) / target.width;
            float rangeY = (1.0f / (mipLevel + 1)) / target.height;

            UnityEngine.Profiling.Profiler.BeginSample("Composite mips");
            for (int channelIndex = 0; channelIndex < source.PackMode.Channels.Count; channelIndex++)
            {
                var  channel    = source.PackMode.Channels[channelIndex];
                var  inIndices  = channel.InputIndices.ToArray();
                var  outIndices = channel.OutputIndices.ToArray();
                bool hasInputs  = inIndices.Length > 0;

                for (int i = 0; i < outIndices.Length; ++i)
                {
                    int storeIndex = outIndices[i];
                    var tex        = mapCache[storeIndex];
                    var channelVal = source.ChannelValues[storeIndex];

                    if (hasInputs)
                    {
                        int readIndex = inIndices[Mathf.Min(i, inIndices.Length - 1)];

                        tex.SetActiveChannel(readIndex);
                    }

                    bool doInvert = source.DoInvert[storeIndex];
                    bool doNormal = channel.UseNormals && !normalCache.EmptyTexture;
                    bool doNative = hasInputs && tex.NativeSize && mipLevel == 0;

                    UnityEngine.Profiling.Profiler.BeginSample("Blit");
                    for (int x = 0; x < w; ++x)
                    {
                        for (int y = 0; y < h; ++y)
                        {
                            var pixelIndex = x + y * w;
                            var input      = 0.0f;

                            if (!hasInputs || tex.EmptyTexture)
                            {
                                input = channelVal;
                            }
                            else if (doNative)
                            {
                                input = tex.ActiveChannel[pixelIndex];
                            }
                            else
                            {
                                input = tex.GetChannelBilinear((float)x / (w - 1), (float)y / (h - 1), mipLevel, rangeX, rangeY);
                            }

                            if (doInvert)
                            {
                                input = 1.0f - input;
                            }

                            if (doNormal)
                            {
                                Vector3 normal;

                                if (normalCache.NativeSize && mipLevel == 0)
                                {
                                    normal = (Vector4)normalCache.Values[pixelIndex];
                                }
                                else
                                {
                                    normal = normalCache.GetPixelNormal((float)x / (w - 1), (float)y / (h - 1), mipLevel, rangeX,
                                                                        rangeY);
                                }

                                normal.x = (normal.x * 2.0f) - 1.0f;
                                normal.y = (normal.y * 2.0f) - 1.0f;
                                normal.z = (normal.z * 2.0f) - 1.0f;

                                // Specular AA for Beckmann roughness.
                                // cf http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf pg92
                                var variance        = 0.0f;
                                var avgNormalLength = normal.magnitude;
                                var applyAA         = avgNormalLength < 1.0f;

                                if (applyAA)
                                {
                                    float avgNormLen2 = avgNormalLength * avgNormalLength;
                                    float kappa       = (3.0f * avgNormalLength - avgNormalLength * avgNormLen2) / (1.0f - avgNormLen2);

                                    variance = Mathf.Clamp01(1.0f / (2.0f * kappa));// - source.VarianceBias);
                                }

                                if (channel.OutputVariance)
                                {
                                    input = variance;
                                }
                                else if (channel.RoughnessCorrect && applyAA)
                                {
                                    float a = input * input;
                                    a     = Mathf.Sqrt(Mathf.Clamp01(a * a + variance));
                                    input = Mathf.Sqrt(a);
                                }
                            }

                            switch (storeIndex)
                            {
                            case 0: colors[pixelIndex].r = input; break;

                            case 1: colors[pixelIndex].g = input; break;

                            case 2: colors[pixelIndex].b = input; break;

                            case 3: colors[pixelIndex].a = input; break;
                            }
                        }
                    }

                    UnityEngine.Profiling.Profiler.EndSample();
                }
            }

            UnityEngine.Profiling.Profiler.BeginSample("Set pixels");
            target.SetPixels(colors, mipLevel);
            UnityEngine.Profiling.Profiler.EndSample();

            UnityEngine.Profiling.Profiler.EndSample();
        }
Пример #2
0
        /// <summary>
        /// Generates the packed material map for an object
        /// </summary>
        public static void GeneratePackedMaterialMap(AlloyCustomImportObject settings, Texture2D target, string filePath)
        {
            var size      = settings.GetOutputSize();
            var normalMap = settings.NormalMapTexture;
            var useUnityGeneratedMipmaps = normalMap == null;
            int width       = (int)size.x;
            int height      = (int)size.y;
            int mipmapCount = 1;

            // When explicitly generating mip levels pick output count based on the largest input texture.
            if (!useUnityGeneratedMipmaps)
            {
                mipmapCount = GetMipmapCount(normalMap);

                for (int i = 0; i < 4; ++i)
                {
                    if (settings.SelectedModes[i] != TextureValueChannelMode.Texture ||
                        settings.GetTexture(i) == null)
                    {
                        continue;
                    }

                    mipmapCount = Math.Max(mipmapCount, GetMipmapCount(settings.GetTexture(i)));
                }
            }

            // Adjust the dimensions of the output texture if necessary.
            if (target.width != width || target.height != height)
            {
                target.Resize(width, height);
            }

            if (!Mathf.IsPowerOfTwo(width) || !Mathf.IsPowerOfTwo(height))
            {
                Debug.LogWarning(
                    "Alloy: Texture resolution is not power of 2; will have issues generating correct mip maps if custom sizing is specified in generated texture platform settings.");
            }

            // Get readable input textures.
            var readableNormal   = AlloyTextureReader.GetReadable(normalMap, true);
            var readableTextures = new Texture2D[settings.TexturesGUID.Length];

            for (int i = 0; i < settings.TexturesGUID.Length; ++i)
            {
                if (settings.SelectedModes[i] != TextureValueChannelMode.Texture)
                {
                    continue;
                }

                var settingsTex = settings.GetTexture(i);

                if (settingsTex == null)
                {
                    readableTextures[i] = null;
                }
                else
                {
                    readableTextures[i] = AlloyTextureReader.GetReadable(settingsTex, false);
                }
            }

            // Use renderer to sample mipmaps.
            try {
                var message  = string.Format("Packing: \"{0}\"", settings.name);
                var progress = 1.0f;
                var bodyText = message;

                for (int mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
                {
                    if (mipmapCount > 1)
                    {
                        progress = (float)mipLevel / (mipmapCount - 1);
                        bodyText = string.Format("{0} ({1})", message, progress.ToString("0%"));
                    }

                    EditorUtility.DisplayProgressBar("Building Packed maps...", bodyText, progress);

                    // CPU Method - more reliable/consistent across GPUs, but slower.
                    var normalCache = new AlloyTextureColorCache(readableNormal, target);

                    UnityEngine.Profiling.Profiler.BeginSample("Read");
                    var texCache = readableTextures.Select(tex => new AlloyTextureColorCache(tex, target)).ToArray();
                    UnityEngine.Profiling.Profiler.EndSample();

                    AlloyPackerCompositor.CompositeMips(target, settings, texCache, normalCache, mipLevel);
                }
            } finally {
                EditorUtility.ClearProgressBar();
            }

            // Clean up the readable textures.
            foreach (var texture in readableTextures)
            {
                Object.DestroyImmediate(texture);
            }

            Object.DestroyImmediate(readableNormal);

            // Update the texture's associated settings .asset object.
            settings.Width         = width;
            settings.Height        = height;
            settings.MaxResolution = 0;
            EditorUtility.SetDirty(settings);

            // Update the texture object.
            target.Apply(useUnityGeneratedMipmaps, false);
        }
Пример #3
0
        /// <summary>
        /// Generates the packed material map for an object
        /// </summary>
        public static void GeneratePackedMaterialMap(AlloyCustomImportObject settings, Texture2D target, string filePath)
        {
            int mipmapCount = 1;


            Vector2 size   = settings.GetOutputSize();
            int     width  = (int)size.x;
            int     height = (int)size.y;

            // Pick output texture dimensions based on the largest input texture.
            for (int i = 0; i < 4; ++i)
            {
                if (settings.SelectedModes[i] != TextureValueChannelMode.Texture || settings.GetTexture(i) == null)
                {
                    continue;
                }

                mipmapCount = Math.Max(mipmapCount, GetMipmapCount(settings.GetTexture(i)));
            }

            bool doMips;

            if (settings.NormalMapTexture != null)
            {
                var tex   = settings.NormalMapTexture;
                var count = GetMipmapCount(tex);

                mipmapCount = Math.Max(mipmapCount, count);
                doMips      = true;
            }
            else
            {
                mipmapCount = 1;
                doMips      = false;
            }

            if (target.width != width || target.height != height)
            {
                target.Resize(width, height);
            }

            if (!Mathf.IsPowerOfTwo(width) || !Mathf.IsPowerOfTwo(height))
            {
                Debug.LogWarning(
                    "Alloy: Texture resolution is not power of 2; will have issues generating correct mip maps if custom sizing is specified in generated texture platform settings.");
            }
            var readableTextures = new Texture2D[settings.TexturesGUID.Length];

            for (int i = 0; i < settings.TexturesGUID.Length; ++i)
            {
                if (settings.SelectedModes[i] != TextureValueChannelMode.Texture)
                {
                    continue;
                }

                var settingsTex = settings.GetTexture(i);

                if (settingsTex == null)
                {
                    readableTextures[i] = null;
                }
                else
                {
                    readableTextures[i] = AlloyTextureReader.GetReadable(settingsTex, false);
                }
            }

            var normal = AlloyTextureReader.GetReadable(settings.NormalMapTexture, true);

            try {
                // Use renderer to sample mipmaps.
                for (int mipLevel = 0; mipLevel < mipmapCount; mipLevel++)
                {
                    // CPU Method - more reliable/consistent across GPUs, but slower.
                    if (mipmapCount > 1)
                    {
                        EditorUtility.DisplayProgressBar("Calculating Mip Maps...", "MipLevel " + mipLevel, (float)mipLevel / mipmapCount);
                    }
                    else
                    {
                        EditorUtility.DisplayProgressBar("Calculating Packed map...", "Packing...", 1.0f);
                    }

                    var normalCache = new AlloyTextureColorCache(normal, target);

                    Profiler.BeginSample("Read");
                    var texCache = readableTextures.Select(tex => new AlloyTextureColorCache(tex, target)).ToArray();
                    Profiler.EndSample();


                    AlloyPackerCompositor.CompositeMips(target, settings, texCache, normalCache, mipLevel);
                }
            } finally {
                EditorUtility.ClearProgressBar();
            }
            foreach (var texture in readableTextures)
            {
                Object.DestroyImmediate(texture);
            }

            Object.DestroyImmediate(normal);

            int maxResolution = 0;

            settings.Width  = width;
            settings.Height = height;

            settings.MaxResolution = maxResolution;
            EditorUtility.SetDirty(settings); // Tells Unity to save changes to the settings .asset object on disk

            target.Apply(!doMips, false);
        }