#if UNITY_EDITOR using UnityEngine; using UnityEditor; using System.IO; 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; 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 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 public void StartUVGBuffer(int size, bool hasEmissive, bool hasNormal) { emissiveEnabled = hasEmissive; normalEnabled = hasNormal; alphaEnabled = false; 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, true); 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)); } static public void RenderUVGBuffer(Mesh mesh, Renderer renderer, Vector4 scaleOffset, Transform worldTransform, bool vertexBake, Vector2[] uvOverride, bool terrainNormals = false, bool metaAlpha = false) { var worldMatrix = worldTransform.localToWorldMatrix; if (pstorage == null) pstorage = ftLightmaps.GetProjectSettings(); if (metaAlpha && !alphaEnabled) { int res = rtAlbedo.width * pstorage.alphaMetaPassResolutionMultiplier; if (res > 8192) res = 8192; InitAlphaBuffer(res); } Material[] materials = renderer.sharedMaterials; #if SUPPORT_MBLOCKS var mb = new MaterialPropertyBlock(); #endif var m = mesh; if (uvOverride != null) { m = Mesh.Instantiate(mesh); //var uvs = m.uv2; //if (uvs.Length == 0) uvs = m.uv; //var pos = new Vector3[uvs.Length]; /*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); } else { if (passAsBlack) { if (blackMat == null) { blackMat = new Material(Shader.Find("Hidden/ftBlack")); } Shader.SetGlobalVector("unity_LightmapST", scaleOffset); blackMat.SetPass(0); } 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); } } } 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); } else { materials[i].SetTexture("bestFitNormalMap", texBestFit); materials[i].SetFloat("_IsPerPixel", (isURP||isHDRP) ? 1.0f : 0.0f); materials[i].SetPass(metaPass); } 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); Shader.SetGlobalVector("unity_MetaFragmentControl", metaControlAlpha); } GL.sRGBWrite = pass == PASS_ALBEDO; if (!vertexBake) { for(int j=0; j= 0) { materials[i].SetPass(bakeryPass); } 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); } } Graphics.DrawMeshNow(m, worldMatrix, i); } } else { UpdateMatrix(worldMatrix, 0, 0); #if SUPPORT_MBLOCKS #if UNITY_2018_1_OR_NEWER renderer.GetPropertyBlock(mb, i); #else renderer.GetPropertyBlock(mb); #endif Graphics.DrawMesh(m, worldMatrix, materials[i], 0, null, i, mb, false, false, false); #else Graphics.DrawMeshNow(m, worldMatrix, i); #endif } } } } 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) { 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); for(int i=0; i<8; i++) { Graphics.Blit(rt, rt2, matDilate); Graphics.Blit(rt2, rt, matDilate); } 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