Page MenuHome

VegGen0_1_36.py

Authored By
Tom Trval (eiler)
Nov 13 2013, 4:34 PM
Size
59 KB
Subscribers
None

VegGen0_1_36.py

# -*- coding: utf-8 -*-
__author__="drake"
__date__ ="$Mar 5, 2012 1:02:27 AM$"
bl_info = {
"name": "VegGen",
"author": "Tom Trval (Ryū)",
"version": (0, 1, 36),
"blender": (2, 6, 0),
"location": "View3D > Add > Mesh > VegGen",
"description": "L-System based addon developed for generating trees and shrub mesh model",
"warning": "",
"wiki_url": "http://www.wix.com/eiler2/treegen",
"tracker_url": "http://www.wix.com/eiler2/treegen#!contact|c1et",
"category": "Add Mesh"}
import bpy
import copy
import random
import time
from bpy.props import IntProperty, BoolProperty, FloatProperty
from mathutils import Matrix as matrix, Vector
from math import acos as arccos, cos, sin, sqrt, pi, degrees, radians
from collections import deque
from fractions import *
##############################
#Data
class Spoj():
__slots__ = ('Poloha','Mlade','Stare')
def __init__ (self, x = 0, y = 0 ,z = 0):
'''Reprezentace bodu ve kterem se strom vetvi
:param x: souradnice na ose X v 3D prostoru
:type x: **Float**
:param y: souradnice na ose Y v 3D prostoru
:type y: **Float**
:param z: souradnice na ose Z v 3D prostoru
:type z: **Float**
'''
self.Poloha = [x,y,z]
self.Mlade = []
self.Stare = []
def __repr__ (self):
return "[%.2f,%.2f,%.2f]"% (self.Poloha[0], self.Poloha[1], self.Poloha[2])
def _unlinkSpoj(self):
for vetev in self.Mlade:
vetev.KeKmenuSpoj = None
for vetev in self.Stare:
vetev.OdKmenuSpoj = None
self.Mlade = None
self.Stare = None
self.Poloha = None
return
def toArray(self):
'''
prevede poluhu spoje na 4 rozmerny sloupcovi vektor
:rtype: **array** [ [**Number**], [**Number**], [**Number**], **1** ]
:return: sloupcovy vektor polohy
'''
return Vector([self.Poloha[0],self.Poloha[1],self.Poloha[2],1])
def ulozPoziciZeSloupcovehoVektoru(self, array):
self.Poloha[0],self.Poloha[1],self.Poloha[2] = array.xyz
return
def projdiMladsiSpoje (self, *ukazateleNaFunkce):
'''projdiMladeSpoje je rekurzivni funkce. Jejim vstupnim parametrem je jina funkce ktera bude provedena se vsemi mladsimi spoji, vcetne tohoto
:param ukazateleNaFunkce: mnozina ukazatelu Na Funkci, ktere dostanou jako parametr aktualni spoj
:type ukazateleNaFunkce: funkce ( **Spoj** )
'''
for funkce in ukazateleNaFunkce:
funkce(self)
for vetev in copy.copy(self.Mlade):
vetev.OdKmenuSpoj.projdiMladsiSpoje(*ukazateleNaFunkce)
return
def tiskStruktury (self):
"""Vzor visitor, slouzi k vytisknuti textove reprezentace stromu
"""
def tisk (vstup):
print (vstup)
return
self.projdiMladsiSpoje(tisk)
class Vetev():
__slots__ = ('KeKmenuSpoj','OdKmenuSpoj','_stupenIterace','_tloustka','_jsem_mrtva','_prepisovaciSymbol', 'Otoceni', 'ObrustaListy')
def __init__ (self, spoj_Ke_Kmenu, spoj_Od_Kmene, stupen_Iterace = 0 , tloustka = 0.1 , prepisovaci_Symbol = None , otoceni = 0.0, obrustaListy = False):
'''Reprezentace vetve v modelu stromu
:param spoj_Ke_Kmenu: spoj z ktereho vetev roste
:type spoj_Ke_Kmenu: **Spoj**
:param spoje_Od_Kmene: spoj kterym vetev konci, nebo se v nem na ni navazuji mladsi generace
:type spoje_Od_Kmene: **Spoj**
:param stupen_Iterace: v kolikate generaci byla vetev vytvorena
:type stupen_Iterace: **Int**
:param tloustka: pocatecni tloustka vetve
:type tloustka: **Float**
:param prepisovaci_Symbol: vetev se bude v dalsi generaci prepisovat timto pravidlem
:type prepisovaci_Symbol: **what ever u like**
:param otoceni: nove vetvicky vyrustaji z hlavni vetve ve spirale k tomu slouzi tento atribut
:type otoceni: **Float**
:param obrustaListy: vetev bude nebo nebude obrustat listim
:type obrustaListy: **Boolean**
'''
self.KeKmenuSpoj = spoj_Ke_Kmenu
spoj_Ke_Kmenu.Mlade += [self]
self.OdKmenuSpoj = spoj_Od_Kmene
spoj_Od_Kmene.Stare += [self]
self.Otoceni = otoceni % (2*pi)
self.ObrustaListy = obrustaListy
self._prepisovaciSymbol = prepisovaci_Symbol
self._stupenIterace = int(stupen_Iterace)
self._tloustka = float(tloustka)
self._jsem_mrtva = False
def __repr__ (self):
return " |%s %s| rek=%s, i=%s, mrtva=%s, tloustka =%s\n"% ( self.KeKmenuSpoj.__repr__(), self.OdKmenuSpoj.__repr__(), self._prepisovaciSymbol, self._stupenIterace, self._jsem_mrtva, self._tloustka )
def tiskStruktury (self):
"""Vzor visitor, slouzi k vytisknuti textove reprezentace stromu
"""
def tisk (vstup):
print( vstup)
return
self.projdiMladsiVetve(tisk)
def _unlinkVetev(self):
self.KeKmenuSpoj.Mlade.remove(self)
self.OdKmenuSpoj.Stare.remove(self)
self.KeKmenuSpoj = None
self.KeKmenuSpoj = None
return
def _unlinkVsechnyZavisleVetve(self):
for vetev in copy.copy(self.OdKmenuSpoj.Mlade):
vetev._unlinkVsechnyZavisleVetve()
self._unlinkVetev()
return
def projdiMladsiVetve (self, *ukazateleNaFunkce):
'''projdiMladsiVetve je rekurzivni funkce. Jejim vstupnim parametrem je jina funkce ktera bude provedena se vsemi mladsimi vetvemi, vcetne teto
:param ukazateleNaFunkce: ukazatel Na Funkci, ktera dostane jako parametr aktualni vetev, muze byt vlozeno vice funkci
:type ukazateleNaFunkce: funkce ( **Vetev** ),...
'''
for funkce in ukazateleNaFunkce:
funkce(self)
for vetev in copy.copy(self.OdKmenuSpoj.Mlade):
vetev.projdiMladsiVetve (*ukazateleNaFunkce)
return
def getVectorTuple(self):
"""Vyextrahuje s primky vector
:rtype: Tuple (**Number**, **Number**, **Number**)
:return: (x,y,z)
"""
return (
(self.OdKmenuSpoj.Poloha[0] -self.KeKmenuSpoj.Poloha[0]),
(self.OdKmenuSpoj.Poloha[1] -self.KeKmenuSpoj.Poloha[1]),
(self.OdKmenuSpoj.Poloha[2] -self.KeKmenuSpoj.Poloha[2])
)
def getBodNaVetvi(self,*parametry):
"""Vrati souradnice bodu C na vetvi dle: C = A + u * parametr; u = B - A
:param parametr: n-tina primky
:type parametr: **Float**
:rtype: Tuple (**Number**, **Number**, **Number**)
:return: poloha bodu dana souradnicemi **(x,y,z)**
note: lze zadat i vice parametru a pote se vrati pole, souradnic odpovidajicich jednotlivim parametrum
"""
A=self.KeKmenuSpoj.Poloha
u = self.getVectorTuple()
ret = None
if len(parametry)>1 :
ret = []
for parametr in parametry:
ret.append( ( A[0]+(u[0]*parametr), A[1]+(u[1]*parametr), A[2]+(u[2]*parametr) ) )
elif len(parametry) == 1:
parametr = parametry[0]
ret = ( A[0]+(u[0]*parametr), A[1]+(u[1]*parametr), A[2]+(u[2]*parametr) )
return ret
def getNorma(self, tupleVec):
""" Funkce vrati normu zadaneho vektoru napr.:\|(a,b)|=sqrt(a*a + b*b)
:param tupleVec: vektor ( x, y, ...)
:type tupleVec: Tuple ( **Number**, **Number**, ...)
:rtype: **Number**
:return: norma_vektoru
"""
suma=0.0
for i in tupleVec:
suma += float(i)**2
return sqrt( suma)
def uhel3D(self):
"""
Funkce zjisti veliksoti sin a cos pro natoceni teto primky tak aby byla rovnobezna s osou Z.
to se da ve 3D vzdy provest otocenim kolem 2 ze 3 os: 1.otoceni kolem Z 2.otoceni kolem Y
:rtype: [[**Number**, **Number**],[**Number**, **Number**]]
:return: [[sin_rotace_kolem_Z, cos_rotace_kolem_Z], [sin_rotace_kolem_Y, cos_rotace_kolem_Y]]
"""
x, y, z = self.getVectorTuple()
#print ('x,y,z:',(x,y,z))
if(x == 0 and y == 0):
if z > 0:#netusim jestli je spravne
return((0,1),(0,1))
elif z<0:#netusim jestli je spravne
return((0,1),(0,-1))
else:
return((0,1),(0,1))
norma_x_y = self.getNorma( (x, y) )
#print ('x,y,z, norma_x_y: ',(x,y,z,norma_x_y))
cos_rotace_kolem_Z = x / norma_x_y #prilehla / prepona
sin_rotace_kolem_Z = y / norma_x_y #(protilehla / prepona )
#sin_rotace_kolem_Z*=-1
# otoceni proti smeru puvodni rotace -> zmena znamenek ale pozor cosinus je suda funkce-> cos(-a)=cos(+a)
x1, y1, z1 = ( #vector_otoceny_do_XZ
(x*cos_rotace_kolem_Z) - (y*-sin_rotace_kolem_Z),
(x *- sin_rotace_kolem_Z) + (y * cos_rotace_kolem_Z),#muzeme rovnou napsat 0 <- (-xy +yx)/norma
z
)
#print(x1,y1,z1)
norma_x1_z1 = self.getNorma( (x1,z1) )
if norma_x1_z1 is 0:
raise Exception('problem norma_x1_z1=0')
cos_rotace_kolem_Y = z1 / norma_x1_z1 #prilehla / prepona
sin_rotace_kolem_Y = x1 / norma_x1_z1 #protilehla / prepona
sin_rotace_kolem_Y*=-1
#sin_rotace_kolem_Z*=-1
#;z1 = sqrt(3);x1 = 0;x2 = (x1*cos_rotace_kolem_Y) -(z1*sin_rotace_kolem_Y);y2 = 0;z2 = (x1 * sin_rotace_kolem_Y) + (z1 * cos_rotace_kolem_Y);print (x2,0,z2) ;x= (x2*cos_rotace_kolem_Z) - (y2*sin_rotace_kolem_Z);y= (x2 *sin_rotace_kolem_Z) + (y2 * cos_rotace_kolem_Z);z = z2;print (x, y, z)
return ((sin_rotace_kolem_Z, cos_rotace_kolem_Z),(sin_rotace_kolem_Y, cos_rotace_kolem_Y))
def getDelka(self):
"""
zjistim svoji delku
:rtype: **Number**
:return: delka_primky
"""
return self.getNorma(self.getVectorTuple())
class PrepisovaciPravidlo(object):
""" prepisovaci pravidlo fraktalu pro jedno oynaceni pravidla . Muze obsahovat vice pravidel s vahou pro nahodny vyber z nic
"""
__slots__ = ('Oznaceni','_spoj_vaha','_sumaVah','RidiciPrimka','OtoceniVetve')
def __init__(self, oznaceni, ridici_primka_pravidla, otoceniVetve, *spoj_vaha ):
"""
:param oznaceni: jak bude pravidlo oznaceno vehem prepisovani
:type oznaceni: What ever u like
:param ridici_primka_pravidla: znazornuje kde se v pravidle vyskytovala puvodni primka kterou pravidlem prepisujeme
:type ridici_primka_pravidla: **Vetev**
:param otoceniVetve: o kolik se vetev otoci kolem sve osy
:type otoceniVetve: **Float**
:param spoj_vaha: (zacatekPravidla, VahaPravidla); zacatekPravidla - je tvar kterym nahradime rostouci primku ;VahaPravidla cim vyssi vyhlede k ostatnim tim je pravdepobnejsi prepis timto tvarem
:type spoj_vaha: (**Spoj**,**Int**)
"""
self.Oznaceni = oznaceni
self.RidiciPrimka = ridici_primka_pravidla
self.OtoceniVetve = otoceniVetve
self._spoj_vaha = {}
self._sumaVah = 0
self.addMoznosti(*spoj_vaha)
def addMoznosti(self,*spoje_vahy):
"""
:param spoje_vahy: (zacatekPravidla, VahaPravidla)
:type spoje_vahy: (**Spoj**,**Int**)
example: .addMoznosti((Spoj(1,2,3),1))
note: pokud je vaha pravidla 0 nebude nikdy vybrano
"""
for spoj_vaha in spoje_vahy:
if len(spoj_vaha)==2:
self._sumaVah += spoj_vaha[1]
self._spoj_vaha[spoj_vaha[0]] = spoj_vaha[1]
return
def getPravidlo(self):
"""
:rtype: **Spoj**
:return: Zacatek vybraneho pravidla
"""
vaha = 0
counter =0
randNum = random.uniform(0,self._sumaVah)
for spoj in self._spoj_vaha:
vaha = self._spoj_vaha[spoj]
if vaha != 0:
counter+=vaha
if randNum <= counter:
return spoj
raise Exception('PrepisovaciPravidlo', 'nelze vybrat zadne pravidlo')
return None
#Data
##############################
#Logick
class Priroda (object):
def __init__ (self, koren = None, *prepisovaciPravidla):
"""Vykonavatel rustu
:param koren: tvar nulte iterace, na ktery se budou opakovane aplikovat pravidla
:type koren: **Spoj**
:param prepisovaciPravidla: aplikovanim tohoto pravidla na strom ziskame strom o jednu iteraci starsi
:type prepisovaciPravidla: **PrepisovaciPravidlo**
"""
self.Koren = koren
self.Pravidla = {}
for pravidlo in prepisovaciPravidla:
self.Pravidla[pravidlo.Oznaceni] = pravidlo
self._maxIterace = 0
# stochasticke promenne
self.set_stochasticke_promene()
return
def set_stochasticke_promene(self, randomScale = 0.2,
growHigh = 0.38,
randomEndpoint = 0.33,
extension = 0.62,
thickening = 0.18,
stopGrow = 0.05):
self.m_randomScale = float(randomScale) #flaot min 0 max 1 ////nahodna_zmena_scale
self.m_growHigh = float(growHigh) #float min 0 max 1 //// sila vektoru up
self.m_randomEndpoint = float(randomEndpoint) #float min 0 max 1////nahody_posun_koncovych_bodu
self.m_extension = float(extension) #float min 0 max 1 o kolik se strom vyroste za rok nepocitaje nove vetve ///prirustek_stromu_za_generaci_delka
self.m_thickening = float(thickening) #float min 0 max 1 o kolik se vetev ztloustne za rok ////prirustek_stromu_za_generaci_tloustka
self.m_stopGrow = float(stopGrow)
return
def fraktalizace (self, vetev):
"""
Nahradi vetev prepisovacim pravidlem
:param vetev: tato vetev bude nahrazena Pravidlem-> vetev vyroste o 1 generaci
:type vetev: **Vetev**
"""
if vetev._jsem_mrtva or (vetev._prepisovaciSymbol == None) or ( vetev._stupenIterace >= self._maxIterace) :
return
prepisovaciPravidlo = self.Pravidla[vetev._prepisovaciSymbol]
#maxOdchylka = min(50,70)
rotace_Z, rotace_Y = vetev.uhel3D()
delkaVetve = vetev.getDelka()
scale = delkaVetve / float(prepisovaciPravidlo.RidiciPrimka.getDelka())
tolerance = self.m_randomScale
roztazeni = (scale* random.uniform(1+tolerance, 1-tolerance),scale* random.uniform(1+tolerance, 1-tolerance),scale* random.uniform(1+tolerance, 1-tolerance))
vetSveOsy = (vetev.Otoceni + prepisovaciPravidlo.OtoceniVetve) % 2*pi
if vetSveOsy == 0 :
rotZ0 = None
else:
rotZ0 = (sin(vetSveOsy),cos(vetSveOsy))
maticeTransformaci = self.sestavTransformaciMatici(vetev.KeKmenuSpoj.Poloha, rotace_Z, rotace_Y, rotZ0, roztazeni)
nejmladsiSpoj_novaVetev = copy.deepcopy(prepisovaciPravidlo.getPravidlo())
#print ('\nZpracovavam vetev:',vetev)
#print 'sinZ,cosZ nsinY,cosY:\n',rotace_Z, rotace_Y
#print 'Transformacni matice:\n',maticeTransformaci
#print 'Vector: ',vetev.getVectorTuple()
def zmenIteraciAndOtoceni(vetev):
vetev._stupenIterace = self._maxIterace
vetev.Otoceni = vetSveOsy
return
for v in nejmladsiSpoj_novaVetev.Mlade:
v.projdiMladsiVetve(zmenIteraciAndOtoceni)
if v._prepisovaciSymbol == None:
v._stupenIterace = self._maxIterace-1
def nasobeni(spoj):
spoj.ulozPoziciZeSloupcovehoVektoru( maticeTransformaci * spoj.toArray() )
return
nejmladsiSpoj_novaVetev.projdiMladsiSpoje ( nasobeni )
napojovaciBod = vetev.KeKmenuSpoj
vetev._unlinkVetev() #python vetev znici po te co na ni nejsou zadne odkazi
poleVetvi = copy.copy(nejmladsiSpoj_novaVetev.Mlade)
#print ('Puvodni vetev zacatek:',napojovaciBod)
#print ('Nahrayujici vetev zacatek:',nejmladsiSpoj_novaVetev)
nejmladsiSpoj_novaVetev._unlinkSpoj()
# nyni propojime odkazi novou vetev(e) a stary spoj v obou smerech
napojovaciBod.Mlade += poleVetvi
for i in poleVetvi:
i.KeKmenuSpoj = napojovaciBod
return
def sestavTransformaciMatici (self, posun = (0,0,0), rotace_z2 = None, rotace_y = None,rotace_z1 = None, scale = None ):
"""
slouzi k preneseni vzoru ktery je na ose Z (0,0,1) na misto puvodni veteve ve stromu
aplikuje transformace v poradi scale, rotace Y, rotace Z, posun a vytvori z nich jednu transformacni matici
:param posun: ( posun po X, posun po Y, posun po Z)
:type posun: Tuple ( **Number**, **Number**, **Number** )
:param rotace_z2: ( **sinAlfa**, **cosAlfa** ) hodnoty sinu a cosinu uhlu rotace kolem osy Z
:type rotace_z: Tuple ( **Number**, **Number** )
:param rotace_y: (**sinAlfa**, **cosAlfa**) hodnoty sinu a cosinu uhlu rotace kolem osy Y
:type rotace_y: Tuple ( **Number**, **Number** )
:param rotace_z1: ( **sinAlfa**, **cosAlfa** ) hodnoty sinu a cosinu uhlu rotace kolem osy Z
:type rotace_z: Tuple ( **Number**, **Number** )
:param scale: (ScaleX, ScaleY, ScaleZ) zvetseni/zmenseni objektu ve smeru kazde s Os
:type scale: Tuple ( **Number**, **Number**, **Number** )
:return: jedna transformacni matice ktera provadi vsechny zadane zmeny
:rtype: **matrix 4x4**
"""
ret = matrix( [[1,0,0,posun[0]], [0,1,0,posun[1]], [0,0,1,posun[2]], [0,0,0,1]] )
if rotace_z2 is not None:
mRotaceZ2 = matrix( [[rotace_z2[1], -rotace_z2[0] ,0,0], [rotace_z2[0], rotace_z2[1],0,0], [0,0,1,0], [0,0,0,1]] )
ret= ret * mRotaceZ2
if rotace_y is not None:
mRotaceY = matrix( [[rotace_y[1], 0, -rotace_y[0],0], [0,1,0,0],[rotace_y[0], 0, rotace_y[1],0], [0,0,0,1]] )
ret= ret * mRotaceY
if rotace_z1 is not None:
mRotaceZ1 = matrix( [[rotace_z1[1], -rotace_z1[0] ,0,0], [rotace_z1[0], rotace_z1[1],0,0], [0,0,1,0], [0,0,0,1]] )
ret= ret * mRotaceZ1
if scale is not None:
mScale = matrix( [[scale[0],0,0,0], [0,scale[1],0,0], [0,0,scale[2],0], [0,0,0,1]] )
ret= ret * mScale
return ret
def rust (self, pocet_iteraci):
"""struktura stromu vyroste o dany pocet generaci
:param pocet_iteraci: pocet generacnich kroku o ktery strom vyroste
:type pocet_iteraci: **Int** >= 0
"""
pocet_iteraci = int(pocet_iteraci)
if 0 >= pocet_iteraci :
return
for i in range(1,pocet_iteraci+1):
self._maxIterace+=1
#print "provadim rust %d iterace. " %(self._maxIterace)
for vetev in self.Koren.Mlade:
vetev.projdiMladsiVetve(self.fraktalizace)
for vetev in self.Koren.Mlade:
vetev.projdiMladsiVetve(self._stochasticke_zmeny)
return
def _stochasticke_zmeny(self, vetev):
"""provadi na vetvi zmeny odpovidajici vlivum prirodnich deju
:param vetev: vetev ktera se bude menit
:type vetev: **Vetev**
"""
if not vetev._jsem_mrtva:
#relativni zmeny - jsou vztahovany na delku vetvu
'''
delka_predchozi = 0
if len(vetev.KeKmenuSpoj.Stare) > 0:
delka_predchozi = vetev.KeKmenuSpoj.Stare[0].getDelka()
delka_vetve = ( delka_predchozi + vetev.getDelka() )*0.5
'''
delka_vetve = vetev.getDelka()
zmeny = []
#rust za svetlem= rust nahor v procentech, nutno prepocist na delku vetve
rozdil = self._maxIterace - vetev._stupenIterace
if rozdil == 0:
vysledna_sila_vektoru_up = self.m_growHigh
else:
vysledna_sila_vektoru_up = (self.m_growHigh / rozdil**2)
#stred roste rzchleji nahoru protoye ma mene svetla
#koren = self.Koren pokud neni koren na pozici 0,0,0
'''vysledna_vyska_koruny = 0.9 + vyska_koruny
vzdalenost_od_stredu = vetev.getNorma(vetev.OdKmenuSpoj.Poloha[:2])
if vzdalenost_od_stredu > 0:
vysledna_sila_vektoru_up = vysledna_sila_vektoru_up**(vysledna_vyska_koruny/vzdalenost_od_stredu**2)
else:
vysledna_sila_vektoru_up = vysledna_sila_vektoru_up**vysledna_vyska_koruny
'''
rustNahoru = (0,0,vysledna_sila_vektoru_up)
if self._maxIterace != 1:
zmeny.append(rustNahoru)
#nahodna zmena pozice koncoveho bodu nejmladsich vetvi
nahody_posun_koncovych_bodu = self.m_randomEndpoint
if len(vetev.OdKmenuSpoj.Mlade) == 0:
nahodna_zmena_pozice_bodu = ( random.uniform(+nahody_posun_koncovych_bodu,-nahody_posun_koncovych_bodu),
random.uniform(+nahody_posun_koncovych_bodu, -nahody_posun_koncovych_bodu),
random.uniform(+nahody_posun_koncovych_bodu, -nahody_posun_koncovych_bodu))
zmeny.append(nahodna_zmena_pozice_bodu)
#aplikace zmen
for zmena in zmeny:
vetev.OdKmenuSpoj.Poloha[0] += zmena[0]*delka_vetve
vetev.OdKmenuSpoj.Poloha[1] += zmena[1]*delka_vetve
vetev.OdKmenuSpoj.Poloha[2] += zmena[2]*delka_vetve
#absolutni zmeny - vztahovany na velikost stromu
absolut_prirustek_tloustka = 1.0 + self.m_thickening
vetev._tloustka *= absolut_prirustek_tloustka
absolut_prirustek_delka = 1.0 + self.m_extension
for index in range(len(vetev.OdKmenuSpoj.Poloha)):
vetev.OdKmenuSpoj.Poloha[index]*= absolut_prirustek_delka
if (len(vetev.OdKmenuSpoj.Mlade) == 0) and (random.random() < self.m_stopGrow):
vetev._jsem_mrtva = True
return
def uhel(sin,cos):
angle = arccos(cos)
if sin<0:
angle *=-1
return angle
#Logick
#######################################################
#Vizualizator
class ModelGen():
"Create tree model from data of class Priroda"
def __init__ (self, priroda, inicialThickness, levelOfDetails = 0.5, branchFaces=8, optimalizeModel = False, creatLeaves = False, scaleNaSpici = 0.9, notGrov = 0.15 ):
"""
:param priroda: Class Priroda is data source for visual output
:type priroda: **Priroda**
:param inicialThickness: Thickness of branch when its borned
:type inicialThickness: **Number**
:param levelOfDetails: Serve to calculate number of branch faces. Higher levelOfDetails-> more faces branch will have
:type levelOfDetails: **Number**
"""
self.upravaPriblizeniListuKVetvi = 1
self.mojePriroda = priroda
self.LOD = levelOfDetails
self.m_inicialThickness= inicialThickness
self.m_branchFaces = branchFaces
self.m_optimalizeModel = optimalizeModel
self.m_createLeaves = creatLeaves
self.m_scaleNaSpici = scaleNaSpici
self.m_notGrov = notGrov
def createLeaves(self, LeaveSize, LeavesSpacing ):
"""Create vertexes and faces of the leaves
:param LeaveSize: lenght of leaf edge
:type LeaveSize: **Number**
:param LeavesSpacing: distance betweeen neighboring leaves
:type LeavesSpacing: **Number**
:rtype: ( [ [ x, y, z ], .. ], [[ indxVert, indxVert, indxVert, indxVert],[ indxVert, indxVert, indxVert], .. ])
:return: (Vertexes, Faces) of leaves
"""
faces = []
verts = []
priroda = self.mojePriroda
topScal = self.m_scaleNaSpici
leaveMissing = self.m_notGrov
leaveSize = LeaveSize * 0.5
defaultLeave = ((0, +leaveSize),
(2*leaveSize, leaveSize),
(2*leaveSize, -leaveSize),
(0, -leaveSize),
)
"""defaultLeave = ((-leaveSize, +leaveSize),
(+leaveSize, +leaveSize),
(+leaveSize, -leaveSize),
(-leaveSize, -leaveSize),
)"""
vzdalenostListu = LeavesSpacing
stepRot = radians(75)
def turnBranchGreen(vetev):
if not vetev.ObrustaListy or vetev._jsem_mrtva:
return;
vzdalenostListu = max(vetev._tloustka * 3, 0.01)
(sinZ, cosZ), (sinY, cosY) = vetev.uhel3D()
tMat = priroda.sestavTransformaciMatici
tranMat = tMat (posun = vetev.KeKmenuSpoj.Poloha, rotace_z2 = (sinZ, cosZ), rotace_y = (sinY, cosY) )
delka = vetev.getDelka()
pocetListu = int(delka/vzdalenostListu)
#radius = leaveSize + vetev._tloustka*self.upravaPriblizeniListuKVetvi
radius = vetev._tloustka * self.upravaPriblizeniListuKVetvi
leavesPosZ = [delka*Fraction(x,pocetListu) for x in range(1,pocetListu+1)]
rot = 0
for i in range(len(leavesPosZ)):#projdeme pozice kde budou listy kolem vetve
if random.random() < leaveMissing: #)0.1=10% chance to step over list
continue
randomnes = leavesPosZ[i]* random.uniform (0.9, 1.1)
if randomnes <= leavesPosZ[len(leavesPosZ)-1]:
leavesPosZ[i] = randomnes
mutRot = rot * random.uniform (0.68, 1.32)
mutAngleY = random.uniform (-0.25*pi, 0.25*pi)
mutAngleX = random.uniform (-0.25*pi, 0.25*pi)
leavesPos = [ radius*cos(mutRot), radius*sin(mutRot), leavesPosZ[i] ]
leaveFace =[]
transMat2 = tMat(posun = leavesPos, rotace_z1 = (sin(mutRot), cos(mutRot)), rotace_y = (sin(mutAngleY), cos(mutAngleY)))
resTranMat = tranMat * transMat2
scal = topScal
if len(leavesPosZ) > 1:# zmensovani listu smerem ke konci vetve
scal = topScal+((1-topScal)/(len(leavesPosZ)-1))*(len(leavesPosZ)-i-1)
for j in range(len(defaultLeave)):#vytvorime na soucasne pozici list
x,y = defaultLeave[j]
x*=scal
y*=scal
z = y*sin(mutAngleX)
y = y*cos(mutAngleX)
leaveFace.append(len(verts))
x,y,z = (resTranMat * Vector([x,y,z,1])).xyz
verts.append([x,y,z])
rot+=stepRot
faces.append(leaveFace)
return
for branch in self.mojePriroda.Koren.Mlade:
branch.projdiMladsiVetve(turnBranchGreen)
return (verts,faces)
def createFacesOptimal(self,vIndxs1, vIndxs2, cyclic = False, flipNorm = False):
faces = deque()
top = vIndxs1
bot = vIndxs2
rozdilVertexuNa1top = Fraction(len(bot)-len(top), len(top))
B = rozdilVertexuNa1top
topIdx = 0
botIdx = 0
pokracuj = True
#botIdx < len(bot) and topIdx < len(top)
if flipNorm:
while pokracuj:
while(B >= 1) and (botIdx < len(bot)) and topIdx < len(top)-1:#vykresli trojuhelnik
B-=1
face = [ bot[botIdx], top[0], bot[botIdx + 1] ]
faces.append(face)
botIdx += 1
if (botIdx >= len(bot)-1) and (topIdx >= (len(top)-1)):
pokracuj = False
while( B < 1) and (botIdx < len(bot)-1) and topIdx < len(top)-1:#vykresli obdelnik
B+=rozdilVertexuNa1top
face = [bot[botIdx], top[topIdx], top[topIdx + 1], bot[botIdx + 1]]
faces.append(face)
topIdx += 1
botIdx += 1
if ( botIdx >= len(bot)-1 ) and ( topIdx >= len(top)-1 ):
pokracuj = False
if cyclic:
face = [ top[0],bot[0], bot[len(bot)-1],top[len(top)-1]]
faces.append(face)
else:
while pokracuj:
while(B >= 1) and (botIdx < len(bot)):#vykresli trojuhelnik
B-=1
face = [ top[ topIdx ], bot[ botIdx ], bot[ botIdx + 1 ] ]
faces.append(face)
botIdx += 1
if (botIdx >= len(bot)-1) and (topIdx >= (len(top)-1)):
pokracuj = False
while( B < 1) and (botIdx < len(bot)-1):#vykresli obdelnik
B+=rozdilVertexuNa1top
face = [top[topIdx], bot[botIdx],bot[botIdx + 1], top[topIdx + 1]]
faces.append(face)
topIdx += 1
botIdx += 1
if ( botIdx >= len(bot)-1 ) and ( topIdx >= len(top)-1 ):
pokracuj = False
if cyclic:
face = [vIndxs2[0], vIndxs1[0],vIndxs1[len(top) - 1],vIndxs2[len(bot) - 1]]
faces.append(face)
return faces
def createFaces(self,vIndxs1, vIndxs2, cyclic = False, flipNorm = False):
""" Funkce vytvori rekurzivne pro model celeho stromu Vertexes a Faces
:param vIndxs1: Koncovy venec poradovych cisel vertexu, pokud obsahuje pouze 1 vertex vytvory se zapouzdreni
:type vIndxs1: [[index], .. ]
:param vIndxs2: Venec poradovych cisel vertexu na ktery budeme napojovat vIndxs1
:type vIndxs2: [[index], .. ]
:param cyclic: Vytvoryme face mezi prvnim a poslednimi vertexy
:type cyclic: **Boolean**
:param flipNorm: Otoceni normal
:type flipNorm: **Boolean**
:rtype: [[ indxVert, indxVert, indxVert, indxVert],[ indxVert, indxVert, indxVert], .. ]
:return: pole, obsahujici ctverice nebo trojce indexu propojenych vertexu
"""
faces = deque()
if not vIndxs1 or not vIndxs2:
raise Exception('vIndxs1 nebo vIndxs2 = None')
return None
if len(vIndxs1) < 2 and len(vIndxs2) < 2:
raise Exception('len(vIndxs1) < 2 and len(vIndxs2) < 2')
return None
pointed = False
if (len(vIndxs1) != len(vIndxs2)):
if (len(vIndxs1) == 1 and len(vIndxs2) > 1):
pointed = True
elif (len(vIndxs1) < len(vIndxs2)) and self.m_optimalizeModel:
return self.createFacesOptimal(vIndxs1, vIndxs2, cyclic, flipNorm)
else:
#raise Exception('(len(vIndxs1) > len(vIndxs2))',len(vIndxs1),len(vIndxs2)); return None
return self.createFacesOptimal(vIndxs2 , vIndxs1, cyclic, flipNorm)
vCelkem = len(vIndxs2)
if flipNorm:
if cyclic:
face = [ vIndxs1[0],vIndxs2[0], vIndxs2[vCelkem-1]]
if not pointed:
face.append(vIndxs1[vCelkem-1])
faces.append(face)
for i in range(vCelkem-1):
if pointed:
face = [vIndxs2[i], vIndxs1[0], vIndxs2[i + 1]]
else:
face = [vIndxs2[i], vIndxs1[i], vIndxs1[i + 1], vIndxs2[i + 1]]
faces.append(face)
else:
if cyclic:
face = [vIndxs2[0], vIndxs1[0]]
if not pointed:
face.append(vIndxs1[vCelkem - 1])
face.append(vIndxs2[vCelkem - 1])
faces.append(face)
for i in range(vCelkem-1):
if pointed:
face = [vIndxs1[0], vIndxs2[i], vIndxs2[i + 1]]
else:
face = [vIndxs1[i], vIndxs2[i],vIndxs2[i + 1], vIndxs1[i + 1]]
faces.append(face)
return faces
def createLoop(self,vetev, souradniceStredu = None, p_radius = None):
vertexes = deque()
if p_radius is None:
radius = vetev._tloustka
else:
radius = p_radius
if self.m_optimalizeModel:
div =max( 4, int ( 3.0 * radius * self.LOD / self.m_inicialThickness ))#dodelat vypocet div z tlousky vetve a urovne detailu self.LOD
else:
div = self.m_branchFaces
#ziskame stred vetve
position = [0,0,0]
if souradniceStredu is None:# pokud nejsou danz bere se polovina vetve
for i in range(len(position)):
position[i] = (vetev.KeKmenuSpoj.Poloha[i]+ vetev.OdKmenuSpoj.Poloha[i]) * 0.5
else:
position = souradniceStredu
#vytvorime kruh vertexu
for i in range(div):
vertex = [ radius*cos(i*(2*pi/div)), radius*sin (i*(2*pi/div)),0 ]
vertexes.append(vertex)
#transformujeme kruh na spravne natoceni a pozici
rotace_Z2, rotace_Y = vetev.uhel3D()
rotace_Z1 = (-rotace_Z2[0],rotace_Z2[1])
transformationMatrix = self.mojePriroda.sestavTransformaciMatici ( posun = position, rotace_z2 = rotace_Z2, rotace_y = rotace_Y,rotace_z1 = rotace_Z1, scale = None )
for vertex in vertexes:
vertex[0],vertex[1],vertex[2]= (transformationMatrix*Vector([vertex[0],vertex[1],vertex[2],1])).xyz
return vertexes
def getModel(self):
"""
Create vertexes and faces of the tree
:rtype: ( [ [ x, y, z ], .. ], [[ indxVert, indxVert, indxVert, indxVert],[ indxVert, indxVert, indxVert], .. ])
:return: (Vertexes, Faces)
"""
if len(self.mojePriroda.Koren.Mlade) == 0:
return
tloustkaPrvni = 0.0
for branch in self.mojePriroda.Koren.Mlade:
tloustkaPrvni += branch._tloustka
tloustkaPrvni = tloustkaPrvni/len(self.mojePriroda.Koren.Mlade)
tloustkaPrvni *= 1.0 + self.mojePriroda.m_thickening
firstLoop = self.createLoop(Vetev(Spoj(),Spoj(),0,tloustkaPrvni))
firstLoopIndexes = range(len(firstLoop))
mVerts = firstLoop
mFaces = deque()
def connectBranchRek(vetev,LastBranchVertexesIndexes):
""" Funkce vytvori rekurzivne pro model celeho stromu Vertexes a Faces
:param vetev: Vetev ktera se bude pripojovat k hotovemu modelu
:type vetev: **Vetev**
:param vertexesLastBranch: Mnozina vertexu reprezentujicich predeslou vetev ve tvaru: [ [x,y,z],[x,y,z],... ]
:type vertexesLastBranch: [[ **Number**, **Number**, **Number** ],[ **Number**, **Number**, **Number** ], ... ]
"""
tloustnuti = 1.0 + self.mojePriroda.m_thickening
#posJednaCtvrtina,posTriCtvrtiny = vetev.getBodNaVetvi(0.25,0.75)
if len(vetev.OdKmenuSpoj.Mlade) > 0 :
radius1 = vetev._tloustka * (1 + 0.25*self.mojePriroda.m_thickening )
radius2 = vetev._tloustka * (0.75 + 0.25/tloustnuti ) # =0.75*(t-t/tloustnuti)+t/tloustnuti
posJednaCtvrtina,posTriCtvrtiny = vetev.getBodNaVetvi(0.25,0.75)
else:#pokud je vetev koncova je polomer mensi a posledni kruh je dale
radius1 = vetev._tloustka
radius2 = vetev._tloustka * 0.6
self.upravaPriblizeniListuKVetvi = 0.6
posJednaCtvrtina,posTriCtvrtiny = vetev.getBodNaVetvi(0.25,0.96)
myVertexLoop1 = self.createLoop( vetev, posJednaCtvrtina, radius1 )
myVertexLoop2 = self.createLoop( vetev, posTriCtvrtiny, radius2 )
mVertLenInitial1 = len(mVerts)
mVerts.extend( myVertexLoop1 )
mVertLenExtendet1 = len(mVerts)
MyBranchVertexesIndexes1 =range( mVertLenInitial1, mVertLenExtendet1 )
mFaces.extend(self.createFaces( MyBranchVertexesIndexes1, LastBranchVertexesIndexes, True, False))
mVertLenInitial2 = len(mVerts)
mVerts.extend(myVertexLoop2)
mVertLenExtendet2 = len(mVerts)
MyBranchVertexesIndexes2 =range( mVertLenInitial2, mVertLenExtendet2 )
mFaces.extend(self.createFaces( MyBranchVertexesIndexes2, MyBranchVertexesIndexes1, True, False))
if len(vetev.OdKmenuSpoj.Mlade) > 0 :
for mladaVetev in vetev.OdKmenuSpoj.Mlade:
connectBranchRek( mladaVetev, MyBranchVertexesIndexes2 )
else:
mVerts.append(vetev.OdKmenuSpoj.Poloha[0:3])
mFaces.extend(self.createFaces( [mVertLenExtendet2], MyBranchVertexesIndexes2, True, False))
return
for branch in self.mojePriroda.Koren.Mlade:
connectBranchRek(branch, firstLoopIndexes)
return (mVerts,mFaces)
def create_mesh_object(self, context, verts, edges, faces, name):
# Create new mesh
mesh = bpy.data.meshes.new(name)
# Make a mesh from a list of verts/edges/faces.
mesh.from_pydata(verts, edges, faces)
# Update mesh geometry after adding stuff.
mesh.update()
from bpy_extras import object_utils
return object_utils.object_data_add(context, mesh, operator=None)
#Vizualizator
#####################################################
#GUI for modul
class TreeOperator(bpy.types.Operator):
"Drzi hodnoty vstupnich promenych a umoznuje menit vlastnosti stromu"
bl_idname = "mesh.tree_operator"
bl_label = "VegGen"
bl_options = {'REGISTER', 'UNDO','PRESET'}
iterace = IntProperty(name="Age",
description="Age of tree, older = difficult structure ",
default=8,
min=0,
max=15)
randomSeed = IntProperty(name="Random Seed",
description="The seed control generator of random numbers ",
default=3,
min=0)
details = FloatProperty(name="Detail",
description="Determines number of faces of tree; higher->more faces",
default=0.7,
min=0.0001)
optimalizeModel = BoolProperty(name="Optimalize Model",
description="Bigger branches have more faces or every all have same number of faces",
default=True)
branchFaces = IntProperty(name="Branch Faces",
description="Number of branch faces ",
default=8,
min=3)
growLeaves = BoolProperty(name="Grow Leaves",
description="Tree is covered by the leaves or not, and same acces or disable leave setting",
default=True)
leaveSize = FloatProperty(name="Leave Size",
description="Choose the size of leave ",
default=1.5,
min=0.0001)
leavesSpacing = FloatProperty(name= "Leaves Spacing",
description="Number of leaves = Branch Length / Leaves Spacing ",
default=0.2,
min=0.0001)
inicialThickness = FloatProperty(name="Inicial Thickness ",
description="Branch Radius in the time of creation ",
default=0.1,
min=0.0001)
randomScale = FloatProperty(name="Random Scale",
description="Random size of branches parts. ( 0.1 = 10% )",
default=0.25,
min=0,
max=1)
randomEndpoint = FloatProperty(name="Endpoint Move",
description="Branches dont look same, after chenge their end point position.( 0.1 = 10% )",
default=0.11,
min=0,
max=1)
extension = FloatProperty(name="Extension",
description="Branches became longer each year by x %. ( 0.1 = 10% )",
default=0.28,
min=0,
max=1)
stepRot = FloatProperty(name="Rotation per step",
description="New branches grow from main tree in spiral, the angel for step of spiral is this property",
default = radians(87),
min=0,
max= 2.0*pi,
unit="ROTATION")
newBranchLength = FloatProperty(name="New Branch Length",
description="What is new branch length agains old ( 0.1 = 10% old )",
default=1.74,
min=0.01)
growHigh = FloatProperty(name="Grow up to sun",
description="Branches grow more vertical then horizontal. ( 0.1 = 10% )",
default=0.20,
min=0,
max=1)
thickening = FloatProperty(name="Thickening",
description="Branches became thicker each year by x %. ( 0.1 = 10% )",
default=0.35,
min=0,
soft_max= 1)
stopGrow = FloatProperty(name="Stop Grow",
description="Chance that branch stops growing. ( 0.1 = 10% )",
default=0.07,
min=0,
max= 1)
updateTree = BoolProperty(name="Update Tree", default=False)
def execute(self, context):
if not self.updateTree:
return {'PASS_THROUGH'}
iterace = self.iterace
randomSeed = self.randomSeed
details = self.details #has mean if optimalizeModel=true
optimalizeModel = self.optimalizeModel #bool
branchFaces = self.branchFaces #has mean if optimalizeModel=false
growLeaves = self.growLeaves
leaveSize = self.leaveSize
leavesSpacing = self.leavesSpacing
inicialThickness = self.inicialThickness
randomScale = self.randomScale
randomEndpoint = self.randomEndpoint
extension = self.extension
stepRot = self.stepRot
growHigh = self.growHigh
thickening = self.thickening
stopGrow = self.stopGrow
t = time.time()
newBranchLength = self.newBranchLength
random.seed(randomSeed)
maxZloc = 1.62 + 0.707
a = Spoj(0,0,0)
b = Spoj(0,0,1.62)
c = Spoj(0,0.707,maxZloc)
d = Spoj(0,-0.707,maxZloc)
VETEV = 1
v1 = Vetev(a, b, 0, inicialThickness, None)
v2 = Vetev(b, c, 0, inicialThickness, VETEV,0,True)
v3 = Vetev(b, d, 0, inicialThickness, VETEV,0,True)
KMEN = 2
a2 = Spoj(0,0,0)
b2 = Spoj(0,0,1.62)
c2 = Spoj(0,0,maxZloc+0.38)
d2 = Spoj(0,-0.85,maxZloc-0.38)
v12 = Vetev(a2, b2, 0, inicialThickness, None)
v22 = Vetev(b2, c2, 0, inicialThickness, KMEN,0,True)
v32 = Vetev(b2, d2, 0, inicialThickness*0.6, VETEV,0,True)
ridiciPrimkaPravidla = Vetev(Spoj(),Spoj(0,0,float(maxZloc)/newBranchLength))
pravidloKmen = PrepisovaciPravidlo(KMEN,ridiciPrimkaPravidla,stepRot,(a,1),(a2,10))
pravidloVetev = PrepisovaciPravidlo(VETEV,ridiciPrimkaPravidla,0,(a,1),(a2,3))
nultaIterace = Vetev(Spoj(),Spoj(0,0,2),0, inicialThickness, KMEN)
PRIRODA = Priroda(nultaIterace.KeKmenuSpoj,pravidloVetev, pravidloKmen)
PRIRODA.set_stochasticke_promene(**self.as_keywords(ignore=('randomSeed', 'iterace', 'details','optimalizeModel','branchFaces',
'inicialThickness', 'newBranchLength', 'updateTree','stepRot',
'growLeaves','leaveSize','leavesSpacing'
)))
PRIRODA.rust(iterace)
ModelBuilder = ModelGen(PRIRODA, inicialThickness, details, branchFaces, optimalizeModel)
mVertexes, mFacec = ModelBuilder.getModel()
#pridame vypoctene face a vertexi do blenderu
#strom
tree = bpy.data.meshes.new('Tree')
tree.from_pydata(mVertexes, [], mFacec)
tree.update()
obTree = bpy.data.objects.new("Tree", tree)
bpy.context.scene.objects.link(obTree)
#tree.uv_textures.new("Tree")
if growLeaves: # vyrostou listy
ver, fac = ModelBuilder.createLeaves(leaveSize,leavesSpacing)
leaves = bpy.data.meshes.new('Leaves')
leaves.from_pydata(ver, [], fac)
leaves.update()
ob = bpy.data.objects.new('Leaves', leaves)
bpy.context.scene.objects.link(ob)
leaves.uv_textures.new("Leaves")
# Set the uv texture coords
# TODO, this is non-functional, default uvs are ok?
'''
for d in tex.data:
uv1, uv2, uv3, uv4 = signList
'''
ob.parent = obTree
for vet in copy.copy(PRIRODA.Koren.Mlade):
vet._unlinkVsechnyZavisleVetve()
print("Tree Complete")
print("Tree generated in %0.2f s" % (time.time() - t))
print('tree_operator.execute - FINISHED')
self.updateTree = False
return {'FINISHED'}
def draw(self, context):
layout = self.layout
layout.prop(self, 'updateTree', icon='MESH_DATA')
properties = layout.operator("mesh.tree_operator", text="Add New Tree")
properties.iterace = self.iterace
properties.randomSeed = self.randomSeed
properties.details = self.details
properties.optimalizeModel = self.optimalizeModel
properties.branchFaces = self.branchFaces
properties.growLeaves = self.growLeaves
properties.leaveSize = self.leaveSize
properties.leavesSpacing = self.leavesSpacing
properties.stepRot = self.stepRot
properties.inicialThickness = self.inicialThickness
properties.randomScale = self.randomScale
properties.extension = self.extension
properties.thickening = self.thickening
properties.randomEndpoint = self.randomEndpoint
properties.newBranchLength = self.newBranchLength
properties.growHigh = self.growHigh
properties.stopGrow = self.stopGrow
properties.updateTree = True
box = layout.box()
box.label("Modul inner setting:")
box.prop(self, 'randomSeed')
box.prop(self, 'optimalizeModel')
if self.optimalizeModel:
box.prop(self, 'details')
else:
box.prop(self, 'branchFaces')
box = layout.box()
box.label("Tree setting:")
box.prop(self, 'iterace')
box.prop(self, 'randomScale')
box.prop(self, 'extension')
box.prop(self, 'thickening')
box.prop(self, 'newBranchLength')
box.prop(self, 'stepRot')
box = layout.box()
box.label("Branch setting:")
box.prop(self,"inicialThickness")
box.prop(self, 'randomEndpoint')
box.prop(self, 'growHigh')
box.prop(self, 'stopGrow')
box.prop(self, 'growLeaves')
if self.growLeaves:
box = layout.box()
box.label("Leaves setting:")
box.prop(self, 'leaveSize')
box.prop(self, 'leavesSpacing')
class ShrubOperator(bpy.types.Operator):
"Drzi hodnoty vstupnich promenych a umoznuje menit vlastnosti kere"
bl_idname = "mesh.shrub_operator"
bl_label = "ShrubGen"
bl_options = {'REGISTER', 'UNDO','PRESET'}
iterace = IntProperty(name="Age",
description="Age of tree, older = difficult structure ",
default=10,
min=0,
max=15)
randomSeed = IntProperty(name="Random Seed",
description="The seed control generator of random numbers ",
default=5,
min=0)
details = FloatProperty(name="Detail",
description="Determines number of faces of tree; higher->more faces",
default=0.75,
min=0.0001)
optimalizeModel = BoolProperty(name="Optimalize model",
description="Bigger branches have more faces or every all have same number of faces",
default=True)
branchFaces = IntProperty(name="Branch faces",
description="Number of branch faces ",
default=6,
min=3)
stepRot = FloatProperty(name="Rotation per step",
description="New branches grow from main tree in spiral, the angel for step of spiral is this property",
default = pi/6.0,
min=0,
max= 2.0*pi,
unit="ROTATION")
inicialThickness = FloatProperty(name="Inicial Thickness ",
description="Branch Radius in the time of creation ",
default=0.1,
min=0.0001)
randomScale = FloatProperty(name="Random Scale",
description="Random size of branches parts. ( 0.1 = 10% )",
default=0.24,
min=0,
max=1)
randomEndpoint = FloatProperty(name="Endpoint Move",
description="Branches dont look same, after chenge their end point position.( 0.1 = 10% )",
default=0.29,
min=0,
max=1)
extension = FloatProperty(name="Extension",
description="Branches became longer each year by x %. ( 0.1 = 10% )",
default=0.23,
min=0,
max=1)
newBranchLength = FloatProperty(name="New Branch Length",
description="What is new branch length agains old ( 0.1 = 10% old )",
default=1.83,
min=0.01)
growHigh = FloatProperty(name="Grow up to sun",
description="Branches grow more vertical then horizontal. ( 0.1 = 10% )",
default=0.22,
min=0,
max=1)
thickening = FloatProperty(name="Thickening",
description="Branches became thicker each year by x %. ( 0.1 = 10% )",
default=0.08,
min=0,
soft_max= 1)
stopGrow = FloatProperty(name="Stop Grow",
description="Chance that branch stops growing. ( 0.1 = 10% )",
default=0.11,
min=0,
max= 1)
growLeaves = BoolProperty(name="Grow Leaves",
description="Shrub is covered by the leaves or not, and same acces or disable leave setting",
default=True)
leaveSize = FloatProperty(name="Leave Size",
description="Choose the size of leave ",
default=1.5,
min=0.0001)
leavesSpacing = FloatProperty(name= "Leaves Spacing",
description="Number of leaves = Branch Length / Leaves Spacing ",
default=0.2,
min=0.0001)
updateShrub = BoolProperty(name="Update Shrub", default=False)
def execute(self, context):
if not self.updateShrub:
return {'PASS_THROUGH'}
iterace = self.iterace
randomSeed = self.randomSeed
details = self.details #has mean if optimalizeModel=true
optimalizeModel = self.optimalizeModel #bool
branchFaces = self.branchFaces #has mean if optimalizeModel=false
stepRot = self.stepRot
growLeaves = self.growLeaves
leaveSize = self.leaveSize
leavesSpacing = self.leavesSpacing
inicialThickness = self.inicialThickness
randomScale = self.randomScale
randomEndpoint = self.randomEndpoint
extension = self.extension
growHigh = self.growHigh
thickening = self.thickening
stopGrow = self.stopGrow
t = time.time()
newBranchLength = self.newBranchLength
random.seed(randomSeed)
maxZloc = 1.62 + 0.707
a = Spoj(0,0,0)
b = Spoj(0,0,1)
c = Spoj(0,0.707,maxZloc -1.2)
d = Spoj(0,-0.707,maxZloc -1.4)
e = Spoj(0,0,maxZloc-1)
ZACATEK = 1
SLAHOUN = 2
v1 = Vetev(a, b, 0, inicialThickness, ZACATEK)
v2 = Vetev(a, c, 0, inicialThickness, SLAHOUN, 0, True)
v3 = Vetev(a, d, 0, inicialThickness, SLAHOUN, 0, True)
v1t = Vetev(a, e, 0, inicialThickness, SLAHOUN, 0, True)
a2 = Spoj(0,0,0)
b2 = Spoj(0,0,1)
c2 = Spoj(0,0,maxZloc-0.6)
d2 = Spoj(0,-0.2,maxZloc-1)
v12 = Vetev(a2, b2, 0, inicialThickness, None)
v22 = Vetev(b2, c2, 0, inicialThickness*0.8, SLAHOUN, 0, True)
v32 = Vetev(b2, d2, 0, inicialThickness*0.6, SLAHOUN, 0, True)
ridiciPrimkaPravidla = Vetev(Spoj(),Spoj(0,0,float(maxZloc)/newBranchLength))
pravidloZACATEK = PrepisovaciPravidlo(ZACATEK,ridiciPrimkaPravidla,stepRot,(a,1))
pravidloSLAHOUN= PrepisovaciPravidlo(SLAHOUN,ridiciPrimkaPravidla,stepRot,(a2,1))
nultaIterace = Vetev(Spoj(),Spoj(0,0,1),0, inicialThickness, ZACATEK)
PRIRODA = Priroda( nultaIterace.KeKmenuSpoj, pravidloZACATEK, pravidloSLAHOUN)
PRIRODA.set_stochasticke_promene(**self.as_keywords(ignore=('randomSeed', 'iterace', 'details','optimalizeModel',
'branchFaces', 'inicialThickness', 'newBranchLength',
'updateShrub','stepRot','growLeaves', 'leaveSize',
'leavesSpacing'
)))
PRIRODA.rust(iterace)
ModelBuilder = ModelGen(PRIRODA, inicialThickness, details, branchFaces, optimalizeModel)
mVertexes, mFacec = ModelBuilder.getModel()
#pridame vypoctene face a vertexi do blenderu
#strom
shrub = bpy.data.meshes.new('Shrub_Mesh')
shrub.from_pydata(mVertexes, [], mFacec)
shrub.update()
obShrub = bpy.data.objects.new("Shrub_Mesh", shrub)
bpy.context.scene.objects.link(obShrub)
if growLeaves: # vyrostou listy
ver, fac = ModelBuilder.createLeaves(leaveSize,leavesSpacing)
leaves = bpy.data.meshes.new('Leaves')
leaves.from_pydata(ver, [], fac)
leaves.update()
ob = bpy.data.objects.new('Leaves', leaves)
bpy.context.scene.objects.link(ob)
ob.parent = obShrub
leaves.uv_textures.new("Leaves")
# Set the uv texture coords
# TODO, this is non-functional, default uvs are ok?
'''
for d in tex.data:
uv1, uv2, uv3, uv4 = signList
'''
#bpy.ops.object.shade_smooth()
for vet in copy.copy(PRIRODA.Koren.Mlade):
vet._unlinkVsechnyZavisleVetve()
print("Shrub Complete")
print("Shrub generated in %0.2f s" % (time.time() - t))
print('shrub_operator.execute - FINISHED')
self.updateShrub = False
return {'FINISHED'}
def draw(self, context):
layout = self.layout
layout.prop(self, 'updateShrub', icon='MESH_DATA')
properties = layout.operator("mesh.shrub_operator", text="Add New Shrub")
properties.iterace = self.iterace
properties.randomSeed = self.randomSeed
properties.details = self.details
properties.optimalizeModel = self.optimalizeModel
properties.branchFaces = self.branchFaces
properties.stepRot = self.stepRot
properties.growLeaves = self.growLeaves
properties.leaveSize = self.leaveSize
properties.leavesSpacing = self.leavesSpacing
properties.inicialThickness = self.inicialThickness
properties.randomScale = self.randomScale
properties.extension = self.extension
properties.thickening = self.thickening
properties.randomEndpoint = self.randomEndpoint
properties.newBranchLength = self.newBranchLength
properties.growHigh = self.growHigh
properties.stopGrow = self.stopGrow
properties.updateShrub = True
box = layout.box()
box.label("Modul inner setting:")
box.prop(self, 'randomSeed')
box.prop(self, 'optimalizeModel')
if self.optimalizeModel:
box.prop(self, 'details')
else:
box.prop(self, 'branchFaces')
box = layout.box()
box.label("Shrub setting:")
box.prop(self, 'iterace')
box.prop(self, 'randomScale')
box.prop(self, 'extension')
box.prop(self, 'thickening')
box.prop(self, 'newBranchLength')
box.prop(self, 'stepRot')
box = layout.box()
box.label("Branch setting:")
box.prop(self,"inicialThickness")
box.prop(self, 'randomEndpoint')
box.prop(self, 'growHigh')
box.prop(self, 'stopGrow')
box.prop(self, 'growLeaves')
if self.growLeaves:
box = layout.box()
box.label("Leaves setting:")
box.prop(self, 'leaveSize')
box.prop(self, 'leavesSpacing')
class MENU_ADD_Vegetation (bpy.types.Menu):
# Define the "Add vegetation" menu
bl_idname = "MENU_ADD_Vegetation"
bl_label = "VegGen"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator(TreeOperator.bl_idname, text="Add Tree").updateTree = True
layout.operator(ShrubOperator.bl_idname, text="Add Shrub").updateShrub = True
#GUI for modul
################################
#interface for add Modul
def menu_func(self, context):
self.layout.menu( MENU_ADD_Vegetation.bl_idname, icon="PLUGIN")
def register():
bpy.utils.register_module(__name__)
# Add "vegetation" menu to the "Add Mesh" menu
bpy.types.INFO_MT_mesh_add.append(menu_func)
def unregister():
bpy.types.INFO_MT_mesh_add.remove(menu_func)
# Remove "vegetation" menu from the "Add Mesh" menu.
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

File Metadata

Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
03/bc/1cd92c13141ff0a160b9faf56c35

Event Timeline