Насколько мне известно и встречалась запись позиций в файл (бинарный или текстовый) это три числа с плавающей запятой(точкой). В большинстве случаев это три 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)
)
Может в скрипте косяк, но я проверял не один раз, всё вроде верно.
В функции преобразования 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
)
Про 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
Но это ничего не меняет.
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.
Был я в библиотеке мелкомягких, точней и там тоже был)
Ну нашёл выражение наиболее подходящее:
D3DDECLTYPE_FLOAT16_4
Four-component, 16-bit, floating point expanded to (value, value, value, value).
А толку то, во всех бинарниках, что мне попадались, позиции всегда записывались просто - три 32 битных Float. Тут же вроде очевидно, что три 16 битных и 1 (или 256, смотря как читать), а на деле... читай первый пост.
В данных у тебя короткое целое со знаком, причём похоже первым идёт младший байт, а потом старший (т.е. последние два байта - это 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, получится:
Если перевести 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, сегодня уже мозг взрывается, попробую завтра, выглядит заманчиво)
Black Sphinx
Не-а, меш похож на бесформенный куб становится)
Это обычные Short числа:
[1873, -2065, 21370]
[2022, -1239, 21529]
[2099, -347, 20411]
Ищу коэффициент на который надо делить. У разных групп моделей разный.
Доступ к резюме доступен только по пакетному доступу HR менеджерам зарегистрированных компаний. Узнать о вариантах корпоративных пакетов можно по ссылке.
Фигли
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)
)
Может в скрипте косяк, но я проверял не один раз, всё вроде верно.
Sphinx Black (Black Sphinx)
Так вроде корректнее:
Там ещё есть случай, когда все 5 бит экспоненты установлены в 1: дают NaN и бесконечность. Но в этом контексте это, думаю, несущественно.
http://en.wikipedia.org/wiki/Half-precision_floating-point_format
Фигли
Интересное решение, спасибо, пригодится.
З.Ы. Добавлял условия
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
Но это ничего не меняет.
Sphinx Black (Black Sphinx)
1. http://msdn.microsoft.com/en-us/library/windows/desktop/bb172534%28v=vs.85%29.aspx
2. http://msdn.microsoft.com/en-us/library/windows/desktop/bb172533%28v=vs.85%29.aspx
Думаю, что тебе надо копать в направлении вышеприведённых ссылок.
Фигли
Ну нашёл выражение наиболее подходящее:
D3DDECLTYPE_FLOAT16_4
Four-component, 16-bit, floating point expanded to (value, value, value, value).
А толку то, во всех бинарниках, что мне попадались, позиции всегда записывались просто - три 32 битных Float. Тут же вроде очевидно, что три 16 битных и 1 (или 256, смотря как читать), а на деле... читай первый пост.
Sphinx Black (Black Sphinx)
Далее см. пост #4, сначала п.2, а затем п.1.
В данных у тебя короткое целое со знаком, причём похоже первым идёт младший байт, а потом старший (т.е. последние два байта - это 1). А вот как преобразуется целые в диапазон от -1 до 1 - это вопрос. Можно предположить, что, например, так:
Точность получается порядка 3e-5.
Если отконвертить твои данные из #1 по POSITION, получится:
что в общем похоже на правду - значения по осям для трёх точек идут с небольшим разбросом.
Фигли
[0.0571594,-0.0630188,0.652161], [0.0617065,-0.0378113,0.657013], [0.0640564,-0.0105896,0.622894]... и тд (по х менял знак)
Меш получился, но раза в три меньше, относительно скелета.
Black Sphinx, сегодня уже мозг взрывается, попробую завтра, выглядит заманчиво)
Фигли
Не-а, меш похож на бесформенный куб становится)
Это обычные Short числа:
[1873, -2065, 21370]
[2022, -1239, 21529]
[2099, -347, 20411]
Ищу коэффициент на который надо делить. У разных групп моделей разный.