Чем открыть файл.3DS.

27.04.2019

Главный писатель по вопросам технологий

Вам кто-то послал по электронной почте файл 3DS, и вы не знаете, как его открыть? Может быть, вы нашли файл 3DS на вашем компьютере и вас заинтересовало, что это за файл? Windows может сказать вам, что вы не можете открыть его, или, в худшем случае, вы можете столкнуться с соответствующим сообщением об ошибке, связанным с файлом 3DS.

До того, как вы сможете открыть файл 3DS, вам необходимо выяснить, к какому виду файла относится расширения файла 3DS.

Tip: Incorrect 3DS file association errors can be a symptom of other underlying issues within your Windows operating system. These invalid entries can also produce associated symptoms such as slow Windows startups, computer freezes, and other PC performance issues. Therefore, it highly recommended that you scan your Windows registry for invalid file associations and other issues related to a fragmented registry.

Ответ:

Файлы 3DS имеют Uncommon Files, который преимущественно ассоциирован с 3D Studio 3D Scene (Mesh File) (Autodesk Inc.).

Файлы 3DS также ассоциированы с Unknown Apple II File (found on Golden Orchard Apple II CD Rom) и FileViewPro.

Иные типы файлов также могут использовать расширение файла 3DS. Если вам известны любые другие форматы файлов, использующие расширение файла 3DS, пожалуйста, свяжитесь с нами , чтобы мы смогли соответствующим образом обновить нашу информацию.

Как открыть ваш файл 3DS:

Самый быстрый и легкий способ открыть свой файл 3DS - это два раза щелкнуть по нему мышью. В данном случае система Windows сама выберет необходимую программу для открытия вашего файла 3DS.

В случае, если ваш файл 3DS не открывается, весьма вероятно, что на вашем ПК не установлена необходимая прикладная программа для просмотра или редактирования файлов с расширениями 3DS.

Если ваш ПК открывает файл 3DS, но в неверной программе, вам потребуется изменить настройки ассоциации файлов в вашем реестре Windows. Другими словами, Windows ассоциирует расширения файлов 3DS с неверной программой.

Установить необязательные продукты - FileViewPro (Solvusoft) | | | |

3DS Multipurpose Internet Mail Extensions (MIME):

3DS Инструмент анализа файлов™

Вы не уверены, какой тип у файла 3DS? Хотите получить точную информацию о файле, его создателе и как его можно открыть?

Теперь можно мгновенно получить всю необходимую информацию о файле 3DS!

Революционный 3DS Инструмент анализа файлов™ сканирует, анализирует и сообщает подробную информацию о файле 3DS. Наш алгоритм (ожидается выдача патента) быстро проанализирует файл и через несколько секунд предоставит подробную информацию в наглядном и легко читаемом формате.†

Уже через несколько секунд вы точно узнаете тип вашего файла 3DS, приложение, сопоставленное с файлом, имя создавшего файл пользователя, статус защиты файла и другую полезную информацию.

Чтобы начать бесплатный анализ файла, просто перетащите ваш файл 3DS внутрь пунктирной линии ниже или нажмите «Просмотреть мой компьютер» и выберите файл. Отчет об анализе файла 3DS будет показан внизу, прямо в окне браузера.

Перетащите файл 3DS сюда для начала анализа

Просмотреть мой компьютер »

Пожалуйста, также проверьте мой файл на вирусы

Ваш файл анализируется... пожалуйста подождите.

Структура формата.3DS

