Get edge vertex points then draw lines across the edge - c#

I am trying to get vertex points of a 3D Object then draw line with LineRenderer. I want the lines to be drawn in order and not crossing through the middle of the model but the lines passes through the model. The image below shows what it looks like:
As you can see, I am almost close to getting this done but the line is passing through the model.
The vertext points probably needs to be sorted. How can I fix this? How I can I make the points draw on the edge without passing through the Object?
Just attach the code below to a simple Cube to see the problem described above:
public class MapEdgeOutline : MonoBehaviour
{
Color beginColor = Color.yellow;
Color endColor = Color.red;
float hightlightSize = 0.1f;
void Start()
{
createEdgeLineOnModel();
}
void createEdgeLineOnModel()
{
EdgeVertices allVertices = findAllVertices();
//Get the points from the Vertices
Vector3[] verticesToDraw = allVertices.vertices.ToArray();
drawLine(verticesToDraw);
}
//Draws lines through the provided vertices
void drawLine(Vector3[] verticesToDraw)
{
//Create a Line Renderer Obj then make it this GameObject a parent of it
GameObject childLineRendererObj = new GameObject("LineObj");
childLineRendererObj.transform.SetParent(transform);
//Create new Line Renderer if it does not exist
LineRenderer lineRenderer = childLineRendererObj.GetComponent<LineRenderer>();
if (lineRenderer == null)
{
lineRenderer = childLineRendererObj.AddComponent<LineRenderer>();
}
//Assign Material to the new Line Renderer
//Hidden/Internal-Colored
//Particles/Additive
lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
//Set color and width
lineRenderer.SetColors(beginColor, endColor);
lineRenderer.SetWidth(hightlightSize, hightlightSize);
//Convert local to world points
for (int i = 0; i < verticesToDraw.Length; i++)
{
verticesToDraw[i] = gameObject.transform.TransformPoint(verticesToDraw[i]);
}
//5. Set the SetVertexCount of the LineRenderer to the Length of the points
lineRenderer.SetVertexCount(verticesToDraw.Length + 1);
for (int i = 0; i < verticesToDraw.Length; i++)
{
//Draw the line
Vector3 finalLine = verticesToDraw[i];
lineRenderer.SetPosition(i, finalLine);
//Check if this is the last loop. Now Close the Line drawn
if (i == (verticesToDraw.Length - 1))
{
finalLine = verticesToDraw[0];
lineRenderer.SetPosition(verticesToDraw.Length, finalLine);
}
}
}
EdgeVertices findAllVertices()
{
//Get MeshFilter from Cube
Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] meshVerts = mesh.vertices;
//Get temp vert array
float[][] meshVertsArray;
meshVertsArray = new float[meshVerts.Length][];
//Where to store the vertex points
EdgeVertices allVertices = new EdgeVertices();
allVertices.vertices = new List<Vector3>();
int indexCounter = 0;
//Get x,y,z vertex point
while (indexCounter < meshVerts.Length)
{
meshVertsArray[indexCounter] = new float[3];
meshVertsArray[indexCounter][0] = meshVerts[indexCounter].x;
meshVertsArray[indexCounter][1] = meshVerts[indexCounter].y;
meshVertsArray[indexCounter][2] = meshVerts[indexCounter].z;
Vector3 tempVect = new Vector3(meshVertsArray[indexCounter][0], meshVertsArray[indexCounter][1], meshVertsArray[indexCounter][2]);
//Store the vertex pont
allVertices.vertices.Add(tempVect);
indexCounter++;
}
return allVertices;
}
}
public struct EdgeVertices
{
public List<Vector3> vertices;
}

Related

How to change the neighboring color of selected triangle?

