### Generating a Julia texture in Lua

Posted:

**Sun Jan 05, 2014 5:12 am**Hi everyone,

Now that we generated the Mandelbrot set, here's a script to generate a Julia set. The principle is the same. The only thing to note here is that there's a function to convert from the HSL colour model to the RGB model. The HSL model (or HSV) comes in very handy when you'd like to generate a full colour spectrum from a single value. Here is the code:

Here's a picture of the generated texture:

cheers,

Thomas

Now that we generated the Mandelbrot set, here's a script to generate a Julia set. The principle is the same. The only thing to note here is that there's a function to convert from the HSL colour model to the RGB model. The HSL model (or HSV) comes in very handy when you'd like to generate a full colour spectrum from a single value. Here is the code:

- Code: Select all
`--`

-- @description Creates a Julia set texture node.

-- @author Stratified

-- @version 0.1

--

-- radius 2 squared

local RADIUS2 = 4

-- max iterations before we stop

local MAX_ITERATIONS = 255

-- real and imaginary part of the constant

local C = { -0.7, 0.27015 }

-- Converts HSL to RGB (input and output range: 0 - 255)

function HSL(h, s, l)

if s == 0 then return l,l,l end

h, s, l = h/256*6, s/255, l/255

local c = (1-math.abs(2*l-1))*s

local x = (1-math.abs(h%2-1))*c

local m,r,g,b = (l-.5*c), 0,0,0

if h < 1 then r,g,b = c,x,0

elseif h < 2 then r,g,b = x,c,0

elseif h < 3 then r,g,b = 0,c,x

elseif h < 4 then r,g,b = 0,x,c

elseif h < 5 then r,g,b = x,0,c

else r,g,b = c,0,x

end

return math.ceil((r+m)*256),math.ceil((g+m)*256),math.ceil((b+m)*256)

end

-- Checks if a pixel in the image plane is in the julia set.

-- Coordinates (x, y) need to be in the range [-1, 1]. Returns if the point is in the set and

-- the number of iterations to figure that out.

local function julia(x, y)

local zr, zi = x, y

local cr, ci = C[1], C[2]

for k=1,MAX_ITERATIONS do

-- calculate z(n+1) from z(n)

local zrzi2 = zr * zi * 2

local zr2 = zr * zr

local zi2 = zi * zi

-- check if we're still in the circle with radius 2, if not the point isn't

-- in the Julia set anymore.

if (zi2 + zr2 > RADIUS2) then

return false, k

end

-- calculate the values for the next iteration

zr = zr2 - zi2 + cr

zi = ci + zrzi2

end

-- after MAX_ITERATIONS, we're pretty confident that the point is in the julia set.

return true, MAX_ITERATIONS

end

-- Generates a Julia set centered around the centre of the image.

function genJuliaTex(w, h)

-- create a data structure for the image

local image = {}

image.size = { w, h }

image.type = octane.image.type.LDR_RGBA

image.buffer = {}

count = 0

-- see which pixels are in the Julia set

for y = 0, h-1 do

for x = 0, w-1 do

-- transform x so it's in the range [-1, 1]

local sx = 2 * (x / w) - 1

-- transform y so it's in the range [-1, 1]

local sy = 2 * (y / h) - 1

local inSet, iterations = julia(sx, sy)

local r, g, b = 0, 0, 0

if inSet then

-- point in the set are red

r, g, b = 255, 0, 0

else

-- points outside are coloured depending on how quickly they

-- converged.

r, g, b = HSL(iterations, 127, 127)

end

-- colour pixel

table.insert(image.buffer, r)

table.insert(image.buffer, g)

table.insert(image.buffer, b)

table.insert(image.buffer, 255)

end

end

return image

end

-- dimensions of the generated texture

local WIDTH, HEIGHT = 500, 500

-- actually create the julia texture

local tex = genJuliaTex(WIDTH, HEIGHT)

assert(#tex.buffer == 4 * WIDTH * HEIGHT, "invalid buffer length")

-- create an image texture node

texNode = octane.node.create{ type=octane.NT_TEX_IMAGE, name="Julia Set Texture" }

-- set up the gradient in the attributes

texNode:setAttribute(octane.A_BUFFER , tex.buffer , false)

texNode:setAttribute(octane.A_SIZE , tex.size , false)

texNode:setAttribute(octane.A_TYPE , tex.type , false)

-- evaluate the texture node

texNode:evaluate()

Here's a picture of the generated texture:

cheers,

Thomas