Вопросы по написанию плагинов

Список разделов Blender 3D Плагины

Описание: Обсуждение расширений для Blender
Модератор: exooman

Сообщение #41 Korchy » 18.12.2018, 08:26

Pavel писал(а):Два полигона смотрят вверх, но у одного индексы вершин возрастают, а у другого нет.
Так не может быть. Значить то, что у тебя на 1-м рисунке - не индексы вершин, а просто какие-то номера.
А индексы вершин если для левого полигона допустим 1-2-0, то для второго допустим 3-5-4. Тогда нормали будут смотреть в одну сторону.
Pavel писал(а):Этот полигон 0, 1, 2. Он смотрит вверх.
Вот, здесь ты как раз продемонстрировал принцип. Был полигон с индексами 2-0-1 - нормаль смотрела в одну сторону. Ты его сделал 0-2-1 (развернул в противоположную сторону) - соотв. нормаль поменяла направление тоже.
Pavel писал(а):Нужно как-то анализировать координаты вершин и нормали полигонов, но я не знаю как.
Я не понимаю, зачем что-то анализировать. Ты брешь первый полигон и сторишь в нужном порядке. Берешь следующий и строишь в том же порядке. Если есть такие же индексы но в противоположном - отбрасываешь их (ну т.е. просто не строишь по ним). Все )
Korchy M В сети
Аватара
Сообщения: 2529



Сообщение #42 Pavel » 18.12.2018, 18:59

mac7 писал(а):зачем так извращаться и делать мод под сталкер?
Я делаю импортёр 3д моделей, потому что интересно. Правда не всегда всё получается.

mac7 писал(а):почему не хочешь изучить какой-то актуальный игровой движок
потому что, только со сталкером у меня есть много воспоминаний :sweet: . Другие игры и движки не интересны. Так как кроме сталкера, не во что практически не играл.

Добавлено спустя 15 минут 55 секунд:
Korchy, а на этом рисунке правильные индексы?:
Изображение

У двух полигонов индексы возрастают, а нормали противоположные.
Я пробовал по твоему способу отбрасывать полигоны, но не получилось. Всё равно икосфера не является нонманифолдной.

Добавлено спустя 19 минут 31 секунду:
Я ведь правильно написал фильтрацию полигонов?:

Код: Выделить всё
import bpy


def find_triangles_pairs(triangles):
    pairs_triangles = {}
    for triangle in triangles:
        triangle_key = tuple(sorted(triangle))
        if pairs_triangles.get(triangle_key):
            pairs_triangles[triangle_key].append(triangle)
        else:
            pairs_triangles[triangle_key] = [triangle, ]
    return pairs_triangles


def filter_second_side(pairs_triangles):
    one_sided_tiangles = []
    for pair_triangles in pairs_triangles.values():
        triangle_0 = pair_triangles[0]
        triangle_1 = pair_triangles[1]
        if triangle_0[1] < triangle_1[1]:
            one_sided_tiangles.append(triangle_0)
        else:
            one_sided_tiangles.append(triangle_1)
    return one_sided_tiangles


def remove_two_sided_triangles(triangles):
    pairs_triangles = find_triangles_pairs(triangles)
    one_sided_tiangles = filter_second_side(pairs_triangles)
    return one_sided_tiangles


vertices = (
    (0.0000, 0.0000, -1.0000),
    (0.7236, -0.5257, -0.4472),
    (-0.2764, -0.8506, -0.4472),
    (-0.8944, 0.0000, -0.4472),
    (-0.2764, 0.8506, -0.4472),
    (0.7236, 0.5257, -0.4472),
    (0.2764, -0.8506, 0.4472),
    (-0.7236, -0.5257, 0.4472),
    (-0.7236, 0.5257, 0.4472),
    (0.2764, 0.8506, 0.4472),
    (0.8944, 0.0000, 0.4472),
    (0.0000, 0.0000, 1.0000)
)

