this demo will show Mandelbrot set 3D as a default, if you want Julia 3D change line 34 from mand = 1 to mand = 0, the time of calculation of 3 million points is 15 seconds on my slow pc, if you want less time reduce iterations to 1 million or less in line 136
iterations = 3000000
the function RandF is from kenmo from http://www.purebasic.fr/english/viewtop ... 13&t=45652.
i have'nt optimized the code so you can make more exploration and optimization
save the file in Examples\3D and use the keys described on the title bar to rotate/stop , zoom+/- , up/down.


ref: a great site for 3d fractals http://www.skytopia.com/project/fractal/mandelbulb.html
PS: the purebasic essential code are from MeshManual2.pb
PureBasic v5.10 code
Code: Select all
Enumeration
#MESH
#LIGHT
#CAMERA_ONE
#BUTTON
#mainwin
EndEnumeration
;constants for the biomorph function
#constreal = 0.5
#constimag = 0
#screenheight = 500
#screenwidth = 500
Global.f dx, dy, x, y, z
Global wd, ht, i, count, n, iter
Global.f w, leng, tx, ty, tz, tem
Global.f cr, ci, cj, ck, wk, inc, distance
Global mand, zval
Global.f angle
Define.f red, green, blue
;zval = 1 shows entire set
;zval = 0 cuts set in half
;zval = 0 is an interesting effect
wd = 500
ht = 500
;defines the shape of the Julia Set
cr = -0.200
ci = 0.800
cj = 0.000
ck = 0.000
wk = 0.000
;mand = 0 is Julia Set
;mand = 1 is Mandelbrot 3D
mand = 1
;zval = 1 shows entire set
;zval = 0 cuts set in half
;zval = 0 is an interesting effect
zval = 1
iter = 5
inc = 5
;#quat = 1
zval = 1
iter = 5
inc = 5
Procedure.f RandF(Min.f, Max.f, Resolution.i = 10000)
ProcedureReturn (Min + (Max - Min) * Random(Resolution) / Resolution)
EndProcedure
Quit.b = #False
rot.l=1 :stopFlag = 1
xs.f = 0.3:ys.f = 0.3:zs.f = 0.3
x.f: y.f :z.f: x0.f: y0.f=1 :z0.f
rotx.f:roty.f=1:rotz.f :rotx0.f: roty0.f: rotz0.f
up.f = 2.2: depth.f=0
ExamineDesktops()
If OpenWindow(#mainwin, 0, 0, DesktopWidth(0), DesktopHeight(0), "PgUp PgD scale mesh..Arrows for rotation, space: stop/rotate, QA Up/Down, WS far/near", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget(#BUTTON, 0, DesktopHeight(0)-60, 60, 30, "rotate/stop")
;Initialize environment
InitEngine3D()
InitSprite()
OpenWindowedScreen(WindowID(#mainwin), 0, 0, DesktopWidth(0), DesktopHeight(0)-70, 0, 0, 0)
WorldShadows(#PB_Shadow_Additive)
InitKeyboard()
SetFrameRate(60)
Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
CreateLight(0,RGB(255,255,255),-100,40,30)
AmbientColor(RGB(100,100,100))
CreateCamera(#CAMERA_ONE, 0, 0, 100, 100)
MoveCamera(#CAMERA_ONE, 0, 4, 9)
CameraLookAt(#CAMERA_ONE, 0, 2, 0)
RotateCamera(#CAMERA_ONE, -15, 0, 0)
EndIf
SetActiveGadget(#BUTTON)
;SkyDome("clouds.jpg", 100) ;for blue color background
;- Mesh Stars
CreateMaterial(0, LoadTexture(0, "White.jpg"))
DisableMaterialLighting(0, #True)
CreateMesh(1, #PB_Mesh_PointList, #False)
;CreateMesh(1, #PB_Mesh_PointList, #PB_Mesh_Static )
SetMeshMaterial(1, MaterialID(0))
Global Stars = CreateNode(#PB_Any)
AttachNodeObject(Stars, MeshID(1))
Procedure.f calcleng( x.f, y.f, z.f)
w.f: kr.f: ki.f: kj.f: kk.f
w = wk
n = 0
If mand = 1 ;full Mandelbrot set
kr = x
ki = y
kj = z
kk = 0
Else ;else draw Julia Set
kr = cr
ki = ci
kj = cj
kk = ck
EndIf
While n < iter
tem = x+x
x = x*x-y*y-z*z-w*w+kr
y = tem*y + ki
z = tem*z + kj
w = tem*w + kk
n+1
distance = x*x+y*y+z*z+w*w
If distance > 4
n = iter
EndIf
Wend
;Return distance
ProcedureReturn distance
EndProcedure
Procedure calcit()
zz.f
foo.l
iterations = 3000000
count = 0
If zval = 0
zz = 2.0
Else
zz = 4.0
EndIf
For foo = 0 To iterations
;x.f = RandF(0, 1)
;y.f = RandF(0, 1)
x.f = RandF(-2, 2)
y.f = RandF(-2, 2)
z.f = zz*RandF(0, 1) -2.0
;calls the quaternion calculation
leng.f = calcleng(x,y,z)
If leng < 4
MeshVertexPosition(x, y, z)
red = (x+Cos(15*leng))*255
green = (y+Sin(1-leng)*Cos(5*leng))*255
blue = (z+Sin(0.75*leng))*255
If red < 0 : red = 0 : EndIf
If green < 0 : green = 0 : EndIf
If blue < 0 : blue = 0 : EndIf
;If red > 255 : red = red-255 : EndIf
;If green > 255 : green = green-255 : EndIf
;If blue > 255 : blue = blue-255 : EndIf
;MeshVertexColor(RGBA(red,green,blue,0))
MeshVertexColor(RGB(red,green,blue))
EndIf
Next
FinishMesh(#False)
NormalizeMesh(1)
EndProcedure
calcit() ; calling the mandel 3D or julia generator function
;Main loop
Repeat
Event = WindowEvent()
If Event = #PB_Event_Gadget
Select EventGadget()
Case #BUTTON
If rot = 0
rot = 1
rotx= rotx0:roty=roty0:rotz=rotz0 ; restore rotation status
stopFlag = 1
Else
rot = 0
rotx0= rotx:roty0=roty:rotz0=rotz ;back up rotation status
rotx=0:roty=0:rotz=0
stopFlag = 0
EndIf
EndSelect
EndIf
If stopFlag=1
x + rotx
y + roty
z + rotz
EndIf
RotateNode(Stars, x, y, z)
RenderWorld()
FlipBuffers()
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Up) ; rotate left
rotx=1:roty=0:rotz=0
rotx0 = rotx: roty0 = roty :rotz0 = rotz
x + rotx
y + roty
z + rotz
stopFlag=0
rot = 0
ElseIf KeyboardPushed(#PB_Key_Down) ; rotate right
rotx=-1:roty=0:rotz=0
rotx0 = rotx: roty0 = roty :rotz0 = rotz
x + rotx
y + roty
z + rotz
stopFlag=0
rot = 0
ElseIf KeyboardPushed(#PB_Key_Right) ; rotate up
rotx=0:roty=1:rotz=0
rotx0 = rotx: roty0 = roty :rotz0 = rotz
x + rotx
y + roty
z + rotz
stopFlag=0
rot = 0
ElseIf KeyboardPushed(#PB_Key_Left) ; rotate down
rotx=0:roty=-1:rotz=0
rotx0 = rotx: roty0 = roty :rotz0 = rotz
x + rotx
y + roty
z + rotz
stopFlag=0
rot = 0
EndIf
If KeyboardPushed(#PB_Key_PageUp) ; scale up model
xs.f = 1.1:ys.f = 1.1:zs.f = 1.1
ScaleNode(Stars,xs,ys,zs)
ElseIf KeyboardPushed(#PB_Key_PageDown) ; scale down model
xs = 0.9:ys = 0.9:zs= 0.9
ScaleNode(Stars,xs,ys,zs)
EndIf
If KeyboardPushed(#PB_Key_Q) ; up move
up + 0.1
MoveNode(Stars,0,up,depth,#PB_Absolute)
ElseIf KeyboardPushed(#PB_Key_A) ; down move
up - 0.1
MoveNode(Stars,0,up,depth,#PB_Absolute)
ElseIf KeyboardPushed(#PB_Key_W) ; forward move
depth - 0.1
MoveNode(Stars,0,up,depth,#PB_Absolute)
ElseIf KeyboardPushed(#PB_Key_S) ; inward move
depth + 0.1
MoveNode(Stars,0,up,depth,#PB_Absolute)
EndIf
If KeyboardPushed(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True Or Event = #PB_Event_CloseWindow
Code: Select all
'Quaternion Fractal program
#include "GL/gl.bi"
#include "GL/glu.bi"
#include "GL/glut.bi"
#include "crt.bi"
declare sub doMain( )
declare sub calcit( )
declare function calcleng( x as GLfloat, y as GLfloat, z as GLfloat) as GLfloat
randomize timer
dim shared as GLfloat dx, dy, x, y, z
dim shared as Long wd, ht, i, count, n, iter
dim shared as GLfloat mouseX, mouseY
dim shared as GLfloat aff(15)
dim shared as GLfloat w, leng, tx, ty, tz, tem
dim shared as GLfloat cr, ci, cj, ck, wk, incr, dist
dim shared as Long mand, zval
dim shared as GLuint quat
for i = 0 to 15
if i mod 5 = 0 then
aff(i) = 1.0
else
aff(i) = 0.0
end if
next i
wd = 600
ht = 600
'defines the shape of the Julia Set
cr = -0.200
ci = 0.800
cj = 0.000
ck = 0.000
wk = 0.000
'mand = 0 is Julia Set
'mand = 1 is Mandelbrot 3D
mand = 0
'zval = 1 shows entire set
'zval = 0 cuts set in half
'zval = 0 is an interesting effect
zval = 1
'for a more precise set increase
'iter. However, too precise may
'not plot anything! Recommend 25
iter = 25
'increments of 1 million points
'20 = 20 million random points
'tested for inclusion in the set
'try 100, but be patient!
incr = 25
doMain
sub doInitGL
glClearColor 0.0, 0.0, 0.0, 0.0
glEnable GL_DEPTH_TEST
calcit()
end sub
sub doReshapeGL CDECL ( byval w as integer, _
byval h as integer )
glMatrixMode GL_PROJECTION
glLoadIdentity
glViewport 0, 0, w, h
gluPerspective 45.0, 1.0, 1.0, 1000.0
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
glMatrixMode GL_MODELVIEW
glLoadIdentity
end sub
'creates the display list
sub calcit
dim as GLfloat zz
dim as GLint foo
count = 0
if zval = 0 then
zz = 2.0
else
zz = 4.0
end if
quat = glGenLists(1)
glNewList(quat, GL_COMPILE)
glBegin(GL_POINTS)
for foo = 0 to 1000000*incr
x = 4.0*rnd-2.0
y = 4.0*rnd-2.0
z = zz*rnd-2.0
'calls the quaternion calculation
leng = calcleng(x,y,z)
if leng < 4 then
glColor3f(x+cos(15*leng),y+sin(1-leng)*cos(5*leng),z+sin(0.75*leng))
glVertex3f(x,y,z)
end if
next foo
glEnd()
glEndList()
end sub
'quaternion calculations
function calcleng( x as GLfloat, y as GLfloat, z as GLfloat) as GLfloat
dim as GLfloat w, kr, ki, kj, kk
w = wk
n = 0
if mand = 1 then 'full Mandelbrot set
kr = x
ki = y
kj = z
kk = 0
else 'Julia Set
kr = cr
ki = ci
kj = cj
kk = ck
end if
do
tem = x+x
x = x*x-y*y-z*z-w*w+kr
y = tem*y + ki
z = tem*z + kj
w = tem*w + kk
n+=1
dist = x*x+y*y+z*z+w*w
if dist > 4 then n = iter
loop while n < iter
return dist
end function
sub doRender cdecl
glClear GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT
glMatrixMode GL_MODELVIEW
glPushMatrix
glLoadIdentity
glMultMatrixf @aff(0)
'glPushMatrix
glCallList(quat)
'glPopMatrix
glPopMatrix
glutSwapBuffers
end sub
sub mousemotion CDECL(byval x as integer, byval y as integer)
mouseX = x
mouseY = y
end sub
sub doInput CDECL ( byval kbcode as unsigned byte, _
byval mousex as integer, _
byval mousey as integer )
if ( kbcode = 27 ) then
'doShutdown
end 0
end if
end sub
sub chaptrack
dx = (mouseX - wd/2)/256.0
dy = (mouseY - ht/2)/256.0
glMatrixMode GL_TEXTURE
glPushMatrix
glLoadIdentity
glRotatef(dx, 0.0, 1.0, 0.0)
glRotatef(dy, 1.0, 0.0, 0.0)
glMultMatrixf @aff(0)
glGetFloatv GL_TEXTURE_MATRIX, @aff(0)
glPopMatrix
end sub
sub doIdle cdecl
chaptrack
glutPostRedisplay
end sub
sub doMain
glutInit 1, strptr( " " )
glutInitWindowPosition 0, 0
glutInitWindowSize wd, ht
glutInitDisplayMode GLUT_RGBA or GLUT_DOUBLE or GLUT_DEPTH
glutCreateWindow "FreeBASIC OpenGL example"
doInitGL
glutDisplayFunc @doRender
glutIdleFunc @doIdle
glutReshapeFunc @doReshapeGL
glutKeyboardFunc @doInput
glutPassiveMotionFunc @mousemotion
glutMainLoop
end sub