Welcome, guest | Sign In | My Account | Store | Cart

Random Planet Generator using 3D Plasma Fractal and Voxel-based Ray Tracing for rendering.

Instead of generating 2D Plasma Fractal and projecting onto sphere, it generates 3D Plasma Fractal (cube) and cuts sphere from it.

Python, 192 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# Random Planet Generator Using 3D Plasma Fractal
# and Voxel-based Ray Tracing for rendering
# (Instead of generating 2D Plasma Fractal and projecting onto sphere,
# it generates 3D Plasma Fractal (cube) and cuts sphere from it.)
# FB - 20160125
import math
import random
from PIL import Image
imgx = 256; imgy = 256; imgz = 256
image = Image.new("RGB", (imgx, imgy))
pixels = image.load()
print "Creating voxels..."
# each voxel can have RGB color
voxelRGB = [[[(0, 0, 0) for x in range(imgx)] for y in range(imgy)] for z in range(imgz)]
# each voxel can have an opacity coefficient 0 or 1 (for simplicity)
opacity = [[[0 for x in range(imgx)] for y in range(imgy)] for z in range(imgz)]
eye = (imgx / 2.0, imgy / 2.0, -imgz / 2.0)
mx = imgx - 1; my = imgy - 1; mz = imgz - 1
f = 5.0 # roughness

def rnd():
    return (random.random() - .5) * f

def putvoxel(x, y, z, r, g, b):
    global voxelRGB, opacity
    x = int(round(x)); y = int(round(y)); z = int(round(z))
    voxelRGB[z][y][x] = (int(round(r)), int(round(g)), int(round(b)))
    opacity[z][y][x] = 1

def getvoxel(x, y, z):
    return voxelRGB[int(round(z))][int(round(y))][int(round(x))]

def CreatePlasmaCube(): # using non-recursive Diamond-square Algorithm
    global voxelRGB, opacity
    # corners
    for kz in range(2):
        for ky in range(2):
            for kx in range(2):
                putvoxel(mx * kx, my * ky, mz * kz, \
                    random.randint(0, 255), \
                    random.randint(0, 255), \
                    random.randint(0, 255))

    j = -1
    while True:
        j += 1; j2 = 2 ** j
        jx = float(mx) / j2; jy = float(my) / j2; jz = float(mz) / j2
        if jx < 1 and jy < 1 and jz < 1: break
        for m in range(j2):
            z0 = m * jz; z1 = z0 + jz; z = z0 + jz / 2.0        
            for i in range(j2):
                y0 = i * jy; y1 = y0 + jy; y = y0 + jy / 2.0        
                for k in range(j2):
                    x0 = k * jx; x1 = x0 + jx; x = x0 + jx / 2.0
                
                    a = getvoxel(x0, y0, z0); b = getvoxel(x1, y0, z0)
                    c = getvoxel(x0, y1, z0); d = getvoxel(x1, y1, z0)
                    e = getvoxel(x0, y0, z1); f = getvoxel(x1, y0, z1)
                    g = getvoxel(x0, y1, z1); h = getvoxel(x1, y1, z1)

                    # center
                    putvoxel(x, y, z, \
                        (a[0] + b[0] + c[0] + d[0] + e[0] + f[0] + g[0] + h[0]) / 8.0, \
                        (a[1] + b[1] + c[1] + d[1] + e[1] + f[1] + g[1] + h[1]) / 8.0, \
                        (a[2] + b[2] + c[2] + d[2] + e[2] + f[2] + g[2] + h[2]) / 8.0)

                    # centers of 6 faces
                    putvoxel(x, y, z0, \
                        (a[0] + b[0] + c[0] + d[0]) / 4.0, \
                        (a[1] + b[1] + c[1] + d[1]) / 4.0, \
                        (a[2] + b[2] + c[2] + d[2]) / 4.0)
                    putvoxel(x, y, z1, \
                        (e[0] + f[0] + g[0] + h[0]) / 4.0, \
                        (e[1] + f[1] + g[1] + h[1]) / 4.0, \
                        (e[2] + f[2] + g[2] + h[2]) / 4.0)
                    putvoxel(x, y0, z, \
                        (a[0] + b[0] + e[0] + f[0]) / 4.0, \
                        (a[1] + b[1] + e[1] + f[1]) / 4.0, \
                        (a[2] + b[2] + e[2] + f[2]) / 4.0)
                    putvoxel(x, y1, z, \
                        (c[0] + d[0] + g[0] + h[0]) / 4.0, \
                        (c[1] + d[1] + g[1] + h[1]) / 4.0, \
                        (c[2] + d[2] + g[2] + h[2]) / 4.0)
                    putvoxel(x0, y, z, \
                        (a[0] + c[0] + e[0] + g[0]) / 4.0, \
                        (a[1] + c[1] + e[1] + g[1]) / 4.0, \
                        (a[2] + c[2] + e[2] + g[2]) / 4.0)
                    putvoxel(x1, y, z, \
                        (b[0] + d[0] + f[0] + h[0]) / 4.0, \
                        (b[1] + d[1] + f[1] + h[1]) / 4.0, \
                        (b[2] + d[2] + f[2] + h[2]) / 4.0)

                    # centers of 12 edges
                    putvoxel(x, y0, z0, \
                        (a[0] + b[0]) / 2.0 + jx * rnd(), \
                        (a[1] + b[1]) / 2.0 + jx * rnd(), \
                        (a[2] + b[2]) / 2.0 + jx * rnd())
                    putvoxel(x0, y, z0, \
                        (a[0] + c[0]) / 2.0 + jy * rnd(), \
                        (a[1] + c[1]) / 2.0 + jy * rnd(), \
                        (a[2] + c[2]) / 2.0 + jy * rnd())
                    putvoxel(x1, y, z0, \
                        (b[0] + d[0]) / 2.0 + jy * rnd(), \
                        (b[1] + d[1]) / 2.0 + jy * rnd(), \
                        (b[2] + d[2]) / 2.0 + jy * rnd()) 
                    putvoxel(x, y1, z0, \
                        (c[0] + d[0]) / 2.0 + jx * rnd(), \
                        (c[1] + d[1]) / 2.0 + jx * rnd(), \
                        (c[2] + d[2]) / 2.0 + jx * rnd())
                    putvoxel(x, y0, z1, \
                        (e[0] + f[0]) / 2.0 + jx * rnd(), \
                        (e[1] + f[1]) / 2.0 + jx * rnd(), \
                        (e[2] + f[2]) / 2.0 + jx * rnd())
                    putvoxel(x0, y, z1, \
                        (e[0] + g[0]) / 2.0 + jy * rnd(), \
                        (e[1] + g[1]) / 2.0 + jy * rnd(), \
                        (e[2] + g[2]) / 2.0 + jy * rnd())
                    putvoxel(x1, y, z1, \
                        (f[0] + h[0]) / 2.0 + jy * rnd(), \
                        (f[1] + h[1]) / 2.0 + jy * rnd(), \
                        (f[2] + h[2]) / 2.0 + jy * rnd()) 
                    putvoxel(x, y1, z1, \
                        (g[0] + h[0]) / 2.0 + jx * rnd(), \
                        (g[1] + h[1]) / 2.0 + jx * rnd(), \
                        (g[2] + h[2]) / 2.0 + jx * rnd())
                    putvoxel(x0, y0, z, \
                        (a[0] + e[0]) / 2.0 + jz * rnd(), \
                        (a[1] + e[1]) / 2.0 + jz * rnd(), \
                        (a[2] + e[2]) / 2.0 + jz * rnd())
                    putvoxel(x1, y0, z, \
                        (b[0] + f[0]) / 2.0 + jz * rnd(), \
                        (b[1] + f[1]) / 2.0 + jz * rnd(), \
                        (b[2] + f[2]) / 2.0 + jz * rnd())
                    putvoxel(x0, y1, z, \
                        (c[0] + g[0]) / 2.0 + jz * rnd(), \
                        (c[1] + g[1]) / 2.0 + jz * rnd(), \
                        (c[2] + g[2]) / 2.0 + jz * rnd())
                    putvoxel(x1, y1, z, \
                        (d[0] + h[0]) / 2.0 + jz * rnd(), \
                        (d[1] + h[1]) / 2.0 + jz * rnd(), \
                        (d[2] + h[2]) / 2.0 + jz * rnd())