triangles = (
    # main sides
    (0, 1, 2),
    (1, 0, 5),
    (0, 2, 3),
    (0, 3, 4),
    (0, 4, 5),
    (1, 5, 10),
    (2, 1, 6),
    (3, 2, 7),
    (4, 3, 8),
    (5, 4, 9),
    (1, 10, 6),
    (2, 6, 7),
    (3, 7, 8),
    (4, 8, 9),
    (5, 9, 10),
    (6, 10, 11),
    (7, 6, 11),
    (8, 7, 11),
    (9, 8, 11),
    (10, 9, 11),
    # second sides
    (0, 2, 1),
    (1, 5, 0),
    (0, 3, 2),
    (0, 4, 3),
    (0, 5, 4),
    (1, 10, 5),
    (2, 6, 1),
    (3, 7, 2),
    (4, 8, 3),
    (5, 9, 4),
    (1, 6, 10),
    (2, 7, 6),
    (3, 8, 7),
    (4, 9, 8),
    (5, 10, 9),
    (6, 11, 10),
    (7, 11, 6),
    (8, 11, 7),
    (9, 11, 8),
    (10, 11, 9)
)

triangles = list(set(triangles))
triangles = remove_two_sided_triangles(triangles)
bpy_mesh = bpy.data.meshes.new('test_two_sided')
bpy_mesh.from_pydata(vertices, (), triangles)
bpy_object = bpy.data.objects.new('test_two_sided', bpy_mesh)
bpy.context.scene.objects.link(bpy_object)
Pavel M
Аватара
Сообщения: 848

Сообщение #43 Korchy » 18.12.2018, 20:16

Pavel писал(а):а на этом рисунке правильные индексы?:
Почему ты упираешься в возрастание? Они не обязательно возрастают. Для нормалей важо направление обхода. И 1-2-3 и 2-3-1 и 3-1-2 - для всех их будет нормаль в одну строну.
Для построения полигона все очень просто. Есть список номеров точек, которые просто показывают, что эти точки соединены полигоном. Все. И есть направление обхода этих номеров, которое показывает направление нормали. По часовой - в одну сторону нормаль, против часовой - нормаль в другую сторону. Вот и все. Все очень просто.
И на твоей картинке нормали у треугольников смотрят в разные стороны именно потому, что направление обхода точек у них противоположное. Все просто )
Korchy M В сети
Аватара
Сообщения: 2529



Сообщение #44 Pavel » 18.12.2018, 20:59

Korchy, всё равно не получилось получить нормальную икосферу. Вот код:
Код: Выделить всё
import bpy


def find_triangles_pairs(triangles):
    pairs_triangles = {}
    for triangle in triangles:
        triangle_key = tuple(sorted(triangle))
        if pairs_triangles.get(triangle_key):
            pairs_triangles[triangle_key].append(triangle)
        else:
            pairs_triangles[triangle_key] = [triangle, ]
    return pairs_triangles


def filter_second_side(pairs_triangles):
    one_sided_tiangles = []
    vertex_offsets = {
        0: (0, 1, 2),
        1: (1, 2, 0),
        2: (2, 0, 1)
    }
    for pair_triangles in pairs_triangles.values():
        triangle = pair_triangles[0]
        min_vertex_index = min(triangle)
        for position, vertex_index in enumerate(triangle):
            if vertex_index == min_vertex_index:
                min_vertex_position = position
        offsets = vertex_offsets[min_vertex_position]
        vertex_order = [
            triangle[offsets[0]],
            triangle[offsets[1]],
            triangle[offsets[2]]
        ]
        if vertex_order == sorted(vertex_order):
            one_sided_tiangles.append(pair_triangles[0])
        else:
            one_sided_tiangles.append(pair_triangles[1])
    return one_sided_tiangles


def remove_two_sided_triangles(triangles):
    pairs_triangles = find_triangles_pairs(triangles)
    one_sided_tiangles = filter_second_side(pairs_triangles)
    return one_sided_tiangles


vertices = (
    (0.0000, 0.0000, -1.0000),
    (0.7236, -0.5257, -0.4472),
    (-0.2764, -0.8506, -0.4472),
    (-0.8944, 0.0000, -0.4472),
    (-0.2764, 0.8506, -0.4472),
    (0.7236, 0.5257, -0.4472),
    (0.2764, -0.8506, 0.4472),
    (-0.7236, -0.5257, 0.4472),
    (-0.7236, 0.5257, 0.4472),
    (0.2764, 0.8506, 0.4472),
    (0.8944, 0.0000, 0.4472),
    (0.0000, 0.0000, 1.0000)
)

