Функция загрузчик с анимациями
This commit is contained in:
		
							parent
							
								
									c0055c378b
								
							
						
					
					
						commit
						a56a4b429e
					
				| @ -5,6 +5,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "Model.h" | #include "Model.h" | ||||||
| #include "Camera.h" | #include "Camera.h" | ||||||
|  | #include "Animation.h" | ||||||
| 
 | 
 | ||||||
| #include <GLM/gtc/type_ptr.hpp> | #include <GLM/gtc/type_ptr.hpp> | ||||||
| #include <GLM/gtc/quaternion.hpp> | #include <GLM/gtc/quaternion.hpp> | ||||||
| @ -34,6 +35,8 @@ class Scene | |||||||
|         std::list<Model> models; // Список моделей для рендера
 |         std::list<Model> models; // Список моделей для рендера
 | ||||||
|         std::list<Camera> cameras; // Список камер
 |         std::list<Camera> cameras; // Список камер
 | ||||||
| 
 | 
 | ||||||
|  |         std::vector<Animation> animations; // Список анимаций
 | ||||||
|  |         std::map<std::string, size_t> animation_names; // Имя анимации - индекс
 | ||||||
|     protected: |     protected: | ||||||
|         void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 |         void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 | ||||||
|         template <class T> |         template <class T> | ||||||
|  | |||||||
							
								
								
									
										161
									
								
								src/Scene.cpp
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								src/Scene.cpp
									
									
									
									
									
								
							| @ -29,7 +29,7 @@ Scene& Scene::operator=(const Scene& other) | |||||||
| // Рендер сцены
 | // Рендер сцены
 | ||||||