Image from unity scene
Hello, by the help of stack overflow (Unity | mesh.colors won't color my custom mesh object I was able to solve the problem where I can see the colorized triangle's face after being selected using ray-cast in unity as shown in the image attached. I was wondering how I can improve my method by making the neighbors of selected triangle also change its color as well. For example, as shown in the image the selected triangle's neighbors change its color to white and be there only for a few seconds.
I have shared my implemented code below. Any guidance will be really appreciated! Thank you.
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class MyRayDraw : MonoBehaviour
{
public GameObject spherePrefab;
// Better to reference those already in the Inspector
[SerializeField] private MeshFilter meshFilter;
[SerializeField] private MeshRenderer meshRenderer;
[SerializeField] private MeshCollider meshCollider;
private Mesh mesh;
private void Awake()
{
if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
if (!meshRenderer) meshRenderer = GetComponent<MeshRenderer>();
if (!meshCollider) meshCollider = GetComponent<MeshCollider>();
mesh = meshFilter.mesh;
// create new colors array where the colors will be created
var colors = new Color[mesh.vertices.Length];
for(var i = 0; i < colors.Length; i++)
{
colors[i] = new Color(1f, 0f, 0.07f);
}
// assign the array of colors to the Mesh.
mesh.colors = colors;
}
private void Update()
{
if (!Input.GetMouseButtonDown(0)) return;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.triangleIndex);
//cube.transform.position = hit.point;
// Get current vertices, triangles, uvs and colors
var vertices = mesh.vertices;
var triangles = mesh.triangles;
//var uv = _mesh.uv;
var colors = mesh.colors;
// Get the vert indices for this triangle
var vertIndex_1 = triangles[hit.triangleIndex * 3 + 0];
var vertIndex_2 = triangles[hit.triangleIndex * 3 + 1];
var vertIndex_3 = triangles[hit.triangleIndex * 3 + 2];
// Get the positions for the vertices
var vertPos_1 = vertices[vertIndex_1];
var vertPos_2 = vertices[vertIndex_2];
var vertPos_3 = vertices[vertIndex_3];
// Now for all three vertices we first check if any other triangle if using it
// by simply count how often the indices are used in the triangles list
var verticesOccur_1 = 0;
var verticesOccur_2 = 0;
var verticesOccur_3 = 0;
for (var i = 0; i < triangles.Length; i++)
{
if (triangles[i] == vertIndex_1) verticesOccur_1++;
if (triangles[i] == vertIndex_2) verticesOccur_2++;
if (triangles[i] == vertIndex_3) verticesOccur_3++;
}
// Create copied Lists so we can dynamically add entries
var newVertices = vertices.ToList();
var newTriangles = triangles.ToList();
//var newUV = uv.ToList();
var newColors = colors.ToList();
// Now if a vertex is shared we need to add a new individual vertex
// and also an according entry for the color array
// and update the vertex index
// otherwise we will simply use the vertex we already have
if (verticesOccur_1 >= 1)
{
newVertices.Add(vertPos_1);
// newUV.Add(vert1UV);
newColors.Add(Color.green);
vertIndex_1 = newVertices.Count - 1;
}
if (verticesOccur_2 >= 1)
{
newVertices.Add(vertPos_2);
//newUV.Add(vert2UV);
newColors.Add(Color.green);
vertIndex_2 = newVertices.Count - 1;
}
if (verticesOccur_3 >= 1)
{
newVertices.Add(vertPos_3);
//newUV.Add(vert3UV);
newColors.Add(Color.green);
vertIndex_3 = newVertices.Count - 1;
}
// Update the indices of the hit triangle to use the (eventually) new
// vertices instead
triangles[hit.triangleIndex * 3 + 0] = vertIndex_1;
triangles[hit.triangleIndex * 3 + 1] = vertIndex_2;
triangles[hit.triangleIndex * 3 + 2] = vertIndex_3;
// Now we can simply add the new triangle
newTriangles.Add(vertIndex_1);
newTriangles.Add(vertIndex_2);
newTriangles.Add(vertIndex_3);
// And update the mesh
mesh.vertices = newVertices.ToArray();
mesh.triangles = newTriangles.ToArray();
//_mesh.uv = newUV.ToArray();
mesh.colors = newColors.ToArray();
// color these vertices
newColors[vertIndex_1] = Color.red;
newColors[vertIndex_2] = Color.red;
newColors[vertIndex_3] = Color.red;
// Recalculate the normals
mesh.RecalculateNormals();
}
else
{
Debug.Log("no hit");
}
}
}

Unity: Finding Lowest Vertices on Mesh

