private static void ComputeCompressionScalers(ProceduralTexture2D target)
 {
     target.compressionScalers = Vector4.one;
     if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None && target.type != ProceduralTexture2D.TextureType.Other)
     {
         target.compressionScalers.x = 1.0f / target.colorSpaceVector1.magnitude;
         target.compressionScalers.y = 1.0f / target.colorSpaceVector2.magnitude;
         target.compressionScalers.z = 1.0f / target.colorSpaceVector3.magnitude;
     }
 }
        private static void PreprocessData(ProceduralTexture2D target)
        {
            if (target.input == null)
            {
                return;
            }

            // Init progress bar
            stepCounter = 0;
            totalSteps  = (target.type != ProceduralTexture2D.TextureType.Other ? 4 : 0) + (target.type != ProceduralTexture2D.TextureType.Other ? 9 : 12) + 1;
            EditorUtility.DisplayProgressBar("Pre-processing Procedural Texture Data", target.name, (float)stepCounter / (totalSteps - 1));

            // Section 1.4 Improvement: using a decorrelated color space for Color RGB and Normal XYZ textures
            TextureFormat inputFormat  = TextureFormat.RGB24;
            TextureData   albedoData   = TextureToTextureData(target.input, ref inputFormat);
            TextureData   decorrelated = new TextureData(albedoData);

            if (target.type != ProceduralTexture2D.TextureType.Other)
            {
                DecorrelateColorSpace(ref albedoData, ref decorrelated, ref target.colorSpaceVector1, ref target.colorSpaceVector2, ref target.colorSpaceVector3, ref target.colorSpaceOrigin, target.name);
            }
            ComputeCompressionScalers(target);

            // Perform precomputations
            TextureData Tinput = new TextureData(decorrelated.width, decorrelated.height);
            TextureData invT   = new TextureData(LUT_WIDTH, (int)(Mathf.Log((float)Tinput.width) / Mathf.Log(2.0f))); // Height = Number of prefiltered LUT levels

            List <int> channelsToProcess = new List <int> {
                0, 1, 2
            };

            if ((target.type == ProceduralTexture2D.TextureType.Color && target.includeAlpha == true) || target.type == ProceduralTexture2D.TextureType.Other)
            {
                channelsToProcess.Add(3);
            }
            Precomputations(ref decorrelated, channelsToProcess, ref Tinput, ref invT, target.name);

            RescaleForCompression(target, ref Tinput);
            EditorUtility.DisplayProgressBar("Pre-processing Procedural Texture Data", target.name, (float)stepCounter++ / (totalSteps - 1));

            // Serialize precomputed data and setup material
            FinalizePrecomputedTextures(ref inputFormat, target, ref Tinput, ref invT);

            target.memoryUsageBytes = target.Tinput.GetRawTextureData().Length + target.invT.GetRawTextureData().Length;

            EditorUtility.ClearProgressBar();

            // Update current applied settings
            target.currentInput              = target.input;
            target.currentIncludeAlpha       = target.includeAlpha;
            target.currentGenerateMipMaps    = target.generateMipMaps;
            target.currentFilterMode         = target.filterMode;
            target.currentAnisoLevel         = target.anisoLevel;
            target.currentCompressionQuality = target.compressionQuality;
        }
        static void FinalizePrecomputedTextures(ref TextureFormat inputFormat, ProceduralTexture2D target, ref TextureData Tinput, ref TextureData invT)
        {
            // Serialize precomputed data as new subasset texture. Reuse existing texture if possible to avoid breaking texture references in shadergraph.
            if (target.Tinput == null)
            {
                target.Tinput = new Texture2D(Tinput.width, Tinput.height, inputFormat, target.generateMipMaps, true);
                AssetDatabase.AddObjectToAsset(target.Tinput, target);
            }
            target.Tinput.Resize(Tinput.width, Tinput.height, inputFormat, target.generateMipMaps);
            target.Tinput.name = target.input.name + "_T";
            target.Tinput.SetPixels(Tinput.data);
            target.Tinput.wrapMode   = TextureWrapMode.Repeat;
            target.Tinput.filterMode = target.filterMode;
            target.Tinput.anisoLevel = target.anisoLevel;
            target.Tinput.Apply();
            if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None)
            {
                if (target.compressionQuality == ProceduralTexture2D.CompressionLevel.HighQuality)
                {
                    EditorUtility.CompressTexture(target.Tinput, TextureFormat.BC7, (int)target.compressionQuality);
                }
                else if (inputFormat == TextureFormat.RGBA32)
                {
                    EditorUtility.CompressTexture(target.Tinput, TextureFormat.DXT5, (int)target.compressionQuality);
                }
                else
                {
                    EditorUtility.CompressTexture(target.Tinput, TextureFormat.DXT1, (int)target.compressionQuality);
                }
            }
            target.Tinput.Apply();

            if (target.invT == null)
            {
                target.invT = new Texture2D(invT.width, invT.height, inputFormat, false, true);
                AssetDatabase.AddObjectToAsset(target.invT, target);
            }
            target.invT.Resize(invT.width, invT.height, inputFormat, false);
            target.invT.name       = target.input.name + "_invT";
            target.invT.wrapMode   = TextureWrapMode.Clamp;
            target.invT.filterMode = FilterMode.Bilinear;
            target.invT.SetPixels(invT.data);
            target.invT.Apply();

            // Update asset database
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
 private bool UnappliedSettingChanges(ProceduralTexture2D target)
 {
     if (target.currentInput != target.input ||
         target.currentIncludeAlpha != target.includeAlpha ||
         target.currentGenerateMipMaps != target.generateMipMaps ||
         target.currentFilterMode != target.filterMode ||
         target.currentAnisoLevel != target.anisoLevel ||
         target.currentCompressionQuality != target.compressionQuality)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
        private void CopyInputTextureImportType(ProceduralTexture2D target)
        {
            string          path          = AssetDatabase.GetAssetPath(target.input);
            TextureImporter inputImporter = (TextureImporter)TextureImporter.GetAtPath(path);

            switch (inputImporter.textureType)
            {
            case TextureImporterType.NormalMap:
                target.type = ProceduralTexture2D.TextureType.Normal;
                break;

            default:
                target.type = ProceduralTexture2D.TextureType.Color;
                break;
            }
        }
        private static void RescaleForCompression(ProceduralTexture2D target, ref TextureData Tinput)
        {
            int channelCount = (target.type == ProceduralTexture2D.TextureType.Color && target.includeAlpha == true) || target.type == ProceduralTexture2D.TextureType.Other ?
                               4 : 3;

            // If we use DXT compression
            // we need to rescale the Gaussian channels (see Section 1.6)
            if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None && target.type != ProceduralTexture2D.TextureType.Other)
            {
                for (int y = 0; y < Tinput.height; y++)
                {
                    for (int x = 0; x < Tinput.width; x++)
                    {
                        for (int i = 0; i < channelCount; i++)
                        {
                            float v = Tinput.GetColor(x, y)[i];
                            v = (v - 0.5f) / target.compressionScalers[i] + 0.5f;
                            Tinput.GetColorRef(x, y)[i] = v;
                        }
                    }
                }
            }
        }
