Circle using Graphics.DrawLine() - c#

I'm trying to make a circle using graphics.DrawLine() property and using BRESENHAM'S CIRCLE ALGORITHM but I'm not able to make it. Here is the method for making the circle
Pen pen = new Pen(Color.Red, 2);
Graphics graphics = this.Shape_PictureBox.CreateGraphics();
int radius = 40;
int x = 0, y = radius;
int xc = 50, yc = 50;
int d = 3 - 2 * radius;
// graphics.DrawLine(pen, xc, yc, x, y);
while (y >= x)
{
x++;
if (d > 0)
{
y--;
d = d + 4 * (x - y) + 10;
}
else
{
d = d + 4 * x + 6;
}
//drawCircle(xc, yc, x, y);
graphics.DrawLine(pen, xc, yc, x, y);
}

Well, there appears to be a bug in your algorithm implementation, as posted - but I suppose you're first and foremost asking as to why nothing is visible in the Shape_PictureBox? You should create a Bitmap buffer (think of it as a canvas) to draw to, and then assign it to the Shape_PictureBox.Image property.
IMPORTANT: Make sure to do this in the Form_Shown, not Form_Load event!
private void Child2_Shown(object sender, EventArgs e)
{
Pen pen = new Pen(Color.Red, 2);
Bitmap canvas = new Bitmap(Shape_PictureBox.Width, Shape_PictureBox.Height);
Graphics graphics = Graphics.FromImage(canvas);
int radius = 40;
int x = 0;
int y = radius;
int xc = 50;
int yc = 50;
int d = 3 - 2 * radius;
graphics.DrawLine(pen, xc, yc, x, y);
while (y >= x)
{
x++;
if (d > 0)
{
y--;
d = d + 4 * (x - y) + 10;
}
else
{
d = d + 4 * x + 6;
}
// drawCircle(xc, yc, x, y);
graphics.DrawLine(pen, xc, yc, x, y);
}
Shape_PictureBox.Image = canvas;
}
Currently, it looks like this:
You'll need to revise your implementation of Bresenham's Circle algorithm :)

Related

i wanted to implement C# Bresenham's line algorithm but it just draw horizontal lines , i want it to draw lines with angles as i saw in many tutorials

what i got when i run it
here's my code i take input from user to draw line using brenesham but it just draw horizontal line even when i tried with many values i have same issue so i want it to draw line with angel as i saw in my tutorials where they implement it with angles not just horizontal angel
private void button2_Click(object sender, EventArgs e)
{
int x1 = Convert.ToInt32(textBox5.Text);
int y1 = Convert.ToInt32(textBox6.Text);
int x2 = Convert.ToInt32(textBox7.Text);
int y2 = Convert.ToInt32(textBox8.Text);
Point p1 = new Point(x1, y1);
Point p2 = new Point(x2, y2);
Bresenham_Line(p1, p2);
}
private void Bresenham_Line(Point p1, Point p2)
{
double x, y, x2, y2;
Bitmap pp = new Bitmap(this.Width, this.Height);
double dx = p2.X - p1.X;
double dy = p2.Y - p2.Y;
double p = 2 * (dy - dx);
double c1 = 2 * dy;
double c2 = 2 * (dy - dx);
x = p1.X; y = p1.Y;
pp.SetPixel((int)x, (int)y, Color.Blue);
x2 = p2.X; y2 = p2.Y;
while (x < x2)
{
if (p < 0)
{
p += c1;
}
else
{
p += c2;
y += 1;
}
x++;
pp.SetPixel((int)x, (int)y, Color.Black);
}
pictureBox1.Image = pp;
}
i added photo from what i get when i run it

Plasma effect in WinForms, how to create continous loop

I'm trying to create some simple graphics ("plasma" effect) with C# and Winforms.
I have two classes in my code, (main)Form1 and Plasmadraw.
In Plasmadraw I have following setup:
class Plasmadraw
{
int y;
int x;
double i;
double pii = 3.1415;
public void Draw(Graphics gfx, int addition)
{
for (int i = 0; i < 23040; i++)
{
x = x + 10;
if (x == 1920)
{
x = 0;
y = y + 10;
}
if (y == 1200)
{
y = 0;
}
double v = Math.Sin((x * 0.5) + i * 0.001 * addition);
double c = v * pii;
double d = c + (2 * pii / 3);
double f = c + (6 * pii / 3);
double r = 255 * Math.Abs(Math.Sin(c));
double g = 255 * Math.Abs(Math.Sin(d));
double b = 255 * Math.Abs(Math.Sin(f));
int r1 = (int)r;
int g1 = (int)g;
int b1 = (int)b;
Color e = Color.FromArgb(r1, g1, b1);
SolidBrush brush = new SolidBrush(e);
Rectangle rect = new Rectangle(x, y, 10, 10);
gfx.FillRectangle(brush, rect);
}
}
}
and then in Form1 I have Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Plasmadraw plasmaeffect = new Plasmadraw();
for (int a = 0; a < 30; a++)
{
plasmaeffect.Draw(e.Graphics, a);
Invalidate();
}
Is this somehow completely wrong way to build the logic ? I've managed to create some graphics effects (moving sprites etc.) by creating a list and then running through the list with Foreach in Paint event (& Invalidate()). However, I'd like to learn some new way to do things, rather than copying the old way.

