Files

295 lines
9.4 KiB
C#
Raw Permalink Normal View History

2025-05-13 03:19:28 +03:00
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections;
using System;
[Serializable]
public struct UInt3 {
public uint x;
public uint y;
public uint z;
}
[Serializable]
public class AxisSuffix3D
{
public string X;
public string Y;
public string Z;
public string this[int index] {
get {
if (index == 0) {
return X;
}
if (index == 1) {
return Y;
} else {
return Z;
}
}
}
}
[Serializable]
public class Plot3DSurface {
public string Title;
public AxisSuffix3D Suffix;
public bool Visible = true;
public Vector3 axisBegin = Vector3.zero;
public Vector3 axisEnd = Vector3.one;
public Plot3DFunction function;
}
public class Plot3D : MonoBehaviour {
public UInt3 sectionsCount = new UInt3() { x = 10, y = 10, z = 10 };
public Mesh plotMesh;
public int tessArg0 = 10;
public int tessArg1 = 10;
public Plot3DSurface[] surfaces;
// Use this for initialization
void Start() {
}
// Update is called once per frame
void Update() {
}
private void ValidateView() {
var mr = GetComponent<MeshRenderer>();
if (mr == null) {
mr = gameObject.AddComponent<MeshRenderer>();
}
var mf = GetComponent<MeshFilter>();
if (mf == null) {
mf = gameObject.AddComponent<MeshFilter>();
}
}
public void UpdateMesh() {
ValidateView();
if (tessArg0 < 1) {
tessArg0 = 1;
}
if (tessArg1 < 1) {
tessArg1 = 1;
}
if (plotMesh == null) {
plotMesh = new Mesh();
}
//build vertices
var surfaceVertexCount = (tessArg0 + 1) * (tessArg1 + 1);
Vector3[] vertices = new Vector3[surfaceVertexCount * surfaces.Length];
var ptsX = tessArg0 + 1;
var ptsZ = tessArg1 + 1;
for (int z = 0; z < ptsZ; ++z) {
for (int x = 0; x < ptsX; ++x) {
float u = (1.0f / (ptsX - 1)) * x;
float v = (1.0f / (ptsZ - 1)) * z;
//for each surface generate vertex
for (int i = 0; i < surfaces.Length; ++i) {
float y = 0;
var surf = surfaces[i];
if (surf.Visible) {
var function = surf.function;
if (function != null) {
y = function.f(Mathf.Lerp(surf.axisBegin[0], surf.axisEnd[0], u), Mathf.Lerp(surf.axisBegin[2], surf.axisEnd[2], v));
if (surf.axisEnd[1] - surf.axisBegin[1] < 0.000001f) {
y = 0;
} else {
y = (y - surf.axisBegin[1]) / (surf.axisEnd[1] - surf.axisBegin[1]);
}
}
vertices[z * ptsX + x + surfaceVertexCount * i] = new Vector3(u, y, v);
} else {
vertices[z * ptsX + x + surfaceVertexCount * i] = Vector3.zero;
}
}
}
}
//build indices
int[] indices_source = new int[tessArg0 * tessArg1 * 6];
int index_id = 0;
for (int z = 0; z < tessArg1; ++z) {
var lineOff0 = z * ptsX;
var lineOff1 = (z + 1) * ptsX;
for (int x = 0; x < tessArg0; ++x) {
//plotMesh.vertices
indices_source[index_id++] = lineOff0 + x;
indices_source[index_id++] = lineOff1 + x + 1;
indices_source[index_id++] = lineOff0 + x + 1;
indices_source[index_id++] = lineOff0 + x;
indices_source[index_id++] = lineOff1 + x;
indices_source[index_id++] = lineOff1 + x + 1;
}
}
var indices = new int[indices_source.Length * surfaces.Length];
//instantiate indices
for (int i = 0; i < surfaces.Length; ++i) {
for (int j = 0; j < indices_source.Length; ++j) {
indices[j + indices_source.Length * i] = indices_source[j] + surfaceVertexCount * i;
}
}
Vector3[] normals = new Vector3[vertices.Length];
//build normals
for (int i = 0; i < indices.Length; i += 3) {
var v0 = vertices[indices[i + 0]];
var v1 = vertices[indices[i + 1]];
var v2 = vertices[indices[i + 2]];
var d0 = v1 - v0;
var d1 = v2 - v1;
var normal = Vector3.Cross(d0, d1).normalized;
normals[indices[i + 0]] = normal;
normals[indices[i + 1]] = normal;
normals[indices[i + 2]] = normal;
}
plotMesh.Clear();
plotMesh.subMeshCount = surfaces.Length;
plotMesh.vertices = vertices;
plotMesh.normals = normals;
for (int i = 0; i < surfaces.Length; ++i) {
var slice_indices = new int[indices_source.Length];
Array.Copy(indices, indices_source.Length * i, slice_indices, 0, indices_source.Length);
plotMesh.SetTriangles(slice_indices, i);
}
plotMesh.RecalculateBounds();
plotMesh.RecalculateNormals();
GetComponent<MeshFilter>().mesh = plotMesh;
var mr = GetComponent<MeshRenderer>();
if (mr.sharedMaterials.Length != surfaces.Length) {
var mats = mr.sharedMaterials;
Array.Resize(ref mats, surfaces.Length);
mr.sharedMaterials = mats;
}
}
private static Vector3[] cubeVertices = new Vector3[]
{
Vector3.zero, Vector3.forward, Vector3.right + Vector3.forward, Vector3.right,
Vector3.zero + Vector3.up, Vector3.forward + Vector3.up, Vector3.right + Vector3.forward + Vector3.up, Vector3.right + Vector3.up,
};
static Color[] axisColor = new Color[] { Color.red, Color.green, Color.blue };
void DrawAxisLabels(int axis, bool begin, Vector3 worldPoint, Vector2 offset)
{
GUIStyle style = new GUIStyle();
Vector3 screenPoint = Camera.current.WorldToScreenPoint(worldPoint);
if (screenPoint.z < 0)
{
return;
}
screenPoint.x += offset.x;
screenPoint.y += offset.y;
for (int j = 0; j < surfaces.Length; ++j)
{
style.normal.textColor = axisColor[axis];
var pos = Camera.current.ScreenToWorldPoint(screenPoint);
var val = begin ? surfaces[j].axisBegin[axis] : surfaces[j].axisEnd[axis];
Handles.Label(pos, val.ToString() + " " + surfaces[j].Suffix[axis], style);
screenPoint.y -= 12;
}
}
void OnDrawGizmos() {
Gizmos.matrix = transform.localToWorldMatrix;
//Draw colored axis
Gizmos.color = axisColor[0];
Gizmos.DrawLine(cubeVertices[0], cubeVertices[3]);
Gizmos.color = axisColor[1];
Gizmos.DrawLine(cubeVertices[0], cubeVertices[4]);
Gizmos.color = axisColor[2];
Gizmos.DrawLine(cubeVertices[0], cubeVertices[1]);
//Draw cube gizmo
Gizmos.color = new Color(1, 1, 1, 0.2f);
//Bottom cap
Gizmos.DrawLine(cubeVertices[1], cubeVertices[2]);
Gizmos.DrawLine(cubeVertices[2], cubeVertices[3]);
//top cap
Gizmos.DrawLine(cubeVertices[4], cubeVertices[5]);
Gizmos.DrawLine(cubeVertices[5], cubeVertices[6]);
Gizmos.DrawLine(cubeVertices[6], cubeVertices[7]);
Gizmos.DrawLine(cubeVertices[7], cubeVertices[4]);
//vertical
Gizmos.DrawLine(cubeVertices[0], cubeVertices[4]);
Gizmos.DrawLine(cubeVertices[1], cubeVertices[5]);
Gizmos.DrawLine(cubeVertices[2], cubeVertices[6]);
Gizmos.DrawLine(cubeVertices[3], cubeVertices[7]);
//draw sections
if (sectionsCount.x < 1) {
sectionsCount.x = 1;
}
if (sectionsCount.y < 1) {
sectionsCount.y = 1;
}
if (sectionsCount.z < 1) {
sectionsCount.z = 1;
}
Gizmos.color = Color.red;
for (int x = 0; x <= sectionsCount.x; ++x) {
Vector3 pt = Vector3.right * ((1.0f / sectionsCount.x) * x);
Gizmos.DrawLine(pt, pt - Vector3.forward * 0.025f);
}
Gizmos.color = Color.green;
for (int x = 0; x <= sectionsCount.y; ++x) {
Vector3 pt = Vector3.up * ((1.0f / sectionsCount.y) * x);
Gizmos.DrawLine(pt, pt - Vector3.right * 0.025f);
}
Gizmos.color = Color.blue;
for (int x = 0; x <= sectionsCount.z; ++x) {
Vector3 pt = Vector3.forward * ((1.0f / sectionsCount.z) * x);
Gizmos.DrawLine(pt, pt - Vector3.right * 0.025f);
}
//Draw labels
Gizmos.matrix = Matrix4x4.identity;
#if UNITY_EDITOR
DrawAxisLabels(0, true, transform.TransformPoint(cubeVertices[0]), Vector2.zero);
DrawAxisLabels(0, false, transform.TransformPoint(cubeVertices[3]), Vector2.zero);
DrawAxisLabels(1, true, transform.TransformPoint(cubeVertices[0]), new Vector2(0, -14 * surfaces.Length));
DrawAxisLabels(1, false, transform.TransformPoint(cubeVertices[4]), new Vector2(0, 14 * surfaces.Length));
DrawAxisLabels(2, true, transform.TransformPoint(cubeVertices[0]), new Vector2(0, -14 * surfaces.Length * 2));
DrawAxisLabels(2, false, transform.TransformPoint(cubeVertices[1]), new Vector2(0, 0));
#endif
}
}