ArabDesert/Assets/Editor/x64/Bakery/scripts/ftUVGBufferGen.cs

599 lines
23 KiB
C#

#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<Camera>();
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<uvs.Length; i++)
{
pos[i] = new Vector3(uvs[i].x * scaleOffset.x + scaleOffset.z, uvs[i].y * scaleOffset.y + scaleOffset.w, 0.0f);
}
m.vertices = pos;*/
m.uv2 = uvOverride;
if (vertexBake)
{
for(int i=0; i<mesh.subMeshCount; i++)
{
var indices = m.GetIndices(i);
m.SetIndices(indices, MeshTopology.Points, i, false);
}
}
}
//var scaleOffsetFlipped = new Vector4(scaleOffset.x, -scaleOffset.y, scaleOffset.z, 1.0f - scaleOffset.w);
//UpdateMatrix(worldMatrix);
for(int pass=0; pass<PASS_COUNT; pass++)
{
if (pass == PASS_EMISSIVE && !emissiveEnabled) continue;
if (pass == PASS_NORMAL && !normalEnabled) continue;
if (pass == PASS_ALPHA && !alphaEnabled) continue; // per Start-End
if (pass == PASS_ALPHA && !metaAlpha) continue; // per this object
if (pass == PASS_ALBEDO)
{
Graphics.SetRenderTarget(rtAlbedo);
}
else if (pass == PASS_EMISSIVE)
{
Graphics.SetRenderTarget(rtEmissive);
}
else if (pass == PASS_NORMAL)
{
Graphics.SetRenderTarget(rtNormal);
}
else if (pass == PASS_ALPHA)
{
Graphics.SetRenderTarget(rtAlpha);
}
for(int i=0; i<mesh.subMeshCount; i++)
{
if (materials.Length <= i) break;
if (materials[i] == null) continue;
if (materials[i].shader == null) continue;
// Optionally skip emission
bool passAsBlack = (pass == PASS_EMISSIVE && materials[i].globalIlluminationFlags != MaterialGlobalIlluminationFlags.BakedEmissive);
var rpTag = materials[i].GetTag("RenderPipeline", true, "");
bool isHDRP = rpTag == "HDRenderPipeline";
if (pass >= 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<materials[i].passCount; mpass++)
{
if (materials[i].GetPassName(mpass).IndexOf("META") >= 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<uvOffset.Length/2; j++)
{
if (pass < PASS_NORMAL)
{
UpdateMatrix(worldMatrix, uvOffset[j*2] * texelSize, uvOffset[j*2+1] * texelSize);
}
else
{
// TODO: use in HDRP as well
var srcVec = scaleOffset;//(isHDRP) ? scaleOffsetFlipped : scaleOffset;
var vec = new Vector4(srcVec.x, srcVec.y, srcVec.z + uvOffset[j*2] * texelSize, srcVec.w + uvOffset[j*2+1] * texelSize);
Shader.SetGlobalVector("unity_LightmapST", vec);
if (bakeryPass >= 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