Mid-Point Circle Drawing Rounding Problem

I'm trying to implement the Mid-point drawing algorithm in C# to scan from a point outward.
I have the following code:
private bool[,] squares;
public Bitmap(int br, int h)
{
squares = new bool[br, h];
MakeCircle(9, 10, 10);
MakeCircle(8, 10, 10);
MakeCircle(7, 10, 10);
MakeCircle(6, 10, 10);
MakeCircle(5, 10, 10);
MakeCircle(4, 10, 10);
MakeCircle(3, 10, 10);
MakeCircle(2, 10, 10);
MakeCircle(1, 10, 10);
MakeCircle(0, 10, 10);
}
public void SelectSymmetry(int x, int y, int x0, int y0)
{
TryPlace(x + x0, y + y0);
TryPlace(-x + x0, y + y0);
TryPlace(x + x0, -y + y0);
TryPlace(-x + x0, -y + y0);
TryPlace(y + x0, x + y0);
TryPlace(-y + x0, x + y0);
TryPlace(y + x0, -x + y0);
TryPlace(-y + x0, -x + y0);
}
public void TryPlace(int x, int y)
{
if (x >= 0 && x < vakjes.GetLength(0) && y >= 0 && y < vakjes.GetLength(1))
{
squares[x, y] = true;
}
}
public void MakeCircle(int radius, int x0, int y0)
{
int x = 0;
int y = radius;
double d = 5 / 4.0 - radius;
SelectSymmetry(x, y, x0, y0);
while (x < y)
{
x++;
if (d < 0)
{
d += 2 * x + 1;
}
else
{
y--;
d += 2 * (x - y) + 1;
}
SelectSymmetry(x, y, x0, y0);
}
}
This creates the following image:
And that's the problem. As far as I can tell no 2 circles occupy the same pixel, but there are pixels that aren't filled by any circle. Is there a way to alter my code so these pixels belong to a circle? Any help would be much appreciated.
P.S. Sorry for the code dump, but I felt this was the most direct way of showing my problem.
Just don't try to make a disk out of circles. Instead of calling MakeCircle 10 times, call this once:
public void MakeDisk(int radius, int x0, int y0)
{
int x = 0;
int y = radius;
double d = 5 / 4.0 - radius;
for (int ty=y; ty>=x; --ty) {
SelectSymmetry(x, ty, x0, y0);
}
while (x < y)
{
x++;
if (d < 0)
{
d += 2 * x + 1;
}
else
{
y--;
d += 2 * (x - y) + 1;
}
for (int ty=y; ty>=x; --ty) {
SelectSymmetry(x, ty, x0, y0);
}
}
}

Get all points within a Triangle