triangles = (
    # main sides
    (0, 1, 2),
    (1, 0, 5),
    (0, 2, 3),
    (0, 3, 4),
    (0, 4, 5),
    (1, 5, 10),
    (2, 1, 6),
    (3, 2, 7),
    (4, 3, 8),
    (5, 4, 9),
    (1, 10, 6),
    (2, 6, 7),
    (3, 7, 8),
    (4, 8, 9),
    (5, 9, 10),
    (6, 10, 11),
    (7, 6, 11),
    (8, 7, 11),
    (9, 8, 11),
    (10, 9, 11),
    # second sides
    (0, 2, 1),
    (1, 5, 0),
    (0, 3, 2),
    (0, 4, 3),
    (0, 5, 4),
    (1, 10, 5),
    (2, 6, 1),
    (3, 7, 2),
    (4, 8, 3),
    (5, 9, 4),
    (1, 6, 10),
    (2, 7, 6),
    (3, 8, 7),
    (4, 9, 8),
    (5, 10, 9),
    (6, 11, 10),
    (7, 11, 6),
    (8, 11, 7),
    (9, 11, 8),
    (10, 11, 9)
)

triangles = list(set(triangles))
triangles = remove_two_sided_triangles(triangles)
bpy_mesh = bpy.data.meshes.new('test_two_sided')
bpy_mesh.from_pydata(vertices, (), triangles)
bpy_object = bpy.data.objects.new('test_two_sided', bpy_mesh)
bpy.context.scene.objects.link(bpy_object)
Pavel M
Аватара
Сообщения: 848

Сообщение #45 Korchy » 18.12.2018, 21:23

У тебя какая-то ерунда с фильтрацией. Выведи отфильтрованный список и посмотри, правильно ли он отфильтровался.
А так, насколькоя вижу, строится то нормально.
И экспериментировать лучше на чем-нибудь попроще. Хоть куб возьми, не так много полигонов, можно глазами понять, где ошибка.
И вообще, можно после посроения просто bpy.ops.mesh.normals_make_consistent(inside=False) вызывать и не париться по поводу нормалей, раз не удается их самому правильно расположить.
Korchy M В сети
Аватара
Сообщения: 2529



Сообщение #46 Pavel » 16.01.2019, 18:35

Как заполнить объект точками? Точнее преобразовать объект в набор точек. Например, есть сфера и из неё нужно сделать следующее:
Изображение
Меня интересует, как это сделать на питоне. Я знаю, что можно добавить систему частиц и включить режим распределения Grid. Именно как это сделать самому.
Pavel M
Аватара
Сообщения: 848

Сообщение #47 Korchy » 16.01.2019, 19:15

Начать с 0,0,0, ставить каждую следующую точку по трехмерной спирали, провряя, попадает ли внутрь сферы.
Korchy M В сети
Аватара
Сообщения: 2529



Сообщение #48 Pavel » 16.01.2019, 19:35

Korchy, а подробнее?
У меня пока такие идеи:
1 - выяснить габариты объекта
2 - на основе габаритов построить куб из вокселей определённого размера (разбить пространство на дискретные элементы)
3 - пройтись в цикле по каждому вокселу, и проверить находится он внутри исходного объекта или нет (если находится, то в центре воксела родить частицу)

Но я не знаю, как именно на питоне выяснить, находиться ли воксел/частица внутри меша или нет.
Pavel M
Аватара
Сообщения: 848

Сообщение #49 Korchy » 16.01.2019, 20:01

Ну так это тоже самое, другими словами. Нафига только воксели какие-то строить? Все формулами просчитывается. Для сферы все очень просто: если квадрат вектора до точки меньше квадрата радиуса сферы - значит внутри. Если условие выполнено - создавай точку, нет - переходи к следующей. Для более сложных объемов есть свои формулы.
Korchy M В сети
Аватара
Сообщения: 2529



Сообщение #50 Bibo » 18.01.2019, 22:23

Pavel писал(а):Меня интересует, как это сделать на питоне. Я знаю, что можно добавить систему частиц и включить режим распределения Grid. Именно как это сделать самому.
Так нужно заполнить объем или поверхность?
Bibo
Аватара
Сообщения: 544

