Функция загрузчик с анимациями
This commit is contained in:
		
							parent
							
								
									c0055c378b
								
							
						
					
					
						commit
						a56a4b429e
					
				| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include "Model.h" | ||||
| #include "Camera.h" | ||||
| #include "Animation.h" | ||||
| 
 | ||||
| #include <GLM/gtc/type_ptr.hpp> | ||||
| #include <GLM/gtc/quaternion.hpp> | ||||
| @ -34,6 +35,8 @@ class Scene | ||||
|         std::list<Model> models; // Список моделей для рендера
 | ||||
|         std::list<Camera> cameras; // Список камер
 | ||||
| 
 | ||||
|         std::vector<Animation> animations; // Список анимаций
 | ||||
|         std::map<std::string, size_t> animation_names; // Имя анимации - индекс
 | ||||
|     protected: | ||||
|         void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 | ||||
|         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)  | ||||
| { | ||||
|     for (auto & model : models) | ||||
|         for (auto & model : models) | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| 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 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++) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user