Всем привет, меня зовут Осипов Дмитрий (AMM1AK), и я хотел бы написать подробную статью о структуре.3DS формата. Не кричите сильно и не кидайте тапками, если не понравится. Просто это моя первая статья J.
Теперь хочу сказать пару слов о том, почему бы я хотел написать именно об этом.
Вообще я занимаюсь программированием 3D графики (Delphi + OpenGL). Раньше для экспорта моделей я использовал 3D Studio Max и писал небольшой экспортер на Max Script’е. Но написать хорошую утилиту, которая бы могла сохранять модель любой сложности, плюс к этому сохранять несколько материалов и помимо текстуры сохранять еще и Bump и Alpha текстуры мне так и не удалось. Хороших учебников на русском я не смог найти, была какая-то книга, но про работу с файлами там ничего не было. Вот таким образом через какое-то время, когда я переписывал свой движок с нуля, я и решил написать небольшую утилиту на Delphi, которая бы могла просматривать модели.3DS формата и плюс к этому сохранять в свой. Но опять появились проблемы. Я перерыл весь Интернет, но не смог найти полной документации о.3DS формате. Конечно, попадались небольшие статьи об этом, но там было все поверхностно, потому и приходилось сидеть часами и угадывать байты J. Вот таким образом я сейчас сижу и пишу статью для тех, кто тоже столкнулся с моей проблемой.
Ну что же? Давайте перейдем к делу. Вообще.3DS это очень сложный формат, который помимо самой геометрии включает в себя всю информацию о материалах, о настройках камеры, о свете, о настройках окон редактора и.т.д. Поэтому для того, чтобы можно было его корректно прочитать, формат выстроен в виде дерева, его ветви это блоки, у каждого блока есть родительский блок (за исключением самого главного) и у некоторых блоков есть дочерние блоки. Теперь давайте расскажу вообще о блоках. Каждый блок состоит из трех частей. Первая часть это его идентификатор, она занимает 2 байта, вторая это длина в байтах всего блока, включая первый и второй блоки, эта часть занимает 4 байта, ну а третья часть это сами данные, она занимает столько, сколько во втором блоке минус шесть (то есть минус длину первого и второго блоков). Тут у разных блоков по-разному, у одних тут какие-то данные, у других дочерние блоки, а у некоторых вообще пусто. Ниже я привел полный, на мой взгляд, список блоков с их идентификаторами. Почему “на мой взгляд”, потому что этот список я составлял сам, складывая блоки увиденные мной в разных демо с исходным кодом, и используя те статьи, что были. Конечно это не полный список, сам проверял, но тут намного больше того, что нужно для полноценного экспорта статичных моделей.

MAIN_CHUNK = $4D4D;
VERSION = $0002;
EDIT3DS = $3D3D;
EDIT_MATERIAL = $AFFF;
MAT_NAME = $A000;
MAT_AMBIENT = $A010;
MAT_DIFFUSE = $A020;
MAT_SPECULAR = $A030;
MAT_SHININESS = $A040;
MAT_SHIN2PCT = $A041;
MAT_SHIN3PCT = $A042;
MAT_TRANSPARENCY = $A050;
MAT_XPFALL = $A052;
MAT_TWO_SIDED = $A081;
MAT_SELF_ILPCT = $A084;
MAT_WIRE = $A085;
MAT_WIRESIZE = $A087;
MAT_XPFALLIN = $A08A;
MAT_SHADING = $A100;
MAT_REFL_BLUR = $A053;
MAT_TEXTURE_MAP = $A200;
MAT_REFLECTION_MAP = $A220;
MAT_BUMP_MAP = $A230;
EDIT_OBJECT = $4000;
EDIT_OBJ_TRIMESH = $4100;
TRI_VERTEX_LIST = $4110;
TRI_FACE_LIST = $4120;
TRI_MESH_MTRGROUP = $4130;
TRI_TEXVERTS = $4140;
TRI_SMOOTHGROUPS = $4150;
TRI_LOCAL_AXES = $4160;
EDIT_CONFIG = $3E3D;
EDIT_CONFIG1 = $0100;
EDIT_VIEWPORT1 = $7012;
KEYF3DS = $B000;

Внимательнее следите за отступами, что бы понять иерархию дерева. Самый главный блок, как видите, это MAIN_CHUNK, его ID - 4D4D в шестнадцатеричной системе. Если мы посмотрим его длину, то получим длину всего файла. Так таковых данных у него нет, но он включает в себя дочерние блоки, такие как VERSION, EDIT3DS, EDIT_CONFIG, EDIT_CONFIG1, EDIT_VIEWPORT1 и KEYF3DS. Теперь вкратце о каждом из них. Блок VERSION содержит 4 байта данных, что в них, я думаю, вы уже догадались. Блок EDIT3DS содержит 10 байт данных, я не знаю что в них и два набора блоков, таких как EDIT_MATERIAL (их столько, сколько материалов на сцене) и EDIT_OBJECT (их столько, сколько мешей на сцене). Блоки EDIT_CONFIG, EDIT_CONFIG1, EDIT_VIEWPORT1 содержат информацию о настройке окон вида и они нам не понадобятся, поэтому их пропускаем. Последний блок KEYF3DS содержит информацию об анимации сцены, для экспорта статичных моделей он тоже не нужен. Теперь давайте разберем блоки EDIT_MATERIAL и EDIT_OBJECT. Как я уже писал выше, блоков EDIT_MATERIAL будет столько, сколько материалов на сцене. Внутри этого блока содержится большое количество дочерних блоков, большая их часть нам даже не понадобятся. Блок EDIT_OBJECT содержит один дочерний блок EDIT_OBJ_TRIMESH, который в свою очередь содержит блоки с информацией меша.
Как видите этот формат очень большой, и именно для нас тут хранится очень много не нужного. Вот именно поэтому я и решил создавать свой формат, а не использовать.3DS. Ниже я привел список блоков, в котором я оставил только самое необходимое для нас.