| void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer)  | void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer)  | ||||||
| { | { | ||||||
|     for (auto & model : models) |         for (auto & model : models) | ||||||
|         model.render(shaderProgram, material_buffer); |         model.render(shaderProgram, material_buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -277,6 +277,55 @@ void collectGLTFnodes(int node_id, std::vector<int> &nodes, tinygltf::Model &in_ | |||||||
|         collectGLTFnodes(child, nodes, in_model); |         collectGLTFnodes(child, nodes, in_model); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | float getFloatChannelOutput(int type, const void* array, int index) | ||||||
|  | { | ||||||
|  |     float result; | ||||||
|  |      | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case TINYGLTF_COMPONENT_TYPE_BYTE: | ||||||
|  |         { | ||||||
|  |             const char*            bvalues = reinterpret_cast<const char*>          (array); | ||||||
|  |             result =  bvalues[index] / 127.0; | ||||||
|  |             if (result < -1.0) | ||||||
|  |                 result = -1.0; | ||||||
|  |          | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: | ||||||
|  |         { | ||||||
|  |             const unsigned char*  ubvalues = reinterpret_cast<const unsigned char*> (array); | ||||||
|  |             result = ubvalues[index] / 255.0; | ||||||
|  |          | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         case TINYGLTF_COMPONENT_TYPE_SHORT: | ||||||
|  |         { | ||||||
|  |             const short*           svalues = reinterpret_cast<const short*>         (array); | ||||||
|  |             result =  svalues[index] / 32767.0; | ||||||
|  |             if (result < -1.0) | ||||||
|  |                 result = -1.0; | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: | ||||||
|  |         { | ||||||
|  |             const unsigned short* usvalues = reinterpret_cast<const unsigned short*>(array); | ||||||
|  |             result = usvalues[index] / 65535.0; | ||||||
|  |          | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             const float*           fvalues = reinterpret_cast<const float*>         (array); | ||||||
|  |             result =  fvalues[index]; | ||||||
|  |         } | ||||||
|  |      | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Scene loadGLTFtoScene(std::string filename) | Scene loadGLTFtoScene(std::string filename) | ||||||
| { | { | ||||||
|     Scene result; |     Scene result; | ||||||
| @ -526,6 +575,116 @@ Scene loadGLTFtoScene(std::string filename) | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // Цикл по анимациям
 | ||||||
|  |         for (auto &in_animation : in_model.animations) | ||||||
|  |         { | ||||||
|  |             Animation animation; | ||||||
|  | 
 | ||||||
|  |             for (auto &in_channel : in_animation.channels) | ||||||
|  |             { | ||||||
|  |                 Channel channel; | ||||||
|  | 
 | ||||||
|  |                 channel.target = pNodes[in_channel.target_node]; // Анимируемый узел
 | ||||||
|  |                 // Анимируемый параметр
 | ||||||
|  |                 if (in_channel.target_path == "translation") | ||||||
|  |                     channel.path = POSITION; | ||||||
|  |                 else | ||||||
|  |                 if (in_channel.target_path == "rotation") | ||||||
|  |                     channel.path = ROTATION; | ||||||
|  |                 else | ||||||
|  |                 if (in_channel.target_path == "scale") | ||||||
|  |                     channel.path = SCALE; | ||||||
|  |                 else | ||||||
|  |                     throw std::runtime_error("Неподдерживаемый параметр анимации"); | ||||||
|  | 
 | ||||||
|  |                  | ||||||
|  |                 // Получение сэмплера для канала
 | ||||||
|  |                 const auto& sampler = in_animation.samplers[in_channel.sampler]; | ||||||
|  | 
 | ||||||
|  |                 // Тип интерполяции
 | ||||||
|  |                 if (sampler.interpolation == "LINEAR") | ||||||
|  |                     channel.interpolation = LINEAR; | ||||||
|  |                 else | ||||||
|  |                 if (sampler.interpolation == "STEP") | ||||||
|  |                     channel.interpolation = STEP; | ||||||
|  |                 else | ||||||
|  |                 if (sampler.interpolation == "CUBICSPLINE") | ||||||
|  |                     channel.interpolation = CUBICSPLINE; | ||||||
|  |                 else | ||||||
|  |                     throw std::runtime_error("Неподдерживаемый тип интерполяции"); | ||||||
|  | 
 | ||||||
|  |                 // Получение временных меток ключевых кадров (Input Accessor)
 | ||||||
|  |                 const auto& inputAccessor = in_model.accessors[sampler.input]; | ||||||
|  |                 const auto& inputBufferView = in_model.bufferViews[inputAccessor.bufferView]; | ||||||
|  |                 const auto& inputBuffer = in_model.buffers[inputBufferView.buffer]; | ||||||
|  |                 const float* keyframeTimes = reinterpret_cast<const float*>(&inputBuffer.data[inputBufferView.byteOffset + inputAccessor.byteOffset]); | ||||||
|  |                 // Скопируем через метод insert
 | ||||||
|  |                 channel.timestamps.insert(channel.timestamps.end(), keyframeTimes, keyframeTimes + inputAccessor.count); | ||||||
|  |                  | ||||||
|  |                 // Получение данных ключевых кадров (Output Accessor)
 | ||||||
|  |                 const auto& outputAccessor = in_model.accessors[sampler.output]; | ||||||
|  |                 const auto& outputBufferView = in_model.bufferViews[outputAccessor.bufferView]; | ||||||
|  |                 const auto& outputBuffer = in_model.buffers[outputBufferView.buffer]; | ||||||
|  | 
 | ||||||
|  |                 // Зарезервируем место
 | ||||||
|  |                 channel.values.resize(inputAccessor.count); | ||||||
|  |                 if (channel.interpolation == CUBICSPLINE) | ||||||
|  |                     channel.tangents.resize(inputAccessor.count); | ||||||
|  | 
 | ||||||
|  |                 // Проверим формат и запишем данные с учетом преобразования
 | ||||||
|  |                 if ((   (channel.path == POSITION || channel.path == SCALE) | ||||||
|  |                      && outputAccessor.type == TINYGLTF_TYPE_VEC3) // == 3
 | ||||||
|  |                 ||  (    channel.path == ROTATION | ||||||
|  |                      && outputAccessor.type == TINYGLTF_TYPE_VEC4) // == 4
 | ||||||
|  |                    ) | ||||||
|  |                 { | ||||||
|  |                     // Цикл по ключевым кадрам
 | ||||||
|  |                     for (int keyframe = 0; keyframe < inputAccessor.count; keyframe++) | ||||||
|  |                         // Цикл по компонентам
 | ||||||
|  |                         for (int component = 0; component < outputAccessor.type; component++) | ||||||
|  |                         { | ||||||
|  |                             // Для CUBICSPLINE интерполяции требуется дополнительно списать касательные
 | ||||||
|  |                             if (channel.interpolation == CUBICSPLINE) | ||||||
|  |                             { | ||||||
|  |                                 if (channel.path == ROTATION) | ||||||
|  |                                 { | ||||||
|  |                                     channel.tangents[keyframe].in. quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3                         + component); | ||||||
|  |                                     channel.values  [keyframe].    quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type   + component); | ||||||
|  |                                     channel.tangents[keyframe].out.quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type*2 + component); | ||||||
|  |                                 } | ||||||
|  |                                 else | ||||||
|  |                                 { | ||||||
|  |                                     channel.tangents[keyframe].in. vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3                         + component); | ||||||
|  |                                     channel.values  [keyframe].    vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type   + component); | ||||||
|  |                                     channel.tangents[keyframe].out.vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type*3 + outputAccessor.type*2 + component); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                             else | ||||||
|  |                                 if (channel.path == ROTATION) | ||||||
|  |                                     channel.values  [keyframe].    quat[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type + component); | ||||||
|  |                                 else | ||||||
|  |                                     channel.values  [keyframe].    vec3[component] = getFloatChannelOutput(outputAccessor.componentType, &outputBuffer.data[outputBufferView.byteOffset + outputAccessor.byteOffset], keyframe*outputAccessor.type + component); | ||||||
|  |                         } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                     throw std::runtime_error("Неподдерживаемые данные анимации"); | ||||||
|  |                  | ||||||
|  |                 animation.channels.push_back(channel); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Имя анимации
 | ||||||
|  |             // Если имени нет - сгенерируем
 | ||||||
|  |             if (in_animation.name.empty()) | ||||||
|  |             { | ||||||
|  |                 std::string name = filename + std::to_string(result.animations.size()); | ||||||
|  |                 result.animation_names[name] = result.animations.size(); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |                 result.animation_names[in_animation.name] = result.animations.size(); | ||||||
|  | 
 | ||||||
|  |             result.animations.push_back(animation); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // Зададим трансформацию и родителей для узлов
 |         // Зададим трансформацию и родителей для узлов
 | ||||||
|         // Цикл по всем индексам узлов
 |         // Цикл по всем индексам узлов
 | ||||||
|         for (int node_id = 0; node_id < in_model.nodes.size(); node_id++) |         for (int node_id = 0; node_id < in_model.nodes.size(); node_id++) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user