コード例 #1
0
        /// <summary>
        /// Gets Unity textures from Daggerfall texture with all options.
        /// Returns all supported texture maps for Standard shader in one call.
        /// </summary>
        /// <param name="settings">Get texture settings.</param>
        /// <param name="alphaTextureFormat">Alpha TextureFormat.</param>
        /// <param name="nonAlphaFormat">Non-alpha TextureFormat.</param>
        /// <param name="allowImport">Import texture from disk if present.</param>
        /// <returns>GetTextureResults.</returns>
        public GetTextureResults GetTexture2D(
            GetTextureSettings settings,
            SupportedAlphaTextureFormats alphaTextureFormat = SupportedAlphaTextureFormats.RGBA32,
            SupportedNonAlphaTextureFormats nonAlphaFormat  = SupportedNonAlphaTextureFormats.RGB24,
            bool allowImport = true)
        {
            GetTextureResults results = new GetTextureResults();

            // Check if window or auto-emissive
            bool isWindow   = ClimateSwaps.IsExteriorWindow(settings.archive, settings.record);
            bool isEmissive = (settings.autoEmission) ? IsEmissive(settings.archive, settings.record) : false;

            // Override readable flag when user has set preference in material reader
            if (DaggerfallUnity.Instance.MaterialReader.ReadableTextures)
            {
                settings.stayReadable = true;
            }

            // Assign texture file
            TextureFile textureFile;

            if (settings.textureFile == null)
            {
                textureFile = new TextureFile(Path.Combine(Arena2Path, TextureFile.IndexToFileName(settings.archive)), FileUsage.UseMemory, true);
            }
            else
            {
                textureFile = settings.textureFile;
            }

            // Get starting DFBitmap and albedo Color32 array
            DFSize   sz;
            DFBitmap srcBitmap = textureFile.GetDFBitmap(settings.record, settings.frame);

            Color32[] albedoColors = textureFile.GetColor32(srcBitmap, settings.alphaIndex, settings.borderSize, out sz);

            // Sharpen source image
            if (settings.sharpen)
            {
                albedoColors = ImageProcessing.Sharpen(ref albedoColors, sz.Width, sz.Height);
            }

            // Dilate edges
            if (settings.borderSize > 0 && settings.dilate && !settings.copyToOppositeBorder)
            {
                ImageProcessing.DilateColors(ref albedoColors, sz);
            }

            // Copy to opposite border
            if (settings.borderSize > 0 && settings.copyToOppositeBorder)
            {
                ImageProcessing.WrapBorder(ref albedoColors, sz, settings.borderSize);
            }

            // Set albedo texture
            Texture2D albedoMap = null;

            if (allowImport && TextureReplacement.CustomTextureExist(settings.archive, settings.record, settings.frame))
            {
                // Import albedo texture
                albedoMap = TextureReplacement.LoadCustomTexture(settings.archive, settings.record, settings.frame);
            }
            else
            {
                // Create albedo texture
                if (settings.alphaIndex < 0)
                {
                    albedoMap = new Texture2D(sz.Width, sz.Height, ParseTextureFormat(nonAlphaFormat), MipMaps);
                }
                else
                {
                    albedoMap = new Texture2D(sz.Width, sz.Height, ParseTextureFormat(alphaTextureFormat), MipMaps);
                }
                albedoMap.SetPixels32(albedoColors);
                albedoMap.Apply(true, !settings.stayReadable);
            }

            // Set normal texture
            Texture2D normalMap = null;

            if (allowImport && TextureReplacement.CustomNormalExist(settings.archive, settings.record, settings.frame))
            {
                // Always import normal if present on disk
                normalMap = TextureReplacement.LoadCustomNormal(settings.archive, settings.record, settings.frame);
            }
            else if (settings.createNormalMap && textureFile.SolidType == TextureFile.SolidTypes.None)
            {
                // Create normal texture - must be ARGB32
                // Normal maps are bypassed for solid-colour textures
                Color32[] normalColors;
                normalColors = ImageProcessing.GetBumpMap(ref albedoColors, sz.Width, sz.Height);
                normalColors = ImageProcessing.ConvertBumpToNormals(ref normalColors, sz.Width, sz.Height, settings.normalStrength);
                normalMap    = new Texture2D(sz.Width, sz.Height, TextureFormat.ARGB32, MipMaps);
                normalMap.SetPixels32(normalColors);
                normalMap.Apply(true, !settings.stayReadable);
            }

            // Import emission map or create basic emissive texture
            Texture2D emissionMap    = null;
            bool      resultEmissive = false;

            if (allowImport && TextureReplacement.CustomEmissionExist(settings.archive, settings.record, settings.frame))
            {
                // Always import emission if present on disk
                emissionMap    = TextureReplacement.LoadCustomEmission(settings.archive, settings.record, settings.frame);
                resultEmissive = true;
            }
            else
            {
                if (settings.createEmissionMap || (settings.autoEmission && isEmissive) && !isWindow)
                {
                    // Just reuse albedo map for basic colour emission
                    emissionMap    = albedoMap;
                    resultEmissive = true;
                }

                // Windows need special handling as only glass parts are emissive
                if ((settings.createEmissionMap || settings.autoEmissionForWindows) && isWindow)
                {
                    // Create custom emission texture for glass area of windows
                    Color32[] emissionColors = textureFile.GetWindowColors32(srcBitmap);
                    emissionMap = new Texture2D(sz.Width, sz.Height, ParseTextureFormat(alphaTextureFormat), MipMaps);
                    emissionMap.SetPixels32(emissionColors);
                    emissionMap.Apply(true, !settings.stayReadable);
                    resultEmissive = true;
                }

                // Lights need special handling as this archive contains a mix of emissive and non-emissive flats
                // This can cause problems with atlas packing due to mismatch between albedo and emissive texture counts
                if ((settings.createEmissionMap || settings.autoEmission) && settings.archive == LightsTextureArchive)
                {
                    // For the unlit flats we create a null-emissive black texture
                    if (!isEmissive)
                    {
                        Color32[] emissionColors = new Color32[sz.Width * sz.Height];
                        emissionMap = new Texture2D(sz.Width, sz.Height, ParseTextureFormat(alphaTextureFormat), MipMaps);
                        emissionMap.SetPixels32(emissionColors);
                        emissionMap.Apply(true, !settings.stayReadable);
                        resultEmissive = true;
                    }
                }
            }

            // Shrink UV rect to compensate for internal border
            float ru = 1f / sz.Width;
            float rv = 1f / sz.Height;

            results.singleRect = new Rect(
                settings.borderSize * ru,
                settings.borderSize * rv,
                (sz.Width - settings.borderSize * 2) * ru,
                (sz.Height - settings.borderSize * 2) * rv);

            // Store results
            results.albedoMap   = albedoMap;
            results.normalMap   = normalMap;
            results.emissionMap = emissionMap;
            results.isWindow    = isWindow;
            results.isEmissive  = resultEmissive;
            results.textureFile = textureFile;

            return(results);
        }