MAIN_CHUNK = $4D4D;
VERSION = $0002;
EDIT3DS = $3D3D;
EDIT_MATERIAL = $AFFF;
MAT_NAME = $A000;
MAT_AMBIENT = $A010;
MAT_DIFFUSE = $A020;
MAT_SPECULAR = $A030;
MAT_TEXTURE_MAP = $A200;
MAT_TRANSPARENCY_MAP = $A210;
MAT_BUMP_MAP = $A230;
EDIT_OBJECT = $4000;
EDIT_OBJ_TRIMESH = $4100;
TRI_VERTEX_LIST = $4110;
TRI_FACE_LIST = $4120;
TRI_MESH_MTRGROUP = $4130;
TRI_TEXVERTS = $4140;

В разделе EDIT_MATERIAL я оставил лишь блок с именем материала (MAT_NAME). Блоки с рассеянным, диффузным и зеркальным цветами (MAT_AMBIENT, MAT_DIFFUSE, MAT _SPECULAR). А также три блока, которые хранят данные о текстуре материала, текстуре прозрачности и текстуре нормалей (MAT_TEXTURE_MAP, MAT_TRANSPARENCY_MAP, MAT_BUMP_MAP) соответственно. В блоке EDIT_OBJ_TRIMESH остались следующие блоки. Это блок координат точек(TRI_VERTEX_LIST), блок с информацией о гранях(TRI_FACE_LIST), блок с информацией о материалах меша (TRI_MESH_MTRGROUP) и, наконец, блок с информацией о текстурных координатах (TRI_TEXVERTS).
Теперь предлагаю разработать наши собственные типы данных для хранения информации о модели. Ниже приведен исходный код всех типов необходимых для работы.
type
TVertex3f = record // Пространственная точка
X, Y, Z: GLFloat;
end;
TVertex2f = record // Точка на плоскости
X, Y: GLFloat;
end;
TColor = array of GLFloat; // Цвет (R, G, B)
TFace = record // Грань
Verts: array of Word; // Индексы точек
Mat: Word; // Номер материала из массива маиериалов
end;
TModel = record // Модель (тут думаю все понятно)
Name: String; // Ее имя
VertexsCount, // Количество точек
FacesCount, // Количество треугольников
TexVertexsCount: Word; // Количество текстурных точек
Vertexs: array of TVertex3f; // Массив точек
Faces: array of TFace; // Массив треугольников
TexVertexs: array of TVertex2f; // Массив текстурных точек
end;
TMaterial = record // Материал
Name: String; // Его имя
AmbientColor, // Рассеянный цвет
DiffuseColor, // Диффузный цвет
SpecularColor: TColor; // Зеркальный цвет
TextureMap, // Путь к текстуре
AlphaMap, // Путь к альфа текстуре
NormalMap: String; // Путь к текстуре нормалей
end;
T3DSModel = object // 3DS сцена
ModelsCount, // Количество моделей
MaterialsCount: Word; // Количество материалов
Models: array of TModel; // Массив моделей
Materials: array of TMaterial; // Массив материалов
TempIndexModel,
TempIndexMaterial: Integer; // Две переменные нужные для работы
Procedure Clear; // Процедура очистки модели
Procedure AddModel; // Процедура выделения памяти под очередную модель
Procedure AddMaterial; // Процедура выделения памяти под очередной материал
Procedure Laod(FileName: String); // Процедура загрузки
Procedure Draw; // Процедура отрисовки
end;

Ну вот, это в принципе все что нужно. В типе TFace массив из трех элементов, это индексы точек, которые сами находятся в массиве, а Mat это индекс материала, который находится в массиве материалов в типе T3DSModel. Также в тип T3DSModel я записал две переменные TempIndexModel и TempIndexMaterial, это что-то вроде индекса текущей модели и текущего материала. Теперь предлагаю написать процедуры типа T3DSModel, пока только до загрузки.

