Как вывернуть полигоны в блендер
правильное направление нормалей
Смоделировал рубашку. Применённые модификаторы видно на скрине ниже.
Нормали направлены таким образом (на воротнике перенаправлял нормали)
После мне нужно заскульптить детали на рубашке. Я удалил модификатор subdivision Surface и применил другой — Multiresolution.
Случилось это. (направление нормалей не трогал)
Ну ладно, ничего страшного в этих тёмных полигонах нет — подумал я и продолжил работу.
Появились артефакты при переключении на уровни подразделения отличные от 5. (На скрине превью уровень 4)
При уровне 5 (именно столько раз я подразделил) всё более менее хорошо. Только на уголках ворота косяки.
Далее я перенаправил нормали выделяя все вершины и нажимая ctrl+N.
Тёмные полигоны остались, но зато артефакты уменьшились.
На скринах последовательное увеличение уровня подразделения:
Подскажите, как правильно направить нормали, чтобы избавиться от артефактов модификатора Multiresolution? Как повлияют на финальный рендер тёмные полигоны? Нужно ли это исправить? И как это сделать?
Есть вероятность, что при рендере ничего видно не будет, но все равно с нормалями нужно разобраться.
Есть два способа: Ctrl + N (как ты уже делал) и вручную Flip Direction.
Модификаторы можешь отключить на время выворачивания нормалей. В итоге все должно быть хорошо без каких либо подразделений.
Как вывернуть полигоны в блендер
В этих уроках я объясняю как правильно работать с вершинами, гранями и полигонами. Здесь целых 3 урока потому что этот этап является одним из самых важных в моделировании сложных объектов с неровной формой.
Очень часто при моделировании приходится сталкиваться с поверхностями которые нельзя отнести к тому или иному примитиву. Предметы лишь смутно напоминают примитивы, но все равно необходимо потратить некоторое время чтобы из примитива ШАР сделать например каску или из цилиндра сделать батарейку, маркер или ручку.
В этом случае нас и выручает редактирование положения вершин, или граней, или полигонов. Вершина является самым маленьким возможным объектом в блендере и одиноко стоящая вершина не будет отображатся при визуализации. Дальше идет грань – она состоит из двух связанных между собой вершин, которая тоже не отобразиться при рендере. И наконец полигон – это 4 соединенные между собой гранями точки. Пустое пространство между этими точками заполнено плоскостью – которая отображается при визуализации и имеет внешнюю и внутреннюю сторону. Или лицо и изнанку. Полигон так же может состоять из 3 вершин но использовать такие полигоны не рекомендуется, так как они значительно усложняют дальнейшую работу с моделью.
В первом видео мы создадим фломастер и научимся работать с операцией Экструдирования (выдавливания). Не смотря на то что фактически выдавливаются полигоны – управлять процессом можно не только с помощью редактирования полигонов но и вершин или граней. Нужно только выделять соответственно 4 вершины или грани для этого.
В следующим видео в отличие от предыдущего мы будем вдавливать полигоны внутрь объекта для закрепления навыка и понимания сути работы выдавливания полигонов.
И наконец для окончательного закрепления навыка создадим парикмахерские ножницы с применением 2 новых модификаторов. Это будет первая работа в которой используются самые часто применяемые модификаторы: Сглаживания – для увеличения полигонов и качества модели. И отзеркаливания – для того что бы создавать симметричные объекты.
Горячие клавиши которые стоит запомнить:
Tab – перейти в режим редактирования
A – выделить все (или снять выделение со всех)
Z – каркасный/твердотельный вид
B – выделение прямоугольником
C – выделение окружностью
Alt+ПКМ – выделение по оси
Ctrl+N – вывернуть полигоны наружу
P – отделение выделенного фрагмента от исходного объекта
W – контекстное меню в режиме редфктирования
Ctrl+Z – отмена последнего действия
Alt+M – слияние вершин
Alt+Tab – смена режима работы вершины/грани/полигоны
H (Alt+H) – скрыть (открыть) объект в окнах проекции
Ctrl+R – рассечь объект дополнительной гранью
Вот что получилось у меня: маркер, органайзер и ножницы
Как вывернуть нормали наружу у сотен объектов с поразному вывернутыми нормалями?
Germanager
Знаток
Bipper
Активный участник
Дмитрий damat Астапкович
Знаток
Ладага
Активный участник
Ладага
Активный участник
А вообще!Встречаются курьёзы в этой жизни что без нормальных нормалей и нет собсно жизни!Прошу прощение за каламбур.Это любовь к майке и снова блэндер.Курьёз вот в чём.Если к этим привязать кэш то тут нашлось решение http://tea3d.blogspot.gr/ а,то что на creative crash пишут там какие то ошибки типа в винде не грузит,так у меня всё работает берём этот код и вставляем в script editote где Python и жмяк на exekute(такой треугольничег похож на значёк плэй в скрипт эдиторе)
»’
Author: Alex Manita
Description: This tool designed primarily for export meshes and particles out of maya,
so they could be imported later into Houdini and other packages
Usage:
import fx_mdd_obj_exporter
fx_mdd_obj_exporter.runUI()
License: You can use it everywhere and modify but you cant sell it.
Use and Modify it at your own risk with absolutelly no warranties.
from struct import pack
import maya.OpenMaya as OpenMaya
import maya.cmds as cmds
import os,re
def zero_file(filepath):
»’
If a file fails, this replaces it with 1 char, better not remove it?
»’
file = open(filepath, ‘w’)
file.write(‘\n’) # aparently macosx needs some data in a blank file?
file.close()
def check_vertcount(exportedObjects,vertcount,mddFile):
»’
check and make sure the vertcount is consistent throghout the frame range
»’
totalCount = 0
for each in exportedObjects:
currentObject = nameToNode(each[1])
def getVertexCount(objects):
numverts = 0
for object in objects:
exportedObjectShape = object[1]
# Convert the string name to an actual object
mesh_orig = nameToNode(exportedObjectShape)
#We should get reference frame from start frame
# Create the vertex iterator with that object
objectSurfaceIt = OpenMaya.MItMeshVertex(mesh_orig)
# Get number of vertices
numverts += objectSurfaceIt.count()
return numverts
def nameToNode( name ):
selectionList = OpenMaya.MSelectionList()
selectionList.add( name )
node = OpenMaya.MObject()
selectionList.getDependNode( 0, node )
return node
#Return the list of CV positions
return vertexPositionList
def getObjectTransform(exportedObjectTransform):
mat_flip = OpenMaya.MMatrix()
mat_flip_list = [1.0, 0.0, 0.0, 0.0,0.0, 1.0, 0.0, 0.0,0.0, 0.0, 1.0, 0.0,0.0, 0.0, 0.0, 1.0]
worldMatrixList = cmds.getAttr(‘%s.worldMatrix’%exportedObjectTransform)
# Convert list to MMatrix object
temp_mMatrix = OpenMaya.MMatrix()
OpenMaya.MScriptUtil.createMatrixFromList(worldMatrixList, temp_mMatrix)
transform = temp_mMatrix * mat_flip
return transform
# exportedObjects have format [(transformNode, objectShape). ]
def mddExport(filepath, exportedObjects, startFrame, endFrame, fps):
(difName,basename) = getDirFromParh(filepath)
filepath = difName+»/»+basename+».mdd»
filepathObj = difName+»/»+basename+».obj»
mddFile = open(filepath, ‘wb’) #no Errors yet:Safe to create file
numframes = endFrame-startFrame+1
# set reference frame time
cmds.currentTime( startFrame, edit=True )
cmds.file(filepathObj,op=»groups=1;ptgroups=1;materials=0;smoothing=1;normals=1″,typ=»OBJexport»,pr=1,es=1,force=1)
# Write the header
numverts = getVertexCount(exportedObjects)
mddFile.write(pack(«>2i», numframes, numverts))
## Write the frame times, sec
mddFile.write( pack(«>%df» % (numframes), *[frame/fps for frame in xrange(numframes)]) ) # seconds
#checking vertex count for the model
check_vertcount(exportedObjects,numverts,mddFile)
for frame in range(startFrame,endFrame,inc):
if cmds.progressWindow( query=True, isCancelled=True ) :
break
cmds.currentTime( frame, edit=True )
cmds.file(difName+»/»+basename+».»+str(frame).zfill(5)+».obj»,op=»groups=1;ptgroups=1;materials=0;smoothing=1;normals=1″,typ=»OBJexport»,pr=1,es=1,force=1)
if cmds.progressWindow( query=True, progress=True ) >= frameRange :
break
amount += 1
cmds.progressWindow( edit=True, progress=amount, status=(‘Finished: ‘ + `amount` + ‘%’ ) )
cmds.progressWindow(endProgress=1)
def particleExport(filepath, startFrame, endFrame, inc,particleTuple, userveca=»»,uservecb=»»,userfloa=»»,userflob=»»):
pTransform = particleTuple[0]
pshape = particleTuple[1]
if cmds.objectType( pshape ) == «particle» or cmds.objectType( pshape ) == «nParticle»:
cmds.runup( maxFrame=startFrame)
arad=1 if cmds.objExists(pshape+».radiusPP») else 0
arot=1 if cmds.objExists(pshape+».rot») else 0
avel=1 if cmds.objExists(pshape+».velocity») else 0
aid=1 if cmds.objExists(pshape+».id») else 0
alife=1 if cmds.objExists(pshape+».lifespanPP») else 0
aage=1 if cmds.objExists(pshape+».age») else 0
argb=1 if cmds.objExists(pshape+».rgbPP») else 0
aopacity=1 if cmds.objExists(pshape+».opacityPP») else 0
amass=1 if cmds.objExists(pshape+».mass») else 0
auserveca=1 if cmds.objExists(pshape+».»+userveca) else 0
auservecb=1 if cmds.objExists(pshape+».»+uservecb) else 0
auserfloa=1 if cmds.objExists(pshape+».»+userfloa) else 0
auserflob=1 if cmds.objExists(pshape+».»+userflob) else 0
attrNum = arad + arot + avel + aid + alife + aage + argb + aopacity + amass + auserveca + auservecb + auserfloa + auserflob;
svel = «v 3 vector 0 0 0 \n» if avel else «»
srad = «pscale 1 float 1 \n» if arad else «»
srot = «rot 3 vector 0 0 0 \n» if arot else «»
sid = «id 1 float 1 \n» if aid else «»
slife = «life 1 float 1 \n» if alife else «»
sage = «age 1 float 1 \n» if aage else «»
srgb = «Cd 3 vector 0 0 0 \n» if argb else «»
sopacity = «opacity 1 float 1 \n» if aopacity else «»
smass = «mass 1 float 1 \n» if amass else «»
suserveca = (userveca +» 3 vector 0 0 0 \n») if auserveca else «»
suservecb = (uservecb +» 3 vector 0 0 0 \n») if auservecb else «»
suserfloa = (userfloa +» 1 float 1 \n») if auserfloa else «»
suserflob = (userflob +» 1 float 1 \n») if auserflob else «»
(difName,basename) = getDirFromParh(filepath)
particleCount = cmds.particle(pTransform,q=1, count=1)
for frame in xrange(startFrame,endFrame+1):#in order to start at desired frame
cmds.currentTime( frame, edit=True )
finalFilePath = difName+»/»+basename+».»+str(frame).zfill(5)+».geo»
particleFile = open(finalFilePath, ‘w’)
particleFile.write(«PGEOMETRY V5 \nNPoints » + str(cmds.particle(pTransform,q=1, count=1)) + » NPrims 0 \nNPointGroups 0 NPrimGroups 0 \nNPointAttrib «+str(attrNum)+» NVertexAttrib 0 NPrimAttrib 0 NAttrib 1 \nPointAttrib \n»+svel+srad+srot+sid+slife+sage+srgb+sopacity+smass+suserveca+suservecb+suserfloa+suserflob);
for fr in range(cmds.particle(pTransform,q=1, count=1)) :
posb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘worldPosition’)
if avel:velb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘velocity’)
if arad:scaleb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘radiusPP’)
if arot:rotb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘rot’)
if aid:idb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘id’)
if alife:lifeb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘lifespanPP’)
if aage:ageb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘age’)
if argb:rgbb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘rgbPP’)
if aopacity pacityb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘opacityPP’)
if amass:massb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = ‘mass’)
if auserveca:uservecab = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = userveca)
if auservecb:uservecbb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = uservecb)
if auserfloa:userfloab = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = userfloa)
if auserflob:userflobb = cmds.getParticleAttr(pshape+».pt»+»[«+str(fr)+»]»,attribute = userflob)
fvel = str(velb[0]) +» «+ str(velb[1])+» «+str(velb[2])+» » if avel else «»
frad = str(scaleb[0])+» » if arad else «»
frot = str(rotb[0]) +» «+ str(rotb[1])+» «+str(rotb[2])+» » if arot else «»
fid = str(idb[0])+» » if aid else «»
flife = str(lifeb[0])+» » if alife else «»
fage = str(ageb[0])+» » if aage else «»
frgb = str(rgbb[0]) +» «+ str(rgbb[1])+» «+str(rgbb[2])+» » if argb else «»
fopacity = str(opacityb[0])+» » if aopacity else «»
fmass = str(massb[0])+» » if amass else «»
fuserveca = str(uservecab[0]) +» «+ str(uservecab[1])+» «+str(uservecab[2])+» » if auserveca else «»
fuservecb = str(uservecbb[0]) +» «+ str(uservecbb[1])+» «+str(uservecbb[2])+» » if auservecb else «»
fuserfloa = str(userfloab[0])+» » if auserfloa else «»
fuserflob = str(userflobb[0])+» » if auserflob else «»
Вывернутые нормали
а как проверить то? Где вывернуты, а где нет?
Ваш способ суперский, сразу нашёл косяк ))
выделяете объект кликаете [Click Here To Update]
зелёным окрашиваются ваши ненормальные нормали))
выделяете объект кликаете [Click Here To Update]
зелёным окрашиваются ваши ненормальные нормали))
круто, детачнул полигон. Зелёный весь. Флип-другая сторона зеленая стала. И весь объект так. И Cut только по изнанке привязывается.
Можно конвертнуть в Mesh, там жмете галку Edit normals, и синенькие палочки показывают в какую сторону развернуты нормали. Использовать _Flip_ либо модификатор Normal для исправления)
Blender по русски
Переход в режим редактирования
Vertex – вершина
Edge – ребро (грань)
Face – плоскость (полигон)
Ctrl-Tab – выбор для выделения Vertex, Edge, Face, или через окно
Ctrl-V, Ctrl-E, Ctrl-F выводят дополнительные операции над этими элементами
Выделить элемент(-ы)
ПКМ – выделение элемента
Shift-ПКМ – выделение нескольких элементов
B – выделение элементов при помощи прямоугольной области (Box)
C – выделение элементов при помощи окружности. Диаметр регулируется КМ. Снимается выделение нажатием на ЦКМ.
Z – каркасный режим, позволяет выделять элементы с обратной (невидимой стороны)
или можно выбрать пиктограмму «Limit selection to visible»
Добавление объекта
Shift-A – добавление нового объекта, как части редактируемого объекта.
Выделить всё, снять выделение
A – выделение всего. Повторное нажатие снимает выделение.
Выделение всех точек грани
Alt-ПКМ
Объединить несколько точек в одну
Alt-M
Создать плоскость (полигон), ребро, объединить NURBS
F – создает плоскость между 3-4 вершинами; ребро между 2 вершинами; объединяет NURBS-поверхности
Разделить грань (нож)
K-ЛКМ – предварительно выделяем грань ПКМ, и режем появившимся инструментом
Добавить грань(-и)
Ctrl-R – добавляет грань, которую можно затем переместить. Если в процессе покрутить КМ, то можно сразу увеличить количество граней.
Специальные возможности с гранями
Ctrl-F – вызывает специальное меню
Добавить точку к Mehs
Ctrl-ЛКМ
Выдавливание
E – выдавливает плоскость (группу плоскостей) для Mesh-объекта, либо добавляет опорную точку для Кривой (Curve). При нажатой Z, позволяет вытягивать объект по оси, а не произвольно.
Нормали – увидеть направление
Нормали – инвертировать направление
Меню «Mesh» > «Normals» > «Flip Normals»
в режиме «Face» выделяем A все полигоны и Ctrl-N выворачиваем все нормали наружу
Объединение объектов
Если в режиме «Edit Mode» добавить новый объект (Shift-A), то он становится частью объекта.
Отделение части от объекта (сепарировать)
P – отделяет выделенные вершины в отдельный объект
Отделить вершину (ребро) от других ребер объекта
Специальные операции над объектом
W – вызывает специальные операции преобразования для данного типа объекта
Пропорциональное редактирование вершин
O или панелька снизу окна
Добавить сглаживание (модификатор Subsurf)
Ctrl-1/2/3/4/5
Смена типа кривой
V – вызывает меню:
Automatic
Vector – изгиб становится прямым
Aligned – изгиб сглажен и рычаги на одной прямой
Free – рычаги независимы друг от друга
Toggle Free/Align
Добавить точку к кривой (продолжить кривую)
E или Ctrl-ЛКМ
Разделить кривую
Добавить точку на кривой
Выделяем две точки Shift-ПКМ, нажимаем W, выбираем Subdivide
Замкнуть кривую
Выбираем крайнюю точку и жмем Alt-C
Изменить наклон кривой (скрутить вдоль пути)
Ctrl-T – изменяет наклон
Alt-T – отменяет наклон
Скрывает/отображает опорную точку (поверхность)
H – скрывает опорную точку
Alt-H – отображает все точки