Интерполяция в marching squares

Нашел на гитхабе самый простой пример кода Marching squares с интерполяцией. Без интерполяции всё вообще просто, даже пример не нужен.
Отрефакторил код (выпилил всё лишнее) и получилось вот что:

	private List<Vector3> GetTriangles(int state, int x, int y)
	{
		float t = 0.5f;
		float lerpAB = Mathf.InverseLerp(aEdgeValue, bEdgeValue, t);
		float lerpBC = Mathf.InverseLerp(bEdgeValue, cEdgeValue, t);
		float lerpCD = Mathf.InverseLerp(cEdgeValue, dEdgeValue, t);
		float lerpDA = Mathf.InverseLerp(dEdgeValue, aEdgeValue, t);
		
		float a = 0.5f;
		Vector3 v0 = new Vector3(x - a, 0, y + a);
		Vector3 v1 = new Vector3(x + a, 0, y + a);
		Vector3 v2 = new Vector3(x - a, 0, y - a);
		Vector3 v3 = new Vector3(x + a, 0, y - a);
		Vector3 v4 = new Vector3(x - a + lerpAB, 0, y + a);
		Vector3 v5 = new Vector3(x + a, 0, y + a - lerpBC);
		Vector3 v6 = new Vector3(x + a - lerpCD, 0, y - a);
		Vector3 v7 = new Vector3(x - a, 0, y - a + lerpDA);
		
		.....
	}

Проблема: квадрат рисуется от центра [x,y], а мне надо чтобы точка [x,y] была в углу квадрата. Не могу натыкать, чтобы оно сместилось.
Можно, конечно, сделать так:

x += 0.5f;
y += 0.5f;

Но это костыль, а не решение.

И еще не получается изменить размер квадрата. Работает только при t == 0.5 a == 0.5. Если что-то изменить, то всё сломается.
Возможно, это потому что

	private int IsEdgeEnabled(float edgeValue)
	{
		return edgeValue > halfResolution ? 1 : 0;
	}

у меня halfResolution == 0.5, а должен быть равен a или чему-то ещё :thinking:

Так мы откуда знаем где там что?)

Если там размер задан в разных местах, а не на основе одной переменной, то видимо надо везде и менять :man_shrugging:

С размером квадрата разобрался. Осталось только сместить. Я уже и так и эдак пробовал, но получается хрень.

x,y - центр квадрата
a - половина размера квадрата
v0,v1,v2,v3 - координаты углов квадрата
v4,v5,v6,v7 - координаты точек между углами
этого не достаточно?

Ну без всего кода непонятно ж как оно работает и с чем могут быть проблемы.

Чтобы рисовать от точки по идее надо просто сдвинуть всё на а.

image

drawRectByPoints(
    [x - a, y + a],
    [x + a, y + a],
    [x + a, y - a],
    [x - a, y - a],
    'red'
);
drawRectByPoints(
    [x, y + 2 * a],
    [x + 2 * a, y + 2 * a],
    [x + 2 * a, y],
    [x, y],
    'green'
);

https://jsfiddle.net/AlexP11223/kqt8x3c4/20/

Вообще просто передавать нужные x и y (увеличенные на а) не выглядит особо костылем.

Проблема была в том, что координаты точек были не там, где я ожидал. По-этому, не было понятно, где какие углы находятся.
Сейчас я, вроде, разобрался. Позже выложу весь код (когда допилю).

