3D-ассеты через агента Материалы, свет и рендер: где интуиция подводит
0%

Материалы, свет и рендер: где интуиция подводит

Материалы, свет и рендер: где интуиция подводит

Модель из https://courses.digitable.life/post/3d-pipeline/03-first-model/ — серый мешок. Чтобы понять, вышла форма или нет, нужны материал и свет: без них не читается ни силуэт, ни объём.

Материал

mat = bpy.data.materials.new("Ceramic")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (0.85, 0.85, 0.82, 1.0)
bsdf.inputs["Roughness"].default_value = 0.35
bsdf.inputs["Metallic"].default_value = 0.0
obj.data.materials.append(mat)

Principled BSDF покрывает почти всё: керамику, металл, пластик, стекло.

Ловушка первая: цвет линейный, а не sRGB

default_value принимает линейные float RGBA, а не sRGB-hex из макета. Подставив 0x20d5d2 / 255, вы получите заметно более светлый и вялый цвет.

Перевод:

def srgb_to_linear(c):
    return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4

hexcol = "20d5d2"
rgb = tuple(srgb_to_linear(int(hexcol[i:i+2], 16) / 255) for i in (0, 2, 4))
bsdf.inputs["Base Color"].default_value = (*rgb, 1.0)

Почему так: sRGB нелинеен намеренно — он тратит больше точности на тёмные тона, к которым чувствительнее глаз. Рендер же складывает и умножает энергию света, а это требует линейности. Blender хранит линейное и переводит в sRGB на выходе. Подсовывая sRGB-числа напрямую, вы вмешиваетесь в середину конвейера.

Ловушка вторая: имена сокетов меняются

В Blender 4.x сокет "Emission" называется "Emission Color". Проверено на 4.5.11: "Emission" там нет, есть "Emission Color" и "Emission Strength".

Обращайтесь по имени, а не по индексу. Индекс молча вернёт не тот сокет; имя даст честный KeyError. Громкая ошибка лучше тихой подмены — ровно та же мысль, что в https://courses.digitable.life/post/3d-pipeline/04-seeing/.

Слоты под перекраску в рантайме

Если один и тот же меш должен существовать в разных цветах, не делайте копию меша под каждый цвет. Делайте один меш с осмысленно названными слотами материалов, а цвет назначайте в рантайме.

Называйте слоты по роли, а не по цвету: Shell, ShellShadow, Visor, Glow, Metal, Gold. Shell может стать любым цветом; Cyan не может стать коралловым, не превратившись во враньё. Подробнее — в https://courses.digitable.life/post/3d-pipeline/07-game-assets/, где один меш обслуживает обе команды.

Свет

Оценивать форму без света бессмысленно: плоская заливка скрывает и вмятины, и углы.

sun = bpy.data.lights.new("Sun", 'SUN')
sun.energy = 3.0
bpy.context.collection.objects.link(bpy.data.objects.new("Sun", sun))

bpy.ops.object.camera_add(location=(6, -6, 4))
bpy.context.scene.camera = bpy.context.active_object

Наводить камеру удобнее ограничителем, чем углами Эйлера:

c = cam.constraints.new('TRACK_TO')
c.target = obj
c.track_axis, c.up_axis = 'TRACK_NEGATIVE_Z', 'UP_Y'

Считать эйлеровы углы для «смотреть на объект» — верный способ потратить полчаса на тригонометрию и получить перевёрнутый кадр. Ограничитель делает это сам и продолжает работать, когда объект переехал.

Лучший же свет для оценки материала — HDRI. Poly Haven включён по умолчанию, ключа не требует:

search_polyhaven_assets(asset_type="hdris", categories="studio")
download_polyhaven_asset(asset_id="...", asset_type="hdris", resolution="1k")

Одна HDRI даёт связное освещение со всех сторон и честные отражения — металл и керамика на ней сразу читаются, чего не даст никакая расстановка точечных ламп.

Рендер и перевёрнутая интуиция

scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.device = 'CPU'
scene.cycles.samples = 16
scene.render.resolution_x, scene.render.resolution_y = 480, 360
scene.render.filepath = "/абсолютный/путь/out.png"
bpy.ops.render.render(write_still=True)

Теперь измерение. На восьми ядрах без GPU, кадр 480×360, 16 сэмплов:

Движок Время
Cycles (CPU) 1.3 с
EEVEE 6.0 с

Cycles — трассировщик пути, «медленный, но честный». EEVEE — растеризатор реального времени, «быстрый и приблизительный». На десктопе с видеокартой EEVEE уделывает Cycles в разы, и это знает каждый.

Здесь всё наоборот, и вчетверо.

Причина в том, на чём каждый из них работает. EEVEE спроектирован под GPU: он опирается на аппаратную растеризацию, шейдеры, работу с текстурами. Под llvmpipe всё это эмулируется на процессоре — крайне неэффективно, потому что процессор исполняет то, для чего есть специальное железо. Cycles же с самого начала умел в CPU: он раскладывается по ядрам и не притворяется видеокартой.

Мораль шире рендеринга: интуиции о производительности привязаны к конфигурации, на которой их получили. «X быстрее Y» почти всегда означает «X быстрее Y на том железе, где я мерил». Меняется железо — проверяйте заново. Та же дисциплина, что в https://courses.digitable.life/post/performance/00-overview/: измерение, а не репутация.

Практический вывод для агента на сервере: ставьте Cycles на CPU и не бойтесь его. 16 сэмплов достаточно для проверки формы; шум на таком превью не мешает понять, правильно ли легли фаски.

Дальше — https://courses.digitable.life/post/3d-pipeline/06-export/: превращаем сцену в файл, который примет игровой движок.

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов
Дальше