Map the custom triangle to Camera’s View Angle - c#

I have make a triangle through my code. see below:
void TriangleMaker()
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
//vertices
const int verticeCount = 3;//how many vertices for triangle its 3
Vector3[] vertices = new Vector3[verticeCount]{
//bottom left.orgin of the gameobject,
new Vector3(0,0,0),
new Vector3(width,0,0),
new Vector3(width, height,0)
};
//triangles
int[] tri = new int[6];
tri[0] = 0; //go clock wise always to make triangle from your vertices
tri[1] = 1;
tri[2] = 2;
//normals
//show the direction of objects
Vector3[] normals = new Vector3[3];
normals[0] = -Vector3.up;
normals[1] = -Vector3.up;
normals[2] = -Vector3.up;
mesh.vertices = vertices;
mesh.triangles = tri;
mesh.normals = normals;
}
The script is attached to child game-object of my camera and its showing the triangle but i want to map exactly my triangle to Camera’s view angle.
Also tried GeometryUtility.CalculateFrustumPlanes as Niki answer suggested and the result is not according to expectation:
2: https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateFrustumPlanes.html

Well I just found it in Unity docs:
https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateFrustumPlanes.html
P.S: I was so surprised to find this in docs. I think you are the only person in the world who needs this, finally. :D
EDIT:
Ok I edited your script. This visualizes camera's upper frustum plane. Note that this works in global space so move the camera at (0 0 0) position and (0 0 0) rotation to see the result. But I guess you can add the rest of the planes and turn this into local space yourself.
using UnityEngine;
using System.Collections;
public class FrustumScript : MonoBehaviour {
private void Start()
{
TriangleMaker();
}
void TriangleMaker()
{
MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
mf.mesh = mesh;
Camera cam = Camera.main;
//vertices
Vector3[] vertices = new Vector3[3]
{
new Vector3(0, 0, 0),
cam.ViewportToWorldPoint(new Vector3(0, 1, cam.farClipPlane)),
cam.ViewportToWorldPoint(new Vector3(1, 1, cam.farClipPlane))
};
//triangles
int[] tri = new int[6];
tri[0] = 0; //go clock wise always to make triangle from your vertices
tri[1] = 1;
tri[2] = 2;
//normals
//show the direction of objects
Vector3[] normals = new Vector3[3];
normals[0] = -Vector3.up;
normals[1] = -Vector3.up;
normals[2] = -Vector3.up;
mesh.vertices = vertices;
mesh.triangles = tri;
mesh.normals = normals;
}
}

Related

Why does when I remove the triangle it removes the back only not the front?