Procedure T3DSModel.Clear;
begin
MaterialsCount:= 0; // Ставим количество материалов
ModelsCount:= 0; // Ставим количество моделей
SetLength(Models, 0); // Устанавливаем длину массива моделей в 0 элементов
SetLength(Materials, 0); // Устанавливаем длину массива материалов в 0 элементов
TempIndexModel:= -1;
TempIndexMaterial:= -1; // Ставим индексы в -1
end;

Вот, это была процедура очистки модели, её можно всунуть куда-нибудь на событие кнопки Reset, как в 3DSMax’е или перед открытием другой модели. Дале пишу код процедур добавления модели и материала.

Procedure T3DSFile.AddModel;
begin
inc(ModelsCount); // Увеличиваем количество моделей на 1
SetLength(Models, ModelsCount); // Устанавливаем новую длину массива моделей
inc(TempIndexModel); // Увеличиваем временной индекс на 1
end;

Procedure T3DSFile.AddMaterial;
begin
inc(MaterialsCount); // Увеличиваем количество материалов на 1
SetLength(Materials, MaterialsCount); // Устанавливаем новую длину массива материалов
inc(TempIndexMaterial); // Увеличиваем временной индекс на 1
end;

Ну вот, тут тоже ничего сложного. Сначала увеличиваем количество, потом устанавливаем длину массива по только что увеличенной переменной, и увеличиваем временной индекс. Заметьте, что временной индекс всегда равен количеству моделей или материалов минус один, т.к. если у нас пять моделей в массиве, а массивы как нам известно начинаются с 0, то последний индекс это четыре. Вот с элементом массива, индекс которого равен TempIndexModel мы и будем производить какие-либо действия.
Вот выкладываю код еще двух процедур необходимых для работы. Первая процедура считывает строку из файла, а вторая цвет, определяя при этом как он зашифрован (его составляющие от 0 до 1 или от 0 до 255). Еще две константы, нужные для работы второй процедуры, которые можно добавить в общий список COLOR_FLOAT = $0010; COLOR_UBYTE = $0011;