コード例 #2
0
        /// <summary>
        /// Gets terrain normal map texture array containing each terrain tile in a seperate array slice.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="stayReadable">Texture should stay readable.</param>
        /// <param name="nonAlphaFormat">Non-alpha TextureFormat.</param>
        /// <returns>Texture2DArray or null</returns>
        public Texture2DArray GetTerrainNormalMapTextureArray(
            int archive,
            bool stayReadable = false,
            SupportedAlphaTextureFormats alphaFormat = SupportedAlphaTextureFormats.RGBA32)
        {
            // Load texture file and check count matches terrain tiles
            TextureFile textureFile = new TextureFile(Path.Combine(Arena2Path, TextureFile.IndexToFileName(archive)), FileUsage.UseMemory, true);
            int         numSlices   = 0;

            if (textureFile.RecordCount == 56)
            {
                numSlices = textureFile.RecordCount;
            }
            else
            {
                return(null);
            }

            Texture2DArray textureArray;
            int            width;
            int            height;

            // try to import first replacement texture for tile archive to determine width and height of replacement texture set (must be the same for all replacement textures for Texture2DArray)
            if (TextureReplacement.CustomNormalExist(archive, 0, 0))
            {
                Texture2D normalMap = TextureReplacement.LoadCustomNormal(archive, 0, 0);
                width  = normalMap.width;
                height = normalMap.height;
            }
            else
            {
                return(null);
            }

            textureArray = new Texture2DArray(width, height, numSlices, TextureFormat.ARGB32, MipMaps);

            // Rollout tiles into texture array
            for (int record = 0; record < textureFile.RecordCount; record++)
            {
                Texture2D normalMap;
                // Import custom texture(s)
                if (TextureReplacement.CustomNormalExist(archive, record, 0))
                {
                    normalMap = TextureReplacement.LoadCustomNormal(archive, record, 0);
                }
                else // if current texture does not exist
                {
                    Debug.LogErrorFormat("Terrain: imported archive {0} does not contain normal for record {1}.", archive, record);
                    return(null);
                }

                // enforce that all custom normal map textures have the same dimension (requirement of Texture2DArray)
                if ((normalMap.width != width) || (normalMap.height != height))
                {
                    Debug.LogErrorFormat("Terrain: failed to inject normal maps for archive {0}, incorrect size at record {1}.", archive, record);
                    return(null);
                }

                // Insert into texture array
                textureArray.SetPixels32(normalMap.GetPixels32(), record, 0);
            }
            textureArray.Apply(true, !stayReadable);

            // Change settings for these textures
            textureArray.wrapMode   = TextureWrapMode.Clamp;
            textureArray.anisoLevel = 8;

            return(textureArray);
        }
