#if UNITY_EDITOR //#define SUPPORT_MBLOCKS using UnityEngine; using UnityEditor; using System.IO; using System.Reflection; public class ftUVGBufferGen { static RenderTexture rtAlbedo, rtEmissive, rtNormal, rtAlpha; public static Texture2D texAlbedo, texEmissive, texNormal, texBestFit, texAlpha; //static GameObject dummyCamGO; //static Camera dummyCam; static float texelSize; //static Vector4 shaBlack, shaWhite; static Material matFromRGBM; static Material matDilate, matMultiply; static bool emissiveEnabled = false; static bool normalEnabled = false; static bool alphaEnabled = false; static Vector4 metaControl, metaControlAlbedo, metaControlEmission, metaControlNormal, metaControlAlpha; static Material fallbackMat, normalMat, blackMat; static int fallbackMatMetaPass; static BakeryProjectSettings pstorage; public static float[] vertexBakeSamples; static int vertexBakeSampleCounter; const int PASS_ALBEDO = 0; const int PASS_EMISSIVE = 1; const int PASS_NORMAL = 2; const int PASS_ALPHA = 3; const int PASS_COUNT = 4; // just a marker #if SUPPORT_MBLOCKS static Material activeMaterial; static int activeMaterialPass; static MaterialPropertyBlock mb = new MaterialPropertyBlock(); #endif static Material tmpMaterial; public static float[] uvOffset = { -2, -2, 2, -2, -2, 2, 2, 2, -1, -2, 1, -2, -2, -1, 2, -1, -2, 1, 2, 1, -1, 2, 1, 2, -2, 0, 2, 0, 0, -2, 0, 2, -1, -1, 1, -1, -1, 0, 1, 0, -1, 1, 1, 1, 0, -1, 0, 1, 0, 0 }; static public void UpdateMatrix(Matrix4x4 worldMatrix, float offsetX, float offsetY)//Matrix4x4 worldMatrix) { // Generate a projection matrix similar to LoadOrtho /*var dummyCamGO = new GameObject(); dummyCamGO.name = "dummyCam"; var dummyCam = dummyCamGO.AddComponent(); dummyCam.cullingMask = 0; dummyCam.orthographic = true; dummyCam.orthographicSize = 0.5f; dummyCam.nearClipPlane = -10; dummyCam.aspect = 1; var proj = dummyCam.projectionMatrix; var c3 = proj.GetColumn(3); proj.SetColumn(3, new Vector4(-1, -1, c3.z, c3.w)); Debug.Log(proj);*/ var proj = new Matrix4x4(); proj.SetRow(0, new Vector4(2.00000f, 0.00000f, 0.00000f, -1.00000f + offsetX)); proj.SetRow(1, new Vector4(0.00000f, 2.00000f, 0.00000f, -1.00000f + offsetY)); proj.SetRow(2, new Vector4(0.00000f, 0.00000f, -0.00198f, -0.98f)); proj.SetRow(3, new Vector4(0.00000f, 0.00000f, 0.00000f, 1.00000f)); //if (ftBuildGraphics.unityVersionMajor < 2018) // Unity 2018 stopped multiplying vertices by world matrix in meta pass //{ #if UNITY_2018_1_OR_NEWER #else proj = proj * worldMatrix.inverse; #endif //} // If Camera.current is set, multiply our matrix by the inverse of its view matrix if (Camera.current != null) { proj = proj * Camera.current.worldToCameraMatrix.inverse; } GL.LoadProjectionMatrix(proj); } static Mesh GenerateVertexBakeSamples(Mesh mesh, int vertexSamplingDensity, Vector3[] wpos) { int vertexCount = mesh.vertexCount; var verts = wpos;//mesh.vertices; var normals = mesh.normals; var uv = mesh.uv; bool hasUV = uv != null && uv.Length > 0; Vector2 tA = Vector2.zero; Vector2 tB = Vector2.zero; Vector2 tC = Vector2.zero; int newVertexCount = ftBuildGraphics.GetNumVertexSamples(mesh, vertexSamplingDensity); var newMesh = new Mesh(); if (newVertexCount > 65000) { #if UNITY_2017_3_OR_NEWER newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #else ftBuildGraphics.DebugLogError("Using this vertexSamplingDensity value (" + vertexSamplingDensity + ") on this mesh (" + mesh.name + ") results in more than 65000 new vertices. Please lower the value, split the mesh, or use Unity >= 2017.3. Alternatively, annoy me via email, so I fix it."); return null; #endif } var newVerts = new Vector3[newVertexCount]; var newNormals = new Vector3[newVertexCount]; var newUV = new Vector2[newVertexCount]; int subMeshCount = mesh.subMeshCount; int sampleCount = 0; UnityEngine.Random.InitState(vertexCount); // instead of storing barycentrics we will regenerate them for(int subMesh=0; subMesh 0) { vertexBakeSamples = new float[vertexBakeSampleBufferSize * 4]; } rtAlbedo = new RenderTexture(size, size, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); texAlbedo = new Texture2D(size, size, TextureFormat.RGBA32, false, false); Graphics.SetRenderTarget(rtAlbedo); GL.Clear(true, true, new Color(0,0,0,0)); if (hasEmissive) { rtEmissive = new RenderTexture(size, size, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); texEmissive = new Texture2D(size, size, TextureFormat.RGBAHalf, false, true); Graphics.SetRenderTarget(rtEmissive); GL.Clear(true, true, new Color(0,0,0,0)); } if (hasNormal) { rtNormal = new RenderTexture(size, size, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); texNormal = new Texture2D(size, size, TextureFormat.RGBA32, false, false); Graphics.SetRenderTarget(rtNormal); GL.Clear(true, true, new Color(0,0,0,0)); } //GL.sRGBWrite = true;//!hasEmissive; GL.invertCulling = false; GL.PushMatrix(); //GL.LoadOrtho(); //UpdateMatrix(); /*float ambR, ambG, ambB; //ambR = ambG = ambB = emissiveOnly ? 0 : 1; Shader.SetGlobalVector("unity_SHBr", Vector4.zero); Shader.SetGlobalVector("unity_SHBg", Vector4.zero); Shader.SetGlobalVector("unity_SHBb", Vector4.zero); Shader.SetGlobalVector("unity_SHC", Vector4.zero);*/ texelSize = (1.0f / size) / 5; //shaBlack = new Vector4(0,0,0,0); //shaWhite = new Vector4(0,0,0,1); metaControl = new Vector4(1,0,0,0); metaControlAlbedo = new Vector4(1,0,0,0); metaControlEmission = new Vector4(0,1,0,0); metaControlNormal = new Vector4(0,0,1,0); metaControlAlpha = new Vector4(0,0,0,1); Shader.SetGlobalVector("unity_MetaVertexControl", metaControl); Shader.SetGlobalFloat("unity_OneOverOutputBoost", 1.0f); Shader.SetGlobalFloat("unity_MaxOutputValue", 10000000.0f); Shader.SetGlobalFloat("unity_UseLinearSpace", PlayerSettings.colorSpace == ColorSpace.Linear ? 1.0f : 0.0f); } static public void InitAlphaBuffer(int size) { alphaEnabled = true; rtAlpha = new RenderTexture(size, size, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); rtAlpha.name = "BakeryRTAlpha"; texAlpha = new Texture2D(size, size, TextureFormat.RGBA32, false, true); texAlpha.name = "BakeryTexAlpha"; Graphics.SetRenderTarget(rtAlpha); GL.Clear(true, true, new Color(0,0,0,0)); } #if SUPPORT_MBLOCKS static void OverrideColor(MaterialPropertyBlock mb, string pname) { #if UNITY_2021_1_OR_NEWER if (!mb.HasColor(pname)) return; tmpMaterial.SetColor(pname, mb.GetColor(pname)); #else #if UNITY_2017_3_OR_NEWER var v = mb.GetColor(pname); if (v.r == 0 && v.g == 0 && v.b == 0 && v.a == 0) return; // not the best workaround - can't override with 0 on < 2021.1 tmpMaterial.SetColor(pname, v); #else var v = mb.GetVector(pname); if (v.x == 0 && v.y == 0 && v.z == 0 && v.w == 0) return; // not the best workaround - can't override with 0 on < 2021.1 tmpMaterial.SetVector(pname, v); #endif #endif } static void OverrideVector(MaterialPropertyBlock mb, string pname) { #if UNITY_2021_1_OR_NEWER if (!mb.HasVector(pname)) return; tmpMaterial.SetVector(pname, mb.GetVector(pname)); #else var v = mb.GetVector(pname); if (v.x == 0 && v.y == 0 && v.z == 0 && v.w == 0) return; // not the best workaround - can't override with 0 on < 2021.1 tmpMaterial.SetVector(pname, v); #endif } static void OverrideFloat(MaterialPropertyBlock mb, string pname) { #if UNITY_2021_1_OR_NEWER if (!mb.HasFloat(pname)) return; tmpMaterial.SetFloat(pname, mb.GetFloat(pname)); #else var v = mb.GetFloat(pname); if (v == 0) return; // not the best workaround - can't override with 0 on < 2021.1 tmpMaterial.SetFloat(pname, v); #endif } static void OverrideTexture(MaterialPropertyBlock mb, string pname) { #if UNITY_2021_1_OR_NEWER if (!mb.HasTexture(pname)) return; tmpMaterial.SetTexture(pname, mb.GetTexture(pname)); #else var v = mb.GetTexture(pname); if (v == null) return; tmpMaterial.SetTexture(pname, v); #endif } #endif static void DrawWithOverrides(Renderer renderer, Mesh m, ref Matrix4x4 worldMatrix, int i) { #if SUPPORT_MBLOCKS #if UNITY_2018_1_OR_NEWER if (renderer.HasPropertyBlock()) #endif { //#if UNITY_2018_1_OR_NEWER // renderer.GetPropertyBlock(mb, i); //#else renderer.GetPropertyBlock(mb); //#endif var shader = activeMaterial.shader; if ((!mb.isEmpty) && activeMaterial != null && shader != null) { tmpMaterial = new Material(activeMaterial); int numPropsInShader = ShaderUtil.GetPropertyCount(shader); for(int j=0; j 8192) res = 8192; InitAlphaBuffer(res); } Material[] materials = renderer.sharedMaterials; var m = mesh; if (uvOverride != null) { if (vertexBake && vertexSamplingDensity > 1) { m = GenerateVertexBakeSamples(mesh, vertexSamplingDensity, tformedPos); } else { m = Mesh.Instantiate(mesh); if (vertexBake) { for(int i=0; i= PASS_NORMAL) isHDRP = false; // custom meta shaders are not affected int bakeryPass = -1; if (pass < PASS_NORMAL) { int metaPass = -1; if (!materials[i].HasProperty("BAKERY_FORCE_NO_META")) { if (!passAsBlack) { metaPass = materials[i].FindPass("META"); if (metaPass < 0) { // Try finding another pass pass with "META" in it for(int mpass=0; mpass= 0) { metaPass = mpass; break; } } } } } Shader.SetGlobalVector("unity_LightmapST", scaleOffset);//(isHDRP) ? scaleOffsetFlipped : scaleOffset); Shader.SetGlobalVector("unity_MetaFragmentControl", pass == PASS_ALBEDO ? metaControlAlbedo : metaControlEmission); if (metaPass >= 0) { materials[i].SetPass(metaPass); #if SUPPORT_MBLOCKS activeMaterial = materials[i]; activeMaterialPass = metaPass; #endif } else { if (passAsBlack) { if (blackMat == null) { blackMat = new Material(Shader.Find("Hidden/ftBlack")); } Shader.SetGlobalVector("unity_LightmapST", scaleOffset); blackMat.SetPass(0); #if SUPPORT_MBLOCKS activeMaterial = blackMat; activeMaterialPass = 0; #endif } else { if (fallbackMat == null) { fallbackMat = new Material(Shader.Find("Standard")); fallbackMat.EnableKeyword("_EMISSION"); fallbackMatMetaPass = fallbackMat.FindPass("META"); } if ((pstorage.logLevel & (int)BakeryProjectSettings.LogLevel.Warning) != 0) { if (materials[i].name != "Hidden/ftFarSphere") { Debug.LogWarning("Material " + materials[i].name + " doesn't have meta pass - maps are taken by name"); } } if (materials[i].HasProperty("_MainTex")) { fallbackMat.mainTexture = materials[i].GetTexture("_MainTex"); } else if (materials[i].HasProperty("_BaseColorMap")) { // HDRP fallbackMat.mainTexture = materials[i].GetTexture("_BaseColorMap"); } else if (materials[i].HasProperty("_BaseMap")) { // URP fallbackMat.mainTexture = materials[i].GetTexture("_BaseMap"); } if (materials[i].HasProperty("_Color")) { fallbackMat.SetVector("_Color", materials[i].GetVector("_Color")); } else { fallbackMat.SetVector("_Color", Color.white); } if (materials[i].HasProperty("_EmissionMap")) { fallbackMat.SetTexture("_EmissionMap", materials[i].GetTexture("_EmissionMap")); } else { fallbackMat.SetTexture("_EmissionMap", null); } if (materials[i].HasProperty("_EmissionColor")) { fallbackMat.SetVector("_EmissionColor", materials[i].GetVector("_EmissionColor")); } else { fallbackMat.SetVector("_EmissionColor", Color.black); } fallbackMat.SetPass(fallbackMatMetaPass); #if SUPPORT_MBLOCKS activeMaterial = fallbackMat; activeMaterialPass = fallbackMatMetaPass; #endif } } } else if (pass == PASS_NORMAL) { bool isURP = rpTag == "UniversalPipeline"; var metaPass = materials[i].FindPass("META_BAKERY"); bakeryPass = metaPass; if (normalMat == null && metaPass < 0) { normalMat = new Material(Shader.Find("Hidden/ftUVNormalMap")); } if (texBestFit == null) { texBestFit = new Texture2D(1024, 1024, TextureFormat.RGBA32, false, true); var edPath = ftLightmaps.GetEditorPath(); var fbestfit = new BinaryReader(File.Open(edPath + "NormalsFittingTexture_dds", FileMode.Open, FileAccess.Read)); fbestfit.BaseStream.Seek(128, SeekOrigin.Begin); var bytes = fbestfit.ReadBytes(1024 * 1024 * 4); fbestfit.Close(); texBestFit.LoadRawTextureData(bytes); texBestFit.Apply(); } if (metaPass < 0) { if (materials[i].HasProperty("_BumpMap")) { normalMat.SetTexture("_BumpMap", materials[i].GetTexture("_BumpMap")); if (materials[i].HasProperty("_MainTex_ST")) { normalMat.SetVector("_BumpMap_scaleOffset", materials[i].GetVector("_MainTex_ST")); //Debug.LogError(materials[i].GetVector("_MainTex_ST")); } else { normalMat.SetVector("_BumpMap_scaleOffset", new Vector4(1,1,0,0)); } } else if (materials[i].HasProperty("_NormalMap")) { normalMat.SetTexture("_BumpMap", materials[i].GetTexture("_NormalMap")); normalMat.SetVector("_BumpMap_scaleOffset", new Vector4(1,1,0,0)); } else { normalMat.SetTexture("_BumpMap", null); } normalMat.SetFloat("_IsTerrain", terrainNormals ? 1.0f : 0.0f); normalMat.SetTexture("bestFitNormalMap", texBestFit); normalMat.SetFloat("_IsPerPixel", (isURP||isHDRP) ? 1.0f : 0.0f); normalMat.SetPass(0); #if SUPPORT_MBLOCKS activeMaterial = normalMat; activeMaterialPass = 0; #endif } else { materials[i].SetTexture("bestFitNormalMap", texBestFit); materials[i].SetFloat("_IsPerPixel", (isURP||isHDRP) ? 1.0f : 0.0f); materials[i].SetPass(metaPass); #if SUPPORT_MBLOCKS activeMaterial = materials[i]; activeMaterialPass = metaPass; #endif } Shader.SetGlobalVector("unity_MetaFragmentControl", metaControlNormal); } else if (pass == PASS_ALPHA) { // Unity does not output alpha in its meta pass, so only custom shaders are supported var metaPass = materials[i].FindPass("META_BAKERY"); if (metaPass < 0) { Debug.LogError("BAKERY_META_ALPHA_ENABLE is set, but there is no META_BAKERY pass in " + materials[i].name); continue; } bakeryPass = metaPass; materials[i].SetPass(metaPass); #if SUPPORT_MBLOCKS activeMaterial = materials[i]; activeMaterialPass = metaPass; #endif Shader.SetGlobalVector("unity_MetaFragmentControl", metaControlAlpha); } GL.sRGBWrite = pass == PASS_ALBEDO; if (!vertexBake) { for(int j=0; j= 0) { materials[i].SetPass(bakeryPass); #if SUPPORT_MBLOCKS activeMaterial = materials[i]; activeMaterialPass = bakeryPass; #endif } else { var s = worldTransform.lossyScale; bool isFlipped = Mathf.Sign(s.x*s.y*s.z) < 0; normalMat.SetFloat("_IsFlipped", isFlipped ? -1.0f : 1.0f); normalMat.SetPass(0); #if SUPPORT_MBLOCKS activeMaterial = normalMat; activeMaterialPass = 0; #endif } } DrawWithOverrides(renderer, m, ref worldMatrix, i); } } else { UpdateMatrix(worldMatrix, 0, 0); DrawWithOverrides(renderer, m, ref worldMatrix, i); } } } } static public void EndUVGBuffer() { GL.PopMatrix(); Graphics.SetRenderTarget(rtAlbedo); texAlbedo.ReadPixels(new Rect(0,0,rtAlbedo.width,rtAlbedo.height), 0, 0, false); texAlbedo.Apply(); Graphics.SetRenderTarget(null); rtAlbedo.Release(); if (emissiveEnabled) { Graphics.SetRenderTarget(rtEmissive); texEmissive.ReadPixels(new Rect(0,0,rtEmissive.width,rtEmissive.height), 0, 0, false); texEmissive.Apply(); Graphics.SetRenderTarget(null); rtEmissive.Release(); } if (normalEnabled) { Graphics.SetRenderTarget(rtNormal); texNormal.ReadPixels(new Rect(0,0,rtNormal.width,rtNormal.height), 0, 0, false); texNormal.Apply(); Graphics.SetRenderTarget(null); rtNormal.Release(); } if (alphaEnabled) { Graphics.SetRenderTarget(rtAlpha); texAlpha.ReadPixels(new Rect(0,0,rtAlpha.width,rtAlpha.height), 0, 0, false); texAlpha.Apply(); Graphics.SetRenderTarget(null); rtAlpha.Release(); rtAlpha = null; } } static public Texture2D DecodeFromRGBM(Texture2D emissive) { var rt = new RenderTexture(emissive.width, emissive.height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); var tex = new Texture2D(emissive.width, emissive.height, TextureFormat.RGBAHalf, false, true); if (matFromRGBM == null) matFromRGBM = new Material(Shader.Find("Hidden/ftRGBM2Half")); Graphics.SetRenderTarget(rt); GL.sRGBWrite = false; matFromRGBM.SetTexture("_MainTex", emissive); Graphics.Blit(emissive, rt, matFromRGBM); tex.ReadPixels(new Rect(0,0,rt.width,rt.height), 0, 0, false); tex.Apply(); Graphics.SetRenderTarget(null); rt.Release(); Object.DestroyImmediate(emissive); return tex; } static public void Dilate(Texture2D albedo, int pass = 0) { if (matDilate == null) matDilate = new Material(Shader.Find("Hidden/ftDilate")); RenderTexture rt, rt2; if (albedo.format == TextureFormat.RGBA32) { rt = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); rt2 = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); } else { rt = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); rt2 = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); } GL.sRGBWrite = albedo.format == TextureFormat.RGBA32; Graphics.Blit(albedo, rt, matDilate, pass); for(int i=0; i<8; i++) { Graphics.Blit(rt, rt2, matDilate, pass); Graphics.Blit(rt2, rt, matDilate, pass); } Graphics.SetRenderTarget(rt); albedo.ReadPixels(new Rect(0,0,rt.width,rt.height), 0, 0, false); albedo.Apply(); Graphics.SetRenderTarget(null); rt.Release(); rt2.Release(); } static public void Multiply(Texture2D albedo, float val) { if (matMultiply == null) matMultiply = new Material(Shader.Find("Hidden/ftMultiply")); RenderTexture rt; if (albedo.format == TextureFormat.RGBA32) { rt = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); } else { rt = new RenderTexture(albedo.width, albedo.height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); } GL.sRGBWrite = albedo.format == TextureFormat.RGBA32; matMultiply.SetFloat("multiplier", val); Graphics.Blit(albedo, rt, matMultiply); Graphics.SetRenderTarget(rt); albedo.ReadPixels(new Rect(0,0,rt.width,rt.height), 0, 0, false); albedo.Apply(); Graphics.SetRenderTarget(null); rt.Release(); } } #endif