Welcome to Fractal Forums

Fractal Software => Programming => Topic started by: ker2x on July 11, 2010, 10:28:16 PM




Title: Mandelbrot in XNA + HLSL
Post by: ker2x on July 11, 2010, 10:28:16 PM
I'm learning Microsoft XNA and HLSL.
Here is my result :

(http://fractals.s3.amazonaws.com/XNAMandelbrot.jpg)

Here is the HLSL code, feel free to comment, please :)
(yes, there is a useless "if ... else" condition, but i keep it to change interior/exterior colouring at will.)

Code:
float2 Pan;
float Zoom;
float Aspect;
int Iterations;

float4 PixelShader(float4 texCoord : TEXCOORD0) : COLOR0
{
float2 c = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
float4 result;
    float2 v = 0;
    int it = 0;
float minV = 4;
float minVx = 4;
float minVy = 4;

result.r = 0; result.g = 0; result.b = 0; result.a = 0;

while((it < Iterations) && (dot(v, v) < 4))
{
v = float2(v.x * v.x - v.y * v.y, v.x * v.y * 2) + c;
if(length(v) < minV) { minV = length(v); }
if(v.x < minVx) { minVx = v.x; }
if(v.y < minVy) { minVy = v.y; }


it = it +1;
}

if(it != Iterations)
{
//result =  (float)((float)it/(float)Iterations);
//result = minV;
result.r = abs(minVx);
result.g = abs(minVy);
result.b = minV;
} else {
result.r = abs(minVx);
result.g = abs(minVy);
result.b = minV;
}
   
return result;
}

technique
{
    pass
    {
    PixelShader = compile ps_3_0 PixelShader();
    }
}




Title: Re: Mandelbrot in XNA + HLSL
Post by: ker2x on July 11, 2010, 10:55:28 PM
Now i have the result i expected (i forgot a few "abs") ! :)
(some kind of Orbit Trap)

(http://fractals.s3.amazonaws.com/XNAMandelbrot2.jpg)

HLSL code :
Code:
float2 Pan;
float Zoom;
float Aspect;
int Iterations;

float4 PixelShader(float4 texCoord : TEXCOORD0) : COLOR0
{
float2 c = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
float2 v = 0;
float4 result;
    int it = 0;
float minV = 4;
float minVx = 4;
float minVy = 4;

result.r = 0; result.g = 0; result.b = 0; result.a = 0;

while((it < Iterations) && (dot(v, v) < 8))
{
v = float2(v.x * v.x - v.y * v.y, v.x * v.y * 2) + c;

if(length(v) < minV) { minV = length(v); }
if(abs(v.x) < minVx) { minVx = abs(v.x); }
if(abs(v.y) < minVy) { minVy = abs(v.y); }

it = it +1;
}

if(it != Iterations)
{
//result =  (float)((float)it/(float)Iterations);
//result = minV;
result.r = (minVx);
result.g = (minVy);
result.b = minV;
} else {
result.r = (minVx);
result.g = (minVy);
result.b = minV;
}
   
return result;
}

technique
{
    pass
    {
    PixelShader = compile ps_3_0 PixelShader();
    }
}

and the (not so clean) C# code :

Code:
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 XNAMandelbrot
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        SpriteBatch spriteBatch;
        SpriteFont font1;

        Effect mandelbrotEffect;
        Texture2D dummyTexture;

        Vector2 pan = new Vector2(0.25f, 0.000f);
        float zoom = 3;
        int iteration = 50;

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

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            font1 = Content.Load<SpriteFont>("SpriteFont1");
            mandelbrotEffect = Content.Load<Effect>("Mandelbrot");
            dummyTexture = new Texture2D(graphics.GraphicsDevice,
                graphics.GraphicsDevice.Viewport.Width,
                graphics.GraphicsDevice.Viewport.Height,
                1,
                TextureUsage.None,
                SurfaceFormat.Color);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            if (keyboardState.IsKeyDown(Keys.Up))
            {
                //pan = pan + new Vector2(0, 0.01f);
                pan.Y += (0.01f * zoom);
            }

            if (keyboardState.IsKeyDown(Keys.Down))
            {
                //pan = pan - new Vector2(0, 0.01f);
                pan.Y -= (0.01f * zoom);
            }

            if (keyboardState.IsKeyDown(Keys.Left))
            {
                pan.X += (0.01f * zoom);
            }

            if (keyboardState.IsKeyDown(Keys.Right))
            {
                pan.X -= (0.01f * zoom);
            }

            if (keyboardState.IsKeyDown(Keys.Add)) {
                zoom /= 1.01f;
            }

            if (keyboardState.IsKeyDown(Keys.Subtract))
            {
                zoom *= 1.01f;
            }

            if (keyboardState.IsKeyDown(Keys.Multiply))
            {
                iteration++;
            }

            if (keyboardState.IsKeyDown(Keys.Divide))
            {
                iteration--;
            }


            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

           

           

            float aspectRatio = (float)GraphicsDevice.Viewport.Height / (float)GraphicsDevice.Viewport.Width;

            mandelbrotEffect.Parameters["Pan"].SetValue(pan);
            mandelbrotEffect.Parameters["Zoom"].SetValue(zoom);
            mandelbrotEffect.Parameters["Aspect"].SetValue(aspectRatio);
            mandelbrotEffect.Parameters["Iterations"].SetValue(iteration);

            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
            mandelbrotEffect.Begin();
            mandelbrotEffect.CurrentTechnique.Passes[0].Begin();

            spriteBatch.Draw(dummyTexture, Vector2.Zero,Color.Black);

            spriteBatch.End();
            mandelbrotEffect.CurrentTechnique.Passes[0].End();
            mandelbrotEffect.End();

            spriteBatch.Begin();
            String IterationText = "Iteration : " + iteration;
            Vector2 FontOrigin = font1.MeasureString(IterationText) / 2;
            spriteBatch.DrawString(font1, IterationText, new Vector2(10, 10) + FontOrigin, Color.Green,
                0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}



Title: Re: Mandelbrot in XNA + HLSL
Post by: Sockratease on July 11, 2010, 11:06:03 PM
I like the coloring on that second one.

Animate a dive!   O0


Title: Re: Mandelbrot in XNA + HLSL
Post by: cbuchner1 on July 11, 2010, 11:57:06 PM

I will be trying something similar in WPF and HLSL (Pixel Shader) soon.

Christian


Title: Re: Mandelbrot in XNA + HLSL
Post by: ker2x on July 11, 2010, 11:59:35 PM
Thx !

I don't know how to create a movie.
However, you can download the compiled app here : http://fractals.s3.amazonaws.com/app.publish.zip
(the setup should download the XNA Runtime, or something like that, if you don't have it)

arrow : up,down, right, left
zoom : zoompad +
unzoom : numpad -
more iteration : numpad *
less iteration : numpad /

i found better coloring (basically, using result.b = sqrt(minV); etc ... instead of result.b = (minV); ), but my girlfriend like the version without sqrt, so i keep it like this. ;)

I could easily create a XBox360 version (XNA is crossplatorm Windows/XBox/Zune)... if i had a XBox :)
(however, the Zune don't support Pixel Shader 3, so no Zune version)


Title: Re: Mandelbrot in XNA + HLSL
Post by: ker2x on July 12, 2010, 08:42:54 AM
using sqrt (as said in previous post) :

(http://fractals.s3.amazonaws.com/XNAMandelbrotSqrt.jpg)