I have three points, for example:
Start 194 171
Right 216 131
Left 216 203
I want to get all the points within that triangle. How would I do that efficiently?
see z3nth10n's answer for better input validation
Introduction:
The general idea was to get the triangle's edges (y-Wise) for every x in it's range, and then you have all the y's that exist within the triangle for every single x, which with simple conversion turns into all points within the triangle.
You can look at it as if you cut the triangle into stripes, each being of width 1.
So for X=0, on the line between A and B, the Y is 6, and on the line between A and C, the Y is -2, so you can see that the stripe of X=0 is between -2 and 6. Therefore, you can tell that (0, -2) (0, -1) (0, 0) ... (0, 5) (0, 6) are all in the triangle. Doing that for X's between the smallest and the largest within the triangle, and you have all the points in the triangle!
Speed:
For the triangle (0, 0) (1, 8) (4, 6) - found 16 points.
Done 1,000,000 times in 3.68 seconds.
Implementation:
public IEnumerable<Point> PointsInTriangle(Point pt1, Point pt2, Point pt3)
{
if (pt1.Y == pt2.Y && pt1.Y == pt3.Y)
{
throw new ArgumentException("The given points must form a triangle.");
}
Point tmp;
if (pt2.X < pt1.X)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
if (pt3.X < pt2.X)
{
tmp = pt2;
pt2 = pt3;
pt3 = tmp;
if (pt2.X < pt1.X)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
}
var baseFunc = CreateFunc(pt1, pt3);
var line1Func = pt1.X == pt2.X ? (x => pt2.Y) : CreateFunc(pt1, pt2);
for (var x = pt1.X; x < pt2.X; x++)
{
int maxY;
int minY = GetRange(line1Func(x), baseFunc(x), out maxY);
for (var y = minY; y <= maxY; y++)
{
yield return new Point(x, y);
}
}
var line2Func = pt2.X == pt3.X ? (x => pt2.Y) : CreateFunc(pt2, pt3);
for (var x = pt2.X; x <= pt3.X; x++)
{
int maxY;
int minY = GetRange(line2Func(x), baseFunc(x), out maxY);
for (var y = minY; y <= maxY; y++)
{
yield return new Point(x, y);
}
}
}
private int GetRange(double y1, double y2, out int maxY)
{
if (y1 < y2)
{
maxY = (int)Math.Floor(y2);
return (int)Math.Ceiling(y1);
}
maxY = (int)Math.Floor(y1);
return (int)Math.Ceiling(y2);
}
private Func<int, double> CreateFunc(Point pt1, Point pt2)
{
var y0 = pt1.Y;
if (y0 == pt2.Y)
{
return x => y0;
}
var m = (double)(pt2.Y - y0) / (pt2.X - pt1.X);
return x => m * (x - pt1.X) + y0;
}
#SimpleVar answer is well, but it lacks a good check for valid triangles. (This can cause an overflow problem).
So I do my own implementation for Unity3D:
public static IEnumerable<T> PointsInTriangle<T>(T pt1, T pt2, T pt3)
where T : IPoint
{
/*
// https://www.geeksforgeeks.org/check-whether-triangle-valid-not-sides-given/
a + b > c
a + c > b
b + c > a
*/
float a = Vector2.Distance(new Vector2(pt1.x, pt1.y), new Vector2(pt2.x, pt2.y)),
b = Vector2.Distance(new Vector2(pt2.x, pt2.y), new Vector2(pt3.x, pt3.y)),
c = Vector2.Distance(new Vector2(pt3.x, pt3.y), new Vector2(pt1.x, pt1.y));
if (a + b <= c || a + c <= b || b + c <= a)
{
Debug.LogWarning($"The given points must form a triangle. {{{pt1}, {pt2}, {pt3}}}");
yield break;
}
if (TriangleArea(pt1, pt2, pt3) <= 1)
{
Point center = GetTriangleCenter(pt1, pt2, pt3);
yield return (T)Activator.CreateInstance(typeof(T), center.x, center.y);
return;
}
T tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
if (pt3.x < pt2.x)
{
tmp = pt2;
pt2 = pt3;
pt3 = tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
}
var baseFunc = CreateFunc(pt1, pt3);
var line1Func = pt1.x == pt2.x ? (x => pt2.y) : CreateFunc(pt1, pt2);
for (var x = pt1.x; x < pt2.x; ++x)
{
int maxY;
int minY = GetRange(line1Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
var line2Func = pt2.x == pt3.x ? (x => pt2.y) : CreateFunc(pt2, pt3);
for (var x = pt2.x; x <= pt3.x; ++x)
{
int maxY;
int minY = GetRange(line2Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
}
private static int GetRange(float y1, float y2, out int maxY)
{
if (y1 < y2)
{
maxY = Mathf.FloorToInt(y2);
return Mathf.CeilToInt(y1);
}
maxY = Mathf.FloorToInt(y1);
return Mathf.CeilToInt(y2);
}
private static Func<int, float> CreateFunc<T>(T pt1, T pt2)
where T : IPoint
{
var y0 = pt1.y;
if (y0 == pt2.y)
return x => y0;
float m = (float)(pt2.y - y0) / (pt2.x - pt1.x);
return x => m * (x - pt1.x) + y0;
}
public static float TriangleArea<T>(T p1, T p2, T p3)
where T : IPoint
{
float a, b, c;
if (!CheckIfValidTriangle(p1, p2, p3, out a, out b, out c))
return 0;
return TriangleArea(a, b, c);
}
public static float TriangleArea(float a, float b, float c)
{
// Thanks to: http://james-ramsden.com/area-of-a-triangle-in-3d-c-code/
float s = (a + b + c) / 2.0f;
return Mathf.Sqrt(s * (s - a) * (s - b) * (s - c));
}
public static Point GetTriangleCenter<T>(T p0, T p1, T p2)
where T : IPoint
{
// Thanks to: https://stackoverflow.com/questions/524755/finding-center-of-2d-triangle
return new Point(p0.x + p1.x + p2.x / 3, p0.y + p1.y + p2.y / 3);
}
public static bool CheckIfValidTriangle<T>(T v1, T v2, T v3, out float a, out float b, out float c)
where T : IPoint
{
a = Vector2.Distance(new Vector2(v1.x, v1.y), new Vector2(v2.x, v2.y));
b = Vector2.Distance(new Vector2(v2.x, v2.y), new Vector2(v3.x, v3.y));
c = Vector2.Distance(new Vector2(v3.x, v3.y), new Vector2(v1.x, v1.y));
if (a + b <= c || a + c <= b || b + c <= a)
return false;
return true;
}
IPoint interface could be a good point for own Point implementations (for libs like Clipper, TessDotNet or Poly2Tri). You can change it at any time (two UnityEngine.Vector2 or System.Drawing.Point).
Hope this helps!
EDIT: I solved all bugs here:
Also I answered my own question asking this: https://stackoverflow.com/a/53734816/3286975

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)
)
)
);
}

Categories

Resources