DeltaVR/Assets/Editor/x64/Bakery/scripts/ftUVGBufferGen.cs
2020-12-03 20:09:51 +02:00

466 lines
18 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.IO;
public class ftUVGBufferGen
{
static RenderTexture rtAlbedo, rtEmissive, rtNormal;
public static Texture2D texAlbedo, texEmissive, texNormal, texBestFit;
//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 Vector4 metaControl, metaControlAlbedo, metaControlEmission, metaControlNormal;
static Material fallbackMat, normalMat, blackMat;
static int fallbackMatMetaPass;
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;
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);
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 RenderUVGBuffer(Mesh mesh, Renderer renderer, Vector4 scaleOffset, Matrix4x4 worldMatrix, bool vertexBake,
Vector2[] uvOverride, bool terrainNormals = false)
{
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<3; pass++)
{
if (pass == 1 && !emissiveEnabled) continue;
if (pass == 2 && !normalEnabled) continue;
if (pass == 0)
{
Graphics.SetRenderTarget(rtAlbedo);
}
else if (pass == 1)
{
Graphics.SetRenderTarget(rtEmissive);
}
else
{
Graphics.SetRenderTarget(rtNormal);
}
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 == 1 && materials[i].globalIlluminationFlags != MaterialGlobalIlluminationFlags.BakedEmissive);
var rpTag = materials[i].GetTag("RenderPipeline", true, "");
bool isHDRP = rpTag == "HDRenderPipeline";
if (pass == 2) isHDRP = false;
int bakeryPass = -1;
if (pass < 2)
{
int metaPass = -1;
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", (isHDRP) ? scaleOffsetFlipped : scaleOffset);
Shader.SetGlobalVector("unity_MetaFragmentControl", pass == 0 ? 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");
}
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");
if (materials[i].HasProperty("_Color")) fallbackMat.SetVector("_Color", materials[i].GetVector("_Color"));
if (materials[i].HasProperty("_EmissionMap")) fallbackMat.SetTexture("_EmissionMap", materials[i].GetTexture("_EmissionMap"));
if (materials[i].HasProperty("_EmissionColor")) fallbackMat.SetVector("_EmissionColor", materials[i].GetVector("_EmissionColor"));
fallbackMat.SetPass(fallbackMatMetaPass);
}
}
}
else
{
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
{
normalMat.SetTexture("_BumpMap", null);
}
normalMat.SetFloat("_IsTerrain", terrainNormals ? 1.0f : 0.0f);
normalMat.SetTexture("bestFitNormalMap", texBestFit);
normalMat.SetPass(0);
}
else
{
materials[i].SetTexture("bestFitNormalMap", texBestFit);
materials[i].SetPass(metaPass);
}
Shader.SetGlobalVector("unity_MetaFragmentControl", metaControlNormal);
}
GL.sRGBWrite = pass == 0;
if (!vertexBake)
{
for(int j=0; j<uvOffset.Length/2; j++)
{
if (pass < 2)
{
UpdateMatrix(worldMatrix, uvOffset[j*2] * texelSize, uvOffset[j*2+1] * texelSize);
}
else
{
// TODO: use in HDRP as well
var srcVec = (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
{
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();
if (emissiveEnabled)
{
Graphics.SetRenderTarget(rtEmissive);
texEmissive.ReadPixels(new Rect(0,0,rtEmissive.width,rtEmissive.height), 0, 0, false);
texEmissive.Apply();
}
if (normalEnabled)
{
Graphics.SetRenderTarget(rtNormal);
texNormal.ReadPixels(new Rect(0,0,rtNormal.width,rtNormal.height), 0, 0, false);
texNormal.Apply();
}
}
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();
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();
}
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();
}
}
#endif