I am implementing triangle removal of a mesh by using ray cast. It removes the triangles from the moves that the ray cast is hitting it, but the problem is when I am trying to remove the triangles, it removes the back part of the mesh not the front, and only when I am hitting with ray cast from inside of the mesh. I am not sure what can be the problem, any help and guidance will be really appreciated. I have attached the picture.
In the imaged uploaded, the scene view is flipped down and the game view shows the object that cast ray is in middle:
Following is my implementation:
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.Numerics;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
using Vector4 = UnityEngine.Vector4;
public class RemoveTriangle : MonoBehaviour
{
[Header("Game Object")][Tooltip("The game object that will be removed its triangles")]
public GameObject spherePrefab;
// Better to reference those already in the Inspector
[Header("Mesh Files to Load")]
[SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private MeshFilter meshFilter;
[SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private MeshRenderer meshRenderer;
[SerializeField][Tooltip("Drag and drop the mesh files you want to load")] private MeshCollider meshCollider;
//[SerializeField] [Range(1.0f, 3.0f)] public float raycastSize = 1.0f;
[Header("Origin and Target objects")]
[Tooltip("Drag and drop the origin and target objects")]public Transform SelectOrigin;
[Tooltip("Drag and drop the origin and target objects")]public MeshFilter SelectTarget;
[Header("Raycast Distance")][Tooltip("The distance of the raycast")]
[SerializeField][Range(0.1f,20.0f)]public float MaxDistance = 10f;
private Mesh mesh;
private void Awake()
{
MeshProperties();
}
private void Update()
{
DeleteTriangle();
}
void MeshProperties()
{// Get the mesh from the mesh filter
if (!meshFilter) meshFilter = GetComponent<MeshFilter>();
if (!meshRenderer) meshRenderer = GetComponent<MeshRenderer>();
if (!meshCollider) meshCollider = GetComponent<MeshCollider>();
mesh = meshFilter.mesh;
}// MeshProperties
void DeleteTriangle()
{//raycast from mouse position
if (Input.GetKey(KeyCode.C))
{//raycast from mouse position
Ray ray = new Ray(SelectOrigin.position, SelectOrigin.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, MaxDistance))
{//if raycast hits a triangle
Debug.DrawRay(SelectOrigin.position,
SelectTarget.transform.position - SelectOrigin.position,
Color.red);
Debug.Log("Triangle Removed at: " + hit.point + "/" + hit.triangleIndex + "/" + hit.normal);
//cube.transform.position = hit.point;
// Get current vertices, triangles, uvs,tangents and normals of the mesh
Vector3[] vertices = mesh.vertices;
Vector2[] uv = mesh.uv;
Vector4[] tangents = mesh.tangents;
Vector3[] normals = mesh.normals;
int[] triangles = mesh.triangles;
// Get the vert indices for this triangle
int vertIndex_1 = triangles[hit.triangleIndex * 3 + 0];
int vertIndex_2 = triangles[hit.triangleIndex * 3 + 1];
int vertIndex_3 = triangles[hit.triangleIndex * 3 + 2];
// Get the vertices for this triangle
var vert_1 = vertices[vertIndex_1];
var vert_2 = vertices[vertIndex_2];
var vert_3 = vertices[vertIndex_3];
// Get the uv for this triangle
var uv_1 = uv[vertIndex_1];
var uv_2 = uv[vertIndex_2];
var uv_3 = uv[vertIndex_3];
//Get the Normals for this triangle
var normal_1 = mesh.normals[vertIndex_1];
var normal_2 = mesh.normals[vertIndex_2];
var normal_3 = mesh.normals[vertIndex_3];
//Get Tangents for this triangle
Vector4 tangent_1 = mesh.tangents[vertIndex_1];
Vector4 tangent_2 = mesh.tangents[vertIndex_2];
Vector4 tangent_3 = mesh.tangents[vertIndex_3];
// Get the positions for the vertices
var vertPos_1 = vertices[vertIndex_1];
var vertPos_2 = vertices[vertIndex_2];
var vertPos_3 = vertices[vertIndex_3];
// Get the center of the triangle
var center = (vertPos_1 + vertPos_2 + vertPos_3) / 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++;
}//end for
// Remove the vertices
if (verticesOccur_1 == 1)
vertices[vertIndex_1] = Vector3.zero;
if (verticesOccur_2 == 1)
vertices[vertIndex_2] = Vector3.zero;
if (verticesOccur_3 == 1)
vertices[vertIndex_3] = Vector3.zero;
// Remove the uv
if (verticesOccur_1 == 1)
uv[vertIndex_1] = Vector2.zero;
if (verticesOccur_2 == 1)
uv[vertIndex_2] = Vector2.zero;
if (verticesOccur_3 == 1)
uv[vertIndex_3] = Vector2.zero;
// Remove the normals
if (verticesOccur_1 == 1)
mesh.normals[vertIndex_1] = Vector3.zero;
if (verticesOccur_2 == 1)
mesh.normals[vertIndex_2] = Vector3.zero;
if (verticesOccur_3 == 1)
mesh.normals[vertIndex_3] = Vector3.zero;
// Remove the tangents
if (verticesOccur_1 == 1)
mesh.tangents[vertIndex_1] = Vector4.zero;
if (verticesOccur_2 == 1)
mesh.tangents[vertIndex_2] = Vector4.zero;
if (verticesOccur_3 == 1)
mesh.tangents[vertIndex_3] = Vector4.zero;
//fix the triangles
//for (var i = 0; i < triangles.Length; i++)
//{
//if (triangles[i] == vertIndex_1) triangles[i] = 0;
// (triangles[i] == vertIndex_2) triangles[i] = 0;
//if (triangles[i] == vertIndex_3) triangles[i] = 0;
//}]
// Find the intersecting triangles by checking if the ray intersects with their vertices
//var intersectingTriangles = new List<int>();
/* for (var i = 0; i < triangles.Length; i += 3)
{
var triangleVertIndex_1 = triangles[i + 0];
var triangleVertIndex_2 = triangles[i + 1];
var triangleVertIndex_3 = triangles[i + 2];
var triangleVertPos_1 = vertices[triangleVertIndex_1];
var triangleVertPos_2 = vertices[triangleVertIndex_2];
var triangleVertPos_3 = vertices[triangleVertIndex_3];
}*/
// Remove the triangles and update the mesh
triangles[hit.triangleIndex * 3] = 0;
triangles[hit.triangleIndex * 3 + 1] = 0;
triangles[hit.triangleIndex * 3 + 2] = 0;
//update the mesh with the new vertices, uv, normals and tangents
mesh.vertices = vertices;
mesh.uv = uv;
mesh.tangents = tangents;
mesh.normals = normals;
//update the tirangles
mesh.triangles = triangles;
// Recalculate the normals
mesh.RecalculateNormals();
// Recalculate the tangents
mesh.RecalculateTangents();
// Recalculate the bounds
mesh.RecalculateBounds();
}//end of if
else
{
Debug.Log("No Triangle to remove" + hit.point);
}//end of if hit.triangleIndex
}//end of remove triangle
}//end of class
}//end of class
I tried to change the setting of mesh, but it did not give me a good result. I feel like there is a problem with the mesh, but I cannot understand what the problem is.

