- Home /
Creating Cubes with Jagged Edges
I have a fairly efficient grid generation routine now for a Dungeon Keeper-esq map. In the spirit of that game, I want the wall cubes not to have straight lines. The cubes don't have to have extremely jagged edges, but just enough to break up the straight lines a bit. Check out the walls in this picture:
Edit: A Solution: After getting advice from many people in this thread (especially @flaviusxvii and @Warwick Allison), I finally came up with this result. This will make a cube distort slightly, and every adjacent cube will have a matching edge. This makes the cubes look rough, but still seamless. For a picture, check out the awesome example provided by @flaviusxvii.
To make this work, you will need the Perlin script provided in Unity's Procedural Examples
function UpdateMesh (myGameObject : Transform){
var mesh : Mesh = myGameObject.GetComponent(MeshFilter).mesh;
var vertices : Vector3[] = mesh.vertices;
for (var i : int =0 ; i < mesh.vertexCount ; i++)
{
// Distills the vector down into one position-relative number
var vectorSum : float = (myGameObject.transform.position + vertices[i]).x +
(myGameObject.transform.position + vertices[i]).y + (myGameObject.transform.position + vertices[i]).z;
var rawp : float = perlin.Noise(vectorSum, 2, 3);
var p : float = rawp * Mathf.PI * 2f;
var myVector3 : Vector3 = new Vector3(Mathf.Sin(p), Mathf.Cos(p), Mathf.Sin(-p * 47.5454f));
// Adjusts the vertices
vertices[i] += myVector3 * vertices[i].y * .1f;
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
The only thing I don't understand yet is why this doesn't work to alter planes.
You need to understand what Perlin noise is for and how it is used, then it will be obvious. Perlin noise, in any form, takes a point in 1D, 2D, or 3D space and returns a smoothly interpolating value at that point in the range (-1 to +1).
So, you if you want 3 different values at each point (to perturb the point in X, Y, and Z axes), you do something like this:
originalPoint += amplitude * Vector3(
Perlin.Noise(originalPoint*scale),
Perlin.Noise(originalPoint*scale+Vector3(100,2,3)),
Perlin.Noise(originalPoint*scale+Vector3(400,5,6)));
Basically, this samples the noise in 3 distant places, effectively removing any correlation between the points - kind of like having 3 independent noise functions. It uses a scale
to choose the "size" of the noise - a high value will mean nearby points are more different to each other; a low value will make nearby points more similar. This is as opposed to the amplitude
, which is the degree by which each point is perturbed.
If your Noise function takes x,y,z then add a vector3 based function:
function Noise(v : Vector3) : float
{
return Noise(v.x,v.y,v.z);
}
Thank you. I realized after you commented that I had accidentally messed up my comments, so I've tidied this up a bit. Thank you for your help, and for everyone else too!
"The only thing I don't understand yet is why this doesn't work to alter planes."
Is the plane located where Y == 0? I added "myVector3 vertices[i].y .1f; " in order to reduce the effect of noise the closer you get to Y == 0. You'll want to fiddle with that to produce the desired effect.
Don't do this "distill" thong to get 1 number from x,y,z then add ,2,3 to it - just use x,y,z in the first place. $$anonymous$$ay fix the plane problem too.
I've made another approach to a similar problem (http://answers.unity3d.com/questions/298703/perlin-noise-continuous-through-different-objects.html) and I would like to have comments from you and from the others who helped here. Thanks.
Answer by flaviusxvii · Jun 23, 2011 at 05:00 PM
You could use Perlin noise to perturb the vertexes of your level geometry a bit.
2ND EDIT: Ok, I have a better screenshot, there were actually a couple of cubes in the last screenshot that had messed up perturbation because I rotated them. The new version of the UpdateMesh function below fixes that.
EDIT: Ok so I had an early answer but I guess it wasn't inspirational enough to merit some research, so here's a simple example. The screenshot is a bunch of cubes that have their mesh perturbed in Start(). It doesn't matter where they are in the world, they get a nice little jostle that works seamlessly with their neighbors.
void UpdateMesh ()
{
Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] vertices = mesh.vertices;
for (int i=0 ; i<mesh.vertexCount ; i++)
{
Vector3 offset = SimplexNoise.Get().onUnitSphere(transform.TransformPoint(vertices[i])) * 0.05f;
vertices[i] += transform.InverseTransformDirection(offset);
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
SimplexNoise is my noise class (Invented by Ken Perlin). onUnitSphere is overloaded but this one takes a Vector3 and returns a noise Vector3, which I add to the vertex.
Oh $$anonymous$$r. Perlin. They don't understand you. They shun you. I love you though.
http://unity3d.com/support/resources/example-projects/procedural-examples.html
That'll get you started until I can put an example together.
I think this is a superior solution to the one I posted above.
The fact that the verts in a given space get the same deformation wins!
I love $$anonymous$$r Perlin too... his Simplex noise algorithm is better than his original though!
Answer by Tasarran · Jun 23, 2011 at 05:05 PM
I'm doing something similar right now, but not with dungeon walls, I am working with hex tiles in an outdoor setting.
However, what I have learned can be applied to your project, too.
function UpdateMesh ()
{
var mesh : Mesh = GetComponent(MeshFilter).mesh;
var vertices : Vector3[] = mesh.vertices;
var randomX : float;
var randomY : float;
var randomZ : float;
for (i=0 ; i<mesh.vertexCount ; i++)
{
randomX = Random.Range(-1 , 1);
randomY = Random.Range(-1 , 1);
randomZ = Random.Range(-1 , 1);
vertices[i] = new Vector3(
(vertices[i].x + randomX),
(vertices[i].y + randomY),
(vertices[i].z + randomZ) );
}
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
Make sure that gets run once and only once on each new Wall GameObject, and you're golden. You might have to play around with the random values to get the look you are looking for, I don't know anything about your scale...
Oh, and you will probably want to not manipulate the Y on the bottom of the cubes. I leave that to you to figure out. You'll have to determine the actual vertex numbers to exclude certain ones from the warp. I did this by making a new scene with only the object I wanted to warp, and making a script similar to the one above that moved one vertex at a time, and Debug.Log'ed the vertex numbers as it was doing it. I wrote down my vertex numbers and plugged them into the script in my original scene.
The trickiest part of this was that where you have a hard edge (like the edges of the cubes), there are actually two or three verts that will have to move together, or it will create a gap.
When you have verts that meet at a soft edge, the vertex is shared, and you only have to move one...
Very nice! Any ideas on how to match the edges of one cube against another with the distorted vertices?
@Wyko sort of as a twist on my answer below, if you could somehow tag the connecting vertices (the ones that are going to be touching the next block) so as to not update them (that is, to leave them in a known and consistent position) it would ensure that they're still matching up, but allow this procedural mesh update, too (with the correct edits).
OR.. ins$$anonymous$$d of using Random directly you could use Perlin noise.. that way your randomness will be "smooth"...(i.e. for the same location in space you always get the same "random" perlin value.)
@ChrisD yeah, use a Perlin noise function with the original vertex position, then use the resulting noise value to compute an offset. Any other vertexes that share that point in space will get the same offset, so you won't get any gaps.
@ChrisD I use it all the time. I may post an example later.
Answer by Chris D · Jun 23, 2011 at 04:56 PM
Quick and dirty: model your walls crookedly. For re-use, ensure that the connecting points are always in the same position - that way you can have them zig-zag all you want and still know that they'll connect.
This seems like the easiest and most efficient way to do it, but I am having some serious trouble figuring out how to model the cubes in $$anonymous$$aya. I downloaded it, but I can't figure out how to duplicate the jagged edges of one polygon onto the matching edge of another. Frustrating.
What I would suggest is sticking to 1x1x1 blocks (or something that's multiple of a nice round number) so that you can model the undistorted object, toss in a bunch of the 'jagged' bits, but leave the peripheral veticies untouched. This way, you can count on the pieces matching.
Think of it as a traditional jigsaw puzzle; the pieces are different, but they still line up in a rough grid because they're a standard size.
Your answer
Follow this Question
Related Questions
How to create a rotating tiles with walls on edges of tiles? 0 Answers
Drag Rigidbody into slots? 2 Answers
Unity 2D tiles and grid 1 Answer
Moving the cube in a grid cell by cell 0 Answers