Select Git revision
control_mouse.py
BlockDeform.cs 7.00 KiB
using System;
using System.Collections.Generic;
using UnityEngine;
public class BlockDeform : MonoBehaviour
{
public GameObject deformAnchorPrefab;
public float wrapDistance;
private Mesh _mesh;
private readonly DeformAnchor[] _deformAnchors = new DeformAnchor[6];
private readonly GameObject[] _spawnedAnchors = new GameObject[6];
private bool loadedType = false;
private bool IsPointOnPlane(Vector3 point, Vector3 normal, Vector3 pointOnPlane, double epsilon)
{
double d = Vector3.Dot(normal, pointOnPlane);
double eq = normal.x * point.x + normal.y * point.y + normal.z * point.z - d;
if (Math.Abs(eq) < epsilon) return true;
else return false;
}
public void HandleAnchorGrabbed(Transform endPosition, Vector3 startPosition, DeformAnchor anchor)
{
Vector3 normal = this.transform.rotation.normalized * anchor.GetNormal();
// calculate deformation
Vector3[] deformedMeshVertices = _mesh.vertices;
for (int i = 0; i < deformedMeshVertices.Length; i++)
{
Vector3 vertex = (this.transform.rotation.normalized * deformedMeshVertices[i]) + this.transform.position;
if (IsPointOnPlane(vertex, normal, startPosition, 0.1d))
{
float distance = Vector3.Distance(startPosition, endPosition.position);
// Vector3 displacement = endPosition.position - startPosition;
// deformedMeshVertices[i] += displacement;
// Debug.Log("startpos: " + startPosition + " normal: " + normal + " vertex: " + vertex);
Vector3 displacement = anchor.GetNormal() * distance;
float direction = Vector3.Dot(endPosition.position - startPosition, normal);
deformedMeshVertices[i] += displacement * (direction > 0 ? 1 : -1);
}
else
{
// Debug.LogError("startpos: " + startPosition + " normal: " + normal + " vertex: " + vertex);
}
}
// check if it's a valid grab
for (int i = 0; i < _deformAnchors.Length; i++)
{
if (_deformAnchors[i] == anchor) continue;
float distance = Vector3.Distance(_deformAnchors[i].GetPosition(), anchor.GetPosition());
if (distance < wrapDistance * 10)
{
anchor.ResetPosition();
return;
}
}
// set new vertices for mesh
_mesh.vertices = deformedMeshVertices;
_mesh.RecalculateBounds();
MeshCollider collider = GetComponent<MeshCollider>();
collider.sharedMesh = _mesh;
UpdateDeformAnchors();
}
private void UpdateDeformAnchors()
{
// collect vertices on the same plane as the anchor
for (int i = 0; i < _deformAnchors.Length; i++)
{
List<Vector3> vertices = new();
Vector3 anchorNormal = this.transform.rotation.normalized * _deformAnchors[i].GetNormal();
Vector3 anchorPosition = _deformAnchors[i].GetPosition();
foreach (Vector3 vertex in _mesh.vertices)
{
Vector3 rotatedVert = this.transform.rotation.normalized * vertex;
if (IsPointOnPlane(rotatedVert + this.transform.position, anchorNormal, anchorPosition, 0.1d))
{
if (vertices.IndexOf(rotatedVert) == -1)
{
vertices.Add(rotatedVert);
}
}
}
if (vertices.Count >= 4)
_deformAnchors[i].SetMeshScale(vertices);
else
Debug.LogError("Couldn't find fitting vertices to update the deform anchors.");
}
}
private void Awake()
{
_mesh = this.GetComponent<MeshFilter>().mesh;
}
// Start is called before the first frame update
void Start()
{
if (!this.loadedType)
InitAnchors();
}
private void InitAnchors()
{
Collider blockCollider = this.GetComponent<Collider>();
for (int i = 0; i < 6; i++)
{
GameObject anchor = Instantiate(deformAnchorPrefab, this.transform.position, Quaternion.identity);
anchor.transform.parent = this.transform;
_deformAnchors[i] = anchor.GetComponent<DeformAnchor>();
_spawnedAnchors[i] = anchor;
}
// z axis anchor setup
_deformAnchors[0].SetupAnchor(this, this.transform.forward, blockCollider.bounds.extents, wrapDistance);
_deformAnchors[1].SetupAnchor(this, -this.transform.forward, blockCollider.bounds.extents, wrapDistance);
// y axis achor setup
_deformAnchors[2].SetupAnchor(this, this.transform.up, blockCollider.bounds.extents, wrapDistance);
_deformAnchors[3].SetupAnchor(this, -this.transform.up, blockCollider.bounds.extents, wrapDistance);
// x axis anchor setup
_deformAnchors[4].SetupAnchor(this, this.transform.right, blockCollider.bounds.extents, wrapDistance);
_deformAnchors[5].SetupAnchor(this, -this.transform.right, blockCollider.bounds.extents, wrapDistance);
}
public void AdjustVertices(Vector3[] vertices, Vector3[] anchorPosition)
{
this.loadedType = true;
InitAnchors();
_mesh = this.GetComponent<MeshFilter>().mesh;
if (_mesh.vertices.Length != vertices.Length)
{
Debug.LogError("cannot adjust vertices: different sized vertex arrays");
return;
}
Vector3[] adjustedVertices = _mesh.vertices;
for (int i = 0; i < adjustedVertices.Length; i++)
{
adjustedVertices[i] = vertices[i];
}
_mesh.vertices = adjustedVertices;
_mesh.RecalculateBounds();
MeshCollider collider = GetComponent<MeshCollider>();
collider.sharedMesh = _mesh;
for (int i = 0; i < _spawnedAnchors.Length; i++)
{
_spawnedAnchors[i].transform.localPosition = anchorPosition[i];
}
UpdateDeformAnchors();
}
private void FixedUpdate()
{
EditState.EditType mode = EditState.Instance._editState;
foreach (GameObject anchor in _spawnedAnchors)
{
anchor.SetActive(mode == EditState.EditType.Deform);
}
}
public GameObject[] GetAnchors()
{
return _spawnedAnchors;
}
public Vector3 GetPosition()
{
return transform.position;
}
public Quaternion GetRotation()
{
return transform.rotation;
}
public void EnableTransparency()
{
Color color = transform.GetComponent<Renderer>().material.GetColor("_BaseColor");
// color.a = grabTransparency;
transform.GetComponent<Renderer>().material.SetColor("_BaseColor", color);
}
public void DisableTransparency()
{
Color color = transform.GetComponent<Renderer>().material.GetColor("_BaseColor");
color.a = 1.0f;
transform.GetComponent<Renderer>().material.SetColor("_BaseColor", color);
}
}