Вот предварительная версия (рабочая):

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MarchingSquareInterpolation : MonoBehaviour
{
    private int fieldSizeX = 2; //must be 2
    private int fieldSizeZ = 2; //must be 2
    private float resolution = 1.0f; //size of the square
	private float halfResolution;
    private float[,] cornerValues;
	
    private float aCornerValue;
	private float bCornerValue;
	private	float cCornerValue;
	private	float dCornerValue;

	[Range(0.0f, 1.0f)]
	public float aSliderValue = 1.0f;
	[Range(0.0f, 1.0f)]
	public float bSliderValue = 0.0f;
	[Range(0.0f, 1.0f)]
	public float cSliderValue = 0.0f;
	[Range(0.0f, 1.0f)]
	public float dSliderValue = 0.0f;

	private MeshFilter meshFilter;
	
    private void Start()
    {
		cornerValues = new float[fieldSizeX, fieldSizeZ];
		
		halfResolution = resolution / 2.0f;

        meshFilter = GetComponent<MeshFilter>();
    }
	
	private void LateUpdate()
	{
		cornerValues[0, 1] = aSliderValue;
		cornerValues[1, 1] = bSliderValue;
		cornerValues[1, 0] = cSliderValue;
		cornerValues[0, 0] = dSliderValue;

		UpdateMesh();
	}

	private void UpdateMesh()
	{
		if (meshFilter == null)
		{
			return;
		}
		
		List<Vector3> verts = new List<Vector3>();
		List<int> tris = new List<int>();

        for (int x = 0; x < fieldSizeX - 1; x++)
        {
            for (int z = 0; z < fieldSizeZ - 1; z++)
            {
				aCornerValue = cornerValues[x,     z    ];
				bCornerValue = cornerValues[x + 1, z    ];
				cCornerValue = cornerValues[x + 1, z + 1];
				dCornerValue = cornerValues[x,     z + 1];

                int aCornerEnabled = IsEdgeEnabled(aCornerValue);
				int bCornerEnabled = IsEdgeEnabled(bCornerValue);
				int cCornerEnabled = IsEdgeEnabled(cCornerValue);
				int dCornerEnabled = IsEdgeEnabled(dCornerValue);

				int state = GetState(aCornerEnabled, bCornerEnabled, cCornerEnabled, dCornerEnabled);
				Debug.Log(state);

				if (state > 0)
				{
					List<Vector3> triangles = GetTriangles(state, (float)x * resolution, (float)z * resolution);
					
					for (int i = 0; i < triangles.Count; i += 3)
					{
						AddTriangle(triangles[i], triangles[i + 1], triangles[i + 2]);
					}
				}
			}
        }

		meshFilter.mesh = new Mesh()
		{
			vertices = verts.ToArray(),
			triangles = tris.ToArray()
		};

		void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
		{
			tris.Add(verts.Count);
			tris.Add(verts.Count + 1);
			tris.Add(verts.Count + 2);
			verts.Add(v1);
			verts.Add(v2);
			verts.Add(v3);
		}
	}

	private List<Vector3> GetTriangles(int state, float xPos, float zPos)
	{
		/*
			D---G---C
			|       |
			H       F
			|       |
			A---E---B
		*/
		float t = 0.5f;
		float lerpAB = Mathf.InverseLerp(aCornerValue, bCornerValue, t) * resolution;
		float lerpBC = Mathf.InverseLerp(bCornerValue, cCornerValue, t) * resolution;
		float lerpCD = Mathf.InverseLerp(cCornerValue, dCornerValue, t) * resolution;
		float lerpDA = Mathf.InverseLerp(dCornerValue, aCornerValue, t) * resolution;
		
		Vector3 aPoint = new Vector3(xPos,              0, zPos + resolution);
		Vector3 bPoint = new Vector3(xPos + resolution, 0, zPos + resolution);
		Vector3 cPoint = new Vector3(xPos + resolution, 0, zPos             );
		Vector3 dPoint = new Vector3(xPos,              0, zPos             );
		Vector3 ePoint = new Vector3(aPoint.x + lerpAB, 0, aPoint.z         );
		Vector3 fPoint = new Vector3(bPoint.x,          0, bPoint.z - lerpBC);
		Vector3 gPoint = new Vector3(cPoint.x - lerpCD, 0, cPoint.z         );
		Vector3 hPoint = new Vector3(aPoint.x,          0, dPoint.z + lerpDA);

		List<Vector3> res = new List<Vector3>();

		switch (state)
		{
			case 1:
				res.Add(hPoint);
				res.Add(gPoint);
				res.Add(dPoint);
				break;
			case 2:
				res.Add(gPoint);
				res.Add(fPoint);
				res.Add(cPoint);
				break;
			case 3:
				res.Add(hPoint);
				res.Add(cPoint);
				res.Add(dPoint);

				res.Add(hPoint);
				res.Add(fPoint);
				res.Add(cPoint);
				break;
			case 4:
				res.Add(fPoint);
				res.Add(ePoint);
				res.Add(bPoint);
				break;
			case 5:
				res.Add(bPoint);
				res.Add(fPoint);
				res.Add(ePoint);

				res.Add(ePoint);
				res.Add(fPoint);
				res.Add(hPoint);

				res.Add(dPoint);
				res.Add(hPoint);
				res.Add(gPoint);

				res.Add(gPoint);
				res.Add(hPoint);
				res.Add(fPoint);
				break;
			case 6:
				res.Add(gPoint);
				res.Add(ePoint);
				res.Add(cPoint);

				res.Add(cPoint);
				res.Add(ePoint);
				res.Add(bPoint);
				break;
			case 7:
				res.Add(dPoint);
				res.Add(hPoint);
				res.Add(gPoint);

				res.Add(gPoint);
				res.Add(hPoint);
				res.Add(ePoint);

				res.Add(gPoint);
				res.Add(ePoint);
				res.Add(bPoint);

				res.Add(gPoint);
				res.Add(bPoint);
				res.Add(cPoint);
				break;
			case 8:
				res.Add(ePoint);
				res.Add(hPoint);
				res.Add(aPoint);
				break;
			case 9:
				res.Add(dPoint);
				res.Add(aPoint);
				res.Add(gPoint);

				res.Add(gPoint);
				res.Add(aPoint);
				res.Add(ePoint);
				break;
			case 10:
				res.Add(gPoint);
				res.Add(hPoint);
				res.Add(cPoint);

				res.Add(cPoint);
				res.Add(hPoint);
				res.Add(aPoint);

				res.Add(cPoint);
				res.Add(aPoint);
				res.Add(ePoint);

				res.Add(cPoint);
				res.Add(ePoint);
				res.Add(fPoint);
				break;
			case 11:
				res.Add(dPoint);
				res.Add(aPoint);
				res.Add(cPoint);

				res.Add(cPoint);
				res.Add(aPoint);
				res.Add(ePoint);

				res.Add(cPoint);
				res.Add(ePoint);
				res.Add(fPoint);
				break;
			case 12:
				res.Add(fPoint);
				res.Add(hPoint);
				res.Add(aPoint);

				res.Add(fPoint);
				res.Add(aPoint);
				res.Add(bPoint);
				break;
			case 13:
				res.Add(aPoint);
				res.Add(bPoint);
				res.Add(dPoint);

				res.Add(dPoint);
				res.Add(bPoint);
				res.Add(gPoint);

				res.Add(gPoint);
				res.Add(bPoint);
				res.Add(fPoint);
				break;
			case 14:
				res.Add(gPoint);
				res.Add(hPoint);
				res.Add(cPoint);

				res.Add(cPoint);
				res.Add(hPoint);
				res.Add(aPoint);

				res.Add(cPoint);
				res.Add(aPoint);
				res.Add(bPoint);
				break;
			case 15:
				res.Add(dPoint);
				res.Add(aPoint);
				res.Add(cPoint);

				res.Add(cPoint);
				res.Add(aPoint);
				res.Add(bPoint);
				break;
		}
		return res;
	}

	private int GetState(int a, int b, int c, int d)
	{
		return a * 8 + b * 4 + c * 2 + d;
	}
	
	private int IsEdgeEnabled(float cornerValue)
	{
		return cornerValue * resolution > halfResolution ? 1 : 0;
	}
}

Однако, есть проблема. Перепутаны местами верх и низ квадрата. Надо как-то отзеркалить вычисления, но у меня пока не получается :man_shrugging:
И ещё надо было массив cornerValues переименовать в field.