Jed*_*urt 5 python dsl context-free-grammar blender
[注意:在提交之前重读这个,我意识到这个Q已经成为一个史诗.感谢您放纵我对这一追求背后的原因的长期解释.我觉得,如果我能够帮助另一个人开展一个类似的项目,如果我知道这个问题背后的动机,我就更有可能加入.]
我最近由Mikael Hvidtfeldt Christensen 进入Structure Synth.它是一种用于从(大多数)上下文无关语法(称为Eisenscript)生成3D几何的工具.结构Synth本身的灵感来自Context Free Art.上下文无关语法可以从令人惊讶的简单规则集创建一些令人惊叹的结果.
我当前的Structure Synth工作流程涉及从Structure Synth导出OBJ文件,将其导入Blender,设置灯光,材质等,然后使用Luxrender进行渲染.不幸的是,导入这些OBJ文件通常会导致Blender暂停,因为可能存在数千个具有相当复杂几何形状的对象.我说"公平"因为Structure Synth只生成基本形状,但是由三角形表示的球体仍然有很多面.
因此,直接在Blender中生成结构将优于当前进程(Blender对Python脚本的深入支持应该使这成为可能).智能Python库可以使用Blender的实例化功能来使用一个网格生成无数对象,从而节省内存.Plus Blender是一个功能齐全的3D套件,它解释CFDG的能力将提供远远超出Structure Synth所能提供的创造性可能性.
所以我的问题是如何最好地将Eisenscript语法翻译成Python DSL.这是一个简单的Eisenscript看起来像:
set maxdepth 2000
{ a 0.9 hue 30 } R1
rule R1 {
{ x 1 rz 3 ry 5 } R1
{ s 1 1 0.1 sat 0.9 } box
}
rule R1 {
{ x 1 rz -3 ry 5 } R1
{ s 1 1 0.1 } box
}
Run Code Online (Sandbox Code Playgroud)
为了解释,第一次调用R1(第2行)将随机调用R1的两个定义之一.R1的每个定义递归调用R1(随机调用两个定义之一)并创建一个框.递归后第一行杀死了一代,已经达到了2000级.
Jeremy Ashkenas(CoffeeScript成名)使用块在Ruby中成功实现了无上下文DSL.在内部,它的工作原理是为每个规则的"名称"创建一个哈希键,并将该规则的每个定义的块存储在一个数组中,以便在调用规则时随机选择.
以前的Eisenscript规则定义将转换为Ruby DSL,如下所示:
rule :r1 do
r1 :x => 1, :rz => 3, :ry => 5
box :s => [1, 1, 0.1], :sat => 0.9
end
rule :r1 do
r1 :x => 1, :rz => -3, :ry => 5
box :s => [1, 1, 0.1]
end
Run Code Online (Sandbox Code Playgroud)
我是一名新手Python用户,因此一直在研究Python的函数编程功能.似乎lambda太有限了,无法创建类似于Jeremy的Ruby DSL的东西,据我所知,lambda是匿名函数的唯一选择?
经验丰富的Pythonista如何接近设计?
我决定通过将 Ruby 库的块转换为预定义函数来构建初始原型,这些函数将传递到 ContextFree 实例中,并使用条件进行扩充以避免无限循环,并作为实例方法添加到实例中。这是当前状态。欢迎批评指正;这是我的第一个 Python 代码,我已经准备好并愿意将我的 Ruby 习惯重新训练为 Python 习惯。
import random
class ContextFree(object):
def __init__(self):
self.rules = {}
# grab any instancemethod to get an instance of the instancemethod class
self.instancemethod = type(self.add_rule)
self.max_depth = 100
self.depth = 0
def add_rule(self, func, prob=1):
rule_name = func.__name__
if not rule_name in self.rules:
self.rules[rule_name] = { 'funcs' : [], 'total' : 0 }
total = self.rules[rule_name]['total']
self.rules[rule_name]['funcs'].append([range(total,(prob+total)), func])
self.rules[rule_name]['total'] += prob
def augmented_func(self, options={}):
if not self.depth >= self.max_depth:
self.depth += 1
pick = self.determine_rule(rule_name)
print('Generation', self.depth)
pick(self)
self.__dict__[rule_name] = self.instancemethod(augmented_func, self)
def determine_rule(self, rule_name):
rule = self.rules[rule_name]
winning_number = random.randrange(0, self.rules[rule_name]['total'])
for func in rule['funcs']:
if winning_number in func[0]:
return func[1]
cf = ContextFree()
def box(self):
print('Rule for box1')
self.box()
cf.add_rule(box)
def box(self):
print('Rule for box2')
self.box()
cf.add_rule(box)
cf.box()
# Output:
## Generation 1
## Rule for box2
## Generation 2
## Rule for box2
## Generation 3
## Rule for box1
## Generation 4
## Rule for box2
## Generation 5
## Rule for box1
## Generation 6
## Rule for box2
## Generation 7
## Rule for box2
## Generation 8
## Rule for box1
## Generation 9
## Rule for box2
## Generation 10
## Rule for box2
## Generation 11
## Rule for box1
## Generation 12
## Rule for box1
## Generation 13
## Rule for box1
## Generation 14
## Rule for box1
## Generation 15
## Rule for box2
## Generation 16
## Rule for box1
## Generation 17
## Rule for box1
## Generation 18
## Rule for box1
## Generation 19
## Rule for box1
## Generation 20
## Rule for box1
## Generation 21
## Rule for box2
## Generation 22
## Rule for box2
## Generation 23
## Rule for box1
## Generation 24
## Rule for box2
## Generation 25
## Rule for box1
## Generation 26
## Rule for box2
## Generation 27
## Rule for box2
## Generation 28
## Rule for box1
## Generation 29
## Rule for box2
## Generation 30
## Rule for box2
## Generation 31
## Rule for box2
## Generation 32
## Rule for box2
## Generation 33
## Rule for box2
## Generation 34
## Rule for box1
## Generation 35
## Rule for box2
## Generation 36
## Rule for box1
## Generation 37
## Rule for box1
## Generation 38
## Rule for box1
## Generation 39
## Rule for box1
## Generation 40
## Rule for box2
## Generation 41
## Rule for box1
## Generation 42
## Rule for box1
## Generation 43
## Rule for box1
## Generation 44
## Rule for box1
## Generation 45
## Rule for box2
## Generation 46
## Rule for box1
## Generation 47
## Rule for box2
## Generation 48
## Rule for box1
## Generation 49
## Rule for box2
## Generation 50
## Rule for box1
## Generation 51
## Rule for box1
## Generation 52
## Rule for box1
## Generation 53
## Rule for box2
## Generation 54
## Rule for box2
## Generation 55
## Rule for box2
## Generation 56
## Rule for box2
## Generation 57
## Rule for box2
## Generation 58
## Rule for box1
## Generation 59
## Rule for box1
## Generation 60
## Rule for box1
## Generation 61
## Rule for box2
## Generation 62
## Rule for box2
## Generation 63
## Rule for box2
## Generation 64
## Rule for box1
## Generation 65
## Rule for box2
## Generation 66
## Rule for box2
## Generation 67
## Rule for box2
## Generation 68
## Rule for box2
## Generation 69
## Rule for box2
## Generation 70
## Rule for box1
## Generation 71
## Rule for box2
## Generation 72
## Rule for box2
## Generation 73
## Rule for box2
## Generation 74
## Rule for box1
## Generation 75
## Rule for box2
## Generation 76
## Rule for box1
## Generation 77
## Rule for box1
## Generation 78
## Rule for box2
## Generation 79
## Rule for box1
## Generation 80
## Rule for box2
## Generation 81
## Rule for box1
## Generation 82
## Rule for box1
## Generation 83
## Rule for box1
## Generation 84
## Rule for box1
## Generation 85
## Rule for box2
## Generation 86
## Rule for box1
## Generation 87
## Rule for box1
## Generation 88
## Rule for box2
## Generation 89
## Rule for box2
## Generation 90
## Rule for box1
## Generation 91
## Rule for box1
## Generation 92
## Rule for box1
## Generation 93
## Rule for box1
## Generation 94
## Rule for box1
## Generation 95
## Rule for box1
## Generation 96
## Rule for box2
## Generation 97
## Rule for box1
## Generation 98
## Rule for box2
## Generation 99
## Rule for box1
## Generation 100
## Rule for box2
Run Code Online (Sandbox Code Playgroud)