# Wiki

Clone wiki# Core / MandelbrotShader

## Mandelbrot Shader

### Introduction

'Mandelbrot' is an example shader provided in Codea's 'Patterns' Shaders Pack. Applied to a rectangular mesh with appropriate texture co-ordinates, it renders a representation of part of the Mandelbrot set.

In addition to the Codea-supplied `modelViewProjection`

, the shader uses the following 'uniform' variables:

Variable | Type | V/F | Comment |
---|---|---|---|

`maxIter` | `int` | F | The maximum number of iterations for the sequence of complex numbers. A value of `255` is recommended. |

`minRe` | `float` | F | The real component of the complex number mapped to texture co-ordinate `(0.0, 0.0)` . |

`minIm` | `float` | F | The imaginary component of the complex number mapped to the texture co-ordinate `(0.0, 0.0)` |

`fRe` | `float` | F | The range of the real component of the complex numbers mapped to the `1.0` range of the 'u' texture co-ordinate. |

`fIm` | `float` | F | The range of the imaginary component of the complex numbers mapped to the `1.0` range of the 'v' texture co-ordinate. |

### Vertex shader

The vertex shader simply passes the 'attribute' variable `texCoord`

on to the accompanying fragment shader as 'varying' variable `vTexCoord`

:

```
void main()
{
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
```

`gl_Position`

is a variable that is intended for outputting the vertex position in homogenous co-ordinates (that is, as a `vec4`

value). All vertex shaders must write a value into that variable. (See Section 7.1 'Vertex Shader Special Variables' of the GLSL ES specification.) Here, the `modelViewProjection`

4x4 matrix is applied to the vertex's `position`

. `modelViewProjection`

is a 'uniform' `mat4`

variable supplied automatically by Codea when the shader is used with a mesh. It is the current model matrix * view matrix * projection matrix. `position`

is a `vec4`

'attribute' variable, also supplied automatically by Codea from the mesh.

### Fragment shader

The fragment shader makes use of the 'varying' `vTextCoord`

passed from the vertex shader and the 'uniform' variables set out above, to set `gl_FragColor`

(which outputs the colour of the fragment - see Section 7.2 'Fragment Shader Special Variables' of the GLSL ES specification).

`gl_FragColor`

is set to a `vec4`

constructed from variables `r`

, `g`

and `b`

and an alpha (opacity) channel set to `1.0`

. `r`

, `g`

and `b`

are set based on the ratio (`c`

) of the number of iterations (`iter`

) to the maximum possible number of interations (`maxIter`

). By multiplying `c`

by three different prime numbers (`11.0`

, `5.0`

and `7.0`

) and then using the built-in `mod()`

function (see Section 8.3 'Common Functions' of the GLSL ES specification) different ratios can be mapped to attractive bands of colour. This is the same colouring algorithm used in Codea's 'Mandelbrot' Example Project.

```
float c = float(iter) / float(maxIter);
float r = mod(c * 11.0, 1.0);
float g = mod(c * 5.0, 1.0);
float b = mod(c * 7.0, 1.0);
gl_FragColor = vec4(r, g, b, 1.0);
```

The number of iterations is determined by a `while {}`

loop. The loop repeats until the maximum number of iterations has been completed or the modulus of the complex number is greater than or equal to 2 (equivalently, `(zRe2 + zIm2) >= 4.0`

).

```
int iter = 0;
...
while ((iter <= maxIter) && ((zRe2 + zIm2) < 4.0)) {
zIm = 2.0 * zRe * zIm + cIm;
zRe = zRe2 - zIm2 + cRe;
iter++;
zRe2 = zRe * zRe;
zIm2 = zIm * zIm;
}
```

During each iteration, the complex number (`zRe`

, `zIm`

) is squared and a constant complex number parameter (`cRe`

, `cIm`

) is added to it:

```
// (zRe + i * zIm)^2 + (cRe + i * cIm) is:
// Real part: zRe * zRe - zIm * zIm + cRe
// Imaginary part: 2.0 * zRe * zIm + cIm
zRe2 = zRe * zRe;
zIm2 = zIm * zIm;
zIm = 2.0 * zRe * zIm + cIm;
zRe = zRe2 - zIm2 + cRe;
```

The constant complex parameter is determined by the texture co-ordinates (`vTexCoord`

), scaled and translated by the values of the relevant 'uniform' variables:

```
float cRe = minRe + fRe * vTexCoord.x;
float cIm = minIm + fIm * vTexCoord.y;
```

The iteration starts at the critical point of `zRe = 0.0`

, `zIm = 0.0`

and after the first iteration, the complex number is equal to the constant complex parameter:

```
float zRe = cRe;
float zIm = cIm;
float zRe2 = zRe * zRe;
float zIm2 = zIm * zIm;
```

### Example of use

The code below is a simple example of the use of the shader:

```
-- With acknowledgements to:
-- Mandelbrot set explorer, by Dr. Phillip Alvelda
supportedOrientations(LANDSCAPE_ANY)
function setup()
re, im, s = -0.65, 0, 1.35
aspect = WIDTH / HEIGHT
myMesh = mesh()
myMesh:addRect(WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)
myMesh.shader = shader("Patterns:Mandelbrot")
img = image(WIDTH, HEIGHT)
render()
print("Tap Viewer to zoom in, Replay to restart.")
end
function draw()
sprite(img, WIDTH/2, HEIGHT/2)
end
function touched(touch)
if touch.state ~= ENDED then return end
re = minRe + touch.x/WIDTH * s * 2 * aspect
im = minIm + touch.y/HEIGHT * s * 2
s = s/3
render()
end
function render()
minRe = re - s * aspect
minIm = im - s
myMesh.shader.minRe = minRe
myMesh.shader.minIm = minIm
myMesh.shader.fRe = s * 2 * aspect
myMesh.shader.fIm = s * 2
myMesh.shader.maxIter = 255
setContext(img)
myMesh:draw()
setContext()
end
```

Updated