I'm trying to convert RGB to HSL and I also want to convert from HSL to RGB,
I have written a class for it but if I do RGB->HSL->RGB to try if it works I get a different value.
Example case: if you create a HSLColor object by doing HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green);
and then do Color ExpectedGreenHere = MyTestConversion.ToRGB() you get a different color than Colors.Green while it was the original input so something goes wrong..
This is the code i'm using:
public class HSLColor
{
public float Hue;
public float Saturation;
public float Luminosity;
public HSLColor(float H, float S, float L)
{
Hue = H;
Saturation = S;
Luminosity = L;
}
public static HSLColor FromRGB(Color Clr)
{
return FromRGB(Clr.R, Clr.G, Clr.B);
}
public static HSLColor FromRGB(Byte R, Byte G, Byte B)
{
float _R = (R / 255f);
float _G = (G / 255f);
float _B = (B / 255f);
float _Min = Math.Min(Math.Min(_R, _G), _B);
float _Max = Math.Max(Math.Max(_R, _G), _B);
float _Delta = _Max - _Min;
float H = 0;
float S = 0;
float L = (float)((_Max + _Min) / 2.0f);
if (_Delta != 0)
{
if (L < 0.5f)
{
S = (float)(_Delta / (_Max + _Min));
}
else
{
S = (float)(_Delta / (2.0f - _Max - _Min));
}
float _Delta_R = (float)(((_Max - _R) / 6.0f + (_Delta / 2.0f)) / _Delta);
float _Delta_G = (float)(((_Max - _G) / 6.0f + (_Delta / 2.0f)) / _Delta);
float _Delta_B = (float)(((_Max - _B) / 6.0f + (_Delta / 2.0f)) / _Delta);
if (_R == _Max)
{
H = _Delta_B - _Delta_G;
}
else if (_G == _Max)
{
H = (1.0f / 3.0f) + _Delta_R - _Delta_B;
}
else if (_B == _Max)
{
H = (2.0f / 3.0f) + _Delta_G - _Delta_R;
}
if (H < 0) H += 1.0f;
if (H > 1) H -= 1.0f;
}
return new HSLColor(H, S, L);
}
private float Hue_2_RGB(float v1, float v2, float vH)
{
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return (v1 + (v2 - v1) * 6 * vH);
if ((2 * vH) < 1) return (v2);
if ((3 * vH) < 2) return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6);
return (v1);
}
public Color ToRGB()
{
Color Clr = new Color();
float var_1, var_2;
if (Saturation == 0)
{
Clr.R = (Byte)(Luminosity * 255);
Clr.G = (Byte)(Luminosity * 255);
Clr.B = (Byte)(Luminosity * 255);
}
else
{
if (Luminosity < 0.5) var_2 = Luminosity * (1 + Saturation);
else var_2 = (Luminosity + Saturation) - (Saturation * Luminosity);
var_1 = 2 * Luminosity - var_2;
Clr.R = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue + (1 / 3)));
Clr.G = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue));
Clr.B = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue - (1 / 3)));
}
return Clr;
}
}
Used reference:
EasyRGB Color Math
Besides the precision issues I think your actual algorithm is incorrect. This should be your FromRGB:
public static HSLColor FromRGB(Byte R, Byte G, Byte B)
{
float _R = (R / 255f);
float _G = (G / 255f);
float _B = (B / 255f);
float _Min = Math.Min(Math.Min(_R, _G), _B);
float _Max = Math.Max(Math.Max(_R, _G), _B);
float _Delta = _Max - _Min;
float H = 0;
float S = 0;
float L = (float)((_Max + _Min) / 2.0f);
if (_Delta != 0)
{
if (L < 0.5f)
{
S = (float)(_Delta / (_Max + _Min));
}
else
{
S = (float)(_Delta / (2.0f - _Max - _Min));
}
if (_R == _Max)
{
H = (_G - _B) / _Delta;
}
else if (_G == _Max)
{
H = 2f + (_B - _R) / _Delta;
}
else if (_B == _Max)
{
H = 4f + (_R - _G) / _Delta;
}
}
return new HSLColor(H, S, L);
}
The next thing you need to understand is that we're taking integer RGB values from 0 to 255 and converting them to decimal values from 0 to 1. The HSL that we get back will thus need to be converted to the normal degree/percent/percent that you're used to. The H value returned should be from 0 to 6 so to convert it to degrees you just multiply by 60. H can actually be negative sometimes so if it is just add 360;
//Convert to degrees
H = H * 60f;
if (H < 0) H += 360;
S and L also need to be multiplied by 100 to give you a percentage from 0 to 100.
UPDATE
This code should get you from HSL to RGB. It assumes that the HSL values are still in their decimal format. Also, I used double instead of float in the code below for better precision.
public Color ToRGB()
{
byte r, g, b;
if (Saturation == 0)
{
r = (byte)Math.Round(Luminosity * 255d);
g = (byte)Math.Round(Luminosity * 255d);
b = (byte)Math.Round(Luminosity * 255d);
}
else
{
double t1, t2;
double th = Hue / 6.0d;
if (Luminosity < 0.5d)
{
t2 = Luminosity * (1d + Saturation);
}
else
{
t2 = (Luminosity + Saturation) - (Luminosity * Saturation);
}
t1 = 2d * Luminosity - t2;
double tr, tg, tb;
tr = th + (1.0d / 3.0d);
tg = th;
tb = th - (1.0d / 3.0d);
tr = ColorCalc(tr, t1, t2);
tg = ColorCalc(tg, t1, t2);
tb = ColorCalc(tb, t1, t2);
r = (byte)Math.Round(tr * 255d);
g = (byte)Math.Round(tg * 255d);
b = (byte)Math.Round(tb * 255d);
}
return Color.FromArgb(r, g, b);
}
private static double ColorCalc(double c, double t1, double t2)
{
if (c < 0) c += 1d;
if (c > 1) c -= 1d;
if (6.0d * c < 1.0d) return t1 + (t2 - t1) * 6.0d * c;
if (2.0d * c < 1.0d) return t2;
if (3.0d * c < 2.0d) return t1 + (t2 - t1) * (2.0d / 3.0d - c) * 6.0d;
return t1;
}
Common bug. You've got
public static HSLColor FromRGB(Byte R, Byte G, Byte B)
{
float _R = (R / 255);
float _G = (G / 255);
float _B = (B / 255);
Tell me precisely what values of R can result in _R not being 0. (Hint: there's only one).
Edit: you've got the same problem in ToRGB() with 1/3.
The problem I see in your code is the following:
float _R = (R / 255);
You are basically doing integer division here, so you are losing tons of precision.
Try changing it to:
float _R = (R / 255f);
(and the same for the other 2 lines).
Also, to increase precision even more, better to use double instead of float.
Related
I'm creating a script that blends 4 textures together based on a mask the code I have so far is this:
public Color GetBlend(Color32 mask, int x, int y,Color baseColor, Color redChannel, Color greenChannel, Color blueChannel) {
float val = 1f / (mask.r + mask.g + mask.b);
float rWeight = mask.r * val;
float gWeight = mask.g * val;
float bWeight = mask.b * val;
// I can't find what follows this though.
}
It is here that I am stuck though. I can't find any information on google about how this blending is supposed to work.
// EDIT //
After fiddling around with it for a bit away from my computer I came up with this idea:
public Color GetBlend(Color32 mask, int x, int y,Color baseColor, Color redChannel, Color greenChannel, Color blueChannel) {
int total = mask.r + mask.g + mask.b;
float alpha = Mathf.Max(mask.r, mask.g, mask.b) / 255f; // not sure this will work
float val = (total == 0) ? 0 : 1f / total;
float rWeight = mask.r * val;
float gWeight = mask.g * val;
float bWeight = mask.b * val;
Color c = (redChannel * rWeight) + (greenChannel * gWeight) + (blueChannel * blueWeight);
c.a = baseColor.a;
return Color.Lerp(baseColor, c, alpha);
}
More fiddling resulted in this idea:
public Color GetBlend(Color32 mask,Color baseColor, Color redChannel, Color greenChannel, Color blueChannel) {
int total = mask.r + mask.g + mask.b;
float alpha = Mathf.Max(mask.r, mask.g, mask.b) / 255f;
float r1 = mask.r == 0 ? baseColor.r : ((redChannel.r * mask.r) + (greenChannel.r * mask.r) + (blueChannel.r * mask.r)) / (mask.r * 3);
float g1 = mask.g == 0 ? baseColor.g : ((redChannel.g * mask.g) + (greenChannel.g * mask.g) + (blueChannel.g * mask.g)) / (mask.g * 3);
float b1 = mask.b == 0 ? baseColor.b : ((redChannel.b * mask.b) + (greenChannel.b * mask.b) + (blueChannel.b * mask.b)) / (mask.b * 3);
float a1 = baseColor.a;
Color blend = new Color(r1, g1, b1);
return Color.Lerp(baseColor, blend, alpha);
}
I have managed to find code to convert RGB to XY. Can't make it work the other way around.
I have looked through Philips Hue SDK
https://github.com/johnciech/PhilipsHueSDK/blob/master/ApplicationDesignNotes/RGB%20to%20xy%20Color%20conversion.md
I have found this javascript code:
Philips hue, convert xy from api to HEX or RGB
and converted it to c# but it doesn't work as expected. I think my math is not strong enough.. please advise.
public class PhilipsHueRgbObject
{
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
}
public static PhilipsHueRgbObject xyBriToRgb(double x, double y, double bri)
{
double z = 1.0d - x - y;
double Y = bri / 255.0d; // Brightness of lamp
double X = (Y / y) * x;
double Z = (Y / y) * z;
double r = X * 1.612d - Y * 0.203d - Z * 0.302d;
double g = -X * 0.509d + Y * 1.412d + Z * 0.066d;
double b = X * 0.026d - Y * 0.072d + Z * 0.962d;
r = (r <= 0.0031308d ? 12.92d * r : (1.0d + 0.055d) * Math.Pow(r, (1.0d / 2.4d)) - 0.055d);
g = (g <= 0.0031308d ? 12.92d * g : (1.0d + 0.055d) * Math.Pow(g, (1.0d / 2.4d)) - 0.055d);
b = (b <= 0.0031308d ? 12.92d * b : (1.0d + 0.055d) * Math.Pow(b, (1.0d / 2.4d)) - 0.055d);
double maxValue = Math.Max(r, Math.Max(g, b));
r /= maxValue;
g /= maxValue;
b /= maxValue;
r = r * 255;
if (r < 0)
{
r = 255;
}
g = g * 255;
if (g < 0)
{
g = 255;
}
b = b * 255;
if (b < 0)
{
b = 255;
}
return new PhilipsHueRgbObject()
{
Red = (int)r,
Green = (int)g,
Blue = (int)b
};
}
public static string groupRBG(string ipAddress, string userName, int groupNumber, int red, int green, int blue)
{
try
{
float redArg = (red > 0.04045f) ? (float) Math.Pow((red + 0.055f)/(1.0f + 0.055f), 2.4f) : (red/12.92f);
// Convert RGB to Hue
float greenArg = (green > 0.04045f)
? (float) Math.Pow((green + 0.055f)/(1.0f + 0.055f), 2.4f)
: (green/12.92f);
float blueArg = (blue > 0.04045f)
? (float) Math.Pow((blue + 0.055f)/(1.0f + 0.055f), 2.4f)
: (blue/12.92f);
float X = redArg*0.664511f + greenArg*0.154324f + blueArg*0.162028f;
float Y = redArg*0.283881f + greenArg*0.668433f + blueArg*0.047685f;
float Z = redArg*0.000088f + greenArg*0.072310f + blueArg*0.986039f;
float x = X/(X + Y + Z);
float y = Y/(X + Y + Z);
return
httpRequest(
#"http://" + ipAddress + #"/api/" + userName + #"/groups/" + groupNumber.ToString() +
#"/action/", #"{" + "\"on\": true,\"xy\": [" + x.ToString() + "," + y.ToString() + "]" + #"}");
}
catch (Exception ex)
{
ErrorLog.Error("Error : {0}", ex.Message);
return null;
}
}
function xyBriToRgb(x, y, bri){
z = 1.0 - x - y;
Y = bri / 255.0; // Brightness of lamp
X = (Y / y) * x;
Z = (Y / y) * z;
r = X * 1.612 - Y * 0.203 - Z * 0.302;
g = -X * 0.509 + Y * 1.412 + Z * 0.066;
b = X * 0.026 - Y * 0.072 + Z * 0.962;
r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055;
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055;
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055;
maxValue = Math.max(r,g,b);
r /= maxValue;
g /= maxValue;
b /= maxValue;
r = r * 255; if (r < 0) { r = 255 };
g = g * 255; if (g < 0) { g = 255 };
b = b * 255; if (b < 0) { b = 255 };
return {
r :r,
g :g,
b :b
}
}
I expect to see exact same values coming back for the group.
http:// --HueBridgeIP --/api/ -- UserString --/groups
I can't make it work for xy. Instead I have decided to convert hsv to rgb and vice versa.
https://www.programmingalgorithms.com/algorithm/hsv-to-rgb
https://www.programmingalgorithms.com/algorithm/rgb-to-hsv
Works like a charm. Remember to convert Philips Hue 0-65535 to 0-360 and 0-254 to 0 to 1.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
For my assignment I need to make to make a color picker that looks like this:
I've got the wheel part but can't figure out how to draw the triangle.
using System.Drawing;
using System.Drawing.Imaging;
void Main()
{
double hue = 3.3;
double sat = 0.4;
double val = 0.9;
var wheel = new ColorPicker(400);
var img = wheel.DrawImage(hue, sat, val);
using (var g = Graphics.FromImage(img))
{
var pen = val < 0.5 ? Pens.White : Pens.Black;
var wheelPosition = wheel.GetWheelPosition(hue);
g.DrawEllipse(pen, (float)wheelPosition.X - 5, (float)wheelPosition.Y - 5, 10, 10);
var trianglePosition = wheel.GetTrianglePosition(sat, val);
g.DrawEllipse(pen, (float)trianglePosition.X - 5, (float)trianglePosition.Y - 5, 10, 10);
}
img.Dump(); // LINQPad extension method
}
public class ColorPicker
{
public int Size { get; }
public int CenterX => Size / 2;
public int CenterY => Size / 2;
public int InnerRadius => Size * 5 / 12;
public int OuterRadius => Size / 2;
public ColorPicker(int size = 400)
{
Size = size;
}
public enum Area
{
Outside,
Wheel,
Triangle
}
public struct PickResult
{
public Area Area { get; set; }
public double? Hue { get; set; }
public double? Sat { get; set; }
public double? Val { get; set; }
}
public PickResult Pick(double x, double y)
{
var distanceFromCenter = Math.Sqrt((x - CenterX) * (x - CenterX) + (y - CenterY) * (y - CenterY));
var sqrt3 = Math.Sqrt(3);
if (distanceFromCenter > OuterRadius)
{
// Outside
return new PickResult { Area = Area.Outside };
}
else if (distanceFromCenter > InnerRadius)
{
// Wheel
var angle = Math.Atan2(y - CenterY, x - CenterX) + Math.PI / 2;
if (angle < 0) angle += 2 * Math.PI;
var hue = angle;
return new PickResult { Area = Area.Wheel, Hue = hue };
}
else
{
// Inside
var x1 = (x - CenterX) * 1.0 / InnerRadius;
var y1 = (y - CenterY) * 1.0 / InnerRadius;
if (0 * x1 + 2 * y1 > 1) return new PickResult { Area = Area.Outside };
else if (sqrt3 * x1 + (-1) * y1 > 1) return new PickResult { Area = Area.Outside };
else if (-sqrt3 * x1 + (-1) * y1 > 1) return new PickResult { Area = Area.Outside };
else
{
// Triangle
var sat = (1 - 2 * y1) / (sqrt3 * x1 - y1 + 2);
var val = (sqrt3 * x1 - y1 + 2) / 3;
return new PickResult { Area = Area.Triangle, Sat = sat, Val = val };
}
}
}
public Image DrawImage(double hue = 0.0, double sat = 1.0, double val = 1.0)
{
var img = new Bitmap(Size, Size, PixelFormat.Format32bppArgb);
for (int y = 0; y < Size; y++)
{
for (int x = 0; x < Size; x++)
{
Color color;
var result = Pick(x, y);
if (result.Area == Area.Outside)
{
// Outside
color = Color.Transparent;
}
else if (result.Area == Area.Wheel)
{
// Wheel
color = HSV(result.Hue.Value, sat, val, 1);
}
else
{
// Triangle
color = HSV(hue, result.Sat.Value, result.Val.Value, 1);
}
img.SetPixel(x, y, color);
}
}
return img;
}
private Color HSV(double hue, double sat, double val, double alpha)
{
var chroma = val * sat;
var step = Math.PI / 3;
var interm = chroma * (1 - Math.Abs((hue / step) % 2.0 - 1));
var shift = val - chroma;
if (hue < 1 * step) return RGB(shift + chroma, shift + interm, shift + 0, alpha);
if (hue < 2 * step) return RGB(shift + interm, shift + chroma, shift + 0, alpha);
if (hue < 3 * step) return RGB(shift + 0, shift + chroma, shift + interm, alpha);
if (hue < 4 * step) return RGB(shift + 0, shift + interm, shift + chroma, alpha);
if (hue < 5 * step) return RGB(shift + interm, shift + 0, shift + chroma, alpha);
return RGB(shift + chroma, shift + 0, shift + interm, alpha);
}
private Color RGB(double red, double green, double blue, double alpha)
{
return Color.FromArgb(
Math.Min(255, (int)(alpha * 256)),
Math.Min(255, (int)(red * 256)),
Math.Min(255, (int)(green * 256)),
Math.Min(255, (int)(blue * 256)));
}
public PointD GetWheelPosition(double hue)
{
double middleRadius = (InnerRadius + OuterRadius) / 2;
return new PointD
{
X = CenterX + middleRadius * Math.Sin(hue),
Y = CenterY - middleRadius * Math.Cos(hue)
};
}
public PointD GetTrianglePosition(double sat, double val)
{
var sqrt3 = Math.Sqrt(3);
return new PointD
{
X = CenterX + InnerRadius * (2 * val - sat * val - 1) * sqrt3 / 2,
Y = CenterY + InnerRadius * (1 - 3 * sat * val) / 2
};
}
}
public class PointD
{
public double X { get; set; }
public double Y { get; set; }
}
Result:
I try to make a meteor like this video,
but I can only get like this:
This is my simplex noise:
public class PerlinNoise{
int B = 256;
int[] m_perm = new int[B+B];
Texture2D m_permTex;
public int octava;
public float frequencia, amplitud;
public PerlinNoise(int seed, float frec, float amp, int oct)
{
octava = oct;
amplitud = amp;
frequencia = frec;
UnityEngine.Random.seed = seed;
int i, j, k;
for (i = 0 ; i < B ; i++)
{
m_perm[i] = i;
}
while (--i != 0)
{
k = m_perm[i];
j = UnityEngine.Random.Range(0, B);
m_perm[i] = m_perm[j];
m_perm[j] = k;
}
for (i = 0 ; i < B; i++)
{
m_perm[B + i] = m_perm[i];
}
}
float FADE(float t) { return t * t * t * ( t * ( t * 6.0f - 15.0f ) + 10.0f ); }
float LERP(float t, float a, float b) { return (a) + (t)*((b)-(a)); }
float GRAD1(int hash, float x )
{
int h = hash & 15;
float grad = 1.0f + (h & 7);
if ((h&8) != 0) grad = -grad;
return ( grad * x );
}
float GRAD2(int hash, float x, float y)
{
int h = hash & 7;
float u = h<4 ? x : y;
float v = h<4 ? y : x;
return (((h&1) != 0)? -u : u) + (((h&2) != 0) ? -2.0f*v : 2.0f*v);
}
float GRAD3(int hash, float x, float y , float z)
{
int h = hash & 15;
float u = h<8 ? x : y;
float v = (h<4) ? y : (h==12 || h==14) ? x : z;
return (((h&1) != 0)? -u : u) + (((h&2) != 0)? -v : v);
}
float Noise1D( float x )
{
//returns a noise value between -0.5 and 0.5
int ix0, ix1;
float fx0, fx1;
float s, n0, n1;
ix0 = (int)Mathf.Floor(x); // Integer part of x
fx0 = x - ix0; // Fractional part of x
fx1 = fx0 - 1.0f;
ix1 = ( ix0+1 ) & 0xff;
ix0 = ix0 & 0xff; // Wrap to 0..255
s = FADE(fx0);
n0 = GRAD1(m_perm[ix0], fx0);
n1 = GRAD1(m_perm[ix1], fx1);
return 0.188f * LERP( s, n0, n1);
}
public float Noise2D( float x, float y )
{
int ix0, iy0, ix1, iy1;
float fx0, fy0, fx1, fy1, s, t, nx0, nx1, n0, n1;
ix0 = (int)Mathf.Floor(x);
iy0 = (int)Mathf.Floor(y);
fx0 = x - ix0;
fy0 = y - iy0;
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
iy1 = (iy0 + 1) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
t = FADE( fy0 );
s = FADE( fx0 );
nx0 = GRAD2(m_perm[ix0 + m_perm[iy0]], fx0, fy0);
nx1 = GRAD2(m_perm[ix0 + m_perm[iy1]], fx0, fy1);
n0 = LERP( t, nx0, nx1 );
nx0 = GRAD2(m_perm[ix1 + m_perm[iy0]], fx1, fy0);
nx1 = GRAD2(m_perm[ix1 + m_perm[iy1]], fx1, fy1);
n1 = LERP(t, nx0, nx1);
return 0.507f * LERP( s, n0, n1 );
}
float Noise3D( float x, float y, float z )
{
//returns a noise value between -1.5 and 1.5
int ix0, iy0, ix1, iy1, iz0, iz1;
float fx0, fy0, fz0, fx1, fy1, fz1;
float s, t, r;
float nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = (int)Mathf.Floor( x ); // Integer part of x
iy0 = (int)Mathf.Floor( y ); // Integer part of y
iz0 = (int)Mathf.Floor( z ); // Integer part of z
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255
iy1 = ( iy0 + 1 ) & 0xff;
iz1 = ( iz0 + 1 ) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
iz0 = iz0 & 0xff;
r = FADE( fz0 );
t = FADE( fy0 );
s = FADE( fx0 );
nxy0 = GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz0]]], fx0, fy0, fz0);
nxy1 = GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz1]]], fx0, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz0]]], fx0, fy1, fz0);
nxy1 = GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz1]]], fx0, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n0 = LERP( t, nx0, nx1 );
nxy0 = GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz0]]], fx1, fy0, fz0);
nxy1 = GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz1]]], fx1, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz0]]], fx1, fy1, fz0);
nxy1 = GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz1]]], fx1, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n1 = LERP( t, nx0, nx1 );
return 0.936f * LERP( s, n0, n1 );
}
public float FractalNoise1D(float x, int octNum, float frq, float amp)
{
float gain = 1.0f;
float sum = 0.0f;
for(int i = 0; i < octNum; i++)
{
sum += Noise1D(x*gain/frq) * amp/gain;
gain *= 2.0f;
}
return sum;
}
public float FractalNoise2D(float x, float y, int octNum, float frq, float amp)
{
float gain = 1.0f;
float sum = 0.0f;
for(int i = 0; i < octNum; i++)
{
sum += Noise2D(x*gain/frq, y*gain/frq) * amp/gain;
gain *= 2.0f;
}
return sum;
}
public int Noise2D(Vector3Int v3) {
return Mathf.RoundToInt(FractalNoise2D(v3.x,v3.z,octava,frequencia,amplitud));
}
public int Noise2D(int x, int z)
{
return Mathf.RoundToInt(FractalNoise2D(x, z, octava, frequencia, amplitud));
}
public float FractalNoise3D(float x, float y, float z, int octNum, float frq, float amp)
{
float gain = 1.0f;
float sum = 0.0f;
for(int i = 0; i < octNum; i++)
{
sum += Noise3D(x*gain/frq, y*gain/frq, z*gain/frq) * amp/gain;
gain *= 2.0f;
}
return sum;
}
public void LoadPermTableIntoTexture()
{
m_permTex = new Texture2D(256, 1, TextureFormat.Alpha8, false);
m_permTex.filterMode = FilterMode.Point;
m_permTex.wrapMode = TextureWrapMode.Clamp;
for(int i = 0; i < 256; i++)
{
float v = (float)m_perm[i] / 255.0f;
m_permTex.SetPixel(i, 0, new Color(0,0,0,v));
}
m_permTex.Apply();
}
}
This is my implementation:
public void Resimulate() {
PerlinNoise per = new PerlinNoise(seed, frec, amp, octa);
for (int x = 0; x < TamX; x++)
{
for (int y = 0; y < TamY; y++)
{
for (int z = 0; z < TamZ; z++)
{
if (per.FractalNoise3D(x, y, z, octa, frec, amp)>0)
{
lista.Add(new Bloque(new Vector3Int(x, y, z)));
}
}
}
}
}
I found information on various pages, blogs and here but found nothing that worked for me. If anyone has information I would greatly appreciate your help.
Thank you for helping me.
First, it's important to note that the code you have is not Simplex noise! It's the older "Perlin noise" algorithm that tends to exhibit visually significant directional artifacts.
I would suggest avoiding both Perlin noise and Simplex noise altogether. Perlin because of the directional artifacts, and Simplex because you run into patent issues with the 3D implementation.
There's an algorithm I've designed recently to get around both of those issues, that's starting to be adopted by a fair number of game developers, called OpenSimplex noise. Code: https://gist.github.com/KdotJPG/b1270127455a94ac5d19
(EDIT: Here's a C# port: https://gist.github.com/omgwtfgames/601497972e4e30fd9c5f)
Do something like this:
const double S = 24; //Sparsity of noise features
public void Resimulate() {
//To get fractal noise, ideally you want multiple instances of noise so you don't get odd behavior near (0,0,0)
OpenSimplexNoise n1 = new OpenSimplexNoise(seed);
OpenSimplexNoise n2 = new OpenSimplexNoise(seed+1);
OpenSimplexNoise n3 = new OpenSimplexNoise(seed+2);
for (int x = 0; x < TamX; x++) {
for (int y = 0; y < Tamy; z++) {
for (int z = 0; z < TamZ; z++) {
double n = (n1.eval(x / S, y / S, z / S)
+ n2.eval(x / S / 2, y / S / 2, z / S / 2) * .5
+ n3.eval(x / S / 4, y / S / 4, z / S / 4) * .25)
/ (1 + .5 + .25);
double dx = (TamX / 2.0 - x);
double dy = (TamY / 2.0 - y);
double dz = (TamZ / 2.0 - z);
double d = dx*dx + dy*dy + dz*dz;
//d is now your squared distance from the center.
//n is your fractal noise value
//you want to combine d and n to form some threshold that
//determines whether or not there is a block.
//threshold = d / C1 + n + C2 > 0 where C1 and C2 are constants you choose
}
}
}
}
EDIT: Here's a visual difference between Perlin and OpenSimplex:
Left is noise(x, y, 0) grayscale
Next is noise(x, y, 0) > 0 ? white : black
Next is |noise(x, y, 0)| > 0.1 ? white : black
Next is noise(x, y, 0.5) grayscale
Our application contains .Net FrameWork3.5 and DirectX For Making 2d drawing.
we are stuck with precision problem.Please give solution to solve the precision problem.
we are using vector3f(vector points) to store the values. while we store the result of point in vector3f only 2 precision value is matched.But we need 5 precision value.
Here i have mentioned my code below..
//Function To find ARC Parameters from Bulge value
polylineVertStart=6919.602,18951.51,0 polylineVertEnd=6916.602,18951.51,0
Arc StartPoint=6919.602,18951.5177,0 Endpoint=6916.602,18951.51,0
public static Arc BulgeToArc(PolylineVertex3d polylineVertStart, PolylineVertex3d polylineVertEnd)
{
PolylineVertex3d polylineVertex3d = polylineVertEnd;
PolylineVertex3d polylineVertex3d1 = polylineVertStart; //get previous point
double x1 = polylineVertex3d1.Position.X; //Assign start and end points
double y1 = polylineVertex3d1.Position.Y;
double x2 = polylineVertex3d.Position.X;
double y2 = polylineVertex3d.Position.Y;
if (y1 == y2)
{
y2 += (y1 * 0.0000001);
}
if (x1 == x2)
{
x2 += (x1 * 0.0000001);
}
double bulge = polylineVertex3d1.Bulge;
double incAngle = 4 * System.Math.Atan(System.Math.Abs(bulge)); //included Angle
double chord = System.Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); //Chord length
double r = 0.5 * chord / System.Math.Cos(0.5 * incAngle - 0.5 * System.Math.PI); //Calculate radius
double Radius = r;
double dx = x2 - x1;
double dy = y2 - y1;
double slope = dy / dx; //slope of two points
double slopeAng = System.Math.Atan(slope);
if (System.Math.Sign(dy) == -1 && System.Math.Sign(dx) == -1)
{
slopeAng = System.Math.PI + slopeAng;
}
else if (System.Math.Sign(dy) == -1 && System.Math.Sign(dx) == 1)
{
slopeAng = 2 * System.Math.PI + slopeAng;
}
else if (System.Math.Sign(dy) == 1 && System.Math.Sign(dx) == -1)
{
slopeAng = System.Math.PI + slopeAng;
}
double d1 = System.Math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
double d2 = d1 / 2;
double startAng = System.Math.Acos(d2 / r); //calculate start angle
double sAngle;
if (System.Math.Abs(bulge) < 1) //get actual start angle based on bulge direction
{
if (System.Math.Sign(bulge) != -1)
{
sAngle = slopeAng + startAng;
}
else
{
sAngle = slopeAng - startAng;
}
}
else
{
if (System.Math.Sign(bulge) != -1)
{
sAngle = slopeAng - startAng;
}
else
{
sAngle = slopeAng + startAng;
}
}
double cx = x1 + r * System.Math.Cos(sAngle);
double cy = y1 + r * System.Math.Sin(sAngle);
Vector3F Center = new Vector3F((float)cx, (float)cy, 0f); //calculate center point
double dx1 = x1 - cx;
double dx2 = x2 - cx;
double dy1 = y1 - cy;
double dy2 = y2 - cy;
double sAng = System.Math.Atan(dy1 / dx1);
double eAng = System.Math.Atan(dy2 / dx2);
if (System.Math.Sign(dy1) == -1 && System.Math.Sign(dx1) == -1)
{
sAng = System.Math.PI + sAng;
}
else if (System.Math.Sign(dy1) == -1 && System.Math.Sign(dx1) != -1)
{
sAng = 2 * System.Math.PI + sAng;
}
else if (System.Math.Sign(dx1) == -1)
{
sAng = System.Math.PI + sAng;
}
if (System.Math.Sign(dy2) == -1 && System.Math.Sign(dx2) == -1)
{
eAng = System.Math.PI + eAng;
}
else if (System.Math.Sign(dy2) == -1 && System.Math.Sign(dx2) != -1)
{
eAng = 2 * System.Math.PI + eAng;
}
else if (System.Math.Sign(dx2) == -1)
{
eAng = System.Math.PI + eAng;
}
double StartAngle;
double EndAngle;
if (System.Math.Sign(bulge) != -1) //finalise start angle and end angle
{
StartAngle = sAng;
EndAngle = eAng;
}
else
{
StartAngle = eAng;
EndAngle = sAng;
}
Direction dir;
if (polylineVertStart.Bulge != 0)
dir = polylineVertStart.Bulge < 0 ? Direction.ClockWise : Direction.CounterClockWise;
else
dir = polylineVertEnd.Bulge < 0 ? Direction.ClockWise : Direction.CounterClockWise;
Arc arc = dir == Direction.ClockWise ? new Arc(Center, new Vector3F(0f, 0f, 1f), Radius, EndAngle, StartAngle, dir) : new Arc(Center, new Vector3F(0f, 0f, 1f), Radius, StartAngle, EndAngle, dir);
return arc;
}
//Function to find ARC from StartAngle,EndAngle,Radius
public RenderingEngine.Geometry GetGeomtry()
{
RenderingEngine.Geometry geometry = new RenderingEngine.Geometry
{
EntityPrimitiveType = EntityPrimitiveType.LineStrip
};
xPoints.Clear();
yPoints.Clear();
zPoints.Clear();
VertexList.Clear();
List<CustomVertex.PositionColored> vertices = new List<CustomVertex.PositionColored>();
if (direction == Direction.ClockWise)
{
#region clockwise
double WedgeAngle = 0.0; //clock wise
if (EndAngle != StartAngle)
{
if (EndAngle < StartAngle)
{
WedgeAngle = (StartAngle - EndAngle) / NUMPOINTS;
}
else
{
WedgeAngle = ((System.Math.PI * 2) - (EndAngle - StartAngle)) / NUMPOINTS;
}
}
double angle = StartAngle;
for (int i = 0; i <= NUMPOINTS; i++)
{
double theta = angle - (i * WedgeAngle);
double x = center.X + (radius * SystemMath.Cos(theta));
double y = center.Y + (radius * SystemMath.Sin(theta));
double z = center.Z;
CustomVertex.PositionColored positionColored = new CustomVertex.PositionColored
{
Position =
new Vector3((float) x, (float) y,
(float) z),
Color = Color.ToArgb()
};
vertices.Add(positionColored);
xPoints.Add((float)x);
yPoints.Add((float)y);
zPoints.Add((float)z);
VertexList.Add(new Vector3F((float)x, (float)y, (float)z));
}
double startx = Center.X + (Radius * System.Math.Cos(StartAngle));
double starty = Center.Y + (Radius * System.Math.Sin(StartAngle));
double startz = Center.Z;
double endx = Center.X + (Radius * System.Math.Cos(EndAngle));
double endy = Center.Y + (Radius * System.Math.Sin(EndAngle));
double endz = Center.Z;
startPoint = new Vector3F((float)startx, (float)starty, (float)startz);
endPoint = new Vector3F((float)endx, (float)endy, (float)endz);
#endregion clockwise
}
else
{
#region Counter ClockWise
double WedgeAngle = 0.0;
if (EndAngle != StartAngle)
{
if (EndAngle > StartAngle)
{
WedgeAngle = (EndAngle - StartAngle) / NUMPOINTS;
}
else
{
WedgeAngle = ((System.Math.PI * 2 - StartAngle) + EndAngle) / NUMPOINTS;
}
}
double angle = StartAngle;
for (int i = 0; i <= NUMPOINTS; i++)
{
double theta = angle + (i * WedgeAngle);
double x = center.X + (radius * SystemMath.Cos(theta));
double y = center.Y + (radius * SystemMath.Sin(theta));
double z = center.Z;
CustomVertex.PositionColored positionColored = new CustomVertex.PositionColored
{
Position =
new Vector3((float) x, (float) y,
(float) z),
Color = Color.ToArgb()
};
vertices.Add(positionColored);
xPoints.Add((float)x);
yPoints.Add((float)y);
zPoints.Add((float)z);
VertexList.Add(new Vector3F((float)x, (float)y, (float)z));
}
double startx = Center.X + (Radius * System.Math.Cos(StartAngle));
double starty = Center.Y + (Radius * System.Math.Sin(StartAngle));
double startz = Center.Z;
double endx = Center.X + (Radius * System.Math.Cos(EndAngle));
double endy = Center.Y + (Radius * System.Math.Sin(EndAngle));
double endz = Center.Z;
startPoint = new Vector3F((float)startx, (float)starty, (float)startz);
endPoint = new Vector3F((float)endx, (float)endy, (float)endz);
#endregion
}
geometry.Vertices.Add(vertices);
return geometry;
}
Here arc start point and endpoint x value always come correctly but y value is some precision problem.
Thanks in Advance..