首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Maya python terrain生成器

Maya python terrain生成器
EN

Stack Overflow用户
提问于 2018-12-05 20:59:54
回答 2查看 780关注 0票数 1

为了一个学校项目,我正在尝试编写一个地形生成器。我是一个完全的python新手,但我已经研究了很多关于地形生成的知识。这是我现在的代码:

代码语言:javascript
复制
#imports
import maya.cmds as cmds
import random
#variables
landsub = 100 #number of subdivisions on the plane
landsize = 400 #size of the plane
maxheight = 100
land = cmds.polyPlane( sx=landsub, sy=landsub, w=landsize, h=landsize)
vtxCount = cmds.polyEvaluate(v=True)
print land
values = [random.triangular(0,1,0) for i in xrange(10)]

#code
for x in range(vtxCount):
    cmds.select(cl=True)
    cmds.select(land[0] + '.vtx[' + str(x) + ']')
    cmds.move(values[x] * maxheight, y=True, absolute=True) 

cmds.select(land[0])
#cmds.polySmooth(dv = 1)

我正在尝试(努力)使maxheight和vtxCount变量相互依赖;最大高度上的顶点数应该是最小的,不断增加,直到大多数顶点都在最小高度上。在我目前的代码中,大多数顶点似乎都在中等高度,很少有最小高度的顶点。我已经寻找了很长一段时间的解决方案,但我不熟悉我可以在python中做什么,因此很难为我的代码找到正确的命令。

我真心希望有人能帮助我,为我指明正确的方向!感谢您的阅读

EN

回答 2

Stack Overflow用户

发布于 2018-12-05 23:55:52

你可以这样做

代码语言:javascript
复制
#imports
import maya.cmds as cmds
import random
#variables
landsub = 100 #number of subdivisions on the plane
landsize = 400 #size of the plane
maxheight = 100
land = cmds.polyPlane( sx=landsub, sy=landsub, w=landsize, h=landsize)
vtxCount = range(cmds.polyEvaluate(v=True))
random.shuffle(vtxCount)
values = [random.triangular(0,1,0) for i in xrange(10)]
values_count = len(values)
SEED = 448
random.seed(SEED)
optimize_setter = []

#code
for x in vtxCount:
    mod = x % values_count
    # cmds.move(values[mod-1] * maxheight, land[0] + '.vtx[' + str(x) + ']',y=True, absolute=True)
    optimize_setter += [float(0),values[mod-1]*maxheight,float(0)]
cmds.setAttr('pPlane1.vtx[:]', *optimize_setter)
cmds.select(land[0])

如果您希望0附近有更多的值,则可以将值更改为具有更多的.1值。我不知道你有什么问题。

代码语言:javascript
复制
values = []
high_values = [random.triangular(0,1,0) for i in xrange(3)]
low_values = [random.uniform(0, .2), for i in xrange(7)]
values = low_values + high_values

编辑

代码语言:javascript
复制
#imports
import maya.cmds as cmds
import random
#variables
landsub = 100 #number of subdivisions on the plane
landsize = 400 #size of the plane
maxheight = 15
land = cmds.polyPlane( sx=landsub, sy=landsub, w=landsize, h=landsize)
vtxnb = cmds.polyEvaluate(v=True)
vtxCount = range(vtxnb)

values = []
high_values = [random.triangular(0,1,0) for i in xrange(vtxnb/10)]
low_values = [random.uniform(0, .3) for i in xrange(vtxnb/2)]
values = low_values + high_values
values_count = len(values)
SEED = 448
random.seed(SEED)
random.shuffle(vtxCount)
random.shuffle(values)
optimize_setter = []

#code
for x in vtxCount:
    mod = x % values_count
    # cmds.move(values[mod-1] * maxheight, land[0] + '.vtx[' + str(x) + ']',y=True, absolute=True)
    optimize_setter += [float(0),values[mod-1]*maxheight,float(0)]
cmds.setAttr('pPlane1.vtx[:]', *optimize_setter)
cmds.select(land[0])
票数 0
EN

Stack Overflow用户

发布于 2018-12-08 07:11:25

地形生成是一个有趣的问题,不幸的是,它经常需要大量的小提琴才能得到令人满意的结果。

问题的'maya‘部分在@drweeny的回答中得到了很好的处理:你只需要批量设置polyPlane的.vtx属性。这里有一个类似的方法,主要的区别是这个函数接受一个位置数组,它的工作方式类似于位图:它是一个列表,它的内容是列表,表示高度图中的行和列,即:[ [0,1], [2,3] ]表示

代码语言:javascript
复制
[0, 1]
[2, 3]

作为一个网格。将其转换为多平面非常简单:

代码语言:javascript
复制
def array_to_plane (array):
    # this expects that array is an list-of-lists
    # arranged as  [ [0,1,2], [3,4,5], ... etc  ]

    h = len(array)
    w = len(array[0])

    # this makes a plane with the same number of samples as your array
    plane, _  = cmds.polyPlane(width = 1, height = 1, sx = w -1 , sy=h-1)
    # the zeros are here just so the final argument list is a set of xyz
    # positions       
    setter = []
    for row in array:
        for column in row:
            setter.append (0.0)
            setter.append (column)
            setter.append (0.0)
    cmds.setAttr(plane + '.vtx[:]', *setter, type='double3')
    return plane

