Автор Тема: Blender и Matt Shlian  (Прочитано 232 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Николай Николаев

  • Житель
  • emerge --keep-going
Blender и Matt Shlian
« : 04 Август 2020, 08:32:58 »
В продолжении темы 3D панель пирамиды волной, в которой упоминалось творческое бумажное моделирование Matt Shlian, добавлю несколько строк о пользе математики и кодерства, опять же с использованием Blender API.

Что требовалось:


Что получилось (viewport):
https://yadi.sk/i/JwiY_kUpfzkv-A

Как делалось:
Во-первых, сейчас не требуется визуализация картинки, поскольку в дальнейшем требуется изготовить бумажную модель (панель). То есть по факту будет множество выкроек для изготовления элементов и сборка из этих элементов панели.
По сути требуется только геометрия.

Этап 1 — построить соты. Строим двумя циклами как обычно по горизонтали и вертикали, но нечетные вертикальные ряды делаем со смещением и на один элемент больше.

Код: python [Выделить]
# generate piramids
    ry = radius*2*math.cos(math.radians(30))
    rx = radius*3*math.sin(math.radians(30))

    for x in range(cols):
        dy = 1 if (x % 2) else 0
        for y in range(rows+dy):


В теле цикла формируем два вектора:
вектор позиции пирамиды:
Код: python [Выделить]
v0=mathutils.Vector((x*rx,(-y+dy/2)*ry,0.0))

и вектор смещения вершины пирамиды относительно основания:
Код: python [Выделить]
vd = cfunc(x/(cols-1),y/(rows-1),scale)


Важно, что этот вектор на самом деле определяется пользовательской функций cfunc, ссылка на которую передается в рутину. Пользовательская функция принимает всего три параметра — относительные координаты основания пирамиды, где X и Y могут принимать значение от 0 до 1 и некоторый масштабный коэффициент, который определяет силу воздействия смещения на вершину пирамиды.

Этап 2 — определение пользовательской функции.
Как уже было выше сказано, пользовательская функция должна определять смещение вершины пирамиды относительно основания и принимает всего три параметра x,y,s и возвращает вектор смещения умноженный на силу влияния (s).
Для примера будем использовать такую функцию, которая приближенно дает похожую геометрию как на исходном изображении.

Код: python [Выделить]
def sin_cos(x,y,s):
    # user define function
    # return offset vector*scale
    A = 3.8
    B = 1.8
    C = 4.2
    D = 1.8
    return mathutils.Vector((math.cos(A*(B*x+y)),math.sin(C*(D*x+y)),0.0))*s


Этап 3 — запускаем рутину.

Делаем автосохранение! Необязательно, но мне помогло.
Код: python [Выделить]
#autosave
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)


Строим 26 рядов по 33 пирамиды в ряду с радиус основания 1 и высотой 3, силой влияния смещения 2 и пользовательской функцией sin_cos
Код: python [Выделить]
#routine(rows,cols,radius,height,function)
routine(26,33,1.0,3.0,2,sin_cos)


Естественно, все параметры можно менять, а самое важно можно и нужно переписать пользовательскую функцию под требуемые задачи.

Весь код:
Код: python [Выделить]
import bpy
import mathutils
import math



def make_mesh(name):
    me = bpy.data.meshes.new(name)
    ob = bpy.data.objects.new(name, me)
    bpy.data.collections[0].objects.link(ob)
    return ob

def add_data(ob,verts,edges,faces):
    me = ob.data
    me.name = ob.name +' mesh'
    me.from_pydata(verts,edges,faces)
    me.update()

def emm(v0,vd,r,h):
    verts = []
    edges = []
    faces = []
    da = 30
    for i in range(6):
        a = 60*i
        a1 = math.radians(a-da)
        a2 = math.radians(a+da)
        v1 = v0 + mathutils.Vector((r*math.sin(a1), r*math.cos(a1),0.0))
        v2 = v0 + mathutils.Vector((r*math.sin(a2), r*math.cos(a2),0.0))       
        last=len(verts)
        vp = v0+vd+mathutils.Vector((0,0,h))
        verts.extend([vp,v1,v2])
        faces.append([last,last+1,last+2])
    return verts,edges,faces

def routine(rows,cols,radius,height,scale,cfunc):
# remove all objects
    for ob in bpy.data.objects:
        ob.parent = None
        bpy.data.objects.remove(ob, do_unlink=True,do_ui_user=True)
       
# init material
    mat = bpy.data.materials.get("Material")
    if mat is None:
        mat = bpy.data.materials.new(name="Material")

# generate piramids
    ry = radius*2*math.cos(math.radians(30))
    rx = radius*3*math.sin(math.radians(30))

    for x in range(cols):
        dy = 1 if (x % 2) else 0
        for y in range(rows+dy):
            v0=mathutils.Vector((x*rx,(-y+dy/2)*ry,0.0))
            vd = cfunc(x/(cols-1),y/(rows-1),scale)

            verts, edges, faces = emm(v0,vd,radius,height)
            ob=make_mesh('frag_'+str(x)+'_'+str(y))
            add_data(ob,verts,edges,faces)

            if ob.data.materials:
                ob.data.materials[0] = mat
            else:
                ob.data.materials.append(mat)           
   
def sin_cos(x,y,s):
    # user define function
    # return offset vector*scale
    A = 3.8
    B = 1.8
    C = 4.2
    D = 1.8
    return mathutils.Vector((math.cos(A*(B*x+y)),math.sin(C*(D*x+y)),0.0))*s

#autosave
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
#bpy.ops.wm.open_mainfile(filepath=bpy.data.filepath)
#routine(rows,cols,radius,height,function)
routine(26,33,1.0,3.0,2,sin_cos)


.blend файл с примером:
https://yadi.sk/d/HH6IHMiPF5MEUw


« Последнее редактирование: 04 Август 2020, 08:50:11 от Николай Николаев »

 


* По форуму

* Последние вложения


Скачано: 124
Автор: Алексей Лябик
untitled1.png
Скачано: 115
Автор: Алексей Лябик
packt200910.jpg
Скачано: 98
Автор: Striver
2020-09-06_12-24-29.png
Скачано: 136
Автор: barmalej
-2.png
Скачано: 147
Автор: R_M_S