Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore unversioniert; letztere sind unter ../backups gesichert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
422 lines
22 KiB
Python
422 lines
22 KiB
Python
"""Authored Phase 9 living wood: braided roots, bark lamellae, leaf veins,
|
|
closed petal shells and fungal gills. No subdivision of the old models.
|
|
Each rigid root has its own semantic animation joint; all geometry is editable.
|
|
"""
|
|
from math import sin, cos, pi
|
|
import bpy
|
|
from mathutils import Vector
|
|
from common import ellipsoid, cylinder, mesh_object, srgb_to_linear
|
|
from reference_geometry import r_lathe
|
|
from reference_high_detail import hd_curve, hd_disc, hd_ring, hd_plate, hd_finish, hd_box, hd_rod, hd_materials
|
|
|
|
|
|
def living_materials(m):
|
|
colors={'bark':('503D2D',.85,0),'wood':('836343',.79,0),
|
|
'endgrain':('92764E',.86,0),'groove':('312B24',.93,0),'moss':('3E6041',.90,0),
|
|
'leaf':('7D9850',.65,0),'vein':('A9B875',.67,0),
|
|
'petal':('AD6D8A',.56,0),'heart':('E9BD79',.52,0),
|
|
'water':('65D6B5',.18,.65)}
|
|
for key,(hexcolor,rough,emission) in colors.items():
|
|
name='SW_HD_W_'+key
|
|
mat=bpy.data.materials.new(name);mat['material_name']=name;mat.use_nodes=True
|
|
c=tuple(srgb_to_linear(int(hexcolor[i:i+2],16)/255) for i in (0,2,4))
|
|
mat.diffuse_color=(*c,1)
|
|
node=mat.node_tree.nodes.get('Principled BSDF')
|
|
node.inputs['Base Color'].default_value=(*c,1)
|
|
node.inputs['Roughness'].default_value=rough
|
|
if emission:
|
|
node.inputs['Emission Color'].default_value=(*c,1)
|
|
node.inputs['Emission Strength'].default_value=emission
|
|
m[key]=mat
|
|
return m
|
|
|
|
|
|
def living_blob(name,loc,scale,mat):
|
|
obj=ellipsoid(name,loc,scale,mat,subdivisions=2 if max(scale) < .085 else 3)
|
|
if 'bark' in mat.name or 'moss' in mat.name:
|
|
for v in obj.data.vertices:
|
|
p=v.co
|
|
p *= 1+.045*sin(p.x*27+p.z*13)*cos(p.y*21)
|
|
for face in obj.data.polygons:face.use_smooth=True
|
|
return obj
|
|
|
|
|
|
def living_leaf(name,start,end,width,m,key='leaf'):
|
|
"""Closed lenticular leaf, curved midrib and six modeled secondary veins."""
|
|
a,b=Vector(start),Vector(end);d=b-a
|
|
tangent=d.normalized();side=tangent.cross(Vector((0,-1,.3))).normalized()
|
|
if side.length<.1:side=Vector((1,0,0))
|
|
normal=side.cross(tangent).normalized()
|
|
verts=[]; rows=9; sides=8
|
|
for j in range(rows):
|
|
t=.005+.99*j/(rows-1)
|
|
center=a+d*t+normal*(sin(t*pi)*width*.20)
|
|
w=max(.001,sin(t*pi)**.85*width*(1+.045*sin(t*13*pi)))
|
|
for k in range(sides):
|
|
angle=2*pi*k/sides
|
|
verts.append(tuple(center+side*cos(angle)*w+normal*sin(angle)*w*.18))
|
|
faces=[tuple(reversed(range(sides)))]
|
|
for j in range(rows-1):
|
|
for k in range(sides):
|
|
n=(k+1)%sides;faces.append((j*sides+k,j*sides+n,(j+1)*sides+n,(j+1)*sides+k))
|
|
faces.append(tuple((rows-1)*sides+k for k in range(sides)))
|
|
obj=mesh_object(name,verts,faces,m[key])
|
|
for face in obj.data.polygons:face.use_smooth=True
|
|
points=[a+d*t+normal*(sin(t*pi)*width*.39+.005) for t in [0,.3,.65,1]]
|
|
hd_curve(name+'_Midrib',points,[.009,.009,.006,.001],m['vein'],6,3)
|
|
for j in range(3):
|
|
t=.25+j*.20
|
|
center=a+d*t+normal*(sin(t*pi)*width*.39+.008)
|
|
for sign in [-1,1]:
|
|
tip=a+d*(t+.12)+side*sign*width*sin((t+.12)*pi)*.8+normal*width*.24
|
|
hd_curve(name+'_Vein%d_%d'%(j,sign),[center,(center+tip)*.5+normal*.005,tip],[.004,.003,.001],m['vein'],5,2)
|
|
return obj
|
|
|
|
|
|
def living_branch(name,points,radius,m,grooves=3):
|
|
points=[Vector(p) for p in points]
|
|
obj=hd_curve(name,points,[radius*(1-.60*j/(len(points)-1)) for j in range(len(points))],m['bark'],16,7)
|
|
for vertex in obj.data.vertices:
|
|
p=vertex.co
|
|
vertex.co += Vector((sin(p.z*35+p.y*17),cos(p.z*27+p.x*18),sin(p.x*19+p.y*31)))*radius*.11
|
|
for k in range(grooves):
|
|
angle=2*pi*k/max(1,grooves)
|
|
ridges=[p+Vector((cos(angle),sin(angle),0))*radius*(.96-.57*j/(len(points)-1)) for j,p in enumerate(points)]
|
|
hd_curve(name+'_Grain'+str(k),ridges,[radius*.11]*(len(points)-1)+[.001],m['wood'],6,5)
|
|
|
|
|
|
def living_roots(m,count=4,spread=.43,height=.55,radius=.12):
|
|
for k in range(count):
|
|
a=2*pi*k/count+pi/4
|
|
group=('LegL' if cos(a)<0 else 'LegR')+('1' if k>=2 else '')
|
|
hip=Vector((.13*cos(a),.13*sin(a),height))
|
|
knee=Vector((spread*.70*cos(a),spread*.60*sin(a),.31))
|
|
foot=Vector((spread*cos(a),spread*sin(a),.12))
|
|
living_branch(group+'_Root',[hip,knee,foot],radius,m,5)
|
|
for j in range(3):
|
|
angle=a+(j-1)*.48
|
|
tip=foot+Vector((.24*cos(angle),.24*sin(angle),-.10))
|
|
hd_curve(group+'_Toe'+str(j),[knee*.18+foot*.82,foot+Vector((.09*cos(angle),.09*sin(angle),.025)),tip],[radius*.65,radius*.4,.003],m['wood'],12,6)
|
|
hd_curve(group+'_Moss',[hip+Vector((0,-radius*.6,0)),knee+Vector((0,-radius*.7,0)),foot],[radius*.28,radius*.22,.001],m['moss'],10,5)
|
|
living_leaf(group+'_Sprout',knee,knee+Vector((.14*cos(a),-.035,.17)),.055,m)
|
|
|
|
|
|
def living_flower(name,loc,m,scale=1):
|
|
center=Vector(loc)
|
|
for k in range(5):
|
|
angle=k*2*pi/5
|
|
p=center+Vector((.035*cos(angle),-.008,.035*sin(angle)))*scale
|
|
obj=living_blob(name+'_Petal'+str(k),p,(.027*scale,.012*scale,.040*scale),m['petal'])
|
|
obj.rotation_euler.y=pi/2-angle
|
|
living_blob(name+'_Pollen',center+Vector((0,-.022,0))*scale,(.017*scale,)*3,m['heart'])
|
|
|
|
|
|
def living_trunk(m,height=.85,radius=.14,base=.35,count=4):
|
|
for k in range(count):
|
|
phase=2*pi*k/count
|
|
points=[]
|
|
for j in range(7):
|
|
t=j/6;a=phase+t*pi*1.8
|
|
points.append((radius*cos(a),radius*sin(a),base+t*height))
|
|
living_branch('Body_Braid'+str(k),points,.073 if count<5 else .09,m,3)
|
|
for k in range(8):
|
|
a=k*2.4;z=base+.15+k*height*.08
|
|
start=(radius*cos(a),radius*sin(a),z)
|
|
living_leaf('Body_TrunkLeaf'+str(k),start,(.34*cos(a),.30*sin(a),z+.16),.064,m)
|
|
|
|
|
|
def living_bark(name,loc,width,height,m,seed=0):
|
|
outline=[(-width*.46,height*.44),(-width*.05,height*.56),(width*.49,height*.35),(width*.46,-height*.29),(width*.12,-height*.54),(-width*.44,-height*.40)]
|
|
obj=hd_plate(name,loc,outline,.075,m['wood'],.012,.045)
|
|
x,y,z=loc
|
|
for j in range(4):
|
|
dx=(j-1.5)*width*.19
|
|
hd_curve(name+'_Fissure'+str(j),[(x+dx,y-.074,z-height*.29),(x+dx+.008*sin(seed+j),y-.096,z),(x+dx-.01,y-.068,z+height*.33)],[.005,.008,.004],m['bark'],6,3)
|
|
return obj
|
|
|
|
|
|
def living_thorn(up,m):
|
|
living_roots(m,4 if up else 2,.38 if up else .32,.52,.12)
|
|
if not up:
|
|
living_blob('Body_MossHeart',(0,.02,.83),(.34,.28,.40),m['moss'])
|
|
for k in range(6):
|
|
a=k*pi/3
|
|
points=[]
|
|
for j in range(6):
|
|
t=j/5;radius=.18+.17*sin(t*pi)
|
|
points.append((radius*cos(a+t*.8),radius*.86*sin(a+t*.8),.48+t*.68))
|
|
living_branch('Body_WovenBark'+str(k),points,.037,m,2)
|
|
for k in range(4):
|
|
a=k*pi/2
|
|
living_leaf('Body_ShoulderLeaf'+str(k),(.20*cos(a),.20*sin(a),1.07),(.34*cos(a),.31*sin(a),1.24),.064,m)
|
|
for k in range(9):
|
|
a=k*2*pi/9
|
|
# Local bark plates turn as a whole, including their carved lines.
|
|
before=set(bpy.context.scene.objects)
|
|
living_bark('Body_Bark'+str(k),(0,-.275,.84),.23,.54,m,k)
|
|
for o in set(bpy.context.scene.objects)-before:
|
|
from mathutils import Matrix
|
|
mat=Matrix.Rotation(a,4,'Z');o.location=mat@o.location;o.rotation_euler.z=a
|
|
hd_curve('Body_Thorn'+str(k),[(.28*cos(a),.25*sin(a),.88),(.45*cos(a),.39*sin(a),1.01),(.56*cos(a),.48*sin(a),1.08)],[.08,.045,.001],m['leaf'],12,6)
|
|
hd_plate('Head_EyeShadow',(0,-.339,.85),[(-.20,.026),(.20,.026),(.12,-.029),(-.16,-.025)],.025,m['groove'],.004)
|
|
for sign in [-1,1]:
|
|
hd_disc('Head_Eye'+str(sign),(sign*.11,-.36,.85),.017,.014,m['heart'])
|
|
living_leaf('Head_Sprout'+str(sign),(0,0,1.18),(sign*.20,.02,1.48),.093,m)
|
|
living_flower('Body_Blossom',(-.24,-.20,1.11),m)
|
|
else:
|
|
living_trunk(m,.60,.23,.31,5)
|
|
living_blob('Head_JawDark',(0,-.12,.94),(.36,.32,.19),m['groove'])
|
|
for upper,z in [(True,1.13),(False,.72)]:
|
|
name='Head_Upper' if upper else 'Head_Lower'
|
|
living_blob(name+'_Jaw',(0,-.14,z),(.41,.38,.13),m['bark'])
|
|
for row in range(3):
|
|
hd_curve(name+'_Lip'+str(row),[(-.32,.02,z),(-.40,-.25,z+.015*row),(-.20,-.51,z+.02*row),(0,-.54,z),( .20,-.51,z+.02*row),(.40,-.25,z+.015*row),(.32,.02,z)],[.05]*7,m['moss'] if row==0 else m['wood'],12,5)
|
|
for k in range(9):
|
|
a=pi+(k/8)*pi
|
|
x=.35*cos(a);y=-.17+.34*sin(a)
|
|
hd_curve(name+'_Fang'+str(k),[(x,y,z+(-.05 if upper else .06)),(x*.97,y-.015,z+(-.11 if upper else .10)),(x*.9,y-.03,z+(-.24 if upper else .20))],[.045,.028,.001],m['heart'],12,5)
|
|
for k in range(6):
|
|
a=k*pi/3
|
|
living_leaf('Head_JawLeaf'+str(k),(.26*cos(a),.21*sin(a),1.13),(.49*cos(a),.41*sin(a),1.30),.11,m)
|
|
living_flower('Head_JawFlower',(-.32,-.20,1.26),m)
|
|
|
|
|
|
def living_log(name,loc,r,m):
|
|
hd_disc(name+'_Bark',loc,r,.15,m['bark'])
|
|
x,y,z=loc
|
|
cut=hd_disc(name+'_Cut',(x,y-.086,z),r*.86,.025,m['endgrain'])
|
|
# Local UVs retain the centre of each log when parts are batched for Godot.
|
|
uv=cut.data.uv_layers.active or cut.data.uv_layers.new(name='GrowthRings')
|
|
for loop in cut.data.loops:
|
|
v=cut.data.vertices[loop.vertex_index].co
|
|
uv.data[loop.index].uv=(.5+v.x/(r*1.72),.5+v.y/(r*1.72))
|
|
for j in range(6):
|
|
radius=r*(.11+j*.127)
|
|
verts=[];faces=[];segments=64;sides=6
|
|
for k in range(segments):
|
|
a=k*2*pi/segments
|
|
organic=1+.045*sin(a*3+j*.61)+.035*cos(a*7-j)
|
|
for side in range(sides):
|
|
b=side*2*pi/sides
|
|
rr=radius*organic+.0019*cos(b)
|
|
verts.append((x+rr*cos(a),y-.102+.0019*sin(b),z+rr*sin(a)))
|
|
for k in range(segments):
|
|
for side in range(sides):
|
|
a=k*sides+side;b=k*sides+(side+1)%sides
|
|
c=((k+1)%segments)*sides+(side+1)%sides;d=((k+1)%segments)*sides+side
|
|
faces.append((a,b,c,d))
|
|
mesh_object(name+'_Growth'+str(j),verts,faces,m['bark'])
|
|
for k in range(13):
|
|
a=k*2*pi/13
|
|
hd_curve(name+'_RoughEdge'+str(k),[(x+r*.92*cos(a),y+.045,z+r*.92*sin(a)),(x+r*cos(a),y-.025,z+r*sin(a)),(x+r*.94*cos(a),y-.09,z+r*.94*sin(a))],[.017,.027,.015],m['wood'],8,4)
|
|
for k in range(3):
|
|
a=k*2.7+r
|
|
hd_curve(name+'_Split'+str(k),[(x+r*.84*cos(a),y-.105,z+r*.84*sin(a)),(x+r*.66*cos(a+.015),y-.109,z+r*.66*sin(a+.015)),(x+r*.50*cos(a-.023),y-.109,z+r*.50*sin(a-.023))],[.0038,.0023,.0007],m['groove'],5,2)
|
|
|
|
|
|
def living_tank(up,m):
|
|
living_roots(m,4,.44,.57,.14)
|
|
living_trunk(m,.70,.20,.32,5)
|
|
living_blob('Body_InnerMoss',(0,.08,.86),(.41,.31,.40),m['moss'])
|
|
if up:
|
|
from mathutils import Matrix
|
|
for row in range(3):
|
|
for k in range(8):
|
|
a=k*2*pi/8+row*.24
|
|
before=set(bpy.context.scene.objects)
|
|
living_bark('Body_OverlappingBark%d_%d'%(row,k),(0,-.30,.62+row*.23),.22,.31,m,k+row)
|
|
rotation=Matrix.Rotation(a,4,'Z')
|
|
for obj in set(bpy.context.scene.objects)-before:
|
|
obj.location=rotation@obj.location;obj.location.y+=.08;obj.rotation_euler.z=a
|
|
for k,(x,y,z,r) in enumerate([(-.28,-.22,1.04,.31),(.28,-.19,.87,.27),(0,.02,1.34,.20),(-.36,-.18,.55,.15),(.39,-.15,.57,.15),(0,.37,1.02,.26)]):
|
|
living_log('Body_Log'+str(k),(x,y,z),r,m)
|
|
else:
|
|
for row in range(3):
|
|
for k in range(7):
|
|
a=k*2*pi/7+row*.45
|
|
from mathutils import Matrix
|
|
before=set(bpy.context.scene.objects)
|
|
living_bark('Body_Cork%d_%d'%(row,k),(0,-(.40-row*.07),.64+row*.23),.26,.31,m,k+row)
|
|
rotation=Matrix.Rotation(a,4,'Z')
|
|
for obj in set(bpy.context.scene.objects)-before:
|
|
obj.location=rotation@obj.location;obj.rotation_euler.z=a
|
|
for k in range(11):
|
|
a=k*2.4
|
|
z=1.22+(k%3)*.07
|
|
living_leaf('Head_Canopy'+str(k),(.12*cos(a),.10*sin(a),z),(.37*cos(a),.30*sin(a),z+.15),.073,m)
|
|
for k in range(5):
|
|
living_flower('Body_Flower'+str(k),(-.30+k*.15,-.26,1.10+.12*sin(k*2)),m,.7)
|
|
|
|
|
|
def living_cup(name,loc,r,m,flower=False):
|
|
x,y,z=loc
|
|
material=m['petal'] if flower else m['moss']
|
|
obj=r_lathe(name+'_Shell',loc,[(0,0),(r*.2,.02),(r*.42,.07),(r*.8,.19),(r,.32),(r*1.02,.35),(r*.94,.365),(r*.76,.24),(r*.4,.12),(0,.09)],material,segments=48)
|
|
for p in obj.data.polygons:p.use_smooth=True
|
|
hd_ring(name+'_Rim',(x,y,z+.35),r,.024,m['leaf'],segments=64)
|
|
count=(12 if r > .2 else 5) if flower else 10
|
|
for k in range(count):
|
|
a=k*2*pi/count
|
|
hd_curve(name+'_Rib'+str(k),[(x+r*.2*cos(a),y+r*.2*sin(a),z+.06),(x+r*.54*cos(a),y+r*.54*sin(a),z+.12),(x+r*.90*cos(a),y+r*.9*sin(a),z+.30)],[.015,.017,.008],m['wood'] if not flower else m['petal'],8,5)
|
|
if flower:
|
|
living_leaf(name+'_Fringe'+str(k),(x+r*.98*cos(a),y+r*.98*sin(a),z+.34),(x+r*1.08*cos(a),y+r*1.08*sin(a),z+.17),.047,m)
|
|
|
|
|
|
def living_ranged(up,m):
|
|
living_roots(m,4 if up else 2,.32,.48,.09)
|
|
living_trunk(m,.77,.09,.32,4)
|
|
living_cup('Head_Launcher',(0,-.04,1.03),.30 if up else .26,m)
|
|
living_blob('Head_Seed',(0,-.04,1.31),(.15,.145,.20 if up else .12),m['wood'])
|
|
for k in range(7):
|
|
a=k*2*pi/7
|
|
hd_curve('Head_SeedSeam'+str(k),[(.10*cos(a),-.04+.10*sin(a),1.24),(.151*cos(a),-.04+.145*sin(a),1.34),(0,-.04,1.51 if up else 1.43)],[.006,.007,.001],m['bark'],6,4)
|
|
for k in range(12 if up else 5):
|
|
a=k*2*pi/(6 if up else 5)
|
|
row=k//6 if up else 0
|
|
living_leaf('Head_LauncherScale'+str(k),(.13*cos(a),-.04+.13*sin(a),1.06+.12*row),(.36*cos(a),-.04+.36*sin(a),1.51+.08*row),.13 if up else .10,m,'wood' if up else 'leaf')
|
|
for sign in [-1,1]:
|
|
living_leaf('Body_BroadLeaf'+str(sign),(sign*.04,0,.64),(sign*.43,-.02,.94),.13,m)
|
|
living_flower('Body_Flower'+str(sign),(sign*.11,-.11,.81),m,.65)
|
|
|
|
|
|
def living_artillery(up,m):
|
|
living_roots(m,4,.43,.56,.12)
|
|
living_trunk(m,.92 if up else .65,.14,.32,4)
|
|
positions=[(-.30,-.03,.78,.30),(.30,.03,.68,.29),(0,.10,1.29,.43)] if up else [(0,0,.96,.48)]
|
|
for k,(x,y,z,r) in enumerate(positions):
|
|
living_branch('Body_FungalTrunk'+str(k),[(0,0,.4),(x*.6,y,.74),(x,y,z+.02)],.11,m,4)
|
|
living_cup('Head_Cup'+str(k),(x,y,z),r,m,True)
|
|
for j in range(5):
|
|
a=j*2*pi/5
|
|
living_blob('Weapon_Spore%d_%d'%(k,j),(x+r*.30*cos(a),y+r*.30*sin(a),z+.18),(.045,.043,.083),m['heart'])
|
|
for k in range(4 if up else 2):
|
|
sign=-1 if k%2 else 1
|
|
living_cup('Body_SmallCup'+str(k),(sign*.26,.04,.48+.13*k),.11,m,True)
|
|
|
|
|
|
def living_support(up,m):
|
|
living_roots(m,4 if up else 2,.39,.52,.105)
|
|
if up:
|
|
for sign in [-1,1]:
|
|
for j in range(3):
|
|
living_branch('Body_Arch%d_%d'%(sign,j),[(sign*.18,.07,.36),(sign*(.36+j*.015),.10,.83),(sign*.26,.07,1.27),(sign*.07,.08,1.48) ],.088-j*.012,m,3)
|
|
for k in range(24):
|
|
a=k*2.4;row=k//8
|
|
living_leaf('Head_Canopy'+str(k),(.05*cos(a),.06,1.48-row*.07),(.45*cos(a),.06+.34*sin(a),1.28-row*.10),.13,m)
|
|
else:
|
|
living_trunk(m,.93,.09,.31,4)
|
|
for k in range(5):
|
|
a=k*2*pi/5
|
|
living_leaf('Head_Crown'+str(k),(.02*cos(a),0,1.18),(.36*cos(a),.17*sin(a),1.45+(k==2)*.17),.14,m)
|
|
r=.33 if up else .25; z=.79
|
|
living_cup('Weapon_Basin',(0,-.22,z-.16),r,m)
|
|
water=hd_finish(cylinder('Weapon_Water',(0,-.22,z+.075),r*.81,.025,m['water'],64),0,0,True)
|
|
for k in range(3):
|
|
hd_ring('Weapon_Ripple'+str(k),(0,-.22,z+.091),r*(.18+k*.24),.006,m['vein'],segments=48)
|
|
if not up:living_blob('Weapon_DewOrb',(0,-.22,z+.18),(.095,.095,.095),m['water'])
|
|
for sign,side in [(-1,'L'),(1,'R')]:
|
|
living_branch('Arm'+side+'_BasinVine',[(sign*.12,0,z+.25),(sign*.28,-.11,z+.22),(sign*r,-.22,z+.025)],.048,m,3)
|
|
for k in range(6 if up else 3):
|
|
a=k*2.4
|
|
living_flower('Body_Blossom'+str(k),(.31*cos(a),-.15,1.25+.20*sin(a)),m,.85)
|
|
|
|
|
|
def build_high_wurzelbund(spec,m):
|
|
living_materials(m)
|
|
{'melee':living_thorn,'tank':living_tank,'ranged':living_ranged,'artillery':living_artillery,'support':living_support}[spec['role']](spec['upgraded'],m)
|
|
|
|
|
|
def build_high_worker(spec,m):
|
|
"""Clay and brass gatherer: real joints, apron, gloves, tool and reservoir."""
|
|
hd_materials(m)
|
|
for sign,side in [(-1,'L'),(1,'R')]:
|
|
name='Leg'+side
|
|
hd_rod(name+'_Shin',(sign*.15,.02,.16),(sign*.15,.02,.37),.065,m['dark'])
|
|
hd_box(name+'_Boot',(sign*.15,-.05,.095),(.22,.32,.16),m['basalt'],.045)
|
|
hd_box(name+'_Sole',(sign*.15,-.055,.035),(.235,.33,.045),m['dark'],.012)
|
|
hd_ring(name+'_Cuff',(sign*.15,.02,.22),.082,.019,m['gold'],segments=40)
|
|
for j in range(3):
|
|
hd_box(name+'_ToeRidge'+str(j),(sign*.15,-.13+j*.055,.179),(.18,.018,.012),m['gold'],.003)
|
|
living_blob('Body_ClayTorso',(0,.025,.53),(.23,.17,.25),m['ceramic'])
|
|
hd_plate('Body_LeatherApron',(0,-.154,.48),[(-.17,.17),(.17,.17),(.21,-.20),(-.21,-.20)],.045,m['basalt'],.018,.02)
|
|
for j in range(7):
|
|
hd_disc('Body_ApronRivet'+str(j),(-.16+j*.053,-.19,.40),.009,.012,m['gold_light'])
|
|
hd_box('Body_ToolPocket',(0,-.195,.50),(.20,.025,.10),m['gold'],.012)
|
|
for sign in [-1,1]:
|
|
hd_curve('Body_Harness'+str(sign),[(sign*.17,-.18,.58),(sign*.15,-.13,.73),(sign*.12,.05,.78),(sign*.17,.17,.59)],[.019]*4,m['gold'],10,5)
|
|
living_blob('Head_Hood',(0,.015,.85),(.22,.19,.21),m['basalt'])
|
|
hd_disc('Head_FaceRecess',(0,-.18,.85),.145,.03,m['dark'])
|
|
for sign in [-1,1]:
|
|
hd_disc('Head_GoggleSocket'+str(sign),(sign*.075,-.205,.87),.064,.036,m['gold'])
|
|
hd_disc('Head_GoggleLens'+str(sign),(sign*.075,-.229,.87),.048,.019,m['bone'])
|
|
hd_disc('Head_GoggleGlint'+str(sign),(sign*.069,-.241,.885),.016,.009,m['ceramic'])
|
|
hd_plate('Head_Cap',(0,-.01,1.005),[(-.24,0),(-.14,.055),(.14,.055),(.24,0),(.14,-.016),(-.14,-.016)],.37,m['gold'],.012)
|
|
hd_disc('Head_LampHousing',(0,-.19,1.017),.038,.035,m['dark'])
|
|
hd_disc('Head_Lamp',(0,-.213,1.017),.025,.013,m['hot'])
|
|
hd_finish(cylinder('Body_Reservoir',(0,.235,.62),.16,.35,m['bone'],32),.01,3,True)
|
|
for z in [.45,.79]:
|
|
hd_ring('Body_TankRim'+str(z),(0,.235,z),.17,.025,m['gold'],segments=48)
|
|
for k in range(8):
|
|
a=k*pi/4
|
|
hd_rod('Body_TankBrace'+str(k),(.17*cos(a),.235+.17*sin(a),.45),(.17*cos(a),.235+.17*sin(a),.79),.012,m['gold'])
|
|
for sign,side in [(-1,'L'),(1,'R')]:
|
|
a=(sign*.21,.0,.66);b=(sign*.30,-.08,.50);c=(sign*.29,-.19,.55)
|
|
hd_rod('Arm'+side+'_Upper',a,b,.065,m['basalt'])
|
|
hd_rod('Arm'+side+'_Forearm',b,c,.06,m['ceramic'])
|
|
hd_disc('Arm'+side+'_Elbow',(b[0],b[1]-.04,b[2]),.053,.04,m['gold'])
|
|
living_blob('Arm'+side+'_Glove',c,(.066,.06,.072),m['dark'])
|
|
for j in range(3):
|
|
hd_rod('Arm'+side+'_Finger'+str(j),(c[0]+(j-1)*.025,c[1]-.045,c[2]),(c[0]+(j-1)*.025,c[1]-.049,c[2]-.055),.013,m['gold'])
|
|
hd_rod('WeaponL_Handle',(-.30,-.22,.23),(-.30,-.22,.93),.025,m['gold'])
|
|
hd_curve('WeaponL_Fork',[(-.44,-.22,.87),(-.40,-.22,.76),(-.30,-.22,.74),(-.20,-.22,.76),(-.16,-.22,.87)],[.022]*5,m['bone'],12,5)
|
|
hd_rod('WeaponR_Probe',(.29,-.22,.53),(.40,-.34,.72),.027,m['gold'])
|
|
|
|
|
|
def build_high_core(spec,m):
|
|
"""Cut mineral held by an engraved stone/brass cradle and satellite shards."""
|
|
hd_materials(m)
|
|
team=int(spec.get('team',0))
|
|
crystal=bpy.data.materials.new('SW_HD_Core_%d'%team);crystal['material_name']=crystal.name;crystal.use_nodes=True
|
|
color=('65D9C1' if team==0 else 'EE9B82')
|
|
c=tuple(srgb_to_linear(int(color[i:i+2],16)/255) for i in (0,2,4))
|
|
node=crystal.node_tree.nodes.get('Principled BSDF');node.inputs['Base Color'].default_value=(*c,1)
|
|
node.inputs['Metallic'].default_value=.28;node.inputs['Roughness'].default_value=.20
|
|
node.inputs['Emission Color'].default_value=(*c,1);node.inputs['Emission Strength'].default_value=.65
|
|
crystal.diffuse_color=(*c,1)
|
|
for j,(r,z,h) in enumerate([(1.20,.12,.24),(1.07,.27,.10),(.88,.39,.18),(.68,.51,.12)]):
|
|
hd_finish(cylinder('Body_CoreStep'+str(j),(0,0,z),r,h,m['basalt'],48),.027,3)
|
|
hd_ring('Body_CoreStepRim'+str(j),(0,0,z+h*.44),r*.98,.018,m['gold'],segments=64)
|
|
if team == 1:
|
|
corners=[Vector((.97*cos(k*2*pi/3),.97*sin(k*2*pi/3),.367)) for k in range(3)]
|
|
for k in range(3):
|
|
hd_rod('Team_Triangle'+str(k),corners[k],corners[(k+1)%3],.022,crystal)
|
|
else:
|
|
hd_ring('Team_Circle',(0,0,.367),.97,.022,crystal,segments=64)
|
|
for k in range(12):
|
|
a=k*pi/6
|
|
hd_box('Body_PlinthBlock'+str(k),(1.08*cos(a),1.08*sin(a),.21),(.23,.25,.24),m['edge'],.025,rotation=(0,0,a))
|
|
hd_ring('Body_Seal'+str(k),(1.06*cos(a),1.06*sin(a),.346),.042,.009,m['gold_light'],segments=24)
|
|
hd_rod('Body_RadialInlay'+str(k),(.90*cos(a),.90*sin(a),.453),(.60*cos(a),.60*sin(a),.453),.012,crystal)
|
|
for k in range(6):
|
|
a=k*pi/3
|
|
hd_curve('Body_Cradle'+str(k),[(.66*cos(a),.66*sin(a),.47),(.75*cos(a),.75*sin(a),.67),(.60*cos(a),.60*sin(a),1.02),(.43*cos(a),.43*sin(a),1.14)],[.09,.083,.060,.035],m['gold'],16,7)
|
|
hd_ring('Body_CradleCollar'+str(k),(.60*cos(a),.60*sin(a),.90),.065,.015,m['gold_light'],segments=32)
|
|
def shard(name,loc,r,height,tilt=0):
|
|
vertices=[(0,0,-height*.45)]
|
|
for j,(radius,z) in enumerate([(r*.78,-height*.23),(r,height*.13),(r*.72,height*.31)]):
|
|
for k in range(7):
|
|
a=k*2*pi/7+.10*j
|
|
vertices.append((radius*cos(a),radius*sin(a),z))
|
|
vertices.append((r*.16,0,height*.57));faces=[]
|
|
for k in range(7):faces.append((0,1+(k+1)%7,1+k))
|
|
for j in range(2):
|
|
for k in range(7):
|
|
a=1+j*7+k;b=1+j*7+(k+1)%7;faces.append((a,b,b+7,a+7))
|
|
for k in range(7):faces.append((15+k,15+(k+1)%7,22))
|
|
obj=mesh_object(name,vertices,faces,crystal);obj.location=loc;obj.rotation_euler=(tilt,tilt*.4,0)
|
|
hd_finish(obj,.006,2)
|
|
shard('Core_CrystalMain',(0,0,1.41),.41,1.68)
|
|
for k in range(5):
|
|
a=k*2*pi/5
|
|
shard('Core_CrystalSatellite'+str(k),(.43*cos(a),.43*sin(a),.89+(k%2)*.10),.15,.71,.18*cos(a))
|
|
hd_ring('Body_CrystalHalo',(0,0,1.19),.60,.021,m['gold_light'],segments=72)
|