2.5d test
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.TestTools;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace BumpCombat.Tests
|
||||
{
|
||||
public sealed class ComparisonSpriteFlipRenderPlayModeTests
|
||||
{
|
||||
private const int FlipRenderTestLayer = 31;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SpriteRendererFlipXMirrorsAsymmetricRenderedSprite()
|
||||
{
|
||||
const int width = 80;
|
||||
const int height = 40;
|
||||
const int textureWidth = 8;
|
||||
const int textureHeight = 4;
|
||||
GameObject cameraObject = null;
|
||||
GameObject spriteObject = null;
|
||||
Texture2D source = null;
|
||||
Texture2D capture = null;
|
||||
RenderTexture target = null;
|
||||
Material material = null;
|
||||
Sprite sprite = null;
|
||||
|
||||
try
|
||||
{
|
||||
Shader shader = Shader.Find("BumpCombat/Comparison Sprite Depth");
|
||||
Assert.That(shader, Is.Not.Null);
|
||||
material = new Material(shader) { enableInstancing = true };
|
||||
source = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false)
|
||||
{
|
||||
filterMode = FilterMode.Point,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
};
|
||||
Color32[] sourcePixels = new Color32[textureWidth * textureHeight];
|
||||
for (int i = 0; i < sourcePixels.Length; i++) sourcePixels[i] = new Color32(0, 0, 0, 0);
|
||||
sourcePixels[0] = new Color32(255, 32, 32, 255);
|
||||
sourcePixels[1] = new Color32(255, 96, 32, 255);
|
||||
sourcePixels[textureWidth + 2] = new Color32(32, 255, 32, 255);
|
||||
sourcePixels[textureWidth * 2 + 5] = new Color32(32, 64, 255, 255);
|
||||
sourcePixels[textureWidth * 3 + 7] = new Color32(255, 255, 32, 255);
|
||||
source.SetPixels32(sourcePixels);
|
||||
source.Apply(false, false);
|
||||
sprite = Sprite.Create(source, new Rect(0, 0, textureWidth, textureHeight),
|
||||
new Vector2(.5f, .5f), 2f);
|
||||
|
||||
target = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32)
|
||||
{
|
||||
filterMode = FilterMode.Point,
|
||||
antiAliasing = 1,
|
||||
};
|
||||
target.Create();
|
||||
cameraObject = new GameObject("Comparison flip render test camera");
|
||||
Camera camera = cameraObject.AddComponent<Camera>();
|
||||
cameraObject.AddComponent<UniversalAdditionalCameraData>().SetRenderer(1);
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = 1f;
|
||||
camera.aspect = (float)width / height;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.backgroundColor = Color.black;
|
||||
camera.targetTexture = target;
|
||||
camera.cullingMask = 1 << FlipRenderTestLayer;
|
||||
camera.transform.position = new Vector3(0f, 0f, -10f);
|
||||
|
||||
spriteObject = new GameObject("Asymmetric flip test sprite");
|
||||
spriteObject.layer = FlipRenderTestLayer;
|
||||
SpriteRenderer renderer = spriteObject.AddComponent<SpriteRenderer>();
|
||||
renderer.sprite = sprite;
|
||||
renderer.sharedMaterial = material;
|
||||
renderer.flipX = false;
|
||||
capture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
yield return null;
|
||||
Color[] forward = Capture(camera, target, capture);
|
||||
|
||||
renderer.flipX = true;
|
||||
yield return null;
|
||||
Color[] flipped = Capture(camera, target, capture);
|
||||
|
||||
int mismatchedPixels = 0;
|
||||
int forwardBrightPixels = 0;
|
||||
int flippedBrightPixels = 0;
|
||||
int flipChangedPixels = 0;
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Color expected = forward[y * width + (width - 1 - x)];
|
||||
Color actual = flipped[y * width + x];
|
||||
Color sameCoordinateForward = forward[y * width + x];
|
||||
if (IsBright(forward[y * width + x])) forwardBrightPixels++;
|
||||
if (IsBright(actual)) flippedBrightPixels++;
|
||||
if (ColorDistance(sameCoordinateForward, actual) > .02f) flipChangedPixels++;
|
||||
if (Mathf.Abs(expected.r - actual.r) + Mathf.Abs(expected.g - actual.g)
|
||||
+ Mathf.Abs(expected.b - actual.b) + Mathf.Abs(expected.a - actual.a) > .02f)
|
||||
mismatchedPixels++;
|
||||
}
|
||||
Assert.That(forwardBrightPixels, Is.GreaterThan(0), "The forward image must contain rendered sprite pixels.");
|
||||
Assert.That(flippedBrightPixels, Is.GreaterThan(0), "The flipped image must contain rendered sprite pixels.");
|
||||
Assert.That(flipChangedPixels, Is.GreaterThan(0), "Flipping this asymmetric sprite must change actual pixels.");
|
||||
Assert.That(mismatchedPixels, Is.Zero,
|
||||
"SpriteRenderer.flipX must mirror the rendered pixels, not merely expose a flip flag.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (spriteObject != null) Object.Destroy(spriteObject);
|
||||
if (cameraObject != null) Object.Destroy(cameraObject);
|
||||
if (sprite != null) Object.Destroy(sprite);
|
||||
if (source != null) Object.Destroy(source);
|
||||
if (capture != null) Object.Destroy(capture);
|
||||
if (target != null) { target.Release(); Object.Destroy(target); }
|
||||
if (material != null) Object.Destroy(material);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SharedSpriteMaterialStillRendersMeshAndLineGeometry()
|
||||
{
|
||||
const int width = 80;
|
||||
const int height = 80;
|
||||
GameObject cameraObject = null;
|
||||
GameObject meshObject = null;
|
||||
GameObject lineObject = null;
|
||||
Texture2D capture = null;
|
||||
RenderTexture target = null;
|
||||
Material material = null;
|
||||
Mesh mesh = null;
|
||||
try
|
||||
{
|
||||
Shader shader = Shader.Find("BumpCombat/Comparison Sprite Depth");
|
||||
Assert.That(shader, Is.Not.Null);
|
||||
material = new Material(shader);
|
||||
target = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
|
||||
target.Create();
|
||||
|
||||
cameraObject = new GameObject("Shared material render test camera");
|
||||
Camera camera = cameraObject.AddComponent<Camera>();
|
||||
cameraObject.AddComponent<UniversalAdditionalCameraData>().SetRenderer(1);
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = 2f;
|
||||
camera.aspect = 1f;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.backgroundColor = Color.black;
|
||||
camera.targetTexture = target;
|
||||
camera.cullingMask = 1 << FlipRenderTestLayer;
|
||||
camera.transform.position = new Vector3(0f, 0f, -10f);
|
||||
|
||||
meshObject = new GameObject("Ground-like MeshRenderer");
|
||||
meshObject.layer = FlipRenderTestLayer;
|
||||
mesh = new Mesh
|
||||
{
|
||||
vertices = new[]
|
||||
{
|
||||
new Vector3(-.6f, .1f, 0f), new Vector3(.6f, .1f, 0f),
|
||||
new Vector3(-.6f, 1.3f, 0f), new Vector3(.6f, 1.3f, 0f),
|
||||
},
|
||||
uv = new[] { Vector2.zero, Vector2.right, Vector2.up, Vector2.one },
|
||||
colors = new[] { Color.white, Color.white, Color.white, Color.white },
|
||||
triangles = new[] { 0, 2, 1, 2, 3, 1 },
|
||||
};
|
||||
mesh.RecalculateBounds();
|
||||
meshObject.AddComponent<MeshFilter>().sharedMesh = mesh;
|
||||
meshObject.AddComponent<MeshRenderer>().sharedMaterial = material;
|
||||
|
||||
lineObject = new GameObject("Ground-like LineRenderer");
|
||||
lineObject.layer = FlipRenderTestLayer;
|
||||
LineRenderer line = lineObject.AddComponent<LineRenderer>();
|
||||
line.useWorldSpace = true;
|
||||
line.positionCount = 2;
|
||||
line.startWidth = line.endWidth = .12f;
|
||||
line.startColor = line.endColor = Color.red;
|
||||
line.sharedMaterial = material;
|
||||
line.SetPosition(0, new Vector3(-1.2f, -1f, 0f));
|
||||
line.SetPosition(1, new Vector3(1.2f, -1f, 0f));
|
||||
|
||||
capture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
yield return null;
|
||||
Color[] pixels = Capture(camera, target, capture);
|
||||
int meshPixels = 0;
|
||||
int linePixels = 0;
|
||||
foreach (Color pixel in pixels)
|
||||
{
|
||||
if (pixel.r > .8f && pixel.g > .8f && pixel.b > .8f) meshPixels++;
|
||||
if (pixel.r > .8f && pixel.g < .3f && pixel.b < .3f) linePixels++;
|
||||
}
|
||||
Assert.That(meshPixels, Is.GreaterThan(10),
|
||||
"The shared shader must keep opaque floor/mesh geometry visible with default SpriteProps.");
|
||||
Assert.That(linePixels, Is.GreaterThan(3),
|
||||
"LineRenderer geometry using the shared comparison material must remain visible.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (meshObject != null) Object.Destroy(meshObject);
|
||||
if (lineObject != null) Object.Destroy(lineObject);
|
||||
if (cameraObject != null) Object.Destroy(cameraObject);
|
||||
if (capture != null) Object.Destroy(capture);
|
||||
if (mesh != null) Object.Destroy(mesh);
|
||||
if (target != null) { target.Release(); Object.Destroy(target); }
|
||||
if (material != null) Object.Destroy(material);
|
||||
}
|
||||
}
|
||||
|
||||
private static Color[] Capture(Camera camera, RenderTexture target, Texture2D capture)
|
||||
{
|
||||
RenderTexture previous = RenderTexture.active;
|
||||
camera.Render();
|
||||
RenderTexture.active = target;
|
||||
capture.ReadPixels(new Rect(0f, 0f, target.width, target.height), 0, 0);
|
||||
capture.Apply(false, false);
|
||||
Color[] pixels = capture.GetPixels();
|
||||
RenderTexture.active = previous;
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static bool IsBright(Color color) => color.r > .25f || color.g > .25f || color.b > .25f;
|
||||
|
||||
private static float ColorDistance(Color a, Color b) => Mathf.Abs(a.r - b.r) + Mathf.Abs(a.g - b.g)
|
||||
+ Mathf.Abs(a.b - b.b) + Mathf.Abs(a.a - b.a);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user