コード例 #3
0
        /// <summary>
        /// Gets Unity Material from Daggerfall texture with more options.
        /// </summary>
        /// <param name="archive">Archive index.</param>
        /// <param name="record">Record index.</param>
        /// <param name="frame">Frame index.</param>
        /// <param name="rectOut">Receives UV rect for texture inside border.</param>
        /// <param name="borderSize">Number of pixels internal border around each texture.</param>
        /// <param name="dilate">Blend texture into surrounding empty pixels.</param>
        /// <param name="isBillboard">Set true when creating atlas material for simple billboards.</param>
        /// <returns>Material or null.</returns>
        public Material GetMaterial(
            int archive,
            int record,
            int frame,
            int alphaIndex,
            out Rect rectOut,
            int borderSize   = 0,
            bool dilate      = false,
            bool isBillboard = false)
        {
            // Ready check
            if (!IsReady)
            {
                rectOut = new Rect();
                return(null);
            }

            // Try to retrieve from cache
            int key = MakeTextureKey((short)archive, (byte)record, (byte)frame);

            if (materialDict.ContainsKey(key))
            {
                CachedMaterial cm = materialDict[key];
                rectOut = cm.singleRect;
                return(cm.material);
            }

            // Create new texture settings
            GetTextureSettings settings = TextureReader.CreateTextureSettings(archive, record, frame, alphaIndex, borderSize, dilate);

            settings.autoEmissionForWindows = true;
            settings.sharpen = Sharpen;
            if (GenerateNormals)
            {
                settings.createNormalMap = true;
                settings.normalStrength  = NormalTextureStrength;
            }

            // Set emissive for self-illuminated textures
            if (textureReader.IsEmissive(archive, record))
            {
                settings.createEmissionMap = true;
                settings.emissionIndex     = -1;
            }

            // Get texture
            GetTextureResults results = textureReader.GetTexture2D(settings, AlphaTextureFormat, NonAlphaTextureFormat);

            rectOut = results.singleRect;

            // Create material
            Material material;

            if (isBillboard)
            {
                material = CreateStandardMaterial(CustomBlendMode.Cutout);
            }
            else
            {
                material = CreateStandardMaterial();
            }

            // Setup material
            material.name                   = FormatName(archive, record);
            material.mainTexture            = results.albedoMap;
            material.mainTexture.filterMode = MainFilterMode;

            // Setup normal map
            bool importedNormals = TextureReplacement.CustomNormalExist(settings.archive, settings.record, settings.frame);

            if ((GenerateNormals || importedNormals) && results.normalMap != null)
            {
                results.normalMap.filterMode = MainFilterMode;
                material.SetTexture("_BumpMap", results.normalMap);
                material.EnableKeyword("_NORMALMAP");
            }

            // Setup emission map
            if (results.isEmissive && !results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", Color.white);
                material.EnableKeyword("_EMISSION");
            }
            else if (results.isEmissive && results.isWindow && results.emissionMap != null)
            {
                results.emissionMap.filterMode = MainFilterMode;
                material.SetTexture("_EmissionMap", results.emissionMap);
                material.SetColor("_EmissionColor", DayWindowColor * DayWindowIntensity);
                material.EnableKeyword("_EMISSION");
            }

            // Import additional custom components of material
            TextureReplacement.CustomizeMaterial(archive, record, frame, material);

            // Setup cached material
            DFSize     size   = results.textureFile.GetSize(record);
            DFSize     scale  = results.textureFile.GetScale(record);
            DFPosition offset = results.textureFile.GetOffset(record);

            Vector2[] recordSizes = new Vector2[1] {
                new Vector2(size.Width, size.Height)
            };
            Vector2[] recordScales = new Vector2[1] {
                new Vector2(scale.Width, scale.Height)
            };
            Vector2[] recordOffsets = new Vector2[1] {
                new Vector2(offset.X, offset.Y)
            };
            CachedMaterial newcm = new CachedMaterial()
            {
                key              = key,
                keyGroup         = 0,
                albedoMap        = results.albedoMap,
                normalMap        = results.normalMap,
                emissionMap      = results.emissionMap,
                singleRect       = rectOut,
                material         = material,
                filterMode       = MainFilterMode,
                isWindow         = results.isWindow,
                recordSizes      = recordSizes,
                recordScales     = recordScales,
                recordOffsets    = recordOffsets,
                singleFrameCount = results.textureFile.GetFrameCount(record),
            };

            materialDict.Add(key, newcm);

            return(material);
        }