Render.ru

Помогите прочитать позиции vertex

Фигли

Пользователь сайта
Рейтинг
2
#1
Насколько мне известно и встречалась запись позиций в файл (бинарный или текстовый) это три числа с плавающей запятой(точкой). В большинстве случаев это три 32-ух битних числа или 12 байт. В этом же файле для записи позиций используется 8 байт. Пример из нескольких строк:
AFF8EFF77A530100 B92AF34D 00800080 8F4E2200 02010000 FC698380 FFFFFFFF 6A10B780 7A510A80
1AF829FB19540100 27183853 00800080 AC2E2500 01000200 FE707D80 FFFFFFFF 720DB580 78570780
CDF7A5FEBB4F0100 519383E9 00800080 96492000 01000200 7275FD80 FFFFFFFF 017B7280 8F027780

3034 <0000101111011010>: 40 bytes

D3DVERTEXELEMENT9[] =
{
{0, 0x00, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 0x08, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 0x0C, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
{0, 0x10, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
{0, 0x14, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0},
{0, 0x18, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 0x1C, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
{0, 0x20, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_FOG, 0},
{0, 0x24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0},
};
Из файла мне нужно извлечь позицию вертекса, текстурные координаты, весы (BLENDWEIGHT) и к какой кости привязано. Единственное что понятно, как читать, это BLENDWEIGHT 8F4E2200 - 8F 4E 22 00 тут просто, каждый байт делим на 255. результат от 0 до 1. К какой кости привязано, уже не понятно.
02010000 это не значит, что 2 1 0 0, костей больше ста, а цифры чередуются в пределах 6 (в данном файле)
Но вопрос дня, как же всё таки записана позиция?
AFF8 EFF7 7A53 0100 если предположить, что тут три числа Float16, а 0100 это какое-то техническое и не понятно для чего число, получается вот что:
-0.124512, -8156.0, 51808.0 (фигня получается), если читать байты в другом порядке:
-38368.0, -32496.0, 59.8125 (снова фигня)
Пробовал читать как обычное число и делить его на 32767, числа получаются красивые, но не верные)
Как ещё можно попробовать прочитать, чтобы получить правильные координаты vertex?
Судя по скелету (его то я вытащил и построил), в данной модели высота около 3 метров, ширина максимум 1.3

P.S.
Для чтения чисел с половинной точностью написал функцию на Maxscript.
Формула взята отсюда - http://www.softelectro.ru/ieee754.html
-- функция, HEX число в кавычках HalfToFloat "AFE8" (младший разряд справа)
fn HalfToFloat hex =
(
dec = bit.HexAsInt hex
Sign = 0
if (bit.get dec 16) == true then Sign = 1
Expon = 0
for bits=11 to 15 do if (bit.get dec bits) == true then Expon = bit.flip Expon (bits-10)
Mant = 0
for bits=1 to 10 do if (bit.get dec bits) == true then Mant = bit.flip Mant bits
return (-1.0)^Sign * 2.0^(Expon - 15.0) * (1.0 + Mant/2.0^10)
)
Может в скрипте косяк, но я проверял не один раз, всё вроде верно.
 
Рейтинг
31
#2
В функции преобразования HalfToFloat есть маленькая ошибка.
Так вроде корректнее:
Код:
fn HalfToFloat2 hexStr = (
	local bin = bit.HexAsInt hexStr
	local s, m, ex
	
	if bit.get bin 16 then s = -1 else s = 1
	
	ex = bit.and (bit.shift bin -10) 0x1f
	
	if ex == 0 then (
		m = (bit.and bin 0x3ff) / 1024.0
		ex = -14
	)
	else (
		m = 1.0 + (bit.and bin 0x3ff) / 1024.0
		ex = ex - 0xf
	)
	
	return s * m * 2.0 ^ ex
)
Там ещё есть случай, когда все 5 бит экспоненты установлены в 1: дают NaN и бесконечность. Но в этом контексте это, думаю, несущественно.
http://en.wikipedia.org/wiki/Half-precision_floating-point_format
 

Фигли

Пользователь сайта
Рейтинг
2
#3
Про NaN, бесконечность, 0 и -0 в курсе, но в этом случае действительно неважно. Мне бы понять, КАК записаны позиции, и прочее.
Интересное решение, спасибо, пригодится.
З.Ы. Добавлял условия
if Expon == 31 and Mant != 0 then return "NaN"
if Expon == 31 and Mant == 0 then return #NaN
if Expon > 0 and Expon < 31 then return (-1.0)^Sign * 2.0^(Expon - 15.0) * (1.0 + Mant/2.0^10)
if Expon == 0 and Mant != 0 then return (-1.0)^Sign * 2.0^(Expon - 14.0) * (0.0 + Mant/2.0^10)
if Expon == 0 and Mant == 0 then return 0
Но это ничего не меняет.
 
Рейтинг
31
#4
Я не спец в D3D, поэтому могу только предполагать...

1. http://msdn.microsoft.com/en-us/library/windows/desktop/bb172534(v=vs.85).aspx
D3DDECLUSAGE_POSITION

Position data ranging from (-1,-1) to (1,1). Use D3DDECLUSAGE_POSITION with a usage index of 0 to specify untransformed position for fixed function vertex processing and the n-patch tessellator. Use D3DDECLUSAGE_POSITION with a usage index of 1 to specify untransformed position in the fixed function vertex shader for vertex tweening.
2. http://msdn.microsoft.com/en-us/library/windows/desktop/bb172533(v=vs.85).aspx
D3DDECLTYPE_SHORT4

Four-component, signed short expanded to (value, value, value, value).
Думаю, что тебе надо копать в направлении вышеприведённых ссылок.
 

Фигли

Пользователь сайта
Рейтинг
2
#5
Был я в библиотеке мелкомягких, точней и там тоже был)
Ну нашёл выражение наиболее подходящее:
D3DDECLTYPE_FLOAT16_4
Four-component, 16-bit, floating point expanded to (value, value, value, value).
А толку то, во всех бинарниках, что мне попадались, позиции всегда записывались просто - три 32 битных Float. Тут же вроде очевидно, что три 16 битных и 1 (или 256, смотря как читать), а на деле... читай первый пост.
 
Рейтинг
31
#6
Угу... Читаю первый пост:
D3DVERTEXELEMENT9[] =
{
{0, 0x00, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
Далее см. пост #4, сначала п.2, а затем п.1.

В данных у тебя короткое целое со знаком, причём похоже первым идёт младший байт, а потом старший (т.е. последние два байта - это 1). А вот как преобразуется целые в диапазон от -1 до 1 - это вопрос. Можно предположить, что, например, так:
Код:
fn conv arg = (
	num = arg as Integer
	if bit.get num 16 then s = -1 else s = 1
	num = bit.and num 0x7fff
	res = num / (0x7fff as float) * s
	return res
)
Точность получается порядка 3e-5.
Если отконвертить твои данные из #1 по POSITION, получится:
63663 -> -0.942869
63471 -> -0.93701
21370 -> 0.652181

63514 -> -0.938322
64297 -> -0.962218
21529 -> 0.657033

63437 -> -0.935972
65189 -> -0.989441
20411 -> 0.622913
что в общем похоже на правду - значения по осям для трёх точек идут с небольшим разбросом.
 

Фигли

Пользователь сайта
Рейтинг
2
#7
Если перевести AFF8 как его читает из бинарного файла Readshort -1873/32767 = -0.0571612 (а ведь пробовал же так, но видимо напутал с разрядами, старший - младший).
[0.0571594,-0.0630188,0.652161], [0.0617065,-0.0378113,0.657013], [0.0640564,-0.0105896,0.622894]... и тд (по х менял знак)
Меш получился, но раза в три меньше, относительно скелета.

Black Sphinx, сегодня уже мозг взрывается, попробую завтра, выглядит заманчиво)
 

Фигли

Пользователь сайта
Рейтинг
2
#8
Black Sphinx
Не-а, меш похож на бесформенный куб становится)
Это обычные Short числа:
[1873, -2065, 21370]
[2022, -1239, 21529]
[2099, -347, 20411]
Ищу коэффициент на который надо делить. У разных групп моделей разный.
 
Сверху