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.) 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 : 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 : 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)
|