# cx, cy, cz: center; r: radius (in voxels)
def CreateSphere(cx, cy, cz, r):
    global voxelRGB, opacity
    # sphere is set of voxels which have distance = r to center
    for z in range(imgz):
        for y in range(imgy):
            for x in range(imgx):
                dx = x - cx
                dy = y - cy
                dz = z - cz
                d = math.sqrt(dx * dx + dy * dy + dz * dz)
                if abs(d - r) > 1.0:
                    voxelRGB[z][y][x] = (0, 0, 0)
                    opacity[z][y][x] = 0

# Ray Tracer (traces the ray and returns an RGB color)
def RayTrace(rayX, rayY, rayZ, dx, dy, dz):
    while True:
        rayX += dx; rayY += dy; rayZ += dz # move the ray by 1 voxel
        rayXint = int(round(rayX)); rayYint = int(round(rayY)); rayZint = int(round(rayZ))
        # if ray goes outside of the voxel-box
        if rayXint < 0 or rayXint > imgx - 1 \
            or rayYint < 0 or rayYint > imgy - 1 \
            or rayZint < 0 or rayZint > imgz - 1:
            return (0, 0, 0)
        # if ray hits an object
        if opacity[rayZint][rayYint][rayXint] == 1:
            return voxelRGB[rayZint][rayYint][rayXint]

def CreateScene():
    print "Creating scene..."
    CreatePlasmaCube()
    CreateSphere(imgx / 2.0, imgy / 2.0, imgz / 2, min(imgx / 2.0, imgy / 2.0, imgz / 2))

def RenderScene():
    print "Rendering scene..."
    for ky in range(imgy):
        print str(100 * ky / (imgy - 1)).zfill(3) + "%"
        for kx in range(imgx):
            dx = kx - eye[0]
            dy = ky - eye[1]
            dz = 0.0 - eye[2]
            d = math.sqrt(dx * dx + dy * dy + dz * dz)
            dx = dx / d; dy = dy / d; dz = dz / d # ray unit vector
            pixels[kx, ky] = RayTrace(kx, ky, 0, dx, dy, dz)

# MAIN
CreateScene()
RenderScene()
image.save("RandomPlanet.png", "PNG")

2 comments

Mad Times 5 years, 8 months ago  # | flag

i tried this code and got errors

FB36 (author) 5 years, 8 months ago  # | flag

Next time post the errors. If I have to guess, you may get error if you run this code in Python 3.x, instead of Python 2.x. Or maybe you don't have PIL library installed.