Сообщение #51 Pavel » 18.01.2019, 22:42

Bibo писал(а):Так нужно заполнить объем или поверхность?
объём
Pavel M
Аватара
Сообщения: 848

  • 1

Сообщение #52 Bibo » 18.01.2019, 23:42

Pavel писал(а):У меня пока такие идеи:
1 - выяснить габариты объекта
2 - на основе габаритов построить куб из вокселей определённого размера (разбить пространство на дискретные элементы)
3 - пройтись в цикле по каждому вокселу, и проверить находится он внутри исходного объекта или нет (если находится, то в центре воксела родить частицу)

Могу предложить пропустить луч через проверяемую частицу (луч берет начало на границе ограничивающей коробки и заканчивается на противоположной). При столкновении с полигоном, найти скалярное произведение направляющего вектора луча и нормали пересекаемого полигона. Результат будет таков:

  • скалярное произведение < 0 => луч входит внутрь объекта
  • скалярное произведение > 0 => луч выходит из объекта
  • скалярное произведение == 0 => луч параллелен полигону (игнорируется)

Проверяешь, находится ли частица между моментами входа и выхода луча. Если да - частица внутри объекта. Если наборы частиц лежат на одной прямой, то можно одним лучом проверить несколько частиц, что упростит вычисления.
Bibo
Аватара
Сообщения: 544

Сообщение #53 Pavel » 12.03.2019, 21:35

Вопрос:

у меня есть некоторые данные из bpy.data. Например, объект (bpy.types.Object). Как выяснить, что эти данные принадлежат именно к коллекции bpy.data.objects?
Pavel M
Аватара
Сообщения: 848

Сообщение #54 denis8424 » 13.03.2019, 21:47

Pavel, а оператор in не подходит?
denis8424
Аватара
Сообщения: 724

Сообщение #55 Pavel » 13.03.2019, 22:19

denis8424, я уже нашёл обходное решение. in не подходит, так как скрипт много объектов обрабатывает. Нужно будет сделать проверку для всех коллекций из bpy.data (object, scenes, actions, armatures...) для каждого объекта.
Pavel M
Аватара
Сообщения: 848

Сообщение #56 Pavel » 27.03.2019, 19:03

Вопрос:
Как применить трансформации к вершинам.
Например, у меня есть меш с изменённой позицией, поворотом и масштабом. Как на питоне сделать аналог функции:
Код: Выделить всё
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)

Добавлено спустя 13 минут 37 секунд:
Вроде бы разобрался:
нужно матрицу умножить на координату вершины:
Код: Выделить всё
obj.matrix_world * vertex.co
Я ведь правильно сделал? По результату вроде бы правильно, но не уверен.
Pavel M
Аватара
Сообщения: 848

  • 1

Сообщение #57 Bibo » 27.03.2019, 21:56

Pavel, да, ты все сделал правильно.
Bibo
Аватара
Сообщения: 544

Сообщение #58 Mephist0 » 31.03.2019, 22:15

Помогите пожалуйста, как правильно активировать инструмент из боковой панели Изображение
Mephist0
Аватара
Сообщения: 3

Сообщение #59 Bibo » 01.04.2019, 15:07

Mephist0, дело в том, что блендер обращается к инструментам текущего активного окна - над которым в данный момент находится курсор мыши. Поскольку ты запускаешь скрипт кнопкой "Run Script", блендер пытается найти этот инструмент в редакторе текста. Необходимо явно указать, в каком пространстве искать инструмент
Код: Выделить всё
bpy.ops.wm.tool_set_by_id(name="builtin.move", space_type="VIEW_3D")
Bibo
Аватара
Сообщения: 544

Сообщение #60 Mephist0 » 01.04.2019, 15:29

Bibo, Огромное спасибо! Не знал, что контекст можно указывать таким способом, но знал если бы внимательней читал документацию :facepalm:
Mephist0
Аватара
Сообщения: 3

Пред.След.

Вернуться в Плагины

Кто сейчас на форуме (по активности за 5 минут)

Сейчас этот раздел просматривают: 2 гостя