error detail
this mesh is generated by my script.I want to generate a voronoi diagram and split a plane to three zones.And I drag a material to one of the zones to test the generated result.
using SharpVoronoiLib;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms.VisualStyles;
using UnityEngine;
public class Fortune : MonoBehaviour
{
List<VoronoiEdge> edges;
private void Awake()
{
List<VoronoiSite> sites = new List<VoronoiSite>
{
new VoronoiSite(22, 26),
new VoronoiSite(10, 40),
new VoronoiSite(38, 5)
};
edges = VoronoiPlane.TessellateOnce(
sites,
0, 0,
50, 50
);
//site represent a zone. ClockwisePoints represent some points,which makes up the zone.
for (int i = 0; i < sites.Count; i++)
{
var ver = new List<Vector3>();
var uv= new List<Vector2>();
foreach (var item in sites[i].ClockwisePoints)
{
float x = (float)item.X;
float y = (float)item.Y;
ver.Add(new Vector3(x, 0, y));
uv.Add(new Vector2(x/50, y/50));
}
ver.Reverse();
uv.Reverse();
List<int> tri = new List<int>();
for (int j = 1; j < ver.Count - 1; j++)
{
tri.Add(0);
tri.Add(j);
tri.Add(j + 1);
}
Mesh mesh = new Mesh();
mesh.vertices = ver.ToArray();
mesh.triangles = tri.ToArray();
mesh.uv=uv.ToArray();
var gameObject = Resources.Load<GameObject>("test");
MeshFilter meshfilter = gameObject.GetComponent<MeshFilter>();
meshfilter.mesh = mesh;
Instantiate(gameObject,Vector3.zero,Quaternion.identity);
}
}
Maybe the uv setting has error.But I don't know the reason.Thank for your reply.
After some try,I find if I delete height map in shader.The error has disappeared.I don't know reason.
shader windows
i saw Unity - How to set the color of an individual face when clicking a mesh? this Question and I'm challenging this. However, I have no understanding of how to reconstruct UV. If there's anyone who can tell me which part to modify in the code below, I'd like to get help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class meshColor : MonoBehaviour
{
public GameObject cube;
[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;
var colors = new Color[_mesh.vertices.Length];
for (var k = 0; k < colors.Length; k++)
{
colors[k] = Color.white;
}
_mesh.colors = colors;
}
private void Update()
{
if (!Input.GetMouseButtonDown(0)) return;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out var hit))
{
Debug.Log(hit.triangleIndex);
var vertices = _mesh.vertices;
var uvs = _mesh.uv;
var triangles = _mesh.triangles;
var colors = _mesh.colors;
var vert1Index = triangles[hit.triangleIndex * 3 + 0];
var vert2Index = triangles[hit.triangleIndex * 3 + 1];
var vert3Index = triangles[hit.triangleIndex * 3 + 2];
var vert1Pos = vertices[vert1Index];
var vert2Pos = vertices[vert2Index];
var vert3Pos = vertices[vert3Index];
var uv1Pos = uvs[vert1Index];
var uv2Pos = uvs[vert2Index];
var uv3Pos = uvs[vert3Index];
var vert1Occurrences = 0;
var vert2Occurrences = 0;
var vert3Occurrences = 0;
foreach (var index in triangles)
{
if (index == vert1Index) vert1Occurrences++;
else if (index == vert2Index) vert2Occurrences++;
else if (index == vert3Index) vert3Occurrences++;
}
var newVertices = vertices.ToList();
var newColors = colors.ToList();
var newUvs = uvs.ToList();
if (vert1Occurrences > 1)
{
newVertices.Add(vert1Pos);
newColors.Add(new Color());
newUvs.Add(uv1Pos);
vert1Index = newVertices.Count - 1;
}
if (vert2Occurrences > 1)
{
newVertices.Add(vert2Pos);
newColors.Add(new Color());
newUvs.Add(uv2Pos);
vert2Index = newVertices.Count - 1;
}
if (vert3Occurrences > 1)
{
newVertices.Add(vert3Pos);
newColors.Add(new Color());
newUvs.Add(uv3Pos);
vert3Index = newVertices.Count - 1;
}
triangles[hit.triangleIndex * 3 + 0] = vert1Index;
triangles[hit.triangleIndex * 3 + 1] = vert2Index;
triangles[hit.triangleIndex * 3 + 2] = vert3Index;
newColors[vert1Index] = Color.red;
newColors[vert2Index] = Color.red;
newColors[vert3Index] = Color.red;
newUvs[vert1Index] = new Vector2(uv1Pos.x, uv1Pos.y);
newUvs[vert2Index] = new Vector2(uv2Pos.x, uv2Pos.y);
newUvs[vert3Index] = new Vector2(uv3Pos.x, uv3Pos.y);
_mesh.vertices = newVertices.ToArray();
_mesh.triangles = triangles;
_mesh.colors = newColors.ToArray();
_mesh.uv = newUvs.ToArray();
_mesh.RecalculateNormals();
}
else
{
Debug.Log("no hit");
}
}
}
I have this code :
public void BrowseColliderToCreateMesh (PolygonCollider2D polygonColliderAdded){
//browse all path from collider
pathCount=polygonColliderAdded.pathCount;
CombineInstance[] combine = new CombineInstance[pathCount];
for (int i = 0; i < pathCount; i++)
{
Vector2[] path = polygonColliderAdded.GetPath(i);
Polygon2D polygon = Polygon2D.Contour(path);
Triangulation2D triangulation = new Triangulation2D(polygon, 22.5f);
// build a mesh from triangles in a Triangulation2D instance
singleMesh = triangulation.Build();
combine[i].mesh = singleMesh;
}
testDelaunay.GetComponent<MeshFilter>().mesh = new Mesh;
testDelaunay.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
}
1- I have a list of point from a polygonCollider2D, divide in 3 :
2- I loop through these path to generate mesh with Delaunay.
For 1 mesh it work well, but I can't find a way to combine it.
Example from unity use some other children gameobject that I don't have...
Does someone has a solution ?
I finally find something which is not optimize but which work :
private Mesh CombineMeshes(List<Mesh> meshes)
{
var combine = new CombineInstance[meshes.Count];
for (int i = 0; i < meshes.Count; i++)
{
combine[i].mesh = meshes[i];
combine[i].transform = transform.localToWorldMatrix;
}
var mesh = new Mesh();
mesh.CombineMeshes(combine);
return mesh;
}
public void BrowseColliderToCreateMesh (PolygonCollider2D polygonColliderAdded){
pathCount=polygonColliderAdded.pathCount;
for (int i = 0; i < pathCount; i++)
{
if(i==0){
Vector2[] path = polygonColliderAdded.GetPath(i);
Polygon2D polygon = Polygon2D.Contour(path);
Triangulation2D triangulation = new Triangulation2D(polygon, 22.5f);
// build a mesh from triangles in a Triangulation2D instance
singleMesh = triangulation.Build();
}else if (i==1){
Vector2[] path = polygonColliderAdded.GetPath(i);
Polygon2D polygon = Polygon2D.Contour(path);
Triangulation2D triangulation = new Triangulation2D(polygon, 22.5f);
// build a mesh from triangles in a Triangulation2D instance
newMesh = triangulation.Build();
combineMesh=CombineMeshes(new List<Mesh> { newMesh, singleMesh });
}else if(i>1){
Vector2[] path = polygonColliderAdded.GetPath(i);
Polygon2D polygon = Polygon2D.Contour(path);
Triangulation2D triangulation = new Triangulation2D(polygon, 22.5f);
newMesh = triangulation.Build();
combineMesh=CombineMeshes(new List<Mesh> { newMesh, combineMesh });
}
}
GetComponent<MeshFilter>().mesh = combineMesh;
}
I've been working on building a procedural generator for Unity, that takes in noise and uses it to build a height map.
So far, everything seems to work as long as I limit the size of the mesh to around 250x250. If I attempt to make a larger mesh, the script won't calculate it.
The puzzling thing is that I get no memory errors or anything of that nature. I've implemented a Regenerate button that allows me to generate a new mesh in Unity and as long as I remain in the range of 250x250 or less, it works fine. If I pick a larger value, the mesh simply remains unchanged.
How I calculate the Mesh:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(Noise))]
public class CustomTerrain : MonoBehaviour {
//Note: sizeX*sizeZ determines mesh size.
public int sizeX = 4; //These values are public so they can be
public int sizeZ = 4; //modified in the Unity Editor.
public float noiseSize = 1.0f;
public float cellSize = 1.0f;
private string mPath = "Assets/Generated/";
Noise noise;
void Start() {
noise = GetComponent<Noise>();
this.LoadMesh();
if (!GetComponent<MeshFilter>().sharedMesh) {
this.Regenerate();
}
}
public void LoadMesh() {
Mesh mesh = Instantiate(AssetDatabase.LoadMainAssetAtPath(mPath + gameObject.name + ".asset") as Mesh);
if (mesh) {
GetComponent<MeshFilter>().mesh = mesh;
}
recalculateMeshCollider(mesh);
}
Vector3[] GenVertices() {
float x, z;
int w = (sizeX+1);
int l = (sizeZ+1);
Vector3[] vertices = new Vector3[w*l];
for (int gx = 0; gx < w; gx++) {
for (int gz = 0; gz < l; gz++) {
x = gx*cellSize;
z = gz*cellSize;
float height = (noiseSize * noise.Get(x,z));
vertices[gx*l+gz] = new Vector3(x, height, z);
}
}
return vertices;
}
int[] GenTriangles() {
int vertciesPerTriangle = 3;
int trianglesPerCell = 2;
int numberCells = sizeX * sizeZ;
int[] triangles = new int[vertciesPerTriangle * trianglesPerCell * numberCells];
int tIndeX = 0;
for (int cX = 0; cX < sizeX; cX++) {
for (int cZ = 0; cZ < sizeZ; cZ++) {
int n = cX*(sizeZ+1)+cZ;
triangles[tIndeX] = n;
triangles[tIndeX+1] = n+1;
triangles[tIndeX+2] = n+sizeZ+2;
triangles[tIndeX+3] = n;
triangles[tIndeX+4] = n+sizeZ+2;
triangles[tIndeX+5] = n+sizeZ+1;
tIndeX +=6;
}
}
return triangles;
}
Vector2[] GenUVs() {
int w = (sizeX + 1);
int l = (sizeZ + 1);
Vector2[] uvs = new Vector2[w * l];
for (int uX = 0; uX < w; uX++) {
for (int uZ = 0; uZ < l; uZ++) {
uvs[uX*l+uZ] = new Vector2((float)uX/sizeX, (float)uZ/sizeZ);
}
}
return uvs;
}
}
My Regenerate function:
public void Regenerate() {
noise.Init();
Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
if(!mesh) {
mesh = new Mesh();
GetComponent<MeshFilter>().sharedMesh = mesh;
}
mesh.vertices = GenVertices();
mesh.triangles = GenTriangles();
mesh.uv = GenUVs();
mesh.RecalculateNormals();
recalculateMeshCollider(mesh);
}
public void recalculateMeshCollider(Mesh mesh) {
if (GetComponent<MeshCollider>()) {
DestroyImmediate(GetComponent<MeshCollider>());
}
transform.gameObject.AddComponent<MeshCollider>();
transform.GetComponent<MeshCollider>().sharedMesh = mesh;
}
By "250x250" do you mean there's 62.400 triangles?
Unity has a vertex limit of 65535 count - just use more than one mesh, no trouble.
So I have a script that shoots an arrow when you click and drag, kinda like Angry Birds.
I want it to work with the 2D RigidBody and 2D collider but when I change the rigidbody.AddForce to rigidbody2D.AddForce, It doesn't work.
How can I fix this to work for 2D?
I also want the arrow to rotate in 2D space either up or down depending on where mouse is pulled back. When I try the mouse look script, it rotates it in the z axis (I think) and distorts the arrow. Any easy solution to fix this??
Thanks guys. I'm new to game making and I've been trying to figure this stuff out for like the last 10 hours. I need some pros to help!
Thanks!!!
Heres my script
using UnityEngine;
using System.Collections;
public class DragShotMover2 : MonoBehaviour {
public float maxDragLength = 2; // this is the base magnitude and the maximum length of the line drawn in the user interface
public float maxMultiplier = 5; // multiply the line length by this to allow for higher force values to be represented by shorter lines
public Vector3 dragPlaneNormal = Vector3.up; // a vector describing the orientation of the drag plan relative to world-space but centered on the target
public SnapDir snapDirection = SnapDir.away; // force is applied either toward or away from the mouse on release
public ForceMode forceTypeToApply = ForceMode.VelocityChange;
public bool overrideVelocity = true; // cancel the existing velocity before applying the new force
public bool pauseOnDrag = true; // causes the simulation to pause when the object is clicked and unpause when released
public Color noForceColor = Color.yellow; // color of the visualization helpers at force 0
public Color maxForceColor = Color.red; // color of the visualization helpers at maximum force
public enum SnapDir {toward, away}
private Vector3 forceVector;
private float magPercent = 0;
private bool mouseDragging = false;
private Vector3 mousePos3D;
private float dragDistance;
private Plane dragPlane;
private Ray mouseRay;
private GameObject dragZone;
private string shaderString = "Transparent/Diffuse";
private Material dzMat;
void Start (){
Color currentColor = noForceColor;
dzMat = new Material(Shader.Find(shaderString));
// create the dragzone visual helper
dragZone = new GameObject("dragZone_" + gameObject.name);
dragZone.AddComponent<MeshFilter>().mesh = MakeDiscMeshBrute(maxDragLength/4);
//dragZone.GetComponent.MeshFilter.
dragZone.AddComponent<MeshRenderer>();
dragZone.renderer.enabled = false;
dragZone.name = "dragZone_" + gameObject.name;
dragZone.transform.localScale = new Vector3(maxDragLength*2, 0.025f, maxDragLength*2);
dragZone.renderer.material = dzMat;
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// create the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseDown (){
mouseDragging = true;
if (pauseOnDrag) {
// pause the simulation
Time.timeScale = 0;
}
// update the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
dragZone.renderer.enabled = true;
}
void OnMouseDrag (){
Color currentColor = noForceColor;
// update the plane if the target object has left it
if (dragPlane.GetDistanceToPoint(transform.position) != 0) {
// update dragplane by constructing a new one -- I should check this with a profiler
dragPlane = new Plane(dragPlaneNormal, transform.position);
}
// create a ray from the camera, through the mouse position in 3D space
mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
// if mouseRay intersects with dragPlane
float intersectDist = 0.0f;
if (dragPlane.Raycast(mouseRay, out intersectDist)) {
// update the world space point for the mouse position on the dragPlane
mousePos3D = mouseRay.GetPoint(intersectDist);
// calculate the distance between the 3d mouse position and the object position
dragDistance = Mathf.Clamp((mousePos3D - transform.position).magnitude, 0, maxDragLength);
// calculate the force vector
if (dragDistance*maxMultiplier < 1) dragDistance = 0; // this is to allow for a "no move" buffer close to the object
forceVector = mousePos3D - transform.position;
forceVector.Normalize();
forceVector *= dragDistance * maxMultiplier;
// update color the color
// calculate the percentage value of current force magnitude out of maximum
magPercent = (dragDistance * maxMultiplier) / (maxDragLength * maxMultiplier);
// choose color based on how close magPercent is to either 0 or max
currentColor = noForceColor * (1-magPercent) + maxForceColor * magPercent;
// dragzone color
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// draw the line
Debug.DrawRay(transform.position, forceVector / maxMultiplier, currentColor);
}
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseUp (){
mouseDragging = false;
if (overrideVelocity) {
// cancel existing velocity
rigidbody.AddForce(-rigidbody.velocity, ForceMode.VelocityChange);
}
// add new force
int snapD = 1;
if (snapDirection == SnapDir.away) snapD = -1; // if snapdirection is "away" set the force to apply in the opposite direction
rigidbody.AddForce(snapD * forceVector, forceTypeToApply);
// cleanup
dragZone.renderer.enabled = false;
if (pauseOnDrag) {
// un-pause the simulation
Time.timeScale = 1;
}
}
void OnGUI (){
if (mouseDragging) {
Vector2 guiMouseCoord = GUIUtility.ScreenToGUIPoint(Input.mousePosition);
GUI.Box ( new Rect(guiMouseCoord.x-30, Screen.height-guiMouseCoord.y+15, 100, 20), "force: "+Mathf.Round((forceVector).magnitude));
}
}
Mesh MakeDiscMeshBrute ( float r ){
Mesh discMesh;
Vector3[] dmVerts = new Vector3[18];
Vector3[] dmNorms = new Vector3[18];
Vector2[] dmUVs = new Vector2[18];
int[] dmTris = new int[48];
int i = 0;
discMesh = new Mesh();
dmVerts[0] = new Vector3(0,0,0);
dmVerts[1] = new Vector3(0,0,r);
dmVerts[2] = new Vector3(1,0,1).normalized * r; // find the vector at the correct distance the hacky-hillbilly way!
dmVerts[3] = new Vector3(r,0,0);
dmVerts[4] = new Vector3(1,0,-1).normalized * r;
dmVerts[5] = new Vector3(0,0,-r);
dmVerts[6] = new Vector3(-1,0,-1).normalized * r;
dmVerts[7] = new Vector3(-r,0,0);
dmVerts[8] = new Vector3(-1,0,1).normalized * r;
// set the other side to the same points
for (i = 0; i<dmVerts.Length/2; i++) {
dmVerts[dmVerts.Length/2 + i] = dmVerts[i];
}
for (i = 0; i<dmNorms.Length; i++) {
if (i<dmNorms.Length/2) dmNorms[i] = Vector3.up; // set side one to face up
else dmNorms[i] = -Vector3.up; // set side two to face down
}
dmUVs[0] = new Vector2(0,0);
dmUVs[1] = new Vector2(0,r);
dmUVs[2] = new Vector2(1,1).normalized * r;;
dmUVs[3] = new Vector2(r,0);
dmUVs[4] = new Vector2(1,-1).normalized * r;;
dmUVs[5] = new Vector2(0,-r);
dmUVs[6] = new Vector2(-1,-1).normalized * r;;
dmUVs[7] = new Vector2(-r,0);
dmUVs[8] = new Vector2(-1,1).normalized * r;;
// set the other side to the same points
for (i = 0; i<dmUVs.Length/2; i++) {
dmUVs[dmUVs.Length/2 + i] = dmUVs[i];
}
dmTris[0] = 0;
dmTris[1] = 1;
dmTris[2] = 2;
dmTris[3] = 0;
dmTris[4] = 2;
dmTris[5] = 3;
dmTris[6] = 0;
dmTris[7] = 3;
dmTris[8] = 4;
dmTris[9] = 0;
dmTris[10] = 4;
dmTris[11] = 5;
dmTris[12] = 0;
dmTris[13] = 5;
dmTris[14] = 6;
dmTris[15] = 0;
dmTris[16] = 6;
dmTris[17] = 7;
dmTris[18] = 0;
dmTris[19] = 7;
dmTris[20] = 8;
dmTris[21] = 0;
dmTris[22] = 8;
dmTris[23] = 1;
// side two
dmTris[24] = 9;
dmTris[25] = 11;
dmTris[26] = 10;
dmTris[27] = 9;
dmTris[28] = 12;
dmTris[29] = 11;
dmTris[30] = 9;
dmTris[31] = 13;
dmTris[32] = 12;
dmTris[33] = 9;
dmTris[34] = 14;
dmTris[35] = 13;
dmTris[36] = 9;
dmTris[37] = 15;
dmTris[38] = 14;
dmTris[39] = 9;
dmTris[40] = 16;
dmTris[41] = 15;
dmTris[42] = 9;
dmTris[43] = 17;
dmTris[44] = 16;
dmTris[45] = 9;
dmTris[46] = 10;
dmTris[47] = 17;
discMesh.vertices = dmVerts;
discMesh.uv = dmUVs;
discMesh.normals = dmNorms;
discMesh.triangles = dmTris;
return discMesh;
}
}
If you want to keep using the 3D Rigidbody, I'd suggest just using RigidbodyConstraints, so you can lock the z (or whatever) axis/rotation, and it will perform exactly the same as a 2D platformer.