Beispiel #7
0
        public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
        {
            // }
            //
            // // Node generations
            // public virtual void GenerateNodeCode(ShaderGenerator visitor, GraphContext graphContext, GenerationMode generationMode)
            // {
            ProceduralTexture2DInputMaterialSlot slot = FindInputSlot <ProceduralTexture2DInputMaterialSlot>(ProceduralTexture2DId);

            // Find Procedural Texture 2D Asset
            ProceduralTexture2D proceduralTexture2D = slot.proceduralTexture2D;
            var edges = owner.GetEdges(slot.slotReference).ToArray();

            if (edges.Any())
            {
                var fromSocketRef = edges[0].outputSlot;
                #if UNITY_2020_2_OR_NEWER
                var fromNode = owner.GetNodeFromId <ProceduralTexture2DNode>(fromSocketRef.node.objectId);
                                #else
                var fromNode = owner.GetNodeFromGuid <ProceduralTexture2DNode>(fromSocketRef.nodeGuid);
                                #endif
                if (fromNode != null)
                {
                    proceduralTexture2D = fromNode.proceduralTexture2D;
                }
            }

            var precision = concretePrecision.ToShaderString();

            // No Procedural Texture 2D Asset found, break and initialize output values to default white
            if (proceduralTexture2D == null || proceduralTexture2D.Tinput == null || proceduralTexture2D.invT == null)
            {
                sb.AppendLine("{0}4 {1} = float4(1, 1, 1, 1);", precision, GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId));
                sb.AppendLine("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId));
                return;
            }

            // Apply hidden inputs stored in Procedural Texture 2D Asset to shader
            FindInputSlot <Texture2DInputMaterialSlot>(TinputId).texture    = proceduralTexture2D.Tinput;
            FindInputSlot <Texture2DInputMaterialSlot>(InvTinputId).texture = proceduralTexture2D.invT;
            FindInputSlot <Vector4MaterialSlot>(CompressionScalersId).value = proceduralTexture2D.compressionScalers;
            FindInputSlot <Vector3MaterialSlot>(ColorSpaceOriginId).value   = proceduralTexture2D.colorSpaceOrigin;
            FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector1Id).value  = proceduralTexture2D.colorSpaceVector1;
            FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector2Id).value  = proceduralTexture2D.colorSpaceVector2;
            FindInputSlot <Vector3MaterialSlot>(ColorSpaceVector3Id).value  = proceduralTexture2D.colorSpaceVector3;
            FindInputSlot <Vector3MaterialSlot>(InputSizeId).value          = new Vector3(
                proceduralTexture2D.Tinput.width, proceduralTexture2D.Tinput.height, proceduralTexture2D.invT.height);

            string code =
                @"
				float4 {9} = float4(0, 0, 0, 0);
				{
					float2 uvScaled = {0} * 3.464; // 2 * sqrt(3)

					const float2x2 gridToSkewedGrid = float2x2(1.0, 0.0, -0.57735027, 1.15470054);
					float2 skewedCoord = mul(gridToSkewedGrid, uvScaled);

					int2 baseId = int2(floor(skewedCoord));
					float3 temp = float3(frac(skewedCoord), 0);
					temp.z = 1.0 - temp.x - temp.y;

					float w1, w2, w3;
					int2 vertex1, vertex2, vertex3;
					if (temp.z > 0.0)
					{
						w1 = temp.z;
						w2 = temp.y;
						w3 = temp.x;
						vertex1 = baseId;
						vertex2 = baseId + int2(0, 1);
						vertex3 = baseId + int2(1, 0);
					}
					else
					{
						w1 = -temp.z;
						w2 = 1.0 - temp.y;
						w3 = 1.0 - temp.x;
						vertex1 = baseId + int2(1, 1);
						vertex2 = baseId + int2(1, 0);
						vertex3 = baseId + int2(0, 1);
					}

					float2 uv1 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex1)) * 43758.5453);
					float2 uv2 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex2)) * 43758.5453);
					float2 uv3 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), (float2)vertex3)) * 43758.5453);

					float2 duvdx = ddx({0});
					float2 duvdy = ddy({0});

					float4 G1 = {1}.SampleGrad({10}, uv1, duvdx, duvdy);
					float4 G2 = {1}.SampleGrad({10}, uv2, duvdx, duvdy);
					float4 G3 = {1}.SampleGrad({10}, uv3, duvdx, duvdy);

					float exponent = 1.0 + {11} * 15.0;
					w1 = pow(w1, exponent);
					w2 = pow(w2, exponent);
					w3 = pow(w3, exponent);
					float sum = w1 + w2 + w3;
					w1 = w1 / sum;
					w2 = w2 / sum;
					w3 = w3 / sum;

					float4 G = w1 * G1 + w2 * G2 + w3 * G3;
					G = G - 0.5;
					G = G * rsqrt(w1 * w1 + w2 * w2 + w3 * w3);
					G = G * {3};
					G = G + 0.5;

					duvdx *= {8}.xy;
					duvdy *= {8}.xy;
					float delta_max_sqr = max(dot(duvdx, duvdx), dot(duvdy, duvdy));
					float mml = 0.5 * log2(delta_max_sqr);
					float LOD = max(0, mml) / {8}.z;

					{9}.r = {2}.SampleLevel(sampler{2}, float2(G.r, LOD), 0).r;
					{9}.g = {2}.SampleLevel(sampler{2}, float2(G.g, LOD), 0).g;
					{9}.b = {2}.SampleLevel(sampler{2}, float2(G.b, LOD), 0).b;
					{9}.a = {2}.SampleLevel(sampler{2}, float2(G.a, LOD), 0).a;
				}
			"            ;

            if (proceduralTexture2D != null && proceduralTexture2D.type != ProceduralTexture2D.TextureType.Other)
            {
                code += "{9}.rgb = {4} + {5} * {9}.r + {6} * {9}.g + {7} * {9}.b;";
            }
            if (proceduralTexture2D != null && proceduralTexture2D.type == ProceduralTexture2D.TextureType.Normal)
            {
                code += "{9}.rgb = UnpackNormalmapRGorAG({9});";
            }

            code = code.Replace("{0}", GetSlotValue(UVInput, generationMode));
            code = code.Replace("{1}", GetSlotValue(TinputId, generationMode));
            code = code.Replace("{2}", GetSlotValue(InvTinputId, generationMode));
            code = code.Replace("{3}", GetSlotValue(CompressionScalersId, generationMode));
            code = code.Replace("{4}", GetSlotValue(ColorSpaceOriginId, generationMode));
            code = code.Replace("{5}", GetSlotValue(ColorSpaceVector1Id, generationMode));
            code = code.Replace("{6}", GetSlotValue(ColorSpaceVector2Id, generationMode));
            code = code.Replace("{7}", GetSlotValue(ColorSpaceVector3Id, generationMode));
            code = code.Replace("{8}", GetSlotValue(InputSizeId, generationMode));
            code = code.Replace("{9}", GetVariableNameForSlot(OutputSlotRGBAId));

            var edgesSampler = owner.GetEdges(FindInputSlot <MaterialSlot>(SamplerInput).slotReference);
            code = code.Replace("{10}", edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : "sampler" + GetSlotValue(TinputId, generationMode));

            code = code.Replace("{11}", GetSlotValue(BlendId, generationMode));

            sb.AppendLine(code);

            sb.AppendLine("{0} {1} = {2}.r;", precision, GetVariableNameForSlot(OutputSlotRId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.g;", precision, GetVariableNameForSlot(OutputSlotGId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.b;", precision, GetVariableNameForSlot(OutputSlotBId), GetVariableNameForSlot(OutputSlotRGBAId));
            sb.AppendLine("{0} {1} = {2}.a;", precision, GetVariableNameForSlot(OutputSlotAId), GetVariableNameForSlot(OutputSlotRGBAId));
        }