Генерация путей на сфере в BlenderPython

Программы на Python
Ответить
Anonymous
 Генерация путей на сфере в Blender

Сообщение Anonymous »

Существует код (который я предоставлю ниже), сгенерированный с использованием ChatGPT. Этот код генерирует сферу (икосферу с большим количеством подразделений, хотя вы можете использовать сферу с большим количеством подразделений) и равномерно распределяет по ней 32 небольшие именованные сферы. Затем он генерирует кратчайший путь от сферы a1 до b6, которые являются двумя наиболее удаленными сферами друг от друга. До этого момента код работает нормально.
Однако после этого возникают проблемы. Мне нужны пути от a1 ко всем остальным сферам, и они должны соответствовать следующим требованиям:
  • Длина пути должна быть как можно ближе к длине пути от a1 до b6.
  • Пути не должны пересекаться с другими сферами, то есть путь например, от а1 до а3 не должно пересекаться ни с какими другими сферами кроме а1 и а3. В идеале пути также должны сохранять некоторую обязательную дистанцию ​​от других сфер и друг от друга. Однако пересечение начальной и конечной сфер обязательно.
  • Пути не должны пересекаться друг с другом. Вначале они могут перекрываться, но в дальнейшем не должны пересекаться.
  • Путь может изгибаться, но изгибы не должны быть резким (90 градусов и более), а количество изгибов также должно быть ограничено (например, не более 10). Вот здесь и нужен работающий алгоритм поиска нужных изгибов.
  • Путь должен лежать на сфере. Он не обязательно должен точно следовать сетке сферы, но должен оставаться на поверхности сферы.
У меня есть пробовал разные подходы, но обычно код не соответствует всем требованиям, а сгенерированные пути очень непривлекательны. Возможно, стоит попробовать условное Q-обучение, но неясно, как его настроить. Ниже приведен пример того, как код строит пути (без отклонений) и какими я хотел бы их видеть (путь я нарисовал сам для приближения, правда длины могут не совпадать точно).
Изображение
Изображение
Изображение
Вот код:


import bpy

import math

import mathutils

bpy.ops.object.select_all(action='SELECT')

bpy.ops.object.delete(use_global=False)

bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=6, radius=1)

sphere = bpy.context.object

sphere.name = "MainSphere"

bpy.ops.object.shade_smooth()

bpy.ops.object.mode_set(mode='OBJECT')

num_points = 32

phi = (1 + math.sqrt(5)) / 2

def calculate_A(n):

if n == 1:

return 1

elif n == 2:

return 4

else:

A = [1, 4]

for i in range(2, n):

A.append(A[i-1] + A[i-2])

return A[n-1]

def calculate_g(N):

k = math.floor(math.log(N / 1.5) / math.log(phi))

if k % 2 == 0:

return 3 - phi

else:

j = (k + 7) // 2

A_j_next = calculate_A(j + 1)

A_j = calculate_A(j)

return A_j_next / A_j

def delini_sphere_points(num_points):

points = []

for k in range(num_points):

g_n = calculate_g(k + 1)

theta = math.acos(1 - 2 * (k + 0.5) / num_points)

phi_angle = math.pi * (1 + 5**0.5) * (k + 1)

x_pos = math.sin(theta) * math.cos(phi_angle)

y_pos = math.sin(theta) * math.sin(phi_angle)

z_pos = math.cos(theta)

points.append((x_pos, y_pos, z_pos))

return points

points = delini_sphere_points(num_points)

sphere_objects = []

for idx, point in enumerate(points):

bpy.ops.mesh.primitive_uv_sphere_add(radius=0.04, location=point)

small_sphere = bpy.context.object

letter = chr(97 + (idx // 26))

number = (idx % 26) + 1

small_sphere.name = f"{letter}{number}"

sphere_objects.append(small_sphere)

a1_location = sphere_objects[0].location

b6_location = sphere_objects[31].location

def distance(point1, point2):

return (point1 - point2).length

def create_constrained_path(start, end, num_segments, max_deviation_angle=90):

path_coords = [start]

prev_direction = (end - start).normalized()

for i in range(1, num_segments - 1):

t = i / (num_segments - 1)

interpolated_point = start.lerp(end, t)

direction = (interpolated_point - start).normalized()

angle = prev_direction.angle(direction)

if math.degrees(angle) > max_deviation_angle:

direction = prev_direction

prev_direction = direction

path_coords.append(start + direction * distance(start, end) * t)

path_coords.append(end)

return path_coords

def normalize_to_sphere(path_coords):

return [point.normalized() for point in path_coords]

num_segments = 35

path_coords_a1_b6 = create_constrained_path(a1_location, b6_location, num_segments)

path_coords_a1_b6 = normalize_to_sphere(path_coords_a1_b6)

def create_tube_from_path(path_coords, radius=0.05):

curve_data = bpy.data.curves.new(name="PathCurve", type='CURVE')

curve_data.dimensions = '3D'

spline = curve_data.splines.new(type='POLY')

spline.points.add(count=len(path_coords) - 1)

for i, vertex in enumerate(path_coords):

spline.points.co = (vertex.x, vertex.y, vertex.z, 1)

curve_object = bpy.data.objects.new("PathCurveObject", curve_data)

bpy.context.scene.collection.objects.link(curve_object)

bpy.ops.object.select_all(action='DESELECT')

curve_object.select_set(True)

bpy.context.view_layer.objects.active = curve_object

bpy.ops.object.convert(target='MESH')

bpy.ops.object.modifier_add(type='BEVEL')

bevel = curve_object.modifiers["Bevel"]

bevel.width = radius

bevel.segments = 4

return curve_object

create_tube_from_path(path_coords_a1_b6, radius=0.05)

distance_a1_b6 = distance(a1_location, b6_location)

def create_paths_to_all_spheres():

for idx, sphere_object in enumerate(sphere_objects):

if sphere_object != sphere_objects[0]:

path_length = distance(a1_location, sphere_object.location)

num_segments = max(int((path_length / distance_a1_b6) * len(path_coords_a1_b6)), 30)

path_coords = create_constrained_path(a1_location, sphere_object.location, num_segments)

path_coords = normalize_to_sphere(path_coords)

create_tube_from_path(path_coords, radius=0.05)

create_paths_to_all_spheres()


Подробнее здесь: https://stackoverflow.com/questions/792 ... in-blender
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»