Render.ru

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

Фигли

Пользователь сайта
Рейтинг
2
#1
Есть куб с двумя текстурами. Первая текстура на верхней грани (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)
Если есть какая-то формула или фрагмент скрипта, поделитесь пожалуйста.
 

igorznag

Мастер
Рейтинг
103
#2
Для каких целей вы пишите скрипт? Что он должен вообще делать?
Объясните более подробно каким способом вы получили массивы 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]
-----------------
Что нужно оптимизировать? Какие дубликаты надо выкинуть в данном случае?
 

Фигли

Пользователь сайта
Рейтинг
2
#3
Скрипт для импорта модели со скелетом в формат *.Х для Активных миров.
Плагинов для экспортва в Х хватает. Панда, 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))
		)
Нормали, смуз группы и прочие излишества не нужны. Не могу разобраться, как вычислить вершины для фейсов...
 

_MIT_

Активный участник
Рейтинг
5
#4
(
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
)

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

Фигли

Пользователь сайта
Рейтинг
2
#5
Не понял, что этот скрипт делает. Есть куб, на нём две текстуры (мульти). Едит меш. Ладно конвертнул в Поли, хотя при Поли не извлекаются текстурные координаты. Скрипт выдал:
" -- 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 пишутся только индексы вершин.
 

_MIT_

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

Фигли

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

_MIT_

Активный участник
Рейтинг
5
#8
я говорю что можно выбирать между скоростью и компактностью.. ты сначала генерируешь например значения функции от аргумента, в диапазоне в каком нить (ну например таблицы mapVert->Vert и Vert->mapVert) а потом по надобности эти таблицы пользуеш как будто функцию. Но тока функция компактнее, а таблицы быстрее и с ограничениями в точности. (в нашем случае нету этого ограничения)
препас типа )
 

_MIT_

Активный участник
Рейтинг
5
#9
хотя никто не запрещает для этого случая генерировать такие таблици не для всех вершин а для части - вот ограничение в точности
 

Фигли

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

_MIT_

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

Фигли

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