I'm a very newbie to using unity and C#. I have a question about spawning an object on the lowest Y coordinate on the mesh.
How to get the lowest Y vertices with other coordinates to spawn an object at that point.
Thank you in advance everyone :)
public Mesh terrain;
public GameObject agents;
void Start()
Mesh terrain = GetComponent<MeshFilter>().mesh;
Vector3[] meshVertices = terrain.vertices;
float minY = float.MinValue;
int count = terrain.vertexCount;
List<Vector3> vertices = new List<Vector3>();
terrain.GetVertices(vertices);
for (int i = 0; i < vertices.Count; i++)
{
Vector3 pos = vertices[i];
minY = Mathf.Min(pos.y,-pos.y);
Vector3 position = transform.TransformPoint(vertices[i]);
if (position.y == minY)
{
Instantiate(agents, position, Quaternion.identity);
}
}
terrain.RecalculateBounds();
If you're looking for a minimum value, then you need to start with something that's so big that anything will be less than that. Something like float.MaxValue. Then you need to go through all the points and compare your current minimum to the running minimum and cache the current point if it's less. Once you're done with all the points then you can use your cached point as the instantiation location. Consider the following:
public Mesh terrain;
public GameObject agents;
void Start()
{
Mesh terrain = GetComponent<MeshFilter>().mesh;
Vector3[] meshVertices = terrain.vertices;
float minY = float.MaxValue; // <--- Change
Vector3 minimumVertex; // <--- Change
int count = terrain.vertexCount;
List<Vector3> vertices = new List<Vector3>();
terrain.GetVertices(vertices);
for (int i = 0; i < vertices.Count; i++)
{
// Vector3 pos = vertices[i]; // <--- Change
// minY = Mathf.Min(pos.y,-pos.y); // <--- Change
Vector3 position = transform.TransformPoint(vertices[i]);
// if (position.y == minY) // <--- Change
if(position.y < minY) // <--- Change
{
minY = position.y; // <--- Change
minimumVertex = position; // <--- Change
//Instantiate(agents, position, Quaternion.identity); // <--- Change
}
}
Instantiate(agents, minimumVertex, Quaternion.identity); // <--- Change
terrain.RecalculateBounds();
}
I was looking for an answer for you that summarizes a large part of the code, all this is possible thanks to system.linq, the following code sorts vertices by y coordinate and puts them in a position list, just enough Set list[0] as position. The other vertices are also arranged in order, which is an advantage.
using System.Linq;
public void Start()
{
var meshFilter = GetComponent<MeshFilter>();
var list = meshFilter.mesh.vertices.Select(transform.TransformPoint).OrderBy(v => v.y).ToList();
Debug.Log(list[0]); // lowest position
Debug.Log(list.Last()); // highest position
}

