Материалы, свет и рендер: где интуиция подводит
Модель из 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/: превращаем сцену в файл, который примет игровой движок.