Sign in to follow this  
wforl

problem with Perlin Noise

Recommended Posts

Hi, Im trying to implement perlin noise, but im getting errors int he rendering. Could anyone take a look at the code to see where im going wrong? Everything ive found online deals with 3d perlin noise, and im trying to get 2d perlin noise to work, so this is probaly where im going wrong. The code is in XNA. Ive also added the project if anyone would find that easier to play with. Thanks Photobucket Photobucket
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace BookCode
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        GraphicsDevice device;
        SpriteBatch spriteBatch;
        Texture2D tex;
        byte[] random = new byte[256];
        Vector2[] gradients = new Vector2[4];

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            device = graphics.GraphicsDevice;
            spriteBatch = new SpriteBatch(GraphicsDevice);

            int winX = this.Window.ClientBounds.Width;
            int winY = this.Window.ClientBounds.Height;
            tex = new Texture2D(device, winX, winY);
            Color[] rcol = new Color[winX * winY];
          
            gradients[0] = new Vector2(1, 1);
            gradients[1] = new Vector2(-1, 1);
            gradients[2] = new Vector2(1, -1);
            gradients[3] = new Vector2(-1, -1);

            Random r = new Random();
            for (int i = 0; i < 256; i++)
            {
                random[i] = (byte)r.Next(0, 256);
            }
            
            float num = 0.02f;
            Vector2 P = new Vector2();
            for (int i = 0; i < winY; i++)
            {
                for (int j = 0; j < winX; j++)
                {
                    float result = noise2d(P);

                    //float f1 = noise2d(P);
                    //float f2 = noise2d(2 * P);
                    //float f3 = noise2d(4 * P);
                    //float f4 = noise2d(8 * P);
                    //float f5 = noise2d(16 * P);

                    //float result = 0.5f * f1 +
                    //                0.25f * f2 +
                    //                0.125f * f3 +
                    //                 0.06f * f4 +
                    //                  0.003f * f5; 


                    result += 1.0f;
                    result *= 0.5f;
                    byte b = (byte)(255.0f * result);

                    //fill temp texture array 
                    rcol[i * winX + j] = new Color(b, b, b);

                    P.X += num;
                }
                P.X = 0.0f;
                P.Y += num;
            }

            //fill actual texture
            tex.SetData<Color>(rcol);
        }

        private float noise2d(Vector2 Pos)
        {
            Vector2 T = new Vector2(Pos.X - (int)Pos.X, Pos.Y - (int)Pos.Y);

            float fx = fade(T.X);
            float fy = fade(T.Y);

            float AA = perm(Pos.X) + Pos.Y;
            float AB = perm(AA + 1);
            float BA = perm(Pos.X + 1) + Pos.Y;
            float BB = perm(BA + 1);

            float u = MathHelper.Lerp(grad(perm(AA), T),
                                        grad(perm(BA), T + new Vector2(-1, 0)),
                                        fx);

            float v = MathHelper.Lerp(grad(perm(AB), T + new Vector2(0, -1)),
                                        grad(perm(BB), T + new Vector2(-1, -1)),
                                        fx);

            float final = MathHelper.Lerp(u, v, fy);
            return final;
        }

        float fade(float t)
        {
            return t * t * t * (t * (t * 6 - 15) + 10);
        }


        private float grad(byte x, Vector2 pos)
        {
            if (x >= 4)
                x = (byte)(x % 4);

            Vector2 g = gradients[x];
            return Vector2.Dot(g, pos);
        }

        private byte perm(float v)
        {
            int v2 = (int)Math.Floor(v);
            byte v3;

            if (v2 > 255)
                v3 = (byte)(v2 % 255);
            else
                v3 = (byte)v2;
            return random[v3];
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);

            spriteBatch.Begin();
            spriteBatch.Draw(tex, new Vector2(0, 0), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

Source Code

Share this post


Link to post
Share on other sites
Quote:
Original post by wforl
Ive noticed that the problem occurs, each time the Y position hits its next integeral value, such as 1, 2, 3 etc etc. Any ideas?
I think the problem is that you are using the input position (Pos) and the fractional portion of it (T). Instead you should be using the integer portion and the fractional portion, as Perlin does here.

Share this post


Link to post
Share on other sites
hi,

I get the integer portion in the perm function. So i believe im following it correctly.

Well, im going to try implementing the 3d noise, as that way i can follow it step by step without making my own bits up. And see how that goes

Share this post


Link to post
Share on other sites
here is my implementation of the perlin2 function (I quickly pulled it out of a larger file, so let me know if it's missing something that you need). It works. I trust you can have a look and compare it to yours to find the problem. Since you're writing managed code, ignore the f2iRoundFast function and just settle for a standard int cast instead. Good luck!


// the function
float NoiseWrapper::perlinNoise2(float x, float y)
{
int ix = f2iRoundFast(x - 0.5f);
int iy = f2iRoundFast(y - 0.5f);

x -= ix; y -= iy;
float x1 = x-1.0f; float y1 = y-1.0f;

ix &= 255; iy &= 255;

float s = qCurve(x);
float t = qCurve(y);

int a = p[ix ]+iy;
int b = p[ix+1]+iy;

return lerp( lerp( grad(p[a ],x ,y ),
grad(p[b ],x1,y ), s),
lerp( grad(p[a+1],x ,y1),
grad(p[b+1],x1,y1), s), t) * PERLIN2_MULT;
}

// some stuff that the function uses
#define PERLIN2_MULT 0.507f

const unsigned char NoiseWrapper::p[512] = {
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,

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

// Quintic curve
float qCurve(float t)
{
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}

// Linear interpolation
float lerp(float a, float b, float t)
{
return a + t * (b - a);
}

float grad(int hash, float x, float y)
{
hash &= 7; // convert low 3 bits of hash code
float s = (hash < 4) ? x : y; // into 8 simple gradient directions
float t = (hash < 4) ? y : x; // and compute the dot product with (x, y)
return ((hash & 1) ? -s : s) + ((hash & 2) ? -2.0f * t : 2.0f * t);
}



[Edited by - y2kiah on June 2, 2009 7:21:17 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this