Can you create a plane from vuforia target images? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
As seen in the photo below i have 4 vuforia target images. What i want to achieve is to measure the angle of the red axis joining two target images, against a plane which i want to generate using the three target images connected by the green line. Hopefully this is more understandable. How would i go about generating that plane with those three target images?
[![][1]][1]
You question is extremely broad! However I'll give it a shot:
I'm assuming by "Plane" you mean an actually visible 3D mesh. Otherwise you could directly use the 3 given coordinates to create a mathematical Plane.
First of all for a plane you usually use a rectangular mesh .. it is unclear in your question how exactly you want to built that from the 3 coordinates you get.
I'm simply assuming here you create a Parallelogram directly using the 3 coordinates for the corners A, B andC and then adding a 4th one D by adding the vector B&rightarrow;C to A
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class PlaneController : MonoBehaviour
{
public Transform target1;
public Transform target2;
public Transform target3;
private MeshFilter meshFilter;
private Mesh mesh;
private Vector3[] vertices;
private void Awake()
{
meshFilter = GetComponent<MeshFilter>();
mesh = meshFilter.mesh;
vertices = new Vector3[4];
// Set the 4 triangles (front and backside)
// using the 4 vertices
var triangles = new int[3 * 4];
// triangle 1 - ABC
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 2;
// triangle 2 - ACD
triangles[3] = 0;
triangles[4] = 2;
triangles[5] = 3;
// triangle 3 - BAC
triangles[6] = 1;
triangles[7] = 0;
triangles[8] = 2;
// triangle 4 - ADC
triangles[9] = 0;
triangles[10] = 3;
triangles[11] = 2;
mesh.vertices = vertices;
mesh.triangles = triangles;
}
// Update is called once per frame
void Update()
{
// build triangles according to target positions
vertices[0] = target1.position - transform.position; // A
vertices[1] = target2.position - transform.position; // B
vertices[2] = target3.position - transform.position; // C
// D = A + B->C
vertices[3] = vertices[0] + (vertices[2] - vertices[1]);
// update the mesh vertex positions
mesh.vertices = vertices;
// Has to be done in order to update the bounding box culling
mesh.RecalculateBounds();
}
}
Edit
After you changed the question: In this case you don't really need the visual plane but as mentioned before create the purely mathematical construct Plane.
The planes normal is a vector standing always 90° to the plane. You then can use e.g. Vector3.Angle in order to get the angular difference between the normal and your red vector (lets say between target1 and target4). Something like
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
public class AngleChecker : MonoBehaviour
{
[Header("Input")]
public Transform target1;
public Transform target2;
public Transform target3;
public Transform target4;
[Header("Output")]
public float AngleOnPlane;
private void Update()
{
AngleOnPlane = GetAngle();
}
private float GetAngle()
{
// get the plane (green line/area)
var plane = new Plane(target1.position, target2.position, target3.position);
// get the red vector
var vector = target4.position - target1.position;
// get difference
var angle = Vector3.Angle(plane.normal, vector);
// since the normal itself stands 90° on the plane
return 90 - angle;
}
#if UNITY_EDITOR
// ONLY FOR VISUALIZATION
private void OnDrawGizmos()
{
// draw the plane
var mesh = new Mesh
{
vertices = new[]
{
target1.position,
target2.position,
target3.position,
target3.position + (target1.position - target2.position)
},
triangles = new[] {
0, 1, 2,
0, 2, 3,
1, 0, 2,
0, 3, 2
}
};
mesh.RecalculateNormals();
Gizmos.color = Color.white;
Gizmos.DrawMesh(mesh);
// draw the normal at target1
var plane = new Plane(target1.position, target2.position, target3.position);
Gizmos.color = Color.blue;
Gizmos.DrawRay(target1.position, plane.normal);
Handles.Label(target1.position + plane.normal, "plane normal");
// draw the red vector
Gizmos.color = Color.red;
Gizmos.DrawLine(target1.position, target4.position);
Handles.Label(target4.position , $"Angle to plane: {90 - Vector3.Angle(plane.normal, target4.position - target1.position)}");
}
#endif
}
After your comment I see you want to make it also visible in the scene.
So we are back to also the first part of my answer where exactly this was done.
Simply add the visible plane to the scene as well by merging both before mentioned scripts.
For making the text visual I recommend to go through the Unity UI Manual.
For making the line appear there are two options. You can either use a LineRenderer (API) or simply use a cube your rotate and scale accordingly:
// ! UNCOMMENT THIS IF YOU RATHER WANT TO USE THE LINERENDERER !
//#define USE_LINERENDERER
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class PlaneController : MonoBehaviour
{
[Header("Input")]
// Reference these in the Inspector
public Transform target1;
public Transform target2;
public Transform target3;
public Transform target4;
[Space]
public MeshFilter meshFilter;
[Header("Output")]
public float AngleOnPlane;
public Text angleText;
public float lineWith = 0.05f;
#if USE_LINERENDERER
public LineRenderer lineRenderer;
#else
public MeshRenderer cubeLine;
#endif
private Mesh mesh;
private Vector3[] vertices;
private Vector3 redLineDirection;
// if using line renderer
private Vector3[] positions = new Vector3[2];
private void Start()
{
InitializePlaneMesh();
#if USE_LINERENDERER
InitializeLineRenderer();
#endif
}
// Update is called once per frame
private void Update()
{
// update the plane mesh
UpdatePlaneMesh();
// update the angle value
UpdateAngle();
#if USE_LINERENDERER
// update the line either using the line renderer
UpdateLineUsingLineRenderer();
#else
// update the line rather using a simple scaled cube instead
UpdateLineUsingCube();
#endif
}
private void InitializePlaneMesh()
{
if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
mesh = meshFilter.mesh;
vertices = new Vector3[4];
// Set the 4 triangles (front and backside)
// using the 4 vertices
var triangles = new int[3 * 4];
// triangle 1 - ABC
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 2;
// triangle 2 - ACD
triangles[3] = 0;
triangles[4] = 2;
triangles[5] = 3;
// triangle 3 - BAC
triangles[6] = 1;
triangles[7] = 0;
triangles[8] = 2;
// triangle 4 - ADC
triangles[9] = 0;
triangles[10] = 3;
triangles[11] = 2;
mesh.vertices = vertices;
mesh.triangles = triangles;
}
#if USE_LINERENDERER
private void InitializeLineRenderer()
{
lineRenderer.positionCount = 2;
lineRenderer.startWidth = lineWith;
lineRenderer.endWidth = lineWith;
lineRenderer.loop = false;
lineRenderer.alignment = LineAlignment.View;
lineRenderer.useWorldSpace = true;
}
#endif
private void UpdatePlaneMesh()
{
// build triangles according to target positions
vertices[0] = target1.position - transform.position; // A
vertices[1] = target2.position - transform.position; // B
vertices[2] = target3.position - transform.position; // C
// D = A + B->C
vertices[3] = vertices[0] + (vertices[2] - vertices[1]);
// update the mesh vertex positions
mesh.vertices = vertices;
// Has to be done in order to update the bounding box culling
mesh.RecalculateBounds();
}
private void UpdateAngle()
{
// get the plane (green line/area)
var plane = new Plane(target1.position, target2.position, target3.position);
// get the red vector
redLineDirection = target4.position - target1.position;
// get difference
var angle = Vector3.Angle(plane.normal, redLineDirection);
// since the normal itself stands 90° on the plane
AngleOnPlane = Mathf.Abs(90 - angle);
// write the angle value to a UI Text element
angleText.text = $"Impact Angle = {AngleOnPlane:F1}°";
// move text to center of red line and a bit above it
angleText.transform.position = (target1.position + target4.position) / 2f + Vector3.up * 0.1f;
// make text always face the user (Billboard)
// using Camera.main here is not efficient! Just for the demo
angleText.transform.forward = Camera.main.transform.forward;
}
#if USE_LINERENDERER
private void UpdateLineUsingLineRenderer()
{
positions[0] = target1.position;
positions[1] = target4.position;
lineRenderer.SetPositions(positions);
}
#else
private void UpdateLineUsingCube()
{
// simply rotate the cube so it is facing in the line direction
cubeLine.transform.forward = redLineDirection.normalized;
// scale it to match both target positions with its ends
cubeLine.transform.localScale = new Vector3(lineWith, lineWith, redLineDirection.magnitude);
// and move it to the center between both targets
cubeLine.transform.position = (target1.position + target4.position) / 2f;
}
#endif
}
Result using the LineRenderer
Result using the cube which looks almost the same