How to create a mesh dynamically In unity

I have vertex that have a color value.
I'd like to make a mesh using vertex with the same color values.
This picture is an example.
I took pictures with my Android Phone, and I did image segmentation on the object
So I got a color value corresponding to the coordinate value.
I succeeded in just making textures. please check the image.
But I want a mesh object.
Below is making texture code.
var pixel = await this.segmentation.SegmentAsync(rotated, scaled.width, scaled.height);
// int pixel[][]; // image segmentation using tensorflow
Color transparentColor = new Color32(255, 255, 255, 0); // transparent
for (int y = 0; y < texture.height; y++)
{
for (int x = 0; x < texture.width; x++)
{
int class_output = pixel[y][x];
texture.SetPixel(x, y, pixel[y][x] == 0 ? transparentColor : colors[class_output]);
}
}
texture.Apply();
How can I make a mesh object?
1- Set a prefab with a MeshFilter and a MeshRenderer.
2- Variables inside the script that you will need to fill.
// This first list contains every vertex of the mesh that we are going to render
public List<Vector3> newVertices = new List<Vector3>();
// The triangles tell Unity how to build each section of the mesh joining
// the vertices
public List<int> newTriangles = new List<int>();
// The UV list is unimportant right now but it tells Unity how the texture is
// aligned on each polygon
public List<Vector2> newUV = new List<Vector2>();
// A mesh is made up of the vertices, triangles and UVs we are going to define,
// after we make them up we'll save them as this mesh
private Mesh mesh;
3- Initialize the mesh
void Start () {
mesh = GetComponent<MeshFilter> ().mesh;
float x = transform.position.x;
float y = transform.position.y;
float z = transform.position.z;
newVertices.Add( new Vector3 (x , y , z ));
newVertices.Add( new Vector3 (x + 1 , y , z ));
newVertices.Add( new Vector3 (x + 1 , y-1 , z ));
newVertices.Add( new Vector3 (x , y-1 , z ));
newTriangles.Add(0);
newTriangles.Add(1);
newTriangles.Add(3);
newTriangles.Add(1);
newTriangles.Add(2);
newTriangles.Add(3);
newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y + tUnit));
newUV.Add(new Vector2 (tUnit * tStone.x + tUnit, tUnit * tStone.y + tUnit));
newUV.Add(new Vector2 (tUnit * tStone.x + tUnit, tUnit * tStone.y));
newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y));
mesh.Clear ();
mesh.vertices = newVertices.ToArray();
mesh.triangles = newTriangles.ToArray();
mesh.uv = newUV.ToArray(); // add this line to the code here
mesh.Optimize ();
mesh.RecalculateNormals ();
}
This code will draw a square at the position of the prefab, if you keep adding vertices you can generate a more complex mesh.
The source of information is a tutorial to generate mensh for a terrain like minecrat, check the link for more information.
The answer which has been selected best is, in my opinion, faulty for four reasons. First, it is deprecated. Second, it is more complex than necessary. Third, it offers little explanation, and finally, it is mostly just a copy from someone else's blog post. For that reason, I offer a new suggestion. For more info, view the documentation here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class meshmaker : MonoBehaviour {
Mesh mesh;
MeshFilter meshFilter;
Vector3[] newVertices;
int[] newTriangles;
// Use this for initialization
void Start () {
//First, we create an array of vector3's. Each vector3 will
//represent one vertex in our mesh. Our shape will be a half
//cube (probably the simplest 3D shape we can make.
newVertices = new Vector3[4];
newVertices [0] = new Vector3 (0, 0, 0);
newVertices [1] = new Vector3 (1, 0, 0);
newVertices [2] = new Vector3 (0, 1, 0);
newVertices [3] = new Vector3 (0, 0, 1);
//Next, we create an array of integers which will represent
//triangles. Triangles are built by taking integers in groups of
//three, with each integer representing a vertex from our array of
//vertices. Note that the integers are in a certain order. The order
//of integers determines the normal of the triangle. In this case,
//connecting 021 faces the triangle out, while 012 faces the
//triangle in.
newTriangles = new int[12];
newTriangles[0] = 0;
newTriangles[1] = 2;
newTriangles[2] = 1;
newTriangles[3] = 0;
newTriangles[4] = 1;
newTriangles[5] = 3;
newTriangles[6] = 0;
newTriangles[7] = 3;
newTriangles[8] = 2;
newTriangles[9] = 1;
newTriangles[10] = 2;
newTriangles[11] = 3;
//We instantiate our mesh object and attach it to our mesh filter
mesh = new Mesh ();
meshFilter = gameObject.GetComponent<MeshFilter> ();
meshFilter.mesh = mesh;
//We assign our vertices and triangles to the mesh.
mesh.vertices = newVertices;
mesh.triangles = newTriangles;
}
Ta da! Your very own half-cube.

