Написание скриптов для Blender 2.49 - Michel Anders
Шрифт:
Интервал:
Закладка:
context.displayMode=0
context.enablePremultiply()
context.renderAnim()
filename= context.getFrameFilename()
camera = os.path.join(os.path.dirname(filename),camera)
try:
os.remove(camera) # удаление, в противном случае
# переименование
# потерпит неудачу в windows
except:
pass
os.rename(filename,camera)
context.enableSky()
return camera
Каждое отрендеренное изображение должно быть преобразовано в подходящий материал, чтобы наложить его на квадрат с UV-отображением. Функция imagemat() будет делать это просто; она принимает объект Блендера Image в качестве аргумента и возвращает объект Материала. Этот материал будет сделан полностью прозрачным (выделено), но эта прозрачность и цвет модифицируются текстурой, которую мы назначаем в первый текстурный канал (вторая выделенная строка). Тип текстур установлен в Image и, поскольку мы визуализировали эти изображения с premultiplied альфа-каналом, мы используем метод setImageFlags(), чтобы указать, что мы хотим использовать этот альфа-канал, и устанавливаем атрибут premul изображения в Истину:
def imagemat(image):
mat = Material.New()
mat.setAlpha(0.0)
mat.setMode(mat.getMode()|Material.Modes.ZTRANSP)
tex = Texture.New()
tex.setType('Image')
tex.image = image
tex.setImageFlags('UseAlpha')
image.premul=True
mat.setTexture(0,tex,Texture.TexCo.UV,
Texture.MapTo.COL|Texture.MapTo.ALPHA)
return mat
Каждая грань, к которой мы применяем материал, должна иметь UV-раскладку. В нашем случае, это будет самой простой из возможных раскладок, так как квадратная грань будет отображена так, чтобы в точности соответствовать прямоугольному изображению. Это часто называют сбросом отображения, и следовательно, функция, которую мы определим, называется reset(). Она принимает объект Блендера MFace, который мы считаем четырёхугольником, и присваивает его атрибуту uv список 2D-векторов, по одному для каждой вершины. Эти векторы размещают каждую из вершин в углах изображения:
def reset(face):
face.uv=[vec(0.0,0.0),vec(1.0,0.0),
vec(1.0,1.0),vec(0.0,1.0)]
Функция cardboard() заботится о создании фактического Меш-объекта из двух объектов Image, переданных как аргументы. Она начинается с создания двух квадратных граней, которые пересекают друг друга вдоль оси z. Следующий шаг должен добавить UV-слой (выделено) и сделать его активным:
def cardboard(left,right):
mesh = Mesh.New('Cardboard')
verts=[(0.0,0.0,0.0),(1.0,0.0,0.0),
(1.0,0.0,1.0),(0.0,0.0,1.0),
(0.5,-0.5,0.0),(0.5,0.5,0.0),
(0.5,0.5,1.0),(0.5,-0.5,1.0)]
faces=[(0,1,2,3),(4,5,6,7)]
mesh.verts.extend(verts)
mesh.faces.extend(faces)
mesh.addUVLayer('Reset')
mesh.activeUVLayer='Reset'
Затем мы создаем подходящие материалы из обоих изображений, и назначаем эти материалы в атрибут меша materials. Далее, мы сбрасываем (reset) UV-координаты обеих граней, и назначаем им материалы (выделено). Мы обновляем (update) меш, чтобы сделать изменения видимыми до возврата из функции:
mesh.materials=[imagemat(left),imagemat(right)]
reset(mesh.faces[0])
reset(mesh.faces[1])
mesh.faces[0].mat=0
mesh.faces[1].mat=1
mesh.update()
return mesh
Чтобы заменить меш дублированием объекта системой частиц, мы строим утилиту setmesh(). Она принимает имя объекта со связанной системой частиц и Меш-объект как аргументы. Она находит Объект по имени, и извлекает первую систему частиц (выделено в следующем куске кода). Объект дублирования находится в атрибуте duplicateObject. Заметьте, что этот атрибут только для чтения, так что к настоящему времени нет возможности поменять объект из Питона. Но мы можем заменить данные объекта и, мы это делаем посредством передачи Меш-объекта в метод link(). Оба объекта, эмиттер и объект дублирования системой частиц изменятся, так что мы удостоверимся, что изменения станут видимыми, вызывая метод makeDisplayList() для них обоих перед запуском обновления изображения (redraw) всех окон Блендера:
def setmesh(obname,mesh):
ob = Object.Get(obname)
ps = ob.getParticleSystems()[0]
dup = ps.duplicateObject
dup.link(mesh)
ob.makeDisplayList()
dup.makeDisplayList()
Window.RedrawAll()
Функция run() включает всю работу, которую нужно сделать, чтобы преобразовать активный объект в набор билбордов, и назначить его в систему частиц. Сначала мы извлекаем ссылку на активный объект, и убеждаемся, что он будет видимым при рендере:
def run():
act_ob = Scene.GetCurrent().objects.active
act_ob.restrictRender = False
Следующим шагом нужно сделать остальные объекты на сцене невидимыми до того, как мы отрендерим билборды. Некоторые из них, возможно, уже были сделаны невидимыми пользователем, следовательно, мы должны запомнить эти состояния, чтобы мы могли восстановить их позже. Также мы не изменяем состояние ламп или камер, так как сделав их невидимыми, мы останемся с полностью черными изображениями (выделено):
renderstate = {}
for ob in Scene.GetCurrent().objects:
renderstate[ob.getName()] = ob.restrictRender
if not ob.getType() in ('Camera','Lamp' ):
ob.restrictRender = True
act_ob.restrictRender = False
Как только всё настроено, чтобы рендерить только активный объект, мы рендерим переднее и правое изображения с должным образом откадрированными камерами, просто подобно тому, как мы это делали в скрипте combine.py. Фактически, здесь мы заново используем функцию frame() (выделено):
cameras = ('Front','Right')
combine.frame(cameras,act_ob.getBoundBox())
images={}
for cam in cameras:
im=Image.Load(render(cam))
im.reload()
images[cam]=im
bpy.data.images.active = im
Window.RedrawAll()
Затем мы восстанавливаем предыдущую видимость всех объектов на сцене прежде, чем мы создадим новый меш из двух изображений. Мы заканчиваем, делая активный объект невидимым для рендера и заменяя меш объекта дублирования в определенной системе частиц нашим новым мешем:
for ob in Scene.GetCurrent().objects:
ob.restrictRender = renderstate[ob.getName()]
mesh = cardboard(images['Front'],images['Right'])
act_ob.restrictRender = True
setmesh('CardboardP',mesh)
Последние строки кода создают камеры, необходимые для рендера билбордов (если эти камеры в данный момент отсутствуют), вызывая функцию createcams() из модуля combine до вызова run():
if __name__ == "__main__":
combine.createcams()
run()
Полный код доступен как cardboard.py в файле combine.blend.
Рабочий процесс - использование cardboard.pyДопустим, что у вас есть высокополигональный объект, и что Вы хотели бы преобразовать его в набор билбордов, тогда работа могла бы выглядеть примерно так:
1. Создать объект с именем CardboardP.
2. Назначить систему частиц на этот объект.
3. Создать временный куб.
4. Назначить временный куб дублированным объектом в первой системе частиц объекта CarboardP.
5. Выбрать (сделать активным) объект, который будет отрендерен как набор билбордов.
6. Запустить cardboard.py.
7. Выбрать первоначальную камеру и отрендерить сцену.
Конечно, скрипт можно изменить, чтобы пропустить автоматизированную замену меша объектов дублирования, если это нужно. Например, если мы хотели бы использовать объекты dupliverts вместо частиц, мы должны просто сгенерировать cardboard объект и назначить свой меш на объект дублирования. Если мы используем систему частиц, мы, вероятно, не хотим, чтобы все размноженные объекты были ориентированы точно в одном и том же направлении. Мы могли бы, следовательно, сделать их вращение случайным, пример настройки для этого показан на следующем скриншоте:
Следующий скриншот иллюстрирует применение билбордов, созданных из модели дерева, и использованных в системе частиц:
Генерация вопросов CAPTCHA
Во многих ситуациях, как например, блогах, форумах, и онлайн-опросах (можно назвать ещё несколько), операторы вебсайтов хотят избежать автоматизированных почтовых отправлений от спамботов, но не хотят напрягать посетителей-людей регистрацией с аутентификацией. В таких ситуациях, которые стали обычными, посетителю предлагают так называемый вопрос CAPTCHA (http://ru.wikipedia.org/wiki/CAPTCHA). Вопрос CAPTCHA (или просто Captcha) в самой своей простой форме - изображение, которое должно быть трудным для компьютерного распознавания, но простым для расшифровки человеком, обычно это искаженное или смазанное слово или число.