有趣和棘手的部分实际上是填充网格,使地形看起来不太像随机噪声。有很多技术,但基本的是:

随机化

您确实希望将随机数应用于您的高度贴图。幸运的是,python的random module对于不同分布的噪声有很多很好的选择。下面是一个将随机数插入地图网格的简单函数:

代码语言:javascript
复制
def randomize(map, scale):
    rows = len(map)
    columns = len(map[0]

    # loop over the map and add random values
    for r in  range(rows): 
        for c in range(columns):
            map[r][c] += (random.gauss(0,1) * scale)

比例尺

随机数网格看起来不像地形--它太混乱了。一种非常常见的技术是以不同的物理大小应用随机化,以模拟大小特征的混合。要做到这一点,最简单的方法是从一个小地图开始,然后逐步放大它--这将为您提供不同大小的混合特征。

这里有一种便宜的方法来获取一个高度图网格,并在每个维度上将其内容加倍。如果你这样做几次,并在上面添加一些随机化,你就会得到从非常大到非常小的混合特征。

代码语言:javascript
复制
def upsize(heightmap):
    output = []
    for row in heightmap:
        new_row = []
        for each_value in row:
            # first double the entries in the horizontal direction
            new_row.append(each_value)
            new_row.append(each_value)

        # then add two copies of the row to the output.
        # don't add it twice -- add a copy to keep
        # the data independent
        output.append(new_row)
        output.append(new_row[:])

    return output

在像[ [0,1], [2,3] ]这样的地图上运行它会生成像[ [0,0,1,1], [0,0,1,1], [2,2,3,3], [2,2,3,3]]这样的地图

过滤

您不希望heightmap中的每个样本都独立于其邻居:这在自然界中很少见,而且看起来非常糟糕。在photoshop这样的程序中,你可以使用'kernel'生成模糊效果,它基本上只是像素和它的邻居的加权平均值。这里有很多选择(这是一个很好的研究你的项目的领域)。这是一个非常简单的模糊内核,它取一个我们的贴图网格,并返回一个模糊的新内核;你会看到,在添加不同的像素权重后,我们还使用了线性插值来控制模糊的强度:

代码语言:javascript
复制
def blur(map):
    output = []
    for row in map:
        output.append(row[:])

    width = len(map[0])
    height = len(map)

    for row in range (1, height-1):
        for column in range (1, height-1):
            v = 0
            v += map [row-1][column - 1]
            v += map [row-1][column] * 2
            v += map [row-1][column + 1]
            v += map [row][column - 1] * 2
            v += map [row][column] * 4
            v += map [row][column + 1] * 2
            v += map [row+1][column - 1]
            v += map [row+1][column]  * 2
            v += map [row+1][column + 1]
            v = v / 16.0

            # lerp the final output based on amount; 0 = no blur, 1 = full blur)
            output[row][column] =  v

    return output

这一步有很多选项,这些选项会影响最终输出的效果。您可以使用Photoshop's custom filter非常轻松地尝试使用过滤器内核,它实际上只是一个简单的内核编辑器。

把它们放在一起

有了随机化,缩放和过滤,你就有足够的能力来制作一个有趣的地形生成工具包。共同的主线是,你在“像素”的“位图”上做所有的艰苦工作,排列成一个列表-lists,当你完成后,你把它交给玛雅来制作一个最终的对象。

这里有一个非常基本的方法来把它们放在一起。我鼓励你把它拆开,然后用满足你创造性想法的方式把它重新组合起来。将这些部分编写为单独的函数,在heightmap列表上工作,这使得添加或调整行为变得很容易,而不会破坏整个过程。

代码语言:javascript
复制
def fractalize(iterations, scale=1.0,  seed = None):

    # this lets you make it repeatable if you want
    if seed:
        random.seed(seed)

    # make a 2-2 starter map
    map = [ [0.0, 0.0], [0.0, 0.0] ] 

    randomize(map, scale)

    for n in range(1, iterations):
        map = upsize(map)
        map = blur(map)

        # this turns down the randomization
        # in each successive step... you could
        # use many formulas here for different effects
        randomize(map, scale / 2**n)

    return array_to_plane(map)

fractalize(7, 0.125, seed=1234)

请注意该迭代次数:每次迭代都会使顶点数增加四倍,因此将其设置得太高会使maya下沉。值为8会生成一个具有255 x 255个顶点的平面;请谨慎使用。

让它成为你自己的一些东西:*什么时候--以及多久一次--你想添加模糊?*如果你使用一个不同的模糊内核会发生什么?*如果你改变randomize(map, scale / 2**n)到其他公式会发生什么?*你可以对位图做什么来模拟水位?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53632937

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档