1. Пользоваться форумом на планшетах и телефонах стало удобнее благодаря Tapatalk

Колличество вершин и текстурных координат. На примере куба.

Тема в разделе "MAXScript", создана пользователем Фигли, 18 фев 2012.

Модераторы: Savin Denis
  1. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    Есть куб с двумя текстурами. Первая текстура на верхней грани (2 фейса), вторая на остальных (10 фейсов)
    mesh1.numverts - 8
    mesh1.numTverts - 4
    mesh1.numfaces - 12
    Есть простой путь, тупо умножить фейсы на три. То есть задать для каждого фейса независимые вершины. получится так:
    Mesh {
    36; - 36 вершин
    12; - 12 фейсов, величина всегда постоянная, в этом случае вершины идут от 0 до 35
    36; - 36 MeshTextureCoords
    Проблем нет, колличество вершин и текстурных координат равно. Только что файл становится больше.
    Но мне надо оптимизировать, выкинуть дубликаты и тд.
    Где-то вычитал, да и это логично, пересчитывать вершины по большему. Если вершин больше, чем текстурных, значит по вершинам и наоборот. Написал скрипт, выровнял вершины и поймал косяк. Нехватает вершин в меше, модель, там где была сделана зеркально, сливается. К примеру смоделили один ботинок, а второй зеркалом. При этом способе два ботинка сливаются в один. Если текстурных координат меньше, чем вершин, тогда при выравнии по текстурным, сама текстура "плывёт". Значит способ не подходит. Иду дальше.
    Извлекаю вершины и текстурные координаты:
    (квадратные скобки [убрал для удобства просмотра.])
    mface
    #(1, 2, 3, 3, 4, 1, 5, 6, 7, 7, 8, 5, 1, 4, 6, 6, 5, 1, 4, 3, 7, 7, 6, 4, 3, 2, 8, 8, 7, 3, 2, 1, 5, 5, 8, 2)
    tface
    #(1, 2, 3, 3, 4, 1, 4, 1, 2, 2, 3, 4, 4, 1, 2, 2, 3, 4, 4, 1, 2, 2, 3, 4, 4, 1, 2, 2, 3, 4, 4, 1, 2, 2, 3, 4)
    Отсеиваю дубликаты и получаю:
    vertM
    #(1, 2, 3, 4, 5, 6, 7, 8, 1, 4, 6, 5, 3, 6, 3, 2, 8, 7, 2, 5) вершины
    vertT
    #(1, 2, 3, 4, 4, 1, 2, 3, 4, 1, 2, 3, 1, 3, 4, 1, 2, 3, 4, 2) текстурные координаты.
    Получается 20 вершин и 20 текстурных координат, всё отлично, но тут возникла проблема, а как же теперь сгенерить или вычислить какому фейсу какие вершины прописывать :(
    На выходе должно получится вот так (взято из экспорта в *.х из kw-плагина) :
    #(1, 2, 3, 3, 4, 1, 5, 6, 7, 7, 8, 5, 9, 10, 11, 11, 12, 9, 4, 13, 7, 7, 14, 4, 15, 16, 17, 17, 18, 15, 19, 1, 20, 20, 8, 19)
    Если есть какая-то формула или фрагмент скрипта, поделитесь пожалуйста.
     
  2. igorznag

    igorznag Знаток

    С нами с:
    23.04.2010
    Сообщения:
    1.254
    Симпатии:
    172
    Баллы:
    65
    Для каких целей вы пишите скрипт? Что он должен вообще делать?
    Объясните более подробно каким способом вы получили массивы mface, tface, vertM, vertT.
    Например, в новой сцене создаем один объект Box (куб), конвертируем его в Editable Mesh и експортируем его с помощью скрипта BFF v.0.3.6. Получаем такой результат:
    Код:
    -------------------------------------------------------------------
    8 	--Vertex Count
    12 	--Face Count
    1 	--Supported Texture Channels Count
    1 	--Texture Channel Number
    24 	--Texture Vertex Count 
    12 	--Texture Faces Count  
    2 	--Available Texture Channels
    --VERTEX LIST:
    1, [-50,-50,0]
    2, [50,-50,0]
    3, [-50,50,0]
    4, [50,50,0]
    5, [-50,-50,100]
    6, [50,-50,100]
    7, [-50,50,100]
    8, [50,50,100]
    --FACE LIST IN FORMAT
    --Index FaceDef MatID SmoothingGroup Edge1 Edge2 Egde3
    1, [1,3,4], 2, 2, true, true, false 
    2, [4,2,1], 2, 2, true, true, false 
    3, [5,6,8], 1, 4, true, true, false 
    4, [8,7,5], 1, 4, true, true, false 
    5, [1,2,6], 5, 8, true, true, false 
    6, [6,5,1], 5, 8, true, true, false 
    7, [2,4,8], 4, 16, true, true, false 
    8, [8,6,2], 4, 16, true, true, false 
    9, [4,3,7], 6, 32, true, true, false 
    10, [7,8,4], 6, 32, true, true, false 
    11, [3,1,5], 3, 64, true, true, false 
    12, [5,7,3], 3, 64, true, true, false 
    --TEXTURE VERTEX LIST FOR CHANNEL 0
    1, [1,0,0]
    2, [0,0,0]
    3, [1,1,0]
    4, [0,1,0]
    5, [0,0,0]
    6, [1,0,0]
    7, [0,1,0]
    8, [1,1,0]
    9, [0,0,0]
    10, [1,0,0]
    11, [0,1,0]
    12, [1,1,0]
    13, [0,0,0]
    14, [1,0,0]
    15, [0,1,0]
    16, [1,1,0]
    17, [0,0,0]
    18, [1,0,0]
    19, [0,1,0]
    20, [1,1,0]
    21, [0,0,0]
    22, [1,0,0]
    23, [0,1,0]
    24, [1,1,0]
    --TEXTURE FACES LIST FOR CHANNEL 0
    1, [1,3,4]
    2, [4,2,1]
    3, [5,6,8]
    4, [8,7,5]
    5, [9,10,12]
    6, [12,11,9]
    7, [13,14,16]
    8, [16,15,13]
    9, [17,18,20]
    10, [20,19,17]
    11, [21,22,24]
    12, [24,23,21]
    -----------------
    Что нужно оптимизировать? Какие дубликаты надо выкинуть в данном случае?
     
  3. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    Скрипт для импорта модели со скелетом в формат *.Х для Активных миров.
    Плагинов для экспортва в Х хватает. Панда, kwxport, Политранс, Фраг, Милк.
    Kwxport (после некоторого вмешательство в исходники) почти устраивает, так же как и фраг. Панда, политранс и Милк с родным плагином не подходят вобще. (только не спрашивайте зачем я изобретаю велосипед. Хочу.)
    Фрагмент кода:
    Код:
    	 mface = #()
    	 tface = #()
    	 f01 = [0,0,0]
    	 for i = 1 to mesh1.numfaces do
     		(
    		 f01 = GetFace mesh1 i
    		 mface[i*3-2] = f01.x as integer
    		 mface[i*3-1] = f01.y as integer
    		 mface[i*3] = f01.z as integer
     		)
    	 f01 = [0,0,0]
    	 for i = 1 to mesh1.numfaces do
    		(
    		 f01 = GetTVFace mesh1 i
    		 tface[i*3-2] = f01.x as integer
    		 tface[i*3-1] = f01.y as integer
    		 tface[i*3] = f01.z as integer
    		)
    
    		-- отсеить дубликаты
    
    	 vertM =#()
    	 vertT = #()
    	 for i = 1 to mesh1.numfaces*3 do
    		(
    		 m = findItem vertM mface[i]
    		 if m == 0 then
    			(
    			 append vertM mface[i]
    			 append vertT tface[i]
    			)
    		 if m != 0 and vertT[m] != tface[i] then
    			(
    			 append vertM mface[i]
    			 append vertT tface[i]
    			 for j = m to vertM.count-1 do
    				(
    				 if vertT[vertT.count] == vertT[j] and \
    					vertM[vertM.count] == vertM[j] then 
    					(
    					 deleteItem vertT vertT.count
    					 deleteItem vertM vertM.count
    					 exit
    					)
    				)
    			)
    		-- pb1.value = (i * 100 / (mesh1.numfaces*3))
    		)
    Нормали, смуз группы и прочие излишества не нужны. Не могу разобраться, как вычислить вершины для фейсов...
     
  4. _MIT_

    _MIT_ Активный участник

    С нами с:
    24.06.2008
    Сообщения:
    30
    Симпатии:
    0
    Баллы:
    5
    (
    local obj = $Box01

    fn getArrayOfVerts2MapVerts mapVerts2Verts =
    (
    verts2MapVerts=#()
    for mv=1 to mapVerts2Verts.count do (
    currentVerts=mapVerts2Verts[mv]
    if currentVerts!=undefined do (
    for v=1 to currentVerts.count do (
    if verts2MapVerts[currentVerts[v]] == undefined
    then verts2MapVerts[currentVerts[v]]=#(mv)
    else append verts2MapVerts[currentVerts[v]] mv
    )
    )
    )
    verts2MapVerts
    )

    fn getArrayOfMapVerts2VertsPOLY obj mapChannel = (

    numMapVerts = polyOp.getNumMapVerts obj mapChannel
    mapVerts2Verts = for mv=1 to numMapVerts collect #() -- links list
    numMapFaces = polyOp.getNumMapFaces obj mapChannel

    for face = 1 to numMapFaces do (
    mapFace = polyOp.getMapFace obj mapChannel face
    polyFace = polyOp.getFaceVerts obj face
    for mv = 1 to mapFace.count do (
    mapVert = mapFace[mv]
    if findItem mapVerts2Verts[mapVert] polyFace[mv] == 0 do append mapVerts2Verts[mapVert] polyFace[mv]
    )
    )
    mapVerts2Verts
    )

    local mapVerts2verts_table = getArrayOfMapVerts2VertsPOLY obj 1
    local verts2mapVerts_table = getArrayOfVerts2MapVerts mapVerts2verts_table

    print " -- Table ( mapVerts -> verts )"
    print mapVerts2verts_table
    print " -- Table ( verts -> mapVerts )"
    print verts2mapVerts_table
    )

    ну вот здесь процедуры генерации таблиц...
     
  5. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    Не понял, что этот скрипт делает. Есть куб, на нём две текстуры (мульти). Едит меш. Ладно конвертнул в Поли, хотя при Поли не извлекаются текстурные координаты. Скрипт выдал:
    " -- Table ( mapVerts -> verts )"
    #(1, 6, 4, 3, 2)
    #(2, 7, 6, 8, 5)
    #(3, 8, 5, 6, 7)
    #(4, 5, 1, 3, 2)
    " -- Table ( verts -> mapVerts )"
    #(1, 4)
    #(1, 2, 4)
    #(1, 3, 4)
    #(1, 4)
    #(2, 3, 4)
    #(1, 2, 3)
    #(2, 3)
    #(2, 3)
    Что с этим делать?
    Но в любом случае спасибо.
    Я писал, точней уже написал экспорт в DirectX(*.x). Проблему я решил, нашёл фрагмент кода (на другом форуме).
    Кто там его выложил первый трудно сказать, автора не знаю.
    Код:
       struct sVertex (c, tc)
    ...
        local face = #()
        local vert = #()
    
        for i = 1 to mesh.numFaces do
        (
          texface = (GetTVFace Mesh i)
          append face (GetFace Mesh i)
          for j = 1 to 3 do
          (
            v = sVertex()  
            v.c  = (GetVert Mesh face[i][j])
            v.tc = (GetTVert Mesh texface[j])  
            idx = 1
            for p in vert do
            (
              if (p.c == v.c) and (p.tc == v.tc) then
                exit
              idx += 1
            )
            if (vert.count < idx) then
              append vert v
            face[i][j] = idx - 1
          )
        )
    
        
    Массив face как раз и собирает нужные и правильные индексы. То что мне и надо было. Но скрипт исключительно медленный (при колличестве фейсов более 3 тысяч это становится заметно, при более 20 бывает и Мах зависает, но в среднем, колличество фейсов на моих аватарах 10-15т., так что терпимо), да и разгонал на сколько смог, добавил поддержку нескольких мешей в одном аватаре. Так что можно считать задача решена, если только кто-нибудь не подскажет более быстрый алгоритм.
    Вот что получилось:
    Код:
    			-- Verts, TextureCoords, Faces
    		 global nMesh = 0
    		 global mface = #()
    		 global tface = #()
    		 f01 = [0,0,0]
    	 for nm=1 to nms do
    		(
    		 mtmp = #()
    		 ttmp = #()
    		 for i = 1 to mesh1[nm].numfaces do
    			(
    			 f01 = GetFace mesh1[nm] i
    			 mtmp[i*3-2] = f01.x as integer
    			 mtmp[i*3-1] = f01.y as integer
    			 mtmp[i*3-0] = f01.z as integer
    			 f01 = GetTVFace mesh1[nm] i
    			 ttmp[i*3-2] = f01.x as integer
    			 ttmp[i*3-1] = f01.y as integer
    			 ttmp[i*3-0] = f01.z as integer
    			)
    		 append mface mtmp
    		 append tface ttmp
    		 nMesh = nMesh + mesh1[nm].numfaces
    		)
    
    		 struct sVertex (c, tc)
    		 global nVert = 0
    		 global face = #()
    		 global vert = #()
    		 global nFace = 0
    	 for nm=1 to nms do
    		(
    		 tmp1 = #()
    		 tmp2 = #()
    		 ftmp = #()
    		 global vtmp = #()
    		 for i = 1 to mesh1[nm].numFaces*3 do
    			(
    			 append ftmp mface[nm][i]
    			 v = sVertex()
    			 v.c  = mface[nm][i]
    			 v.tc = tface[nm][i]
    			 m = findItem tmp1 mface[nm][i]
    			 if m == 0 and vtmp.count > 0 then (m = vtmp.count)
    				else (if m == 0 then m=1)
    			 idx = m
    			 for j=m to vtmp.count do
    				(
    				 if keyboard.escPressed == true then exit	-- avariynyi exit. dergat' ESC
    				 if (vtmp[j].c == mface[nm][i]) then
    					(
    					 if (vtmp[j].tc == tface[nm][i]) then exit
    					)
    				 idx +=1
    				 )
    			 if vtmp.count < idx then
    				( append vtmp v
    				 append tmp1 v.c)
    				 ftmp[i] = idx - 1 + nFace
    				 tmp2[i] = idx - 1 
    			 pb1.value = (i * 100 / (mesh1[nm].numFaces*3))
    			)
    		 append face ftmp
    		 append vert vtmp
    		 nVert = nVert + vert[nm].count
    		 nFace = nFace + (amax tmp2 + 1)
    		)
    
    Решил, что набивать массивы координатами вершин не есть хорошо, да и сравнение замедляет, поэтому в моём коде в массив vert пишутся только индексы вершин.
     
  6. _MIT_

    _MIT_ Активный участник

    С нами с:
    24.06.2008
    Сообщения:
    30
    Симпатии:
    0
    Баллы:
    5
    скрипт устанавливает соответствие между вершинами карты и вершинами меша, первый table[map_vert_index] = #(mesh_verts_indexes); второй table[mesh_vert_index] = #(map_vert_indexes)
    мне примеры помогли разобраться как вершинные координаты в максе устроены
    идея в том что общего для нахождения соответствия там только грани, с помощью них и надо производить поиск
    в твоём скрипте разбираться не буду, прости, влом =Р
    может чем поможет
    а про скорость решение - это либо памяти надо брать больше либо на скорость не гундеть - для скорости только использование таблиц могу порекомендовать - самая быстрая и тупая тема
     
  7. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    В скрипте и не просил разбираться, выложил может кому пригодится.
    С памятью всё в порядке - 16 гиг. Скорость работы штука сугубо субьективная :0). Мах 2011-64 открывается 20 секунд, мне это кажется долго (9 мах за секунд 10-15). Аватар 21 тысяча фейсов сохраняется чуть больше полутора минут.
    А про таблицы можно поподробней?
     
  8. _MIT_

    _MIT_ Активный участник

    С нами с:
    24.06.2008
    Сообщения:
    30
    Симпатии:
    0
    Баллы:
    5
    я говорю что можно выбирать между скоростью и компактностью.. ты сначала генерируешь например значения функции от аргумента, в диапазоне в каком нить (ну например таблицы mapVert->Vert и Vert->mapVert) а потом по надобности эти таблицы пользуеш как будто функцию. Но тока функция компактнее, а таблицы быстрее и с ограничениями в точности. (в нашем случае нету этого ограничения)
    препас типа )
     
  9. _MIT_

    _MIT_ Активный участник

    С нами с:
    24.06.2008
    Сообщения:
    30
    Симпатии:
    0
    Баллы:
    5
    хотя никто не запрещает для этого случая генерировать такие таблици не для всех вершин а для части - вот ограничение в точности
     
  10. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    Практически ничего не понял))
    Для записи в файл, нужны все координаты и вершины, так что не понимаю выигрыша генерить по частям. Точность нужна, иначе аватары будут ломаться или кривые.
    Или я вобще ничего не понял. Но да ладно наверно)) Скрипт рабочий. Зрею до написания плагинов (там проблем со скоростью выполнения нет), а пока разбираюсь с разными форматами.
     
  11. _MIT_

    _MIT_ Активный участник

    С нами с:
    24.06.2008
    Сообщения:
    30
    Симпатии:
    0
    Баллы:
    5
    эх и не влом же мне в пятницу вечером это писать )
    да. почитал свои посты, поплакал и задумал исправиться )
    в своих постах я имею ввиду подход к проектированию программы. Вот есть например задача фунцию вычислить в зависимости от аргумента (ну как у нас функция индексов вершины с координатами XYZ от индекса вершины с координатами UW), и значений аргументов у нас много и функция сложная, и считается она для одного значения долго. Но мы например знаем, что аргументы у нас будут в диапазоне от 0 до 1 и с шагом .1, и по этому мы можем вычислить эти значения заранее и составить из них таблицу. А потом, когда надо меньше терять времени на поиск значения, функцию не вычислять, а читать эти значения из таблицы.
    Про точность я говорю потому что, если вдруг нам приспичит вытащить из таблицы значение для аргумента .12, то мы сможем получить только приблизительное значение, найдя его каким то образом из значений от аргументов .1 и .2 (табличных) например
    В случае с координатами у нас есть соответствие индексу пространственной вершины индексам текстурной вершины и наоборот, индексу текстурной вершины индексам пространственной - вершины то разные
    Из соответствия индексов мы находим соответствие координат.. вроде) (тока они не однозначные)
    Скрипт который я запостил, находит такие соотношения и оформляет их ввиде таблиц
    Про еПоли к стати - координаты текстурные извлекаются со свистом на самом деле, скрипт это и демонстрирует, причём, обратите внинмание, переменная mapChannel, написанная с ошибкой, задаёт номер канала текстурных координат. Поменяете значение - поменяется канал.
    Про генерацию по частям - если памяти предполагается занимать не много то можно генерировать эти таблицы для.. например, одного элемента, за раз
    Про точность - ну можно например куски в страйпах пропускать, и считать их координаты интерполяцией.
    мм..
    про то что такое аватар смотрел только в кино, советовал бы Вам не использовать глобальные переменные (но впрочем дело вкуса), и еще называйте переменные как то более осмысленно, не бойтесь длинных имён) MXS`у всё равно , а читать приятнее ...
    фух.. )
    грамматические ошибки в телеге выше прошу считать опечатками по уважительной причине
     
  12. Фигли

    Фигли Пользователь сайта

    С нами с:
    20.01.2012
    Сообщения:
    23
    Симпатии:
    0
    Баллы:
    2
    Хех. ))
    Много буквов, но прочитал внимательно. Хоть и не понимаю, но это одно из направлений, куда можно "рыть", для ускорения скрипта. Может как-нибудь и покопаю.
    Только сразу вопрос, а разве таблицы не занимают память, а разве для вычисления не надо время? Так же к ним надо обращаться как к переменным, так же искать нужное значение и тд и тп. Не получается ли это - те же, только вид сбоку?
    Аватар - вид, облик, скин, перс, модель персонажа и прочее. Или так - текстуреный меш привязаный к скелету.
    Не уверен, что *.х поддерживает Поли, обычно по три вершины у фейса (в *.х файле). А если и поддерживает, я таких Х не видел и не уверен, что Активные миры его поймут.
    Как прочитать текстурную координату из Поли, понятия не имею
    Editable Mesh
    $.numverts
    1578
    $.numTverts
    1578
    Convert_to_Poly
    $.numverts
    1578
    $.numTverts
    -- Runtime error: Mesh operation on non-mesh: Editable Poly
    Да и не надо мне Поли, я не моделю, а конверирую из одного формата в другой. Так что вся работа с мешем+скелет. Конечно не помешало бы, чтоб скрипт и поли понимал, но это уже необязательно.
     
Модераторы: Savin Denis

Поделиться этой страницей