I am trying to update a Quadtree code to an Octree - c#
I am trying to Use the QuadTree code to develop an Octree code. However I am stuck when it comes to changing the Rectangle3d to a Box. Basically I have a function to split the nodes, when slitting the rectangle I used the width and height and divided them, then use the constructor - Rectangle3d(Plane, Double, Double) but I am stuck as to which constructor to use and how to calculate it when I change from Rectangle3d to Box. Can anyone help me with this?
public static Octree oct;
public static DataTree < Point3d > psOUT;
public static List<Line> lns = new List<Line>();
//////////Octree////////
public class Octree
{
public int MAX_OBJECTS = 10;
public int MAX_LEVELS = 8;
private int level;
private List<Point3d>objects;
private Box bounds;
private Octree[] nodes;
/*
* Constructor
*/
public Octree(int pLevel, Box pBounds)
{
level = pLevel;
objects = new List<Point3d>();
bounds = pBounds;
nodes = new Octree[8];
}
// implement the five methods of a Octree: clear, split, getIndex, insert, and retrieve.
/*
* Clears the Octree
*/
public void clear()
{
objects.Clear();
for (int i = 0; i < nodes.Length; i++)
{
if (nodes[i] != null)
{
nodes[i].clear();
nodes[i] = null;
}
}
}
/*
* Splits the node into 8 subnodes
*/
private void split()
{
double subWidth = bounds.X * 0.5;
double subDepth = bounds.Y * 0.5;
double subHeight = bounds.Z *0.5;
double x = bounds.X.T0;
double y = bounds.Y.T0;
double z = bounds.Z.T0;
nodes[3] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x + subWidth, y, 0), new Point3d(x + 2 * subWidth, y + subHeight, 0)));
nodes[2] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x, y, 0), new Point3d(x + subWidth, y + subHeight, 0)));
nodes[1] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x, y + subHeight, 0), new Point3d(x + subWidth, y + 2 * subHeight, 0)));
nodes[0] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x + subWidth, y + subHeight, 0), new Point3d(x + 2 * subWidth, y + 2 * subHeight, 0)));
}
Maybe a little late but here it goes:
Considering you have a Box in 3D space already constructed. In order to divide it into 8 smaller boxes you can use the X,Y,Z coordinate interval between each of the corners and the box center point. So, you would have something like this:
private List<Box> Split(Box box)
{
List<Box> boxes = new List<Box>();
foreach(Point3d corner in box.GetCorners())
{
Box newbox = CreateBoxFromPlaneAndTwoCorners(box.Plane, box.Center, corner);
boxes.Add(newbox);
}
return boxes;
}
private Box CreateBoxFromPlaneAndTwoCorners(Plane plane, Point3d cornerA, Point3d cornerB) {
plane.RemapToPlaneSpace(cornerA, out Point3d remapA);
plane.RemapToPlaneSpace(cornerB, out Point3d remapB);
Interval intX = new Interval(remapA.X,remapB.X);
Interval intY = new Interval(remapA.Y,remapB.Y);
Interval intZ = new Interval(remapA.Z,remapB.Z);
return new Box(plane,intX,intY,intZ);
}
Related
Terrain having visible seams at vertices - How can i fix this?
i'm a newbie and i am following a tutorial on procedural landmass generation. However, my plane does not look right. It has a lot of seams/cracks. Is there someone who can point me in the right direction? Below is my MeshGenerator scripts: public static class MeshGenerator { public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve heightCurve) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; MeshData meshData = new MeshData(width, height); int vertexIndex = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x,y]) * heightMultiplier, topLeftZ - y); meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height); if (x < width - 1 && y < height - 1) { meshData.AddTriangle(vertexIndex, vertexIndex + width + 1, vertexIndex + width); meshData.AddTriangle(vertexIndex, + width + 1, vertexIndex + 1); } vertexIndex++; } } return meshData; } } public class MeshData { public Vector3[] vertices; public int[] triangles; public Vector2[] uvs; int triangleIndex; public MeshData(int meshWidth, int meshHeight) { vertices = new Vector3[meshWidth * meshHeight]; uvs = new Vector2[meshWidth * meshHeight]; triangles = new int[(meshWidth-1) * (meshHeight-1)*6]; } public void AddTriangle(int a, int b, int c) { triangles[triangleIndex] = a; triangles[triangleIndex+1] = b; triangles[triangleIndex+2] = c; triangleIndex += 3; } public Mesh CreateMesh() { Mesh mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = uvs; mesh.RecalculateNormals(); return mesh; } }
You triangle indices are wrong, this is rather obvious since you have a bunch of triangle-shaped holes. Notably meshData.AddTriangle(vertexIndex, + width + 1, vertexIndex + 1); the second vertex of the second triangle is a constant value, and that is most likely incorrect You should not need to keep a running total of vertexIndex, you should be perfectly able to compute the triangle indices from the grid indices: var v1 = y * (width+1) + x; // You should have one more column of vertices than you have grid cells var v2 = v2 + 1; // the vertex one column to the right var v3 = v1 + width+1; // the vertex one row down var v4 = v3 + 1; meshData.AddTriangle(v1, v2, v4); meshData.AddTriangle(v1, v4, v3); You may need to invert the vertex order to ensure the normals are oriented correctly.
How to construct a graph of weights from an image
Project: intelligence scissors. The first part of the project is to load an image (in the form of RGBPixel 2d array) then to construct a graph of weights to use it later to determine the shortest path between 2 points on the image (the 2 points will be determined by an anchor and a free point..In short i will have the source and the destination points). I have a function that open the image and return a RGBPixel 2d array already made.Now image is loaded i want to construct the graph to do the i should use a function called CalculatePixelEnergies here is the code public static Vector2D CalculatePixelEnergies(int x, int y, RGBPixel[,] ImageMatrix) { if (ImageMatrix == null) throw new Exception("image is not set!"); Vector2D gradient = CalculateGradientAtPixel(x, y, ImageMatrix); double gradientMagnitude = Math.Sqrt(gradient.X * gradient.X + gradient.Y * gradient.Y); double edgeAngle = Math.Atan2(gradient.Y, gradient.X); double rotatedEdgeAngle = edgeAngle + Math.PI / 2.0; Vector2D energy = new Vector2D(); energy.X = Math.Abs(gradientMagnitude * Math.Cos(rotatedEdgeAngle)); energy.Y = Math.Abs(gradientMagnitude * Math.Sin(rotatedEdgeAngle)); return energy; } This function use CalculateGradientAtPixel, Here is the code in case you want it. private static Vector2D CalculateGradientAtPixel(int x, int y, RGBPixel[,] ImageMatrix) { Vector2D gradient = new Vector2D(); RGBPixel mainPixel = ImageMatrix[y, x]; double pixelGrayVal = 0.21 * mainPixel.red + 0.72 * mainPixel.green + 0.07 * mainPixel.blue; if (y == GetHeight(ImageMatrix) - 1) { //boundary pixel. for (int i = 0; i < 3; i++) { gradient.Y = 0; } } else { RGBPixel downPixel = ImageMatrix[y + 1, x]; double downPixelGrayVal = 0.21 * downPixel.red + 0.72 * downPixel.green + 0.07 * downPixel.blue; gradient.Y = pixelGrayVal - downPixelGrayVal; } if (x == GetWidth(ImageMatrix) - 1) { //boundary pixel. gradient.X = 0; } else { RGBPixel rightPixel = ImageMatrix[y, x + 1]; double rightPixelGrayVal = 0.21 * rightPixel.red + 0.72 * rightPixel.green + 0.07 * rightPixel.blue; gradient.X = pixelGrayVal - rightPixelGrayVal; } return gradient; } In my code of graph construction i decided to make a 2d double array to hold the weights, here what i do but it seems to be a wrong construction public static double [,] calculateWeights(RGBPixel[,] ImageMatrix) { double[,] weights = new double[1000, 1000]; int height = ImageOperations.GetHeight(ImageMatrix); int width = ImageOperations.GetWidth(ImageMatrix); for (int y = 0; y < height - 1; y++) { for (int x = 0; x < width - 1; x++) { Vector2D e; e = ImageOperations.CalculatePixelEnergies(x, y, ImageMatrix); weights[y + 1, x] = 1 / e.X; weights[y, x + 1] = 1 / e.Y; } } return weights; } an example for an image an other example for an image
Saving triangle object in a list and paint again
I am trying to save the triangle I drew and draw again while the previous triangle is still there. I did this in rectangle, square, circle and ellipse and it worked. I don't know why it won't in Triangle. Is there something wrong in the code? This is how I draw and "save (not working)" Shape Class public void DrawTriangle(Color c, int stroke,PointF[] tpoints, float w, Graphics g) { this.width = w; this.strokeThickness = stroke; this.tPoints = tpoints; g.InterpolationMode = InterpolationMode.High; g.SmoothingMode = SmoothingMode.AntiAlias; g.DrawPolygon(new Pen(c, stroke), tpoints); } Form 1 public void DrawTriangle() { tC = Color.Red; strokeTriangle = trackBar_Stroke.Value; tW = Convert.ToInt32((Convert.ToInt32(tbox_Width.Text) * 96) / 25.4); tH = (Convert.ToInt32((tW * (Math.Sqrt(3))) / 2)); tX = (pictureBox_Canvass.Width - tW) / 2; tY = ((pictureBox_Canvass.Width - (tH)) / 2) + tH; float angle = 0; t_Points[0].X = tX; t_Points[0].Y = tY; t_Points[1].X = (float)(tX + tW * Math.Cos(angle)); t_Points[1].Y = (float)(tY + tW * Math.Sin(angle)); t_Points[2].X = (float)(tX + tW * Math.Cos(angle - Math.PI / 3)); t_Points[2].Y = (float)(tY + tW * Math.Sin(angle - Math.PI / 3)); } public void AcceptTriangle() { Shape shape = new Shape(); tC = Color.Gray; shape.strokeThickness = strokeTriangle; shape.width = tW; shape.x = tX; shape.y = tY; shape.tPoints = t_Points; s._triangle.Add(shape); } s.DrawTriangle(tC, strokeTriangle,t_Points, tX, tY, tW, e.Graphics); This is how I iterate it. public List<Shape> _triangle = new List<Shape>(); foreach(Shape shapes3 in s._triangle) { shapes3.DrawTriangle(shapes3.color, shapes3.strokeThickness, shapes3.tPoints, shapes3.width, e.Graphics); }
At two points in your code you write an array assignment like this.: this.tPoints = tpoints; .. and this: shape.tPoints = t_Points; It is a common error to assume that this creates an array with data. It doesn't. All it does is make an array variable point to an array that was there before. The data are not duplicated. So when you overwrite the data or clear them the 'new' array now points to the changed or cleared data. So all your objects have the very same points. To correct create actual copies of the data! The simplest way is to add a ToArray() call like this: this.tPoints = tpoints.ToArray(); .. and this: shape.tPoints = t_Points.ToArray(); To reiterate: int[] p1 = new int[2] { 23, 42 }; // Now we have one array. int[] p2 = new int[2] { 3, 2 }; // Now we have two arrays. p2 = p1; // Now we have only one array again. p2[1]=1234; // Now p1[1] is 1234
Accepting the Triangle (Saving to the list) var triangle = new Shape { strokeThickness = strokeTriangle, color = tC, tPoints = t_Points.ToArray(), x=tX, y=tY, width = tW, }; s._triangle.Add(triangle); Iterating through the list foreach(Shape shapes3 in s._triangle) { shapes3.DrawTriangle(shapes3.color, shapes3.strokeThickness,shapes3.tPoints.ToArray(), shapes3.x, shapes3.y, shapes3.width, e.Graphics); }
Fast way to detect rectangles, which intersect with the given rectangle
The application I'm maintaining has custom drawing functionality, which draws some king of "objects" on an Graphics surface. Object boundaries are described with Rectangle. Sometimes I need to detect objects, whose rectangles are intersecting with given rectangle. If the number of objects is large enough, simple iteration like this: var objectsToManage = _objects.Where(_ => rc.IntersectsWith(_.InscribeRect)); obviously, too slow (_objects here is List<MyObjType>, IscribeRect is object boundaries, and rc is a given rectangle). I'm thinking about how to do this much faster. First idea is to "sort" objects by theirs rectangles and put them into sorted set... But I'm suspecting, that I'm re-inventing the wheel. Is there any well-known approaches to achieve what I want?
This is can be done using Quadtrees. You can find a c# implementation here: Virtualized WPF Canvas (the quadtree code is not strictly related to WPF), also lots of info here: ZoomableApplication2: A Million Items and another implementation here: PriorityQuadTree
#region FnLineMerginRectandLines public static bool LineIntersectsRect(Point p1, Point p2, Rectangle r) { return LineIntersectsLine(p1, p2, new Point(r.X, r.Y), new Point(r.X + r.Width, r.Y)) || LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y), new Point(r.X + r.Width, r.Y + r.Height)) || LineIntersectsLine(p1, p2, new Point(r.X + r.Width, r.Y + r.Height), new Point(r.X, r.Y + r.Height)) || LineIntersectsLine(p1, p2, new Point(r.X, r.Y + r.Height), new Point(r.X, r.Y)) || (r.Contains(p1) && r.Contains(p2)); } private static bool LineIntersectsLine(Point l1p1, Point l1p2, Point l2p1, Point l2p2) { float q = (l1p1.Y - l2p1.Y) * (l2p2.X - l2p1.X) - (l1p1.X - l2p1.X) * (l2p2.Y - l2p1.Y); float d = (l1p2.X - l1p1.X) * (l2p2.Y - l2p1.Y) - (l1p2.Y - l1p1.Y) * (l2p2.X - l2p1.X); if (d == 0) { return false; } float r = q / d; q = (l1p1.Y - l2p1.Y) * (l1p2.X - l1p1.X) - (l1p1.X - l2p1.X) * (l1p2.Y - l1p1.Y); float s = q / d; if (r < 0 || r > 1 || s < 0 || s > 1) { return false; } return true; } #endregion public class Line { private int Point1X; private int Point1Y; private int Point2X; private int Point2Y; public Point P1; public Point P2; public Line() { } public Line(int left, int top, int width, int height) { this.Point1X = Convert.ToInt32(left); this.Point1Y = Convert.ToInt32(top); this.Point2X = Convert.ToInt32(width); this.Point2Y = Convert.ToInt32(height); P1 = new Point(Point1X, Point1Y); P2 = new Point(Point2X, Point2Y); } public Line(string left, string top, string width, string height) { this.Point1X = Convert.ToInt32(left); this.Point1Y = Convert.ToInt32(top); this.Point2X = Convert.ToInt32(width); this.Point2Y = Convert.ToInt32(height); P1 = new Point(Point1X, Point1Y); P2 = new Point(Point2X, Point2Y); } public Line(Point p1, Point P2) { this.P1 = p1; this.P2 = P2; } } public static List<Line>getfourborders(Rectangle RT) { Line topline = new Line(new Point(RT.Left,RT.Top),new Point(RT.Width+RT.Left,RT.Top));// Top Line Line leftline = new Line((new Point(RT.Left,RT.Top)),new Point(RT.Left,RT.Top+RT.Height));// left Line Line rightline = new Line((new Point(RT.Left+RT.Width,RT.Top)),new Point(RT.Left + RT.Width,RT.Top+RT.Height));// Right Line Line bottomline = new Line((new Point(RT.Left,RT.Top+RT.Height)),new Point(RT.Left+RT.Width,RT.Top+RT.Height));//bottom line List<Line> borderlines = new List<Line>(); borderlines.Add(leftline); borderlines.Add(topline); borderlines.Add(rightline); borderlines.Add(bottomline); return borderlines; } //YourObjectList() contains a rectangle type public class myobject { public myobject(object S, Rectangle RT) { this.Rt = RT; this.anyobjecttype= S; } public Rectangle Rt; public object anyobjecttype ; } public List<myobject> CompareRectangles(List<myobject> Rect ,Rectangle GivenRectangle) { List<myobject> intersectingobjects = new List<myobject>(); Rectangle CompareWith = new Rectangle();//"_objects.Where(_ => rc.IntersectsWith(_.InscribeRect));" foreach(myobject iterate in Rect) { List<Line> BorderLines = new List<Line>(); BorderLines.AddRange(getfourborders(iterate.Rt)); bool Intersects = BorderLines.Any(x=>LineIntersectsRect(x.P1,x.P2,CompareWith)); if (Intersects) intersectingobjects.Add(iterate); } return intersectingobjects; } create another function to get all the border lines(get four points and create four lines from rectangle 1 ) and check if any of the line merges with another rectanglecompare using lineintersectsRect if any of that returns true then the rectangle 1 will intersect with your rectangle R, you can loop it to check rectangle 2 intersects with rectanglecompare and so on.. make sure that you don't pass divide by zero exception in line intersects with line
2D Perlin Noise
I have fully mastered the art of Perlin Noise in 3D, and now I'm trying to use my same implementation for a 2D algorithm. The problem seems to be in picking my gradient directions. In 3D I use 16 gradients in evenly distributed directions and this works great. In 2D I figured I'd use 8 gradients. up, down, left, right, and the four diagonal directions. Here is what I get: The general look of the noise is always correct, but the edges of the squares don't quite match up. I have also tried using other gradients or fewer gradients but get similar results. Here in another example you can see that the edges do match up sometimes and the results are fine in that area - When I don't use gradients and instead just interpolate between a value picked randomly at each of the 4 corners I get the right results, which is what makes me think it is the gradient part that is messing it up. Here is my code: //8 different gradient directions private Point[] grads = new Point[] { new Point(0, 1), new Point(1, 1), new Point(1, 0), new Point(1, -1), new Point(0, -1), new Point(-1, -1), new Point(-1, 0), new Point(-1, 1),}; //takes the dot product of a gradient and (x, y) private float dot2D(int i, float x, float y) { return grads[i].X * x + grads[i].Y * y; } public float Noise2D(float x, float y) { int ix = (int)(x), iy = (int)(y); x = x - ix; y = y - iy; float fx = fade(x), fy = fade(y); ix &= 255; iy &= 255; // here is where i get the index to look up in the list of // different gradients. // hashTable is my array of 0-255 in random order int g00 = hashTable[ix + hashTable[iy ]], g10 = hashTable[ix + 1 + hashTable[iy ]], g01 = hashTable[ix + hashTable[iy + 1]], g11 = hashTable[ix + 1 + hashTable[iy + 1]]; // this takes the dot product to find the values to interpolate between float n00 = dot2D(g00 & 7, x, y), n10 = dot2D(g10 & 7, x, y), n01 = dot2D(g01 & 7, x, y), n11 = dot2D(g11 & 7, x, y); // lerp() is just normal linear interpolation float y1 = lerp(fx, n00, n10), y2 = lerp(fx, n01, n11); return lerp(fy, y1, y2); }
I'm in a bit of a rush, but this might be helpful. I adapted Perlin's reference implementation to C#. For 2D, just use the 3D Noise() function with a fixed z parameter. (public static float Noise(float x, float y, float z) towards the end of the class.) using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using System.Diagnostics; namespace GoEngine.Content.Entities { public class NoiseMaker { /// adapted from http://cs.nyu.edu/~perlin/noise/ // JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. private static int[] p = new int[512]; private static int[] permutation = { 151,160,137,91,90,15, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; static NoiseMaker() { CalculateP(); } private static int _octaves; private static int _halfLength = 256; public static void SetOctaves(int octaves) { _octaves = octaves; var len = (int)Math.Pow(2, octaves); permutation = new int[len]; Reseed(); } private static void CalculateP() { p = new int[permutation.Length * 2]; _halfLength = permutation.Length; for (int i = 0; i < permutation.Length; i++) p[permutation.Length + i] = p[i] = permutation[i]; } public static void Reseed() { var random = new Random(); var perm = Enumerable.Range(0, permutation.Length).ToArray(); for (var i = 0; i < perm.Length; i++) { var swapIndex = random.Next(perm.Length); var t = perm[i]; perm[i] = perm[swapIndex]; perm[swapIndex] = t; } permutation = perm; CalculateP(); } public static float Noise(Vector3 position, int octaves, ref float min, ref float max) { return Noise(position.X, position.Y, position.Z, octaves, ref min, ref max); } public static float Noise(float x, float y, float z, int octaves, ref float min, ref float max) { var perlin = 0f; var octave = 1; for (var i = 0; i < octaves; i++) { var noise = Noise(x * octave, y * octave, z * octave); perlin += noise / octave; octave *= 2; } perlin = Math.Abs((float)Math.Pow(perlin,2)); max = Math.Max(perlin, max); min = Math.Min(perlin, min); //perlin = 1f - 2 * perlin; return perlin; } public static float Noise(float x, float y, float z) { int X = (int)Math.Floor(x) % _halfLength; int Y = (int)Math.Floor(y) % _halfLength; int Z = (int)Math.Floor(z) % _halfLength; if (X < 0) X += _halfLength; if (Y < 0) Y += _halfLength; if (Z < 0) Z += _halfLength; x -= (int)Math.Floor(x); y -= (int)Math.Floor(y); z -= (int)Math.Floor(z); var u = Fade(x); var v = Fade(y); var w = Fade(z); int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS, return MathHelper.Lerp( MathHelper.Lerp( MathHelper.Lerp( Grad(p[AA], x, y, z) // AND ADD , Grad(p[BA], x - 1, y, z) // BLENDED , u ) , MathHelper.Lerp( Grad(p[AB], x, y - 1, z) // RESULTS , Grad(p[BB], x - 1, y - 1, z) , u ) , v ) , MathHelper.Lerp( MathHelper.Lerp( Grad(p[AA + 1], x, y, z - 1) // CORNERS , Grad(p[BA + 1], x - 1, y, z - 1) // OF CUBE , u ) , MathHelper.Lerp( Grad(p[AB + 1], x, y - 1, z - 1) , Grad(p[BB + 1], x - 1, y - 1, z - 1) , u ) , v ) , w ); } static float Fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } static float Grad(int hash, float x, float y, float z) { int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. v = h < 4 ? y : h == 12 || h == 14 ? x : z; return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); } } } Update Okay, I managed to create a working 2D version. Here's the class: /// implements improved Perlin noise in 2D. /// Transcribed from http://www.siafoo.net/snippet/144?nolinenos#perlin2003 /// </summary> public static class Noise2d { private static Random _random = new Random(); private static int[] _permutation; private static Vector2[] _gradients; static Noise2d() { CalculatePermutation(out _permutation); CalculateGradients(out _gradients); } private static void CalculatePermutation(out int[] p) { p = Enumerable.Range(0, 256).ToArray(); /// shuffle the array for (var i = 0; i < p.Length; i++) { var source = _random.Next(p.Length); var t = p[i]; p[i] = p[source]; p[source] = t; } } /// <summary> /// generate a new permutation. /// </summary> public static void Reseed() { CalculatePermutation(out _permutation); } private static void CalculateGradients(out Vector2[] grad) { grad = new Vector2[256]; for (var i = 0; i < grad.Length; i++) { Vector2 gradient; do { gradient = new Vector2((float)(_random.NextDouble() * 2 - 1), (float)(_random.NextDouble() * 2 - 1)); } while (gradient.LengthSquared() >= 1); gradient.Normalize(); grad[i] = gradient; } } private static float Drop(float t) { t = Math.Abs(t); return 1f - t * t * t * (t * (t * 6 - 15) + 10); } private static float Q(float u, float v) { return Drop(u) * Drop(v); } public static float Noise(float x, float y) { var cell = new Vector2((float)Math.Floor(x), (float)Math.Floor(y)); var total = 0f; var corners = new[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 0), new Vector2(1, 1) }; foreach (var n in corners) { var ij = cell + n; var uv = new Vector2(x - ij.X, y - ij.Y); var index = _permutation[(int)ij.X % _permutation.Length]; index = _permutation[(index + (int)ij.Y) % _permutation.Length]; var grad = _gradients[index % _gradients.Length]; total += Q(uv.X, uv.Y) * Vector2.Dot(grad, uv); } return Math.Max(Math.Min(total, 1f), -1f); } } Call it like this: private void GenerateNoiseMap(int width, int height, ref Texture2D noiseTexture, int octaves) { var data = new float[width * height]; /// track min and max noise value. Used to normalize the result to the 0 to 1.0 range. var min = float.MaxValue; var max = float.MinValue; /// rebuild the permutation table to get a different noise pattern. /// Leave this out if you want to play with changing the number of octaves while /// maintaining the same overall pattern. Noise2d.Reseed(); var frequency = 0.5f; var amplitude = 1f; var persistence = 0.25f; for (var octave = 0; octave < octaves; octave++) { /// parallel loop - easy and fast. Parallel.For(0 , width * height , (offset) => { var i = offset % width; var j = offset / width; var noise = Noise2d.Noise(i*frequency*1f/width, j*frequency*1f/height); noise = data[j * width + i] += noise * amplitude; min = Math.Min(min, noise); max = Math.Max(max, noise); } ); frequency *= 2; amplitude /= 2; } if (noiseTexture != null && (noiseTexture.Width != width || noiseTexture.Height != height)) { noiseTexture.Dispose(); noiseTexture = null; } if (noiseTexture==null) { noiseTexture = new Texture2D(Device, width, height, false, SurfaceFormat.Color); } var colors = data.Select( (f) => { var norm = (f - min) / (max - min); return new Color(norm, norm, norm, 1); } ).ToArray(); noiseTexture.SetData(colors); } Note that I've used a couple of XNA structures (Vector2 and Texture2D), but it should be pretty clear what they do. If you want higher frequency (more "noisy") content with fewer octaves, increase the initial frequency value that used in the octave loop. This implementation uses "improved" Perlin noise, which should be a bit faster than the standard version. You might also have a look at Simplex noise, which is quite a bit faster at higher dimensions.
I had to change this: n00 = dot2D(g00 & 7, x, y), n10 = dot2D(g10 & 7, x, y), n01 = dot2D(g01 & 7, x, y), n11 = dot2D(g11 & 7, x, y); to this: n00 = dot2D(g00 & 7, x , y ), n10 = dot2D(g10 & 7, x - 1, y ), n01 = dot2D(g01 & 7, x , y - 1), n11 = dot2D(g11 & 7, x - 1, y - 1); Basically just subtracting 1 from the x and y where needed.
If you plug in a zero value for z into your 3D equation and simply follow the math through, removing terms, you'll see that you end up with a simpler equation in the end. Your implementation looks kind of different to the one I'm using though. Here's a comparison of a 3D and 2D function I'm using (in JavaScript): noise3d: function(x, y, z) { // Find unit cube that contains point. var X = Math.floor(x) & 255, Y = Math.floor(y) & 255, Z = Math.floor(z) & 255; // Find relative x,y,z of point in cube. x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); // Compute fade curves for each of x,y,z. var u = fade(x), v = fade(y), w = fade(z); // Hash coordinates of the corners. var A = p[X ] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // Add blended results from 8 corners of cube. return scale( lerp( w, lerp( v, lerp( u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z) ), lerp( u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z) ) ), lerp( v, lerp( u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1) ), lerp( u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1) ) ) ) ); } The 2D version involves fewer computations. noise2d: function(x, y) { // Find unit square that contains point. var X = Math.floor(x) & 255, Y = Math.floor(y) & 255; // Find relative x,y of point in square. x -= Math.floor(x); y -= Math.floor(y); // Compute fade curves for each of x,y. var u = fade(x), v = fade(y); // Hash coordinates of the corners. var A = p[X ] + Y, AA = p[A], AB = p[A + 1], B = p[X + 1] + Y, BA = p[B], BB = p[B + 1]; // Add blended results from the corners. return scale( lerp( v, lerp( u, grad(p[AA], x, y, 0), grad(p[BA], x - 1, y, 0) ), lerp( u, grad(p[AB], x, y - 1, 0), grad(p[BB], x - 1, y - 1, 0) ) ) ); }