Function ReadString(var F: TFileStream): string;
var
lchar: char;
res: string;
begin
res:="";
f.Read(lchar, 1);
while (lchar <> #0) do
begin
res:=res + lchar;
f.Read(lchar, 1);
end;
Result:=res;
end;

Function ReadColor(var f: TFileStream): TColor;
var Rf, Gf, Bf: GLfloat;
Rub, Gub, Bub: GLubyte;
chunk_id: GLushort;
chunk_length: GLuint;
begin
Rub:=0; Gub:=0; Bub:=0;
f.Read(chunk_id, 2);
f.Read(chunk_length, 4);
case chunk_id of
COLOR_FLOAT:
begin
f.Read(Rf, 4);
f.Read(Gf, 4);
f.Read(Bf, 4);
end;
COLOR_UBYTE:
begin
f.Read(Rub, 1);
f.Read(Gub, 1);
f.Read(Bub, 1);
Rf:=Rub/255;
Gf:=Gub/255;
Bf:=Bub/255;
end;
else f.Seek(chunk_length-6, soFromCurrent);
end;
Result:=Rf;
Result:=Gf;
Result:=Bf;
end;

Теперь предлагаю перейти к самому главному в этой статье, это загрузке сцены из.3DS формата. Ниже я приведу исходный код с комменьариями.

Procedure T3DSFile.Load(FileName: String);
var
ChunkID, usTemp: Word; // Тот самый идентификатор блоков (ID) и одна вспомогательная переменная
ChunkLen: Cardinal; // Переменная для записи в неё длины блоков
f: TFileStream; // файл
i: Integer; // просто I J
Patch: String; // Строка
//==================================
FormatVesion: Cardinal; // Версия файла, может кому пригодится, мне нет, но все равно считываю J
MatNum: Word;
TriangleNum: Word; // Тоже две вспомогательные переменные
begin
f:= TFileStream.Create(FileName, fmOpenRead); // Открываем файл, заметьте что при запуске процедуры мы получаем путь к файлу
f.Read(ChunkID, 2); // Считываем ID первого блока, это как вы помните MAIN_CHUNK
f.Read(ChunkLen, 4); // Считываем его длину
if ChunkID <> MAIN_CHUNK then {Если только что прочитанный ID не равен MAIN_CHUNK, то это не.3DS файл. Нужно вывести сообщение и выйти из процедуры}
begin
MessageBox(0, PChar("Файл: "+FileName+" поврежден"), "Ошибка!", 0);
Exit;
end;
while f.Position < f.Size do // Цикл. Пока позиция чтения меньше размера всего файла, делаем …
begin
f.Read(ChunkID, 2); // Снова считываем ID
f.Read(ChunkLen, 4); // Считываем длину
case ChunkID of // Далее идет оператор case. Ищем совпадения считанного ID с известными нам константами.
EDIT3DS: f.Seek(10, soFromCurrent); // Если это EDIT3DS, то пропускаем 10 байт. Выше я писал про это.
VERSION: f.Read(FormatVersion, 4); // Если это VERSION, то считываем 4 байта в переменную, потом юзайте её как душе угодно
EDIT_OBJECT: // Если это блок объектов, то …
begin
AddModel; // Та самая процедура выделения памяти еще под одну модель.
Models.Name:= ReadString(f); {Тут же считываем имя модели. Заметьте, вот тут мы начинаем пользоваться теми самыми временными индексам}.
end;
EDIT_OBJ_TRIMESH: ; {если это EDIT_OBJ_TRIMESH, то ничего не делаем. Прошу обратить внимание, что мы не пропускаем байты этого блока, как в EDIT3DS, так как длина данного блока включает длину дочерних блоков, а они нам нужны}
TRI_VERTEX_LIST: // Если это TRI_VERTEX_LIST, то …
begin
f.Read(Models.VertexsCount, SizeOf(Word)); // Считываем количество точек текущего объекта
SetLength(Models.Vertexs, Models.VertexsCount); // Устанавливаем длину массива
for i:= 0 to Models.VertexsCount - 1 do // Запускаем цикл …
begin
f.Read(Models.Vertexs.X, SizeOf(Single)); // Считываем х координату итой точки, далее z, далее у, заметьте z и у поменяны
.Z, SizeOf(Single)); // местами, так как в 3DSMax’е перепутаны оси J
f.Read(Models.Vertexs
.Y, SizeOf(Single));
end;
end;
TRI_FACE_LIST: // Если это TRI_FACE_LIST, то …
begin
f.Read(Models.FacesCount, SizeOf(Word)); // Считываем количество треугольников
SetLength(Models.Faces, Models.FacesCount); // Настраиваем длину массива
for i:= 0 to Models.FacesCount - 1 do
begin
.Verts, SizeOf(Word));
f.Read(Models.Faces
.Verts, SizeOf(Word));
f.Read(Models.Faces
.Verts, SizeOf(Word)); // Считываем индексы вершин данного треугольника
f.Read(usTemp, SizeOf(Word)); // Еще выделены два байта под флаги треугольника, за что они отвечают я не знаю
end;
end;
TRI_TEXVERTS: // Если это TRI_TEXVERTS
begin
f.Read(Models.TexVertexsCount, SizeOf(Word)); // Считываем количество текстурных точек
SetLength(Models.TexVertexs, Models.TexVertexsCount); // Настраиваем массивы
for i:= 0 to Models.TexVertexsCount - 1 do
begin
.X, SizeOf(Single));
f.Read(Models.TexVertexs
.Y, SizeOf(Single)); // Циклом считываем Х и У координаты
end;
end;
EDIT_MATERIAL: // Если это EDIT_MATERIAL
begin
AddMaterial; // Добавляем материал в массив
Materials.Clear; // Очищаем добавленный материал (на всякий случай J)
end;
MAT_NAME: // Если это MAT_NAME
begin
Materials.Name:= ReadString(f); // Считываем строку с именем материала
end;
MAT_AMBIENT: // Если это MAT_AMBIENT
begin
Materials.Ambient:= ReadColor(f); // Считываем цвет
end;
MAT_DIFFUSE: // По аналогии
begin
Materials.Diffuse:= ReadColor(f);
end;
MAT_SPECULAR: // По аналогии
begin
Materials.Specular:= ReadColor(f);
end;
MAT_TEXTURE_MAP: // Если это MAT_TEXTURE_MAP, то … Последние три блока, это пожалуй самое сложное J
begin
f.Read(ChunkID, 2); // Тут должны быть какие-то вложенные
f.Read(ChunkLen, 4); // блоки, но про них ничего не известно,
f.Read(ChunkID, 2); // поэтому просто пропускаем байты
f.Read(ChunkLen, 4);
f.Read(usTemp, 2);
Materials}