Move Gameobject generating Objects based on Data

I am generating gameobjects (spheres) based on coordinates, which are stored in a .csv file. I have a Gameobject with a Single Sphere as primitive childobject. Based on the data the Object will clone this sphere 17 times and move them around. I can move the whole thing around like i want it to by accessing the parent object, but in editing mode the position of the root sphere makes it uneasy to use.
The following Code makes this possible.
public GameObject parentObj;
public TextAsset csvFile;
[SerializeField]
private float scaleDownFactor = 10;
private int index = 0;
//class Deck : MonoBehaviour
//{
[SerializeField]
private GameObject[] deck;
private GameObject[] instanciatedObjects;
private void Start()
{
Fill();
}
public void Fill()
{
instanciatedObjects = new GameObject[deck.Length];
for (int i = 0; i < deck.Length; i++)
{
instanciatedObjects[i] = Instantiate(deck[i]) as GameObject;
}
}
//}
// Update is called once per frame
void Update()
{
readCSV();
}
void readCSV()
{
string[] frames = csvFile.text.Split('\n');
int[] relevant = {
0
};
string[] coordinates = frames[index].Split(',');
for (int i = 0; i < 17; i++)
{
float x = float.Parse(coordinates[relevant[i] * 3]) / scaleDownFactor;
float y = float.Parse(coordinates[relevant[i] * 3+1]) / scaleDownFactor;
float z = float.Parse(coordinates[relevant[i] * 3+2]) / scaleDownFactor;
//objectTest.transform.Rotate(float.Parse(fields[1]), float.Parse(fields[2]), float.Parse(fields[3]));
//objectTest.transform.Translate(x, y, z);
//parentObj.transform.position = new Vector3(x, y, z);
instanciatedObjects[i].transform.position = new Vector3(parentObj.transform.position.x, parentObj.transform.position.y, parentObj.transform.position.z);
instanciatedObjects[i].transform.eulerAngles = new Vector3(parentObj.transform.eulerAngles.x, parentObj.transform.eulerAngles.y, parentObj.transform.eulerAngles.z);
//instanciatedObjects[i].transform.position = new Vector3(x, y, z);
instanciatedObjects[i].transform.Translate(x, y, z);
}
if (index < frames.Length - 1)
{
index++;
}
if (index >= frames.Length -1)
{
index = 0;
}
}
Here is a Screenshot:
So my question is:
How can I set the Position of this Sphere to one of the moving points, without changing the position of the cloned objects? Since all behave based on the BaseSphere?
Is it possible to make the BaseSphere not visible While the Objects are getting cloned or generated?
I am looking for a solution, that makes it easier to move the datagenerated Object around in Editor.
I would appreciate any kind of input.
Make all Spheres children of Empty Gameobject (for example. Sphere_root) and use this for moving Spheres.
Also check Scriptable Objects. It is simple and very quick method to manage data in Unity.
#Edit
public void Fill()
{
instanciatedObjects = new GameObject[deck.Length];
for (int i = 0; i < deck.Length; i++)
{
instanciatedObjects[i] = Instantiate(deck[i]) as GameObject;
instanciatedObjects[i].transform.parent = Baumer; // or Sphere Root or somehing else.
}
}

