Files
2026-02-21 16:45:37 +08:00

634 lines
16 KiB
C#

using System;
using System.Collections;
using System.IO;
using UnityEngine;
public class MegaGrab : MonoBehaviour
{
public Camera SrcCamera;
public KeyCode GrabKey = KeyCode.S;
public int ResUpscale = 1;
public float Blur = 1f;
public int AASamples = 8;
public AnisotropicFiltering FilterMode = AnisotropicFiltering.ForceEnable;
public bool UseJitter;
public string SaveName = "Grab";
public string Format = "dddd MMM dd yyyy HH_mm_ss";
public string Enviro = string.Empty;
public string Path = string.Empty;
public bool UseDOF;
public float focalDistance = 8f;
public int totalSegments = 8;
public float sampleRadius = 1f;
public bool CalcFromSize;
public int Dpi = 300;
public float Width = 24f;
public int NumberOfGrabs;
public float EstimatedTime;
public int GrabWidthWillBe;
public int GrabHeightWillBe;
public bool UseCoroutine;
private float mleft;
private float mright;
private float mtop;
private float mbottom;
private int sampcount;
private Vector2[] poisson;
private Texture2D grabtex;
private Color[,] accbuf;
private Color[,] blendbuf;
private byte[] output1;
private Color[] outputjpg;
private AnisotropicFiltering filtering;
private MGBlendTable blendtable;
private int DOFSamples;
private Vector3 camfor;
private Vector3 campos;
private Matrix4x4 camtm;
public IMGFormat OutputFormat = IMGFormat.Jpg;
public float Quality = 75f;
public bool uploadGrabs;
public string m_URL = "http://www.west-racing.com/uploadtest1.php";
private void CalcDOFInfo(Camera camera)
{
camtm = camera.transform.localToWorldMatrix;
campos = camera.transform.position;
camfor = camera.transform.forward;
}
private void ChangeDOFPos(int segment)
{
float f = (float)segment / (float)totalSegments * (float)Math.PI * 2f;
float num = sampleRadius;
float x = num * Mathf.Cos(f);
float y = num * Mathf.Sin(f);
Vector3 point = new Vector3(x, y, 0f);
Vector3 vector = camfor * focalDistance;
Vector3 worldPosition = vector + campos;
SrcCamera.transform.position = camtm.MultiplyPoint3x4(point);
SrcCamera.transform.LookAt(worldPosition);
}
private static Matrix4x4 PerspectiveOffCenter(float left, float right, float bottom, float top, float near, float far)
{
Matrix4x4 identity = Matrix4x4.identity;
identity[0, 0] = 2f * near / (right - left);
identity[1, 1] = 2f * near / (top - bottom);
identity[0, 2] = (right + left) / (right - left);
identity[1, 2] = (top + bottom) / (top - bottom);
identity[2, 2] = (0f - (far + near)) / (far - near);
identity[2, 3] = (0f - 2f * far * near) / (far - near);
identity[3, 2] = -1f;
identity[3, 3] = 0f;
return identity;
}
private Matrix4x4 CalcProjectionMatrix(float left, float right, float bottom, float top, float near, float far, float xoff, float yoff)
{
float num = (right - left) / (float)Screen.width;
float num2 = (top - bottom) / (float)Screen.height;
return PerspectiveOffCenter(left - xoff * num, right - xoff * num, bottom - yoff * num2, top - yoff * num2, near, far);
}
private void Cleanup()
{
QualitySettings.anisotropicFiltering = filtering;
}
private bool InitGrab(int width, int height, int aasamples)
{
blendtable = new MGBlendTable(32, 32, totalSegments, 0.4f, true);
if (ResUpscale < 1)
{
ResUpscale = 1;
}
if (AASamples < 1)
{
AASamples = 1;
}
if (SrcCamera == null)
{
SrcCamera = Camera.main;
}
if (SrcCamera == null)
{
Debug.Log("No Camera set as source and no main camera found in the scene");
return false;
}
CalcDOFInfo(SrcCamera);
if (OutputFormat == IMGFormat.Tga)
{
output1 = new byte[width * ResUpscale * (height * ResUpscale) * 3];
}
else
{
outputjpg = new Color[width * ResUpscale * (height * ResUpscale)];
}
if (output1 != null || outputjpg != null)
{
filtering = QualitySettings.anisotropicFiltering;
QualitySettings.anisotropicFiltering = FilterMode;
grabtex = new Texture2D(width, height, TextureFormat.RGB24, false);
if (grabtex != null)
{
accbuf = new Color[width, height];
blendbuf = new Color[width, height];
if (accbuf != null)
{
float a = (1f - Blur) * 0.5f;
float b = 1f + (Blur - 1f) * 0.5f;
if (UseJitter)
{
poisson = new Vector2[aasamples];
sampcount = aasamples;
for (int i = 0; i < aasamples; i++)
{
Vector2 vector = new Vector2
{
x = Mathf.Lerp(a, b, UnityEngine.Random.value),
y = Mathf.Lerp(a, b, UnityEngine.Random.value)
};
poisson[i] = vector;
}
}
else
{
int num = (int)Mathf.Sqrt(aasamples);
if (num < 1)
{
num = 1;
}
sampcount = num * num;
poisson = new Vector2[num * num];
int num2 = 0;
for (int j = 0; j < num; j++)
{
for (int k = 0; k < num; k++)
{
float t = (float)k / (float)num;
float t2 = (float)j / (float)num;
Vector2 vector2 = new Vector2
{
x = Mathf.Lerp(a, b, t),
y = Mathf.Lerp(a, b, t2)
};
poisson[num2++] = vector2;
}
}
}
return true;
}
}
}
Debug.Log("Cant create a large enough texture, Try lower ResUpscale value");
return false;
}
private Texture2D GrabImage(int samples, float x, float y)
{
float num = 1f / (float)ResUpscale;
for (int i = 0; i < sampcount; i++)
{
float num2 = poisson[i].x * num;
float num3 = poisson[i].y * num;
float xoff = x + num2;
float yoff = y + num3;
SrcCamera.projectionMatrix = CalcProjectionMatrix(mleft, mright, mbottom, mtop, SrcCamera.nearClipPlane, SrcCamera.farClipPlane, xoff, yoff);
SrcCamera.Render();
grabtex.ReadPixels(new Rect(0f, 0f, Screen.width, Screen.height), 0, 0);
grabtex.Apply();
if (i == 0)
{
for (int j = 0; j < Screen.height; j++)
{
for (int k = 0; k < Screen.width; k++)
{
accbuf[k, j] = grabtex.GetPixel(k, j);
}
}
continue;
}
for (int l = 0; l < Screen.height; l++)
{
for (int m = 0; m < Screen.width; m++)
{
accbuf[m, l] += grabtex.GetPixel(m, l);
}
}
}
for (int n = 0; n < Screen.height; n++)
{
for (int num4 = 0; num4 < Screen.width; num4++)
{
grabtex.SetPixel(num4, n, accbuf[num4, n] / sampcount);
}
}
grabtex.Apply();
return grabtex;
}
private void GrabAA(float x, float y)
{
float num = 1f / (float)ResUpscale;
for (int i = 0; i < Screen.height; i++)
{
for (int j = 0; j < Screen.width; j++)
{
accbuf[j, i] = Color.black;
}
}
for (int k = 0; k < sampcount; k++)
{
float num2 = poisson[k].x * num;
float num3 = poisson[k].y * num;
float xoff = x + num2;
float yoff = y + num3;
SrcCamera.projectionMatrix = CalcProjectionMatrix(mleft, mright, mbottom, mtop, SrcCamera.nearClipPlane, SrcCamera.farClipPlane, xoff, yoff);
SrcCamera.Render();
grabtex.ReadPixels(new Rect(0f, 0f, Screen.width, Screen.height), 0, 0);
grabtex.Apply();
for (int l = 0; l < Screen.height; l++)
{
for (int m = 0; m < Screen.width; m++)
{
accbuf[m, l] += grabtex.GetPixel(m, l);
}
}
}
for (int n = 0; n < Screen.height; n++)
{
for (int num4 = 0; num4 < Screen.width; num4++)
{
accbuf[num4, n] /= sampcount;
}
}
}
private Texture2D GrabImageDOF(int samples, float x, float y)
{
for (int i = 0; i < Screen.height; i++)
{
for (int j = 0; j < Screen.width; j++)
{
blendbuf[j, i] = Color.black;
}
}
for (int k = 0; k < totalSegments; k++)
{
ChangeDOFPos(k);
GrabAA(x, y);
blendtable.BlendImages(blendbuf, accbuf, Screen.width, Screen.height, k);
}
return grabtex;
}
private void DoGrabTGA()
{
if (!InitGrab(Screen.width, Screen.height, AASamples))
{
return;
}
mtop = SrcCamera.nearClipPlane * Mathf.Tan(SrcCamera.fieldOfView * 0.5f * ((float)Math.PI / 180f));
mbottom = 0f - mtop;
mleft = mbottom * SrcCamera.aspect;
mright = mtop * SrcCamera.aspect;
int width = Screen.width;
int height = Screen.height;
if (AASamples < 1)
{
AASamples = 1;
}
int num = 0;
for (int i = 0; i < ResUpscale; i++)
{
float y = (float)i / (float)ResUpscale;
for (int j = 0; j < ResUpscale; j++)
{
num++;
float x = (float)j / (float)ResUpscale;
Texture2D texture2D;
if (UseDOF)
{
texture2D = GrabImageDOF(AASamples, x, y);
for (int k = 0; k < Screen.height; k++)
{
int num2 = (ResUpscale - i + k * ResUpscale - 1) * (width * ResUpscale);
for (int l = 0; l < Screen.width; l++)
{
Color color = blendbuf[l, k];
int num3 = (num2 + (ResUpscale - j + l * ResUpscale - 1)) * 3;
output1[num3] = (byte)(color.b * 255f);
output1[num3 + 1] = (byte)(color.g * 255f);
output1[num3 + 2] = (byte)(color.r * 255f);
}
}
continue;
}
texture2D = GrabImage(AASamples, x, y);
for (int m = 0; m < Screen.height; m++)
{
int num4 = (ResUpscale - i + m * ResUpscale - 1) * (width * ResUpscale);
for (int n = 0; n < Screen.width; n++)
{
Color pixel = texture2D.GetPixel(n, m);
int num5 = (num4 + (ResUpscale - j + n * ResUpscale - 1)) * 3;
output1[num5] = (byte)(pixel.b * 255f);
output1[num5 + 1] = (byte)(pixel.g * 255f);
output1[num5 + 2] = (byte)(pixel.r * 255f);
}
}
}
}
string text = string.Empty;
if (Enviro != null && Enviro.Length > 0)
{
text = Environment.GetEnvironmentVariable(Enviro);
}
string text2 = text + Path + SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
SaveTGA(text2 + ".tga", width * ResUpscale, height * ResUpscale, output1);
SrcCamera.ResetProjectionMatrix();
Cleanup();
}
private void DoGrabJPG()
{
if (!InitGrab(Screen.width, Screen.height, AASamples))
{
return;
}
mtop = SrcCamera.nearClipPlane * Mathf.Tan(SrcCamera.fieldOfView * 0.5f * ((float)Math.PI / 180f));
mbottom = 0f - mtop;
mleft = mbottom * SrcCamera.aspect;
mright = mtop * SrcCamera.aspect;
int width = Screen.width;
int height = Screen.height;
if (AASamples < 1)
{
AASamples = 1;
}
int num = 0;
for (int i = 0; i < ResUpscale; i++)
{
float y = (float)i / (float)ResUpscale;
for (int j = 0; j < ResUpscale; j++)
{
num++;
float x = (float)j / (float)ResUpscale;
Texture2D texture2D;
if (UseDOF)
{
texture2D = GrabImageDOF(AASamples, x, y);
for (int k = 0; k < Screen.height; k++)
{
int num2 = (ResUpscale - i + k * ResUpscale - 1) * (width * ResUpscale);
for (int l = 0; l < Screen.width; l++)
{
Color color = blendbuf[l, k];
int num3 = num2 + (ResUpscale - j + l * ResUpscale - 1);
outputjpg[num3] = color;
}
}
continue;
}
texture2D = GrabImage(AASamples, x, y);
for (int m = 0; m < Screen.height; m++)
{
int num4 = (ResUpscale - i + m * ResUpscale - 1) * (width * ResUpscale);
for (int n = 0; n < Screen.width; n++)
{
Color pixel = texture2D.GetPixel(n, m);
int num5 = num4 + (ResUpscale - j + n * ResUpscale - 1);
outputjpg[num5] = pixel;
}
}
}
}
string text = string.Empty;
if (Enviro != null && Enviro.Length > 0)
{
text = Environment.GetEnvironmentVariable(Enviro);
}
if (uploadGrabs)
{
string text2 = SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
UploadJPG(text2 + ".jpg", width * ResUpscale, height * ResUpscale, outputjpg);
}
else
{
string text3 = text + Path + SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
SaveJPG(text3 + ".jpg", width * ResUpscale, height * ResUpscale, outputjpg);
}
SrcCamera.ResetProjectionMatrix();
Cleanup();
}
private void SaveJPG(string filename, int width, int height, Color[] pixels)
{
FileStream fileStream = new FileStream(filename, FileMode.Create);
if (fileStream != null)
{
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
if (binaryWriter != null)
{
Quality = Mathf.Clamp(Quality, 0f, 100f);
JPGEncoder jPGEncoder = new JPGEncoder(pixels, width, height, Quality);
jPGEncoder.doEncoding();
byte[] bytes = jPGEncoder.GetBytes();
binaryWriter.Write(bytes);
binaryWriter.Close();
}
fileStream.Close();
}
}
private void UploadJPG(string filename, int width, int height, Color[] pixels)
{
Quality = Mathf.Clamp(Quality, 0f, 100f);
JPGEncoder jPGEncoder = new JPGEncoder(pixels, width, height, Quality);
jPGEncoder.doEncoding();
byte[] bytes = jPGEncoder.GetBytes();
UploadFile(bytes, m_URL, filename);
}
private void SaveTGA(string filename, int width, int height, byte[] pixels)
{
FileStream fileStream = new FileStream(filename, FileMode.Create);
if (fileStream == null)
{
return;
}
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
if (binaryWriter != null)
{
binaryWriter.Write((short)0);
binaryWriter.Write((byte)2);
binaryWriter.Write(0);
binaryWriter.Write(0);
binaryWriter.Write((byte)0);
binaryWriter.Write((short)width);
binaryWriter.Write((short)height);
binaryWriter.Write((byte)24);
binaryWriter.Write((byte)0);
for (int i = 0; i < pixels.Length; i++)
{
binaryWriter.Write(pixels[i]);
}
binaryWriter.Close();
}
fileStream.Close();
}
private void CalcUpscale()
{
float num = Width / ((float)Screen.width / (float)Dpi);
ResUpscale = (int)num;
GrabWidthWillBe = Screen.width * ResUpscale;
GrabHeightWillBe = Screen.height * ResUpscale;
}
private void CalcEstimate()
{
NumberOfGrabs = ResUpscale * ResUpscale * AASamples;
if (UseDOF)
{
NumberOfGrabs *= totalSegments;
}
EstimatedTime = (float)NumberOfGrabs * 0.41f;
}
private IEnumerator GrabCoroutine()
{
yield return new WaitForEndOfFrame();
if (OutputFormat == IMGFormat.Tga)
{
DoGrabTGA();
}
else
{
DoGrabJPG();
}
yield return null;
}
private void LateUpdate()
{
if (!Input.GetKeyDown(GrabKey))
{
return;
}
if (CalcFromSize)
{
CalcUpscale();
}
CalcEstimate();
if (UseCoroutine)
{
StartCoroutine(GrabCoroutine());
return;
}
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (OutputFormat == IMGFormat.Tga)
{
DoGrabTGA();
}
else
{
DoGrabJPG();
}
Debug.Log("Took " + (Time.realtimeSinceStartup - realtimeSinceStartup).ToString("0.00000000") + "s");
}
private void OnDrawGizmos()
{
if (CalcFromSize)
{
CalcUpscale();
}
CalcEstimate();
}
private IEnumerator UploadFileCo(byte[] data, string uploadURL, string filename)
{
WWWForm postForm = new WWWForm();
Debug.Log("uploading " + filename);
postForm.AddField("action", "Upload Image");
postForm.AddBinaryData("theFile", data, filename, "images/jpg");
Debug.Log("url " + uploadURL);
WWW upload = new WWW(uploadURL, postForm);
yield return upload;
Debug.Log("upload done :" + upload.text);
Debug.Log("Error during upload: " + upload.error);
}
private void UploadFile(byte[] data, string uploadURL, string filename)
{
Debug.Log("Start upload");
StartCoroutine(UploadLevel(data, uploadURL, filename));
Debug.Log("len " + data.Length);
}
private IEnumerator UploadLevel(byte[] data, string uploadURL, string filename)
{
WWWForm form = new WWWForm();
form.AddField("action", "level upload");
form.AddField("file", "file");
form.AddBinaryData("file", data, filename, "images/jpg");
Debug.Log("url " + uploadURL);
WWW w = new WWW(uploadURL, form);
yield return w;
if (w.error != null)
{
MonoBehaviour.print("error");
MonoBehaviour.print(w.error);
}
else if (w.uploadProgress == 1f && w.isDone)
{
yield return new WaitForSeconds(5f);
}
}
}