#!BPY """ Name: 'Cloud Generator' Blender: 245 Group: 'Wizards' Tooltip: 'Generate volumetric clouds' """ __author__ = 'Alan Dennis' __version__ = '0.5' __email__ = "alan@curiousexistence.com" __url__ = ["Curious Existence, http://www.curiousexistence.com"] __bpydoc__ = """\ This script generates previewable interactive volumetrics. Mainly for cloud creation. """ # ***** BEGIN GPL LICENSE BLOCK ***** # # Script copyright (C): Alan Dennis # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- import Blender, time, webbrowser from Blender import Constraint, Material, Mathutils, Mesh, Noise, Object, Scene, Texture, Window, Image from Blender.Noise import random from Blender.Mathutils import Vector from Blender.BGL import * from Blender.Draw import * from Blender.Noise import * def draw(): global tglBounds, tglShape, tglBillboards, pixHeader, pixPreview #Generic global txtBounds, mnuPreset, tglPreview, tglHull #Bounds global texPreview1, texPreview2, texHeader, sldJitter, sldResolution, txtCloudName, tglTexture1, tglTexture2, tglColorband, colDark1, colDark2, mnuMode, sldPreview, sldZoom, sldDepth1, sldDepth2, mnuType1, mnuType2 #Shape global mnuBlend1, tglFlipXY1, mnuBlend2, tglFlipXY2, mnuShape1, sldTurbulence1, mnuShape2, sldTurbulence2, mnuFractal1, sldSmooth1, sldLacu1, sldOctaves1, sldIntens1, mnuFractal2, sldSmooth2, sldLacu2, sldOctaves2, sldIntens2, mnuMetric1, mnuMetric2, tglInvert1, tglInvert2 #Noise-Specific global mnuBasis1, sldThreshold1, sldContrast1, sldBrightness1, sldSize1, mnuBasis2, sldThreshold2, sldContrast2, sldBrightness2, sldSize2 global sldBillboardSize, txtTracking, EmptyLayers, BillboardLayers #Billboards global strLine1, strLine2, strLine3, strLine4, strBounds1, strBounds2, strBounds3, strBounds4, strPoints1, strPoints2, strPoints3, strPoints4, strBillboard1, strBillboard2, strBillboard3, strBillboard4, strPreset #Helptext ################## #Generic ################## glClearColor(0.753, 0.753, 0.753, 0.0) #Background color glClear(GL_COLOR_BUFFER_BIT) #Header# glRasterPos2f(0, guih-30) glDrawPixels(guiw, 31, GL_RGB, GL_UNSIGNED_BYTE, pixHeader) #Borders glColor3f(0.5,0.5,0.5) glRecti(0,guih-30,guiw,guih - 107) glColor3i(0,0,0) glRecti(0,guih-107,guiw,guih-108) #top glRecti(guiw,0,guiw+1,guih) #right glRecti(0,0,guiw,1) #bottom #Toggles tglBounds = Toggle('Bounds', 1, 0, guih - 54, togw-1, 23, tglBounds.val, '') tglShape = Toggle('Shape', 2, togw+1, guih - 54, togw-1, 23, tglShape.val, '') tglBillboards = Toggle('Billboards', 3, togw*2+2, guih - 54, togw-1, 23, tglBillboards.val, '') #Helptext glRasterPos2i(2, guih-64) Text(strLine1) glRasterPos2i(2, guih-77) Text(strLine2) glRasterPos2i(2, guih-90) Text(strLine3) glRasterPos2i(2, guih-103) Text(strLine4) ################## #Bounds ################## if tglBounds.val: glRasterPos2i(2, guih-133+7) Text('Cloud\'s Name:') txtCloudName = String('', 201, guiw/2 +1 , guih-133, (guiw/2)-3, 23, txtCloudName.val, 64, '') glRasterPos2i(2, guih-158+7) Text('Bounding Object:') txtBounds = String('', 101, guiw/2 +1 , guih-158, (guiw/2)-31, 23, txtBounds.val, 64, '') Button('Sel', 103, guiw-28, guih-158, 26, 23, 'Use the currently selected object as the Bounding Object') tglHull = Toggle('Convex Hull', 105, 10, guih-200, 110, 31, tglHull.val, 'Uses the interior of a solid mesh as the bounds') Button('Create Bounds', 102, guiw-120, guih-200, 110, 31, 'Create a new Bounding Object') #Presets glColor3f(0.85,0.85,0.85) glRecti(0, guih - 238, guiw, guih - 239) glColor3f(0.5,0.5,0.5) glRecti(0, guih - 239, guiw, guih - 419) glColor3f(0.2,0.2,0.2) glRecti(0, guih - 419, guiw, guih - 420) mnuPreset = Menu('Built-In Presets%t|Cirrus %x1|Cumulus %x2|Mammatus %x3|Nimbus %x4|Stratus %x5|Streaks %x6', 110, 2, guih-265, guiw / 2 - 3, 23, mnuPreset.val, '') tglPreview = Toggle('Show Preview', 111, 2, guih-290, guiw/2 - 3, 23, tglPreview.val, '') if tglPreview.val: sldPreview = Slider('Preview ', 299, 2, guih-315, guiw / 2 - 3, 23, sldPreview.val, 1, 3, 1, 'Preview quality (simulates cloud thickness)') glRasterPos2f(guiw /2 + 2 , guih - 316) glDrawPixels(guiw/2 - 4 , 74, GL_RGB, GL_UNSIGNED_BYTE, pixPreview) Button('Load External', 131, 10, guih-414, 111, 31, 'Load the settings from a .cld file') Button('Save As', 132, guiw-121, guih-414, 111, 31, 'Save the current settings to a .cld file') Label(strPreset[0], 0, guih - 331, guiw - 2, 7) Label(strPreset[1], 0, guih - 344, guiw - 2, 7) Label(strPreset[2], 0, guih - 357, guiw - 2, 7) Label(strPreset[3], 0, guih - 370, guiw - 2, 7) Button('Website', 999, (guiw / 2) - 55, 6, 110, 31, 'For the latest help, tutorials, and a place to donate') ################## #Shape ################## elif tglShape.val: sldResolution = Slider('Points / Unit ', 202, 2, guih-133, guiw - 4, 23, sldResolution.val, 0.1, 10, 0, 'How many points to generate for every Blender Unit') sldJitter = Slider('Jitter ', 203, 2, guih-158, guiw - 4, 23, sldJitter.val, 0.0, 1.0, 0, 'Percent to randomize the placement of points') sldZoom = Slider('Zoom ', 299, 2, guih-183, guiw - 4, 23, sldZoom.val, 0.01, 10.0, 0, 'Percent to magnify the overall cloud shape') #Colorband tglColorband = Toggle('Colorband', 299, 2, guih-208, guiw/3 -2, 23, tglColorband.val, 'Enable or disable the shading colorband') if tglColorband.val: colDark1 = ColorPicker(299, guiw/3 + 3, guih-204, 13, 13, colDark1.val, '') glColor3f(0.000,0.000,0.000) glRecti(guiw/3 + 17,guih-197,guiw/3 + 20,guih-198) glRecti(guiw-19,guih-197,guiw-16,guih-198) DrawGradient(guiw/3 + 20,guih-189,guiw-19,guih-205, colDark1.val, colDark2.val) colDark2 = ColorPicker(299, guiw-16, guih-204, 13, 13, colDark2.val, '') #Texture group glColor3f(0.85,0.85,0.85) glRecti(0, guih - 213, guiw, guih - 214) glColor3f(0.5,0.5,0.5) glRecti(0, guih - 214, guiw, guih - 445) glColor3f(0.2,0.2,0.2) glRecti(0, guih - 445, guiw, guih - 446) tglTexture1 = Toggle('Texture 1', 250, 2, guih-240, guiw/3 -2, 23, tglTexture1.val, '') tglTexture2 = Toggle('Texture 2', 251, guiw/3+2, guih-240, guiw/3 -3, 23, tglTexture2.val, '') mnuMode = Menu('Mix Mode%t|Tex 1 Only %x1|Tex 2 Only %x2|Add %x3|Subtract %x4|Multiply %x5|Divide %x6|Difference %x7', 299, (guiw*2)/3+1, guih-240, guiw/3 -2 , 23, mnuMode.val, '') if tglTexture1.val: #Texture 1 Controls mnuType1 = Menu('Noise Type%t|Blend %x5|Clouds %x1|Marble %x3|Musgrave %x11|Voronoi %x12', 299, 2, guih-265, guiw / 2 - 3, 23, mnuType1.val, '') sldSize1 = Slider('Size ', 299, 2, guih-290, guiw / 2 - 3, 23, sldSize1.val, 0.01, 10.0, 0, 'Texture size') sldBrightness1 = Slider('Bright ', 299, 2, guih-315, guiw / 2 - 3, 23, sldBrightness1.val, 0.0, 2.0, 1, 'Texture brightness') sldContrast1 = Slider('Cont ', 299, 2, guih-340, guiw / 2 - 3, 23, sldContrast1.val, 0.0, 5.0, 1, 'Texture contrast') sldThreshold1 = Slider('Thresh', 299, 2, guih-365, guiw / 2 - 3, 23, sldThreshold1.val, 0.0, 0.999, 1, 'Edge threshold') if mnuType1.val == 5: #Blend mnuBlend1 = Menu('Blend Basis%t|Diagonal %x3|Linear %x0|Sphere %x4', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBlend1.val, '') tglFlipXY1 = Toggle('Flip XY', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, tglFlipXY1.val, '') elif mnuType1.val == 1: #Cloud mnuBasis1 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis1.val, '') sldDepth1 = Slider('Depth ', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, sldDepth1.val, 0, 6, 1, 'Texture depth') elif mnuType1.val == 3: #Marble mnuBasis1 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis1.val, '') mnuShape1 = Menu('Noise Shape%t|Saw %x1|Sine %x0|Triangular %x2', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, mnuShape1.val, '') sldTurbulence1 = Slider('Turb ', 299, 2, guih-415, guiw / 2 - 3, 23, sldTurbulence1.val, 0, 100, 1, 'Turbulence (Distortion Amount)') elif mnuType1.val == 11: #Musgrave mnuBasis1 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis1.val, '') mnuFractal1 = Menu('Fractal%t|Brownian %x3|Hetero-Terrain %x4|Hybrid %x2|Multifractal %x0|Ridged %x1', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, mnuFractal1.val, '') sldSmooth1 = Slider('Smooth ', 299, 2, guih-415, guiw / 2 - 3, 23, sldSmooth1.val, 0.001, 2.0, 1, 'Fractal smoothing') sldIntens1 = Slider('Intens ', 299, guiw / 2 + 1, guih-415, guiw / 2 - 3, 23, sldIntens1.val, 0.001, 3.0, 1, 'Intensity') sldLacu1 = Slider('Lacu ', 299, 2, guih-440, guiw / 2 - 3, 23, sldLacu1.val, 0.0, 6.0, 1, 'Fractal spacing') sldOctaves1 = Slider('Oct ', 299, guiw / 2 + 1, guih-440, guiw / 2 - 3, 23, sldOctaves1.val, 0.0, 8.0, 1, 'Octaves (Frequencies)') else: #Voronoi mnuMetric1 = Menu('Distance Metric%t|Actual Distance %x0|Distance Squared %x1|Chebychev %x3|Manhattan %x2|Minkovsky 4 %x5|Minkovsky 1/2 %x4|', 299, 2, guih-390, guiw / 2 - 3, 23, mnuMetric1.val, '') sldIntens1 = Slider('Intens ', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, sldIntens1.val, 0.001, 10.0, 1, 'intensity') tglInvert1 = Toggle('Invert', 299, guiw / 2 + 1, guih-365, guiw / 2 - 3, 23, tglInvert1.val, '') else: #Texture 2 Controls mnuType2 = Menu('Noise Type%t|Blend %x5|Clouds %x1|Marble %x3|Musgrave %x11|Voronoi %x12', 299, 2, guih-265, guiw / 2 - 3, 23, mnuType2.val, '') sldSize2 = Slider('Size ', 299, 2, guih-290, guiw / 2 - 3, 23, sldSize2.val, 0.01, 10.0, 0, 'Texture size') sldBrightness2 = Slider('Bright ', 299, 2, guih-315, guiw / 2 - 3, 23, sldBrightness2.val, 0.0, 2.0, 1, 'Texture brightness') sldContrast2 = Slider('Cont ', 299, 2, guih-340, guiw / 2 - 3, 23, sldContrast2.val, 0.0, 5.0, 1, 'Texture contrast') sldThreshold2 = Slider('Thresh', 299, 2, guih-365, guiw / 2 - 3, 23, sldThreshold2.val, 0.0, 0.999, 1, 'Edge threshold') if mnuType2.val == 5: #Blend mnuBlend2 = Menu('Blend Basis%t|Diagonal %x3|Linear %x0|Sphere %x4', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBlend2.val, '') tglFlipXY2 = Toggle('Flip XY', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, tglFlipXY2.val, '') elif mnuType2.val == 1: #Cloud mnuBasis2 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis2.val, '') sldDepth2 = Slider('Depth ', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, sldDepth2.val, 0, 6, 1, 'Texture depth') elif mnuType2.val == 3: #Marble mnuBasis2 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis2.val, '') mnuShape2 = Menu('Noise Shape%t|Saw %x1|Sine %x0|Triangular %x2', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, mnuShape2.val, '') sldTurbulence2 = Slider('Turb ', 299, 2, guih-415, guiw / 2 - 3, 23, sldTurbulence2.val, 0, 100, 1, 'Turbulence (Distortion Amount)') elif mnuType2.val == 11: #Musgrave mnuBasis2 = Menu('Noise Basis%t|Blender %x0|Perlin %x1|Improved Perlin %x2|Voronoi F1 %x3|Voronoi F2 %x4|Voronoi F3 %x5|Voronoi F4 %x6|Voronoi F2-F1 %x7|Voronoi Crackle %x8|Cellnoise %x14', 299, 2, guih-390, guiw / 2 - 3, 23, mnuBasis2.val, '') mnuFractal2 = Menu('Fractal%t|Brownian %x3|Hetero-Terrain %x4|Hybrid %x2|Multifractal %x0|Ridged %x1', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, mnuFractal2.val, '') sldSmooth2 = Slider('Smooth ', 299, 2, guih-415, guiw / 2 - 3, 23, sldSmooth2.val, 0.001, 2.0, 1, 'Fractal smoothing') sldIntens2 = Slider('Intens ', 299, guiw / 2 + 1, guih-415, guiw / 2 - 3, 23, sldIntens2.val, 0.001, 3.0, 1, 'Intensity') sldLacu2 = Slider('Lacu ', 299, 2, guih-440, guiw / 2 - 3, 23, sldLacu2.val, 0.0, 6.0, 1, 'Fractal spacing') sldOctaves2 = Slider('Oct ', 299, guiw / 2 + 1, guih-440, guiw / 2 - 3, 23, sldOctaves2.val, 0.0, 8.0, 1, 'Octaves (Frequencies)') else: #Voronoi mnuMetric2 = Menu('Distance Metric%t|Actual Distance %x0|Distance Squared %x1|Chebychev %x3|Manhattan %x2|Minkovsky 4 %x5|Minkovsky 1/2 %x4|', 299, 2, guih-390, guiw / 2 - 3, 23, mnuMetric2.val, '') sldIntens2 = Slider('Intens ', 299, guiw / 2 + 1, guih-390, guiw / 2 - 3, 23, sldIntens2.val, 0.001, 10.0, 1, 'intensity') tglInvert2 = Toggle('Invert', 299, guiw / 2 + 1, guih-365, guiw / 2 - 3, 23, tglInvert2.val, '') #Noise Preview glRasterPos2f(guiw /2 + 2 , guih - 316) glDrawPixels(guiw/2 - 4 , 74, GL_RGB, GL_UNSIGNED_BYTE, pixPreview) sldPreview = Slider('Preview ', 299, guiw / 2 + 1, guih-340, guiw / 2 - 3, 23, sldPreview.val, 1, 3, 1, 'Preview quality (simulates cloud thickness)') #Disabled to make room for sldDepth Button('Create Points', 209, (guiw / 2) - 55, 6, 110, 31, '') ################## #Billboards ################## else: Button('Autosize Billboards', 330, 2, guih-133, guiw/2 - 3, 23, 'Calculates the optimal billboard size based on Points / Unit') sldBillboardSize = Slider('Size ', 302, guiw / 2 + 1, guih-133, guiw / 2 - 3, 23, sldBillboardSize.val, 0.1, 5.0, 0, "The billboards' size") glRasterPos2i(2, guih-151) Text('Tracking Object:') txtTracking = String('', 201, guiw/2 +1 , guih-158, (guiw/2)-30, 23, txtTracking.val, 64, '') Button('Sel', 331, guiw - 28, guih-158, 26, 23, 'Use the currently selected object (usually a camera) as the billboard tracking object') #Create the array of buttons for the Billboard Layer and Empty Layer glRasterPos2i(2, guih-180) Text('Billboard Mesh Layer:') for x in range(10): for y in range(2): if (x + y*10 +1) in BillboardLayers: checked = True else: checked = False Toggle('',500 + x+(y*10) + 1, guiw/2 + 2 + x*13 +(int(x/5) * 5) , guih - 175 - y*13,12,12,checked,'') glRasterPos2i(2, guih-210) Text('Control Handle Layer:') for x in range(10): for y in range(2): if (x + y*10 +1) in EmptyLayers: checked = True else: checked = False Toggle('',600 + x+(y*10) + 1, guiw/2 + 2 + x*13 +(int(x/5) * 5) , guih - 205 - y*13,12,12,checked,'') Button('Clear Bounds',304, 10, guih - 260, 111, 31, '') Button('Create Billboards', 303, guiw - 121, guih - 260, 111, 31, '') def event(evt, val): if (evt in[QKEY, ESCKEY] and not val): result = PupMenu("Quit Alan's Cloud Generator?%t|No|Yes") if result == 2:Exit() def bevent(evt): global txtBounds, EmptyLayers, BillboardLayers, pixPreview global strLine1, strLine2, strLine3, strLine4 ################## #Toggles ################## if evt == 1: #tglBounds tglBounds.val = True tglShape.val = False tglBillboards.val = False strLine1 = strBounds1 strLine2 = strBounds2 strLine3 = strBounds3 strLine4 = strBounds4 elif evt == 2: #tglShape tglBounds.val = False tglShape.val = True tglBillboards.val = False strLine1 = strShape1 strLine2 = strShape2 strLine3 = strShape3 strLine4 = strShape4 elif evt == 3: #tglBillboards tglBounds.val = False tglShape.val = False tglBillboards.val = True strLine1 = strBillboard1 strLine2 = strBillboard2 strLine3 = strBillboard3 strLine4 = strBillboard4 ################## #Bounds ################## elif evt == 101: #txtBounds if not objectExists(txtBounds.val): txtBounds.val = '' elif evt == 102: #CreateBounds Window.WaitCursor(True) createBoundingObject() Window.WaitCursor(False) Window.Redraw(Window.Types.VIEW3D) elif evt == 103: #AssignBounds try: txtBounds.val = Object.GetSelected()[0].getName() except: txtBounds.val = '' elif evt == 105: #tglHull if Blender.Get('version') < 246: result = PupMenu('Only available in Blender 2.46 and above%t|OK') tglHull.val = False elif evt == 110: #Preset loadDefaultPreset(mnuPreset.val) elif evt == 111: #tglPreview if tglPreview.val: renderPreview() elif evt in [131, 132]: result = PupMenu('Sorry, load and save are not implemented yet.%t|OK') ################## #Shape ################## elif evt == 209: #btnPoints Window.WaitCursor(True) if objectExists(txtBounds.val): delBillboards(txtCloudName.val + 'plane') createPoints(Object.Get(txtBounds.val), txtCloudName.val, 1.0 / sldResolution.val, sldJitter.val, texPreview1, sldSize1.val, sldThreshold1.val, tglInvert1.val, texPreview2, sldSize2.val, sldThreshold2.val, tglInvert2.val, sldZoom.val, mnuMode.val, tglHull.val) else: print 'Error creating points: The bounding object "' + txtBounds.val + '" does not exist.' Window.WaitCursor(False) Window.Redraw(Window.Types.VIEW3D) elif evt == 250: #Texture1 tglTexture1.val = True tglTexture2.val = False elif evt == 251: #Texture2 tglTexture1.val = False tglTexture2.val = True elif evt == 299: #Any control that should update the noise preview buildTextures() renderPreview() ################## #Billboards ################## elif evt == 301: #txtTracking if not objectExists(txtTracking.val): txtTracking.val = '' #Could not find the Camera Object elif evt == 303: #btnBillboards Window.WaitCursor(True) if not txtTracking.val == '' and not objectExists(txtTracking.val): #Billboard tracking will be disabled txtTracking.val = '' print 'Error creating billboards. Cannot find the object "' + txtTracking.val + '".\nTracking will not work without an object to track.' else: if objectExists(txtBounds.val): if objectExists(txtCloudName.val + 'Preview'): delBillboards(txtCloudName.val + 'plane') Window.Redraw(Window.Types.VIEW3D) createEmpties(txtCloudName.val, txtBounds.val, EmptyLayers) mat = create= createMaterials(txtCloudName.val, texPreview1, sldSize1.val, sldThreshold1.val, texPreview2, sldSize2.val, sldThreshold2.val, sldZoom.val, tglColorband.val, colDark1.val, colDark2.val, mnuMode.val, mtTranslate, mtDarkening) createPlanes(txtCloudName.val + 'Preview', sldBillboardSize.val, txtTracking.val, mat, txtCloudName.val, txtBounds.val, BillboardLayers) #Remove the Bounding Object and the preview point cloud # #Make sure the constraints are updated scn.update(1) else: print 'Error creating billboards. You must first create the points from the Shape tab.' else: txtBounds.val = '' print 'Error creating billboards. You must first create a bounding Object on the Bounds tab.' Window.WaitCursor(False) Window.Redraw(Window.Types.VIEW3D) elif evt == 304: #Delete Boundsss result = PupMenu('Erase bounds and points?%t|No|Yes') if result == 2: if objectExists(txtCloudName.val + 'Preview'): deleteObject(txtCloudName.val + 'Preview') if objectExists(txtBounds.val): deleteObject(txtBounds.val) Window.Redraw(Window.Types.VIEW3D) elif evt == 330: #Autosize Billboards sldBillboardSize.val = (1.0/sldResolution.val) * 1.35 elif evt == 331: #Get tracking object try: txtTracking.val = Object.GetSelected()[0].getName() except: txtTracking.val = '' elif evt >=500 and evt <=520: value = evt - 500 if value in BillboardLayers: if not len(BillboardLayers) == 1: BillboardLayers.remove(value) else: BillboardLayers.append(value) elif evt >=600 and evt <=620: value = evt - 600 if value in EmptyLayers: if not len(EmptyLayers) == 1: EmptyLayers.remove(value) else: EmptyLayers.append(value) elif evt == 999: #Website webbrowser.open('http://www.curiousexistence.com/projects/cloudgen') Window.Redraw(Window.Types.SCRIPT) def buildTextures(): #This function takes all user parameters and builds the noise preview textures global texPreview1, texPreview2 #Texture 1 texPreview1.type = mnuType1.val if mnuType1.val == 5: #Blend texPreview1.stype = mnuBlend1.val elif mnuType1.val == 1: #Clouds texPreview1.stype = Texture.STypes.CLD_DEFAULT elif mnuType1.val == 3: #Marble texPreview1.stype = Texture.STypes.MBL_SOFT elif mnuType1.val == 11: #Musgrave texPreview1.stype = mnuFractal1.val else: #Voronoi texPreview1.stype = Texture.STypes.VN_INT texPreview1.noiseSize = 1.0 texPreview1.brightness = sldBrightness1.val texPreview1.contrast = sldContrast1.val texPreview1.noiseDepth = sldDepth1.val texPreview1.noiseBasis = mnuBasis1.val texPreview1.noiseBasis2 = mnuShape1.val texPreview1.turbulence = sldTurbulence1.val texPreview1.stype = mnuFractal1.val texPreview1.hFracDim = sldSmooth1.val texPreview1.iScale = sldIntens1.val texPreview1.lacunarity = sldLacu1.val texPreview1.octs = sldOctaves1.val texPreview1.distMetric = mnuMetric1.val if tglInvert1.val: if sldThreshold1.val < 0.01: texPreview1.colorband = [[1,1,1,1,0], [0,0,0,0,1]] else: texPreview1.colorband = [[1,1,1,1,0], [0,0,0,0,1.0 - sldThreshold1.val]] else: if sldThreshold1.val < 0.01: texPreview1.colorband = [[0,0,0,0,0],[1,1,1,1,1]] else: texPreview1.colorband = [[0,0,0,0,sldThreshold1.val],[1,1,1,1,1]] if tglFlipXY1.val: texPreview1.flags = Texture.Flags.FLIPBLEND | Texture.Flags.COLORBAND else: texPreview1.flags = Texture.Flags.COLORBAND #Texture 2 texPreview2.type = mnuType2.val if mnuType2.val == 5: #Blend texPreview2.stype = mnuBlend2.val elif mnuType2.val == 1: #Clouds texPreview2.stype = Texture.STypes.CLD_DEFAULT elif mnuType2.val == 3: #Marble texPreview2.stype = Texture.STypes.MBL_SOFT elif mnuType2.val == 11: #Musgrave texPreview2.stype = mnuFractal2.val else: #Voronoi texPreview2.stype = Texture.STypes.VN_INT texPreview2.noiseSize = 1.0 texPreview2.brightness = sldBrightness2.val texPreview2.contrast = sldContrast2.val texPreview2.noiseDepth = sldDepth2.val texPreview2.noiseBasis = mnuBasis2.val texPreview2.noiseBasis2 = mnuShape2.val texPreview2.turbulence = sldTurbulence2.val texPreview2.stype = mnuFractal2.val texPreview2.hFracDim = sldSmooth2.val texPreview2.iScale = sldIntens2.val texPreview2.lacunarity = sldLacu2.val texPreview2.octs = sldOctaves2.val texPreview2.distMetric = mnuMetric2.val if tglInvert2.val: if sldThreshold2.val < 0.01: texPreview2.colorband = [[1,1,1,1,0], [0,0,0,0,1]] else: texPreview2.colorband = [[1,1,1,1,0], [0,0,0,0,1.0 - sldThreshold2.val]] else: if sldThreshold2.val < 0.01: texPreview2.colorband = [[0,0,0,0,0],[1,1,1,1,1]] else: texPreview2.colorband = [[0,0,0,0,sldThreshold2.val],[1,1,1,1,1]] if tglFlipXY2.val: texPreview2.flags = Texture.Flags.FLIPBLEND | Texture.Flags.COLORBAND else: texPreview2.flags = Texture.Flags.COLORBAND def loadDefaultPreset(numPreset): #For loading built-in presets global texPreview1, texPreview2, pixPreview, strPreset global sldResolution, tglColorband, colDark1, colDark2, mnuMode, sldZoom, mnuBasis1, sldThreshold1, sldContrast1, sldBrightness1, sldSize1, mnuBasis2, sldThreshold2, sldContrast2, sldBrightness2, sldSize2, sldBillboardSize, sldPreview if numPreset == 1: #Cirrus mnuMode.val = 4 sldPreview.val = 1 sldResolution.val = 0.5 sldZoom.val = 1.0 tglColorband.val = False colDark1.val = (0.5,0.5,0.5) colDark2.val = (1.0,1.0,1.0) mnuType1.val = 1 sldSize1.val = 0.5 sldBrightness1.val = 0.00 sldContrast1.val = 1.77 sldThreshold1.val = 0.0 mnuBasis1.val = 6 sldDepth1.val = 2 tglInvert1.val = 0 mnuType2.val = 1 sldSize2.val = 2.5 sldBrightness2.val = 0.71 sldContrast2.val = 1.31 sldThreshold2.val = 0.00 mnuBasis2.val = 0 sldDepth2.val = 2 tglInvert1.val = 0 strPreset = ['Cirrus clouds are thin and wispy. For best','results use a thin bounding object and erase','the tracking object on the Billboards tab.',''] elif numPreset == 2: #Cumulus mnuMode.val = 5 sldPreview.val = 3 sldResolution.val = 1.0 sldZoom.val = 1.0 tglColorband.val = True colDark1.val = (0.15,0.15,0.15) colDark2.val = (0.868,0.868,0.868) mnuType1.val = 1 sldSize1.val = 4.00 sldBrightness1.val = 0.93 sldContrast1.val = 5.0 sldThreshold1.val = 0.75 mnuBasis1.val = 0 sldDepth1.val = 6 tglInvert1.val = 0 mnuType2.val = 1 sldSize2.val = 3.45 sldBrightness2.val = 0.87 sldContrast2.val = 4.13 sldThreshold2.val = 0.00 mnuBasis2.val = 0 sldDepth2.val = 6 tglInvert2.val = 0 strPreset = ['Cumulus clouds usually have a puffy cotton-','like appearance.','',''] elif numPreset == 3: #Mammatus mnuMode.val = 5 sldPreview.val = 3 sldResolution.val = 1.0 sldZoom.val = 1.0 tglColorband.val = True colDark1.val = (0.1,0.1,0.1) colDark2.val = (0.8,0.8,0.8) mnuType1.val = 12 sldSize1.val = 4.00 sldBrightness1.val = 1.06 sldContrast1.val = 1.01 sldThreshold1.val = .15 mnuMetric1.val = 0 sldIntens1.val = 1 tglInvert1.val = 1 mnuType2.val = 1 sldSize2.val = 2.73 sldBrightness2.val = 1.37 sldContrast2.val = 1.0 sldThreshold2.val = 0.00 mnuBasis2.val = 0 sldDepth2.val = 1 tglInvert2.val = 0 strPreset = ['Mammatus clouds have large bumps on their','under side. They generally are overcast.','',''] elif numPreset == 4: #Nimbus mnuMode.val = 5 sldPreview.val = 2 sldResolution.val = 1.5 sldZoom.val = 1.0 tglColorband.val = True colDark1.val = (0.1,0.1,0.1) colDark2.val = (1.0,1.0,1.0) mnuType1.val = 1 sldSize1.val = 10.00 sldBrightness1.val = 1.13 sldContrast1.val = 5.0 sldThreshold1.val = 0.75 sldDepth1.val = 5 tglInvert1.val = 0 mnuType2.val = 11 sldSize2.val = 2.0 sldBrightness2.val = 1.0 sldContrast2.val = 1.0 sldThreshold2.val = 0.00 mnuBasis2.val = 0 mnuFractal1.val = 0 sldIntens2.val = 0.92 sldLacu2.val = 2.0 sldSmooth2.val = 0.99 sldOctaves2.val = 3.35 tglInvert2.val = 0 strPreset = ['Nimbus clouds are also known as rain clouds.','They are generally large and low to the ground.','',''] elif numPreset == 5: #Stratus mnuMode.val = 4 sldPreview.val = 1 sldResolution.val = 1.5 sldZoom.val = 2.0 tglColorband.val = False mnuType1.val = 3 sldSize1.val = 1.0 sldBrightness1.val = 1.01 sldContrast1.val = 0.74 sldThreshold1.val = 0 mnuBasis1.val = 0 mnuShape1.val = 0 sldTurbulence1.val = 7.87 tglInvert1.val = 0 mnuType2.val = 5 sldSize2.val = 2.0 sldBrightness2.val = 0.73 sldContrast2.val = 1.0 sldThreshold2.val = 0.00 mnuBlend2.val = 0 tglInvert2.val = 0 strPreset = ['Stratus clouds, like Cirrus, often found at high','altitude. They are mainly composed of ice','crystals. Use a thin bounding object and','erase the tracking object on the Billboards tab.'] elif numPreset == 6: #Streaks mnuMode.val = 5 sldPreview.val = 1 sldResolution.val = 1.5 sldZoom.val = 1 tglColorband.val = False mnuType1.val = 1 sldSize1.val = 1.7 sldBrightness1.val = 1.02 sldContrast1.val = 1.70 sldThreshold1.val = 0.25 mnuBasis1.val = 0 sldDepth1.val = 6 tglInvert1.val = 0 mnuType2.val = 3 sldSize2.val = 3.33 sldBrightness2.val = 0.74 sldContrast2.val = 3.18 sldThreshold2.val = 0.00 mnuBasis2.val = 0 sldDepth2.val = 5 tglInvert2.val = 0 sldTurbulence2.val = 9.72 strPreset = ['These streaking clouds follow the same rules as','Stratus. Use a thin bounding object and','erase the tracking object on the Billboards tab.',''] sldBillboardSize.val = (1.0/sldResolution.val) * 1.35 #Assign values to textures buildTextures() #Render the previews if tglPreview.val: renderPreview() Window.Redraw(Window.Types.SCRIPT) def renderHeader(x, y, w, h, texture): #Render a unique header to texture memory so that it draws quickly DrawPreview (x-1, y, x+w+1, y-h-1, 7, 1, [.2,.2,.2], [.9,.9,.9], 1, texture, texture, 10, 0, False, 5, 0, False, 1, int((random() - .5) * 1000),int((random() - .5) * 1000)) Image(loadHeaderText(),w/2-112,y-23) glRasterPos2f(x, y-h) offset = Buffer(GL_INT, [4]) glGetIntegerv(GL_CURRENT_RASTER_POSITION,offset) pixels = Buffer(GL_BYTE, [w, h, 3]) glReadPixels(offset[0], offset[1], w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels) return pixels def renderPreview(): #Render the noise preview to texture memory so that it draws quickly #This function is executed every time the user makes a change to a noise variable global guiw, guih, sldPreview, mnuMode, colDark1, colDark2, tglColorband, tglTexture1, texPreview1, texPreview2, sldSize1, sldThreshold1, sldSize2, sldThreshold2, sldZoom, blnFirstRun, sldDepth1, sldDepth2, tglInvert1, tglInvert2, pixPreview x = guiw /2 + 2 y = guih - 242 w = guiw /2 - 4 h = 74 DrawPreview (x, y, x+w, y-h, (sldPreview.val - 1) * 3 + 1, mnuMode.val, colDark1.val, colDark2.val, tglColorband.val, texPreview1, texPreview2, sldSize1.val, sldThreshold1.val, tglInvert1.val, sldSize2.val, sldThreshold2.val, tglInvert2.val, sldZoom.val, 0, 0) glRasterPos2f(x-1, y-h) offset = Buffer(GL_INT, [4]) glGetIntegerv(GL_CURRENT_RASTER_POSITION,offset) #For some reason the offset is off by 1 pixel when this is ran before the window is created if blnFirstRun: offset[0]+=1 blnFirstRun = False pixels = Buffer(GL_BYTE, [w+1, h, 3]) glReadPixels(offset[0], offset[1], w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels) pixPreview = pixels def loadHeaderText(): #Loads the Hex string, imgHeader, and transforms it into the bold text "Alan's Cloud Generator" #I had to do it this way because there are no access to fonts in BGL global imgHeader try: img = Blender.Image.Get('CloudGenHeaderText') except: img = Blender.Image.New('CloudGenHeaderText', 224, (len(imgHeader)*4)/224 -1, 24) z = -1 for y in range(0,len(imgHeader)-56, 56): bitmask = hex2bin(imgHeader[y:y+56]) z+=1 for x in range(len(bitmask)): if bitmask[x] == '0': img.setPixelF(x,z,(0,0,0,0)) return img def hex2bin(chars): #Decodes imgHeader, a black and white bmp which spells out "Alan's Cloud Generator" retVal = '' for char in chars: if char == '0': retVal += '0000' if char == '1': retVal += '0001' if char == '2': retVal += '0010' if char == '3': retVal += '0011' if char == '4': retVal += '0100' if char == '5': retVal += '0101' if char == '6': retVal += '0110' if char == '7': retVal += '0111' if char == '8': retVal += '1000' if char == '9': retVal += '1001' if char == 'A': retVal += '1010' if char == 'B': retVal += '1011' if char == 'C': retVal += '1100' if char == 'D': retVal += '1101' if char == 'E': retVal += '1110' if char == 'F': retVal += '1111' return retVal def DrawGradient(x1, y1, x2, y2, col1, col2): #Draws the gradient (colorband) control glColor3i(0,0,0) #Border glRecti(x1, y1, x2, y2) if x2 < x1: temp = x2 x2 = x1 x1 = temp if y2 < y1: temp = y2 y2 = y1 y1 = temp x1 += 1 x2 -= 1 y1 += 1 y2 -= 1 dist = abs(x2 - x1) dr = (col1[0] - col2[0]) / dist dg = (col1[1] - col2[1]) / dist db = (col1[2] - col2[2]) / dist for x in range(dist): glColor3f(col1[0] - (dr*x),col1[1] - (dg*x),col1[2] - (db*x)) glRecti(x + x1, y1, x + x1 + 1, y2) def DrawPreview (x1, y1, x2, y2, depth, mode, col1, col2, useDark, tex1, tex2, size1, thresh1, invert1, size2, thresh2, invert2, zoom, ofsx, ofsy): #This function is only called by RenderPreview, and is the function that draws the preview pixel-by-pixel glColor3i(0,0,0) #Border glRecti(x1,y1,x2,y2) if x2 < x1: temp = x2 x2 = x1 x1 = temp if y2 < y1: temp = y2 y2 = y1 y1 = temp x1 += 1 x2 -= 1 y1 += 1 y2 -= 1 xc = (x1 + x2) / 2 yc = (y1 + y2) / 2 dr = col2[0] - col1[0] dg = col2[1] - col1[1] db = col2[2] - col1[2] glColor3f(0.057, 0.221, 0.400) #Sky color glRecti(x1,y1,x2,y2) glEnable(GL_BLEND) for z in range(depth): if useDark: if depth ==1: percent = 1 else: percent = float(z) / float(depth-1) red = percent * dr + col1[0] green = percent * dg + col1[1] blue = percent * db + col1[2] else: red = 1 green = 1 blue = 1 for x in range(x1, x2): for y in range(y1, y2): sample1 = Vector((x-xc)/(10.0 * size1 * zoom)+ofsx, (y-yc-z/2.0)/(10.0 * size1 * zoom)+ofsy, z/(10.0 * size1 * zoom)) alpha1 = tex1.evaluate(sample1)[3] if invert1: alpha1 = 1.0 - alpha1 if alpha1 < thresh1: alpha1 = 0 else: alpha1 = (alpha1 - thresh1)/(1 - thresh1) if mode == 1: #Tex1 Only alpha = alpha1 else: sample2 = Vector((x-xc)/(10.0 * size2 * zoom)+ofsx, (y-yc-z/2.0)/(10.0 * size2 * zoom)+ofsy, z/(10.0 * size2 * zoom)) alpha2 = tex2.evaluate(sample2)[3] if invert2: alpha2 = 1.0 - alpha2 if alpha2 < thresh2: alpha2 = 0 else: alpha2 = (alpha2 - thresh2)/(1 - thresh2) alpha = mixSamples(alpha1, alpha2, mode) glColor4f(red,green,blue,alpha) glRecti(x, y, x + 1, y + 1) def objectExists(objName): #Returns True if objName is the name of an existing Blender Object, otherwise False try: obj = Object.Get(objName) return True except: return False def deleteObject(objName): #Unlinks (Deletes) the Blender Object with the name objName if objectExists(objName): scn = Scene.GetCurrent() scn.objects.unlink(Object.Get(objName)) def delBillboards(prefix): length = len(prefix) if length > 0: scn = Scene.GetCurrent() for ob in scn.objects: if len(ob.name) >= length: if ob.name[0:length] == prefix: scn.objects.unlink(ob) Window.Redraw(Window.Types.VIEW3D) def createBoundingObject(): #Creates a boundingbox cube at the 3D cursor's location global txtBounds scn = Scene.GetCurrent() me = Mesh.Primitives.Cube(2.0) ob = scn.objects.new(me,'Bounds') ob.drawType = Object.DrawTypes.WIRE ob.loc = Window.GetCursorPos() txtBounds.val = ob.getName() def getMaxBounds(boundsName): #Determines the minimum and maximum corners in a Blender.Object.boundingBox boundsObj = Object.Get(boundsName).boundingBox bounds = [[boundsObj[0].x,boundsObj[0].y,boundsObj[0].z],[boundsObj[0].x,boundsObj[0].y,boundsObj[0].z]] for i in range(1,8): for n in range(3): if bounds[0][n] > boundsObj[i][n]: bounds[0][n] = boundsObj[i][n] if bounds[1][n] < boundsObj[i][n]: bounds[1][n] = boundsObj[i][n] return bounds def mixSamples(sample1, sample2, mixmode): #Mixes two float values together with a mixmode operator (mnuMode.val) if mixmode == 1: #First Only return sample1 if mixmode == 2: #First Only return sample2 elif mixmode == 3: #Add return sample1 + sample2 elif mixmode == 4: #Subtract return sample1 - sample2 elif mixmode == 5: #Multiply return sample1 * sample2 elif mixmode == 6: #Divide try: return sample1 / sample2 except: return 1.0 else: #Difference if sample1 < sample2 : return sample2 - sample1 else: return sample1 - sample2 def createPoints(boundingObject, baseName, resolution, jitter, tex1, size1, threshold1, invert1, tex2, size2, threshold2, invert2, zoom, mixmode, hull): #This is the function that sparked the whole project! It evaluates multiple points in space and determines if a point should be created depending on the value returned from a 3D Procedural Texture scn = Scene.GetCurrent() scale = 1000.0 point = [0.0,0.0,0.0] coords = [] meshExists = False meshName = baseName + 'Preview' editmode = Window.EditMode() if editmode: Window.EditMode(0) #Bounding Object's boundingbox (worldspace) center = boundingObject.getLocation('worldspace') bounds = getMaxBounds(boundingObject.getName()) for i in range(2): for n in range(3): bounds[i][n] += (resolution / 2.0) - center[n] bounds = [tuple([x*scale for x in bounds[0]]),tuple([x*scale for x in bounds[1]])] step = int(resolution * scale) timer = time.time() Window.DrawProgressBar (0.0, 'Creating...') if hull: #Bounding Object's Mesh (worldspace) meshBOrig = boundingObject.getData(False,True) meshBO = meshBOrig.__copy__() meshBO.transform(boundingObject.getMatrix(), True, False) for x in range(int(bounds[0][0]), int(bounds[1][0] - step / 2), step): Window.DrawProgressBar (1-((bounds[1][0] - x)/(bounds[1][0] - bounds[0][0])), 'Creating...') for y in range(int(bounds[0][1]), int(bounds[1][1] - step / 2), step): for z in range(int(bounds[0][2]), int(bounds[1][2] - step / 2), step): point = [x/scale,y/scale,z/scale] worldvec = Vector(point[0], point[1],point[2]) if meshBO.pointInside(worldvec): vec = Vector(point[0]/(size1 * zoom), point[1]/(size1 * zoom), point[2]/(size1 * zoom)) sample1 = tex1.evaluate(vec)[3] if invert1: sample1 = 1.0 - sample1 if sample1 < threshold1: sample1 = 0 if mixmode == 1: #Tex1 Only sample = sample1 else: #Mix Tex1 and Tex2 vec = Vector(point[0]/(size2 * zoom), point[1]/(size2 * zoom), point[2]/(size2 * zoom)) sample2 = tex2.evaluate(vec)[3] if invert2: sample2 = 1.0 - sample2 if sample2 < threshold2: sample2 = 0 sample = mixSamples(sample1, sample2, mixmode) if sample > 0: jitterpoint = [ point[0] + ((random()-.5) * resolution * jitter), point[1] + ((random()-.5) * resolution * jitter), point[2] + ((random()-.5) * resolution * jitter)] coords.extend([jitterpoint]) else: for x in range(int(bounds[0][0]), int(bounds[1][0] - step / 2), step): Window.DrawProgressBar (1-((bounds[1][0] - x)/(bounds[1][0] - bounds[0][0])), 'Creating...') for y in range(int(bounds[0][1]), int(bounds[1][1] - step / 2), step): for z in range(int(bounds[0][2]), int(bounds[1][2] - step / 2), step): point = [x/scale,y/scale,z/scale] vec = Vector(point[0]/(size1 * zoom), point[1]/(size1 * zoom), point[2]/(size1 * zoom)) sample1 = tex1.evaluate(vec)[3] if invert1: sample1 = 1.0 - sample1 if sample1 < threshold1: sample1 = 0 if mixmode == 1: #Tex1 Only sample = sample1 else: #Mix Tex1 and Tex2 vec = Vector(point[0]/(size2 * zoom), point[1]/(size2 * zoom), point[2]/(size2 * zoom)) sample2 = tex2.evaluate(vec)[3] if invert2: sample2 = 1.0 - sample2 if sample2 < threshold2: sample2 = 0 sample = mixSamples(sample1, sample2, mixmode) if sample > 0: jitterpoint = [ point[0] + ((random()-.5) * resolution * jitter), point[1] + ((random()-.5) * resolution * jitter), point[2] + ((random()-.5) * resolution * jitter)] coords.extend([jitterpoint]) try: CloudPreview = Mesh.Get(meshName) CloudPreview.verts.delete(CloudPreview.verts) meshExists = True except: CloudPreview = Mesh.New(meshName) Window.DrawProgressBar (1.0, '') CloudPreview.verts.extend(coords) if meshExists: CloudPreview.update() try: ob = Object.Get(meshName) try: scn.link(ob) except: meshExists = True except: ob = scn.objects.new(CloudPreview, meshName) else: ob = scn.objects.new(CloudPreview, meshName) origlayers = ob.layers ob.layers = [scn.getLayers()[0]] ob.setLocation(center[0],center[1],center[2]) ob.layers = origlayers print "cloudgen:", round(time.time() - timer,3), "seconds" def createEmpties(baseName, boundingObject, EmptyLayers): #Creates the Darkening and Translation empties so that the Textures are mapped correctly global mtTranslate, mtDarkening bounds = getMaxBounds(boundingObject) boundsObj = Object.Get(boundingObject) #Translation handle try: mtTranslate = Object.Get(baseName + 'Translate') except: mtTranslate = scn.objects.new('Empty',baseName + 'Translate') #We have to set the handles' layer to one of the active layers to change its location to draw correctly #After we're done translating, then we move it to the destination layer below mtTranslate.layers = [scn.getLayers()[0]] mtTranslate.setLocation(boundsObj.getLocation('worldspace')) mtTranslate.setSize(1,1,1) mtTranslate.drawMode = Object.DrawModes.XRAY | Object.DrawModes.NAME #Darkening handle try: mtDarkening = Object.Get(baseName + 'Darkening') except: mtDarkening = scn.objects.new('Empty',baseName + 'Darkening') mtDarkening.layers = [scn.getLayers()[0]] mtDarkening.setLocation(((bounds[0][0] + bounds[1][0])/2.0, (bounds[0][1] + bounds[1][1])/2.0, bounds[0][2])) mtDarkening.setSize(1,1,bounds[1][2] - bounds[0][2]) mtDarkening.drawMode = Object.DrawModes.XRAY | Object.DrawModes.NAME #For some reason you MUST add both empties and makeDisplayList() on a current layer before setting eithers' destination layers! mtTranslate.makeDisplayList() mtDarkening.makeDisplayList() mtTranslate.layers = EmptyLayers mtDarkening.layers = EmptyLayers def createMaterials (strName, tex1, size1, threshold1, tex2, size2, threshold2, zoom, blnColorband, col1, col2, mixmode, objTrans, objDark): #This creates the renderable materials which are applied to the billboards. ################### #Material ################### mat = Material.New(strName) mat.setRGBCol([0.5,0.5,0.5]) mat.setRef(1.0) mat.setSpec(0.0) mat.setAlpha(0.0) mat.setTranslucency(1.0) mat.setSpecTransp(0.0) mat.mode = Material.Modes.ZTRANSP | Material.Modes.SHADELESS if not mixmode == 2: ################### #Texture - Cloud Shape 1 ################### texShape1 = Texture.New(strName + '_Shape') texShape1.type = tex1.type texShape1.stype = tex1.stype texShape1.noiseSize = 1.0 texShape1.colorband = tex1.colorband texShape1.flags = tex1.flags texShape1.brightness = tex1.brightness texShape1.contrast = tex1.contrast texShape1.noiseDepth = tex1.noiseDepth texShape1.noiseBasis = tex1.noiseBasis texShape1.noiseBasis2 = tex1.noiseBasis2 texShape1.turbulence = tex1.turbulence texShape1.lacunarity = tex1.lacunarity texShape1.hFracDim = tex1.hFracDim texShape1.iScale = tex1.iScale texShape1.octs = tex1.octs texPreview2.noiseSize = 1.0 texShape1.distMetric = tex1.distMetric mat.setTexture(0, texShape1) texOptions = mat.getTextures()[0] texOptions.mapto = Texture.MapTo.COL | Texture.MapTo.ALPHA texOptions.colfac = 0.1 texOptions.object = objTrans texOptions.texco = Texture.TexCo.OBJECT texOptions.size = (1.0 / (size1 * zoom), 1.0 / (size1 * zoom), 1.0 / (size1 * zoom)) if not mixmode == 1: ################### #Texture - Cloud Shape 2 ################### texShape2 = Texture.New(strName + '_Shape') texShape2.type = tex2.type texShape2.stype = tex2.stype texShape2.noiseSize = 1.0 texShape2.colorband = tex2.colorband texShape2.flags = tex2.flags texShape2.brightness = tex2.brightness texShape2.contrast = tex2.contrast texShape2.noiseDepth = tex2.noiseDepth texShape2.noiseBasis = tex2.noiseBasis texShape2.noiseBasis2 = tex2.noiseBasis2 texShape2.turbulence = tex2.turbulence texShape2.lacunarity = tex2.lacunarity texShape2.hFracDim = tex2.hFracDim texShape2.iScale = tex2.iScale texShape2.octs = tex2.octs texShape2.distMetric = tex2.distMetric mat.setTexture(1, texShape2) texOptions = mat.getTextures()[1] if mixmode == 3: texOptions.blendmode = Texture.BlendModes.ADD elif mixmode == 4: texOptions.blendmode = Texture.BlendModes.SUBTRACT elif mixmode == 5: texOptions.blendmode = Texture.BlendModes.MULTIPLY elif mixmode == 6: texOptions.blendmode = Texture.BlendModes.DIVIDE elif mixmode == 7: texOptions.blendmode = Texture.BlendModes.DIFFERENCE texOptions.mapto = Texture.MapTo.COL | Texture.MapTo.ALPHA texOptions.colfac = 0.1 texOptions.object = objTrans texOptions.texco = Texture.TexCo.OBJECT texOptions.size = (1.0 / (size2 * zoom), 1.0 / (size2 * zoom), 1.0 / (size2 * zoom)) ################### #Texture - Cloud Darkening ################### if blnColorband: texColor = Texture.New(strName + '_Darkening') texColor.type = Texture.Types.BLEND texColor.setImageFlags('Rot90') texColor.colorband = [[col1[0],col1[1],col1[2],1,0],[col2[0],col2[1],col2[2],1,1]] texColor.flags = Texture.Flags.COLORBAND mat.setTexture(2, texColor) texOptions = mat.getTextures()[2] texOptions.blendmode = Texture.BlendModes.MULTIPLY texOptions.object = objDark texOptions.mapto = Texture.MapTo.COL texOptions.texco = Texture.TexCo.OBJECT texOptions.xproj = Texture.Proj.Z texOptions.yproj = Texture.Proj.Z texOptions.zproj = Texture.Proj.Z ################### #Texture - Ease ################### texEase = Texture.New(strName + '_Ease') texEase.type = Texture.Types.BLEND texEase.colorband = [[0,0,0,0,0],[1,1,1,1,1-threshold1]] texEase.flags = Texture.Flags.COLORBAND texEase.setSType('BlendSphere') mat.setTexture(3, texEase) texOptions = mat.getTextures()[3] texOptions.blendmode = Texture.BlendModes.MULTIPLY texOptions.mapto = Texture.MapTo.ALPHA return mat def createPlanes(points, scale, track, material, baseName, boundingName, BillboardLayers): #Creates the billboards, and sets up TrackTo constraints if necessary editmode = Window.EditMode() if editmode: Window.EditMode(0) if objectExists(track): trackobj = Object.Get(track) blnTrack = True else: blnTrack = False Window.DrawProgressBar (0.0, 'Creating...') scn = Scene.GetCurrent() pointcloudobj = Object.Get(points) pointcloud = pointcloudobj.getData(False, True).verts boundingobj = Object.Get(boundingName) center = boundingobj.getLocation('worldspace') #Generic Cloud Plane coords=[[-scale,scale,0], [scale,scale,0], [scale,-scale,0], [-scale,-scale,0]] faces= [[0,1,2,3]] cloudplane = Mesh.New(baseName + 'plane') cloudplane.verts.extend(coords) cloudplane.faces.extend(faces) cloudplane.materials += [material] Window.DrawProgressBar (0.5, 'Creating...') timer = time.time() obs = [] #Loop through current object's vertices and add planes for v in range(len(pointcloud)): #MUCH faster to create an array of unlinked objects instead of using scn.objects.new and then append them all at once! ob = Object.New('Mesh', baseName + 'plane') ob.layers = [scn.getLayers()[0]] ob.link(cloudplane) ob.setLocation (pointcloud[v].co[0] + center[0],pointcloud[v].co[1] + center[1] ,pointcloud[v].co[2] + center[2]) ob.layers = BillboardLayers #Camera Tracking if blnTrack: trackto = ob.constraints.append(Constraint.Type.TRACKTO) trackto[Constraint.Settings.TARGET] = trackobj trackto[Constraint.Settings.TRACK] = Constraint.Settings.TRACKNEGZ trackto[Constraint.Settings.UP] = Constraint.Settings.UPY obs.append(ob) Window.DrawProgressBar (0.9, 'Linking...') for ob in obs: scn.link(ob) print len(pointcloud),'planes created in', round(time.time() - timer,3), "seconds" Window.DrawProgressBar (1.0, '') #This is where the script starts, declaring variables for each section of the interface ################## #Bounds ################## try: bounds = Object.GetSelected()[0] if bounds.getType() == 'Mesh': boundsName = Object.GetSelected()[0].getName() else: boundsName = '' except: boundsName = '' txtBounds = Create(boundsName) txtCloudName = Create('MyClouds') mnuPreset = Create(0) tglPreview = Create(1) tglHull = Create(0) strBounds1 = 'The Bounding Object is the name of a Blender' strBounds2 = 'Object that defines a cube-shaped region where' strBounds3 = 'clouds will be generated. If you leave this blank' strBounds4 = 'and press [Assign], one will be created for you.' strPreset = ['','','',''] ################## #Shape ################## tglColorband = Create(1) colDark1 = Create(0.5,0.5,0.5) colDark2 = Create(1.0,1.0,1.0) tglTexture1 = Create(1) tglTexture2 = Create(0) mnuMode = Create(1) sldSize1 = Create(2.0) sldBrightness1 = Create(0.1) sldContrast1 = Create(5.0) sldThreshold1 = Create(0.0) mnuBasis1 = Create(0) sldDepth1 = Create(5) mnuType1 = Create(1) mnuBlend1 = Create(0) tglFlipXY1 = Create(0) mnuShape1 = Create(0) sldTurbulence1 = Create(5.0) mnuFractal1 = Create(0) sldSmooth1 = Create(0.33) sldLacu1 = Create(2.0) sldOctaves1 = Create(3.0) sldIntens1 = Create(0.5) mnuMetric1 = Create(0) tglInvert1 = Create(0) sldSize2 = Create(2.0) sldBrightness2 = Create(0.1) sldContrast2 = Create(5.0) sldThreshold2 = Create(0.0) mnuBasis2 = Create(0) sldDepth2 = Create(5) mnuType2 = Create(1) mnuBlend2 = Create(0) tglFlipXY2 = Create(0) mnuShape2 = Create(0) sldTurbulence2 = Create(5.0) mnuFractal2 = Create(0) sldSmooth2 = Create(0.33) sldLacu2 = Create(2.0) sldOctaves2 = Create(3.0) sldIntens2 = Create(0.5) mnuMetric2 = Create(0) tglInvert2 = Create(0) sldJitter = Create(1.0) sldResolution = Create(1.0) sldZoom = Create(1.0) sldPreview = Create(1) #Create preview textures and header try: texPreview1 = Texture.Get('Preview1') except: texPreview1 = Texture.New('Preview1') try: texPreview2 = Texture.Get('Preview2') except: texPreview2 = Texture.New('Preview2') buildTextures() try: texHeader = Texture.Get('Header') except: texHeader = Texture.New('Header') texHeader.type = Texture.Types.CLOUDS texHeader.noiseSize = 1.0 texHeader.noiseDepth = 5 texHeader.brightness = 1.0 texHeader.contrast = 4.0 texHeader.noiseBasis = 0 strShape1 = 'The Shape of the clouds are represented as a' strShape2 = 'grid of points within the Bounding Object. The' strShape3 = 'points are drawn in localspace. Edit the Bounding' strShape4 = 'Object\'s vertices to change the region of interest.' ################## #Billboards ################## sldBillboardSize = Create(1.350) scn = Scene.GetCurrent() try: cameraName = scn.objects.camera.getName() except: cameraName = '' txtTracking = Create(cameraName) strBillboard1 = 'Billboards are textured planes that always face' strBillboard2 = 'the camera. These replace the points from the' strBillboard3 = 'previous step. You can later adjust the size of' strBillboard4 = 'all planes by resizing any plane from edit mode.' ################## #General ################## guiw = 280 guih = 490 togw = guiw/3 mtTranslate = '' mtDarkening = '' tglBounds = Create(1) tglShape = Create(0) tglBillboards = Create(0) EmptyLayers = [2] BillboardLayers = [1] blnFirstRun = True strLine1 = strBounds1 strLine2 = strBounds2 strLine3 = strBounds3 strLine4 = strBounds4 #imgHeader contains the Hex values that represent the image-text "Alan's Cloud Generator". Each character represents 4 black & white pixels. imgHeader = 'F03CE0CE38E078000F0E0701CE0738007C01E1C701E1C067070701C07038E1FE38E0FE007F8E1FC3FE1FF807FF0FF1C70FF1C0FF0F1FC1C07078E39E38E08701F08E38E79E1C780F870F11C70F11C1CF1E38E1C07878E38E38E00701C00E70F70E38380F071C01C71C01C1C71C70F1C03FF0E3CE38E03F03C00E70770E38381E071FF9C71FF9C1E71C7071C03FF0E1FE38E07E03800E70770E38381C071FF9C71FF9C0FF1C7071C038F0E07E38E0FC03800E70770E38381C3F1C39C71C39C03F1C7071C03CF0E00E38E0E003800E70770E3C381C3F0C39C70C39C0071C7071C01CE0E11E3DE0E203800E38E70E1C781C000E71EF0E71E08F1C38E1E01CE0E1FC3FD87E03800E1FC70E1FF81C0007E1FE07E1F8FE3F1FC1F81DE0E070398C1F01C00E07070E07380E000181CC018198383F0701980FC0E000000C0001C00E00000000380F00000000000000001C0000000FC0E000000E0000F08E000000003807C2000000000000001C0000000FC0E000000E00007F8E000000003803FE00000000000000040000000780E000000700000F8E0000000038003D00000000000000000000000000E00000000000000E000000003800000000000000000000000000' texPreview1.brightness = 1.0 texPreview1.contrast = 4.0 pixHeader = renderHeader(0,guih,guiw,31, texPreview1) texPreview1.brightness = sldBrightness1.val texPreview1.contrast = sldContrast1.val renderPreview() ################## #Main Loop ################## Register(draw, event, bevent)