How to show vertices on a cube when selected in Unity (during runtime)?

I'm trying to write a script that makes a cube turn blue and display the vertices of the cube on it when selected during runtime. So basically when clicked, it will show all the vertices and then allow a user to select different vertices of the cube.
This is what i have so far, essentially only turning the cube blue. How can I display vertices of the cube as spheres? I want to be able to select these vertices later.
using UnityEngine;
using System.Collections;
public class Cube : MonoBehaviour {
void OnMouseDown() {
Renderer rend = GetComponent<Renderer>();
rend.material.color = Color.blue;
//insert method to display vertices
}
}
Since both the cube and spheres are primitives:
you find the vertices like this (assuming cube is a GameObject):
Vector3[] vertices = cube.GetComponent<MeshFilter>().mesh.vertices;
And then to create your spheres (need using System.Linq):
GameObject[] spheres = vertices.Select(vert =>
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere)
sphere.transform.position = vert;
return sphere;
})
.ToArray();
UPDATE: Okay i see your problem with too many vertices now, and this is how i would do it, and i would personally make threshold be the radius of your spheres, so that once the spheres begin overlapping they just become one:
float threshold = 0.1f;
public void CreateSpheres()
{
List<GameObject> spheres = new List<GameObject>();
foreach (Vector3 vert in vertices)
{
if (spheres.Any(sph => (sph.transform.position - vert) < threshold)) continue;
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere)
sphere.transform.position = vert;
spheres.Add(sphere);
}
}
Couldn't get the Select Function to work as show in one of the previous example. The coordinates were found using GetComponent<MeshFilter>.mesh.vertices; as described in the other answer.
void OnMouseDown() {
Renderer rend = GetComponent<Renderer>();
rend.material.color = Color.blue;
Vector3[] vertices = GetComponent<MeshFilter>().mesh.vertices;
Vector3[] verts = removeDuplicates(vertices);
drawSpheres(verts);
}
The vertices array contains 24 elements for the reason shown here. So the function removeDuplicates was written to get rid of the duplicate vertices. This function is shown below:
Vector3[] removeDuplicates(Vector3[] dupArray) {
Vector3[] newArray = new Vector3[8]; //change 8 to a variable dependent on shape
bool isDup = false;
int newArrayIndex = 0;
for (int i = 0; i < dupArray.Length; i++) {
for (int j = 0; j < newArray.Length; j++) {
if (dupArray[i] == newArray[j]) {
isDup = true;
}
}
if (!isDup) {
newArray[newArrayIndex] = dupArray[i];
newArrayIndex++;
isDup = false;
}
}
return newArray;
}
Lastly the Spheres were drawn using the new verts Array using the drawSpheres function shown here:
void drawSpheres(Vector3[] verts) {
GameObject[] Spheres = new GameObject[verts.Length];
for (int i = 0; i < verts.Length; i++) {
Spheres[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
Spheres[i].transform.position = verts[i];
Spheres[i].transform.localScale -= new Vector3(0.8F, 0.8F, 0.8F);
}
}

Categories

Resources