Why when trying to draw a triangle I'm getting exception out of bounds on the uv's?

It's drawing a triangle but also give exception.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshGenerator : MonoBehaviour
{
public GameObject meshPrefab;
public Vector3[] newVertices;
public Vector2[] newUV;
public int[] newTriangles;
private Mesh mesh;
void Start()
{
Mesh meshprefab = meshPrefab.GetComponent<MeshFilter>().sharedMesh;
newVertices = meshprefab.vertices;
newUV = meshprefab.uv;
newTriangles = meshprefab.triangles;
mesh = new Mesh();
mesh = gameObject.GetComponent<MeshFilter>().mesh;
mesh.Clear();
mesh.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 0.25f), new Vector2(0.25f, 0.25f) };
mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 0.25f, 0), new Vector3(0.25f, 0.25f, 0) };
mesh.triangles = new int[] { 0, 1, 2 };
}
}
The exception is on the line:
mesh.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 0.25f), new Vector2(0.25f, 0.25f) };
Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
UnityEngine.Mesh:set_uv(Vector2[])
You need to move the vertex array assignment statement to before the uv one, because Unity currently thinks that the number of vertices is zero.
mesh.vertices = ...
mesh.uv = ...

Procedural maze remove old colliders

I followed a tutorial on making a procedural generated maze in unity using C# that when you click the mouse button, it generates a new maze.
However, when I generate a new maze everything looks right but the MeshCollider for the old maze mesh is still in place, in addition to the new maze MeshCollider making numerous invisible walls.
How would I clear the old MeshColliders in my script, so that they are removed and only the newly generated mesh remains?
Initial maze image
Second maze image
Each maze, after the first, has the old MeshColliders represented by the green outline and it looks like it is just making new MeshColliders and not replacing the old one with a new one. I thought I could fix this by setting the mesh and MeshCollider to null, then new mesh at the beginning of each new maze generation, but it does nothing:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mesh_Generator : MonoBehaviour {
public SquareGrid squareGrid;
public MeshFilter walls;
public MeshFilter cave;
public bool is2D;
List<Vector3> vertices;
List<int> triangles;
Dictionary<int,List<Triangle>> triangleDictionary = new Dictionary<int, List<Triangle>> ();
List<List<int>> outlines = new List<List<int>> ();
HashSet<int> checkedVerticies = new HashSet<int> ();
public void GenerateMesh(int[,] map, float squareSize){
triangleDictionary.Clear ();
outlines.Clear ();
checkedVerticies.Clear ();
squareGrid = new SquareGrid (map, squareSize);
vertices = new List<Vector3> ();
triangles = new List<int> ();
for (int x = 0; x < squareGrid.squares.GetLength (0); x++) {
for (int y = 0; y < squareGrid.squares.GetLength (1); y++) {
TriangulateSquare (squareGrid.squares [x, y]);
}
}
Mesh mesh = null;
mesh = new Mesh ();
cave.mesh = mesh;
mesh.vertices = vertices.ToArray ();
mesh.triangles = triangles.ToArray ();
mesh.RecalculateNormals ();
if (!is2D) {
CreateWallMesh ();
}
}
void CreateWallMesh(){
CalculateMeshOutLines ();
List<Vector3> wallVerticies = new List<Vector3> ();
List<int> wallTriangles = new List<int> ();
Mesh wallMesh = new Mesh ();
float wallHeight = 5;
foreach (List<int> outline in outlines){
for (int i = 0; i < outline.Count -1; i ++){
int startIndex = wallVerticies.Count;
wallVerticies.Add (vertices [outline [i]]); // left vertex
wallVerticies.Add (vertices [outline [i+1]]); // right vertex
wallVerticies.Add (vertices [outline [i]] - Vector3.up * wallHeight); // bottom left vertex
wallVerticies.Add (vertices [outline [i+1]] - Vector3.up * wallHeight); // bottom right vertex
wallTriangles.Add (startIndex + 0); //triangle 1
wallTriangles.Add (startIndex + 2);
wallTriangles.Add (startIndex + 3);
wallTriangles.Add (startIndex + 3); //triangle 2
wallTriangles.Add (startIndex + 1);
wallTriangles.Add (startIndex + 0);
}
}
wallMesh.vertices = wallVerticies.ToArray ();
wallMesh.triangles = wallTriangles.ToArray ();
walls.mesh = wallMesh;
MeshCollider wallCollider = walls.gameObject.AddComponent<MeshCollider> ();
wallCollider = null;
wallCollider = new MeshCollider ();
wallCollider.sharedMesh = wallMesh;
}
From here, you should call Mesh.Clear "before rebuilding triangles array."
mesh = new Mesh ();
cave.mesh.Clear();
cave.mesh = mesh;

Unity C# generated mesh is offset why is it not in the correct location?

I am attempting to generate a mesh in unity from script. The mesh is generated by raycasting out in a particular direction. Then getting the vertices from the hit point or from where the ray terminates. The mesh generates fine and is working well, however the mesh generates approximately 5 to 10 unity units above the location of the object with the attached script. I will attach me script below.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Torch : MonoBehaviour {
public GameObject lightmeshholder;
private int RaysToShoot = 128;
private float distance = 50;
private Vector3[] vertices;
private Vector2[] vertices2d;
private int[] triangles;
private Mesh mesh;
private Texture2D texture;
private int screenwidth;
private int screenheight;
private int grab = 0;
private RaycastHit hit;
// Use this for initialization
void Start () {
screenwidth = Screen.width;
screenheight = Screen.height;
texture = new Texture2D (screenwidth, screenheight, TextureFormat.RGB24, false);
vertices = new Vector3[RaysToShoot];
vertices2d = new Vector2[RaysToShoot];
triangles = new int[(RaysToShoot) +1 ];
mesh= lightmeshholder.GetComponent<MeshFilter>().mesh;
}
// Update is called once per frame
void Update () {
float angle =0;
for(int i=0;i<RaysToShoot;i++){
float x = Mathf.Sin(0);
x=-5;
if(Input.GetKey(KeyCode.P)){
x = 5;
}
float y = Mathf.Cos(angle);
if (angle <= 90){
angle += 2*Mathf.PI/RaysToShoot;
}
Vector3 dir = new Vector3(x,y,0);
if (Physics.Raycast (this.transform.position, dir,out hit, distance))
{
Debug.DrawLine (this.transform.position, hit.point,new Color(1,1,0,1));
Vector3 tmp = lightmeshholder.transform.InverseTransformPoint(hit.point);
vertices2d[i] = new Vector2(tmp.x,tmp.y);
}else{
Vector3 tmp = lightmeshholder.transform.InverseTransformPoint(this.transform.position + dir*distance);
vertices2d[i] = new Vector2(tmp.x,tmp.y);
Debug.DrawLine(this.transform.position,dir * distance,Color.red,0);
}
}
// build mesh
Vector2[] uvs = new Vector2[vertices2d.Length +1];
Vector3[] newvertices = new Vector3[vertices2d.Length+1];
for (int n = 0; n<newvertices.Length-1 ;n++)
{
if(n==0){
newvertices[0]=this.transform.position;
newvertices[1] = vertices2d[0];
uvs[0] = new Vector2(this.transform.position.x,this.transform.position.y);
uvs[1] = vertices2d[0];
}else{
newvertices[n+1] = vertices2d[n];
uvs[n+1] = vertices2d[n];
}
if(n==0){
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 2;
}else if(n<newvertices.Length/3){
triangles[n*3] = 0;
triangles[1+n*3] = n+1;
triangles[2+n*3] = n+2;
}
}
Mesh mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.Clear();
mesh.vertices = newvertices;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
}
The hitpoints you're getting from the raycasts are global. You can either:
1) Make sure the mesh is in a gameobject that is positioned at 0,0,0. Whenever I create a dynamic mesh based on ray hitpoints I usually create a new parent-less gameobject at 0,0,0 and add the mesh to it. (instead of getting a container GameObject externally)
2) Call lightmeshholder.transform.InverseTransformPoint on the hitpoints from the raycast before building the mesh
When you are assigning vertices back to mesh they are calculated in local coordinates with respect to object root. So if you want to bring it back "where it should be" process them with .TransformPoint() call to get proper offsets. This should fix your problem with them being in different location than you expect. I had same problem.

Categories