framework2

Форк
0
1288 строк · 38.0 Кб
1
#include "ofxAssimpModelLoader.h"
2
#include "ofxAssimpUtils.h"
3
#include "ofLight.h"
4
#include "ofImage.h"
5
#include "ofPixels.h"
6
#include "ofGraphics.h"
7
#include "ofConstants.h"
8

9
#include <assimp/cimport.h>
10
#include <assimp/scene.h>
11
#include <assimp/postprocess.h>
12
#include <assimp/config.h>
13
#include <assimp/DefaultLogger.hpp>
14

15
using std::shared_ptr;
16
using std::vector;
17

18
ofxAssimpModelLoader::ofxAssimpModelLoader(){
19
	clear();
20
}
21

22
ofxAssimpModelLoader::~ofxAssimpModelLoader(){
23
	clear();
24
}
25

26

27
// DEPRECATED
28
bool ofxAssimpModelLoader::load(string modelName, bool optimize){
29
	int optimizeFlags = OPTIMIZE_DEFAULT;
30
	if( optimize ){
31
		optimizeFlags = OPTIMIZE_HIGH;
32
	}
33
	return load(modelName, optimizeFlags);
34
}
35

36
// DEPRECATED
37
bool ofxAssimpModelLoader::load(ofBuffer & buffer, bool optimize, const char * extension){
38
	int optimizeFlags = OPTIMIZE_DEFAULT;
39
	if( optimize ){
40
		optimizeFlags = OPTIMIZE_HIGH;
41
	}
42
	return load(buffer, optimizeFlags, extension);
43
}
44

45
// DEPRECATED
46
bool ofxAssimpModelLoader::loadModel(string modelName, bool optimize){
47
	int optimizeFlags = OPTIMIZE_DEFAULT;
48
	if( optimize ){
49
		optimizeFlags = OPTIMIZE_HIGH;
50
	}
51
	return load(modelName, optimizeFlags);
52
}
53

54
// DEPRECATED
55
bool ofxAssimpModelLoader::loadModel(ofBuffer & buffer, bool optimize, const char * extension){
56
	int optimizeFlags = OPTIMIZE_DEFAULT;
57
	if( optimize ){
58
		optimizeFlags = OPTIMIZE_HIGH;
59
	}
60
	return load(buffer, optimizeFlags, extension);
61
}
62

63
//------------------------------------------
64
bool ofxAssimpModelLoader::load(string modelName, int assimpOptimizeFlags){
65

66
	file.open(modelName, ofFile::ReadOnly, true); // Since it may be a binary file we should read it in binary -Ed
67
	if(!file.exists()) {
68
		ofLogVerbose("ofxAssimpModelLoader") << "load(): model does not exist: \"" << modelName << "\"";
69
		return false;
70
	}
71

72
	ofLogVerbose("ofxAssimpModelLoader") << "load(): loading \"" << file.getFileName()
73
	<< "\" from \"" << file.getEnclosingDirectory() << "\"";
74

75
	if(scene.get() != nullptr){
76
		clear();
77
		// we reset the shared_ptr explicitly here, to force the old
78
		// aiScene to be deleted **before** a new aiScene is created.
79
		scene.reset();
80
	}
81

82
	// sets various properties & flags to a default preference
83
	unsigned int flags = initImportProperties(assimpOptimizeFlags);
84

85
	//	//enable assimp logging based on ofGetLogLevel
86
	//	if( ofGetLogLevel() < OF_LOG_NOTICE ){
87
	//		auto logLevel = Assimp::DefaultLogger::LogSeverity::VERBOSE;
88
	//		Assimp::DefaultLogger::create(ASSIMP_DEFAULT_LOG_NAME, logLevel, aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_STDOUT );
89
	//	}
90

91
	// loads scene from file
92
	std::string path = file.getAbsolutePath();
93
	const aiScene * scenePtr = importer.ReadFile(path.c_str(), flags);
94

95
	//this is funky but the scenePtr is managed by assimp and so we can't put it in our shared_ptr without disabling the deleter with: [](const aiScene*){}
96
	scene = shared_ptr<const aiScene>(scenePtr,[](const aiScene*){});
97

98
	bool bOk = processScene();
99
	return bOk;
100
}
101

102

103
bool ofxAssimpModelLoader::load(ofBuffer & buffer, int assimpOptimizeFlags, const char * extension){
104

105
	ofLogVerbose("ofxAssimpModelLoader") << "load(): loading from memory buffer \"." << extension << "\"";
106

107
	if(scene.get() != nullptr){
108
		clear();
109
		// we reset the shared_ptr explicitly here, to force the old
110
		// aiScene to be deleted **before** a new aiScene is created.
111
		scene.reset();
112
	}
113

114
	// sets various properties & flags to a default preference
115
	unsigned int flags = initImportProperties(assimpOptimizeFlags);
116

117
	// 	//enable assimp logging based on ofGetLogLevel
118
	//	if( ofGetLogLevel() < OF_LOG_NOTICE ){
119
	//		auto logLevel = Assimp::DefaultLogger::LogSeverity::VERBOSE;
120
	//		Assimp::DefaultLogger::create(ASSIMP_DEFAULT_LOG_NAME, logLevel, aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_STDOUT );
121
	//	}
122

123
	// loads scene from memory buffer - note this will not work for multipart files (obj, md3, etc)
124
	const aiScene * scenePtr = importer.ReadFileFromMemory(buffer.getData(), buffer.size(), flags, extension);
125

126
	// this is funky but the scenePtr is managed by assimp and so we can't put it in our shared_ptr without disabling the deleter with: [](const aiScene*){}
127
	scene = shared_ptr<const aiScene>(scenePtr,[](const aiScene*){});
128

129
	bool bOk = processScene();
130
	return bOk;
131
}
132

133
unsigned int ofxAssimpModelLoader::initImportProperties(int assimpOptimizeFlags) {
134
	store.reset(aiCreatePropertyStore(), aiReleasePropertyStore);
135

136
	// only ever give us triangles.
137
	aiSetImportPropertyInteger(store.get(), AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT );
138
	aiSetImportPropertyInteger(store.get(), AI_CONFIG_PP_PTV_NORMALIZE, true);
139

140
	unsigned int flags = assimpOptimizeFlags;
141

142
	if( flags <= OPTIMIZE_HIGH ){
143

144
		if( flags == OPTIMIZE_NONE ){
145
			flags = 0;
146
		}else if( flags == OPTIMIZE_DEFAULT || flags == OPTIMIZE_HIGH ){
147
			flags =     aiProcess_CalcTangentSpace              |  \
148
			aiProcess_GenSmoothNormals              |  \
149
			aiProcess_JoinIdenticalVertices         |  \
150
			aiProcess_ImproveCacheLocality          |  \
151
			aiProcess_LimitBoneWeights              |  \
152
			aiProcess_RemoveRedundantMaterials      |  \
153
			aiProcess_SplitLargeMeshes              |  \
154
			aiProcess_Triangulate                   |  \
155
			aiProcess_GenUVCoords                   |  \
156
			aiProcess_SortByPType                   |  \
157
			aiProcess_FindDegenerates               |  \
158
			aiProcess_FindInstances                 |  \
159
			aiProcess_OptimizeMeshes;
160
		}
161

162
		if( flags == OPTIMIZE_HIGH ){
163
			flags |= aiProcess_OptimizeGraph |  \
164
			aiProcess_FindInstances |  \
165
			aiProcess_ValidateDataStructure;
166
		}
167

168
		// this fixes things for OF both tex uvs and model not flipped in z
169
		flags |= aiProcess_ConvertToLeftHanded;
170
	}
171

172
	return flags;
173
}
174

175
bool ofxAssimpModelLoader::processScene() {
176

177
	normalizeFactor = ofGetWidth() / 2.0;
178

179
	if(scene){
180
		loadGLResources();
181
		update();
182
		calculateDimensions();
183

184
		if(getAnimationCount())
185
			ofLogVerbose("ofxAssimpModelLoader") << "load(): scene has " << getAnimationCount() << "animations";
186
		else {
187
			ofLogVerbose("ofxAssimpModelLoader") << "load(): no animations";
188
		}
189

190
		return true;
191
	}else{
192
		ofLogError("ofxAssimpModelLoader") << "load(): " + (string) aiGetErrorString();
193
		clear();
194
		return false;
195
	}
196

197
	return false;
198
}
199

200

201
//-------------------------------------------
202
void ofxAssimpModelLoader::createEmptyModel(){
203
	if(scene){
204
		clear();
205
		scene.reset();
206
	}
207
}
208

209

210
void ofxAssimpModelLoader::setNormalizationFactor(float factor){
211
	normalizeFactor = factor;
212
}
213

214
//-------------------------------------------
215
void ofxAssimpModelLoader::calculateDimensions(){
216
	if(!scene) return;
217
	ofLogVerbose("ofxAssimpModelLoader") << "calculateDimensions(): inited scene with "
218
	<< scene->mNumMeshes << " meshes & " << scene->mNumAnimations << " animations";
219

220
	getBoundingBoxWithMinVector(&scene_min, &scene_max);
221
	scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
222
	scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
223
	scene_center.z = (scene_min.z + scene_max.z) / 2.0f;
224

225
	// optional normalized scaling
226
	normalizedScale = scene_max.x-scene_min.x;
227
	normalizedScale = std::max(double(scene_max.y - scene_min.y), normalizedScale);
228
	normalizedScale = std::max(double(scene_max.z - scene_min.z), normalizedScale);
229
	if (fabs(normalizedScale) < std::numeric_limits<float>::epsilon()){
230
		ofLogWarning("ofxAssimpModelLoader") << "Error calculating normalized scale of scene" << std::endl;
231
		normalizedScale = 1.0;
232
	} else {
233
		normalizedScale = 1.f / normalizedScale;
234
		normalizedScale *= normalizeFactor;
235
	}
236

237
	updateModelMatrix();
238
}
239

240
//-------------------------------------------
241
static GLint getGLFormatFromAiFormat(const char * aiFormat){
242

243
	std::string formatStr(aiFormat);
244

245
	if( formatStr.size() >= 8 ){
246
		if( formatStr.substr(0, 4) == "rgba" ){
247
			if(formatStr.substr(4,4) == "8888"){
248
				return GL_RGBA;
249
			}else if(formatStr.substr(4,4) == "8880"){
250
				return GL_RGB;
251
			}
252
		}else{
253
			ofLogError("getGLFormatFromAiFormat") << " can't parse format " << formatStr;
254
		}
255
	}
256

257
	ofLogWarning("getGLFormatFromAiFormat") << " can't parse format " << formatStr << " returning GL_RGB";
258
	return GL_RGB;
259
}
260

261
//-------------------------------------------
262
void ofxAssimpModelLoader::createLightsFromAiModel(){
263
	lights.clear();
264
	lights.resize(scene->mNumLights);
265
	for(unsigned int i = 0; i < scene->mNumLights; i++){
266
		lights[i].enable();
267
		if(scene->mLights[i]->mType==aiLightSource_DIRECTIONAL){
268
			lights[i].setDirectional();
269
			lights[i].setOrientation(aiVecToOfVec(scene->mLights[i]->mDirection));
270
		}
271
		if(scene->mLights[i]->mType!=aiLightSource_POINT){
272
			lights[i].setSpotlight();
273
			lights[i].setPosition(aiVecToOfVec(scene->mLights[i]->mPosition));
274
		}
275
		lights[i].setAmbientColor(aiColorToOfColor(scene->mLights[i]->mColorAmbient));
276
		lights[i].setDiffuseColor(aiColorToOfColor(scene->mLights[i]->mColorDiffuse));
277
		lights[i].setSpecularColor(aiColorToOfColor(scene->mLights[i]->mColorSpecular));
278
	}
279
}
280

281
//-------------------------------------------
282
void ofxAssimpModelLoader::optimizeScene(){
283
	aiApplyPostProcessing(scene.get(),aiProcess_ImproveCacheLocality | aiProcess_OptimizeGraph |
284
						  aiProcess_OptimizeMeshes | aiProcess_JoinIdenticalVertices |
285
						  aiProcess_RemoveRedundantMaterials);
286
}
287

288
#ifndef TARGET_WIN32
289
//this is a hack to allow for weak definations of functions that might not exist in older assimp versions
290
const char *aiTextureTypeToString(enum aiTextureType in)__attribute__((weak));
291
#endif
292

293
//-------------------------------------------
294
void ofxAssimpModelLoader::loadGLResources(){
295

296
	ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): starting";
297

298
	// we do this as we have textures and vbos and in meshHelper and we don't want to copy them
299
	// this should really be a vector of shared_ptr's but keeping it as objects for legacy reasons
300
	modelMeshes.clear();
301
	modelMeshes.reserve(scene->mNumMeshes);
302

303
	// create OpenGL buffers and populate them based on each meshes pertinant info.
304
	for (unsigned int i = 0; i < scene->mNumMeshes; ++i){
305
		ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): loading mesh " << i;
306
		// current mesh we are introspecting
307
		aiMesh* mesh = scene->mMeshes[i];
308

309
		// the current meshHelper we will be populating data into.
310
		modelMeshes.push_back(ofxAssimpMeshHelper());
311
		ofxAssimpMeshHelper & meshHelper = modelMeshes[i];
312
		//ofxAssimpMeshHelper meshHelper;
313

314
		//meshHelper.texture = NULL;
315

316
		// Handle material info
317
		aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex];
318
		aiColor4D tcolor;
319

320
		if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &tcolor)){
321
			auto col = aiColorToOfColor(tcolor);
322
			meshHelper.material.setDiffuseColor(col);
323
		}
324

325
		if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &tcolor)){
326
			auto col = aiColorToOfColor(tcolor);
327
			meshHelper.material.setSpecularColor(col);
328
		}
329

330
		if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &tcolor)){
331
			auto col = aiColorToOfColor(tcolor);
332
			meshHelper.material.setAmbientColor(col);
333
		}
334

335
		if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &tcolor)){
336
			auto col = aiColorToOfColor(tcolor);
337
			meshHelper.material.setEmissiveColor(col);
338
		}
339

340
		float shininess;
341
		if(AI_SUCCESS == aiGetMaterialFloat(mtl, AI_MATKEY_SHININESS, &shininess)){
342
			meshHelper.material.setShininess(shininess);
343
		}
344

345
		int blendMode;
346
		if(AI_SUCCESS == aiGetMaterialInteger(mtl, AI_MATKEY_BLEND_FUNC, &blendMode)){
347
			if(blendMode==aiBlendMode_Default){
348
				meshHelper.blendMode=OF_BLENDMODE_ALPHA;
349
			}else{
350
				meshHelper.blendMode=OF_BLENDMODE_ADD;
351
			}
352
		}
353

354
		// Culling
355
		unsigned int max = 1;
356
		int two_sided=0;
357
		if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided){
358
			meshHelper.twoSided = true;
359
			ofLogVerbose("ofxAssimpModelLoader::loadGLResources") <<": mesh is two sided";
360
		}else{
361
			meshHelper.twoSided = false;
362
			ofLogVerbose("ofxAssimpModelLoader::loadGLResources") <<": mesh is one sided";
363
		}
364

365
		// Load Textures
366
		int texIndex = 0;
367
		aiString texPath;
368

369
		//this gets the wrapping in u and v coodinates
370
		//we don't support different wrapping in OF so just read u
371
		aiTextureMapMode texMapMode[2];
372

373
		for(int d = 0; d <= AI_TEXTURE_TYPE_MAX; d++){
374
			if(AI_SUCCESS == mtl->GetTexture((aiTextureType)d, texIndex, &texPath, NULL, NULL, NULL, NULL, &texMapMode[0])){
375

376
				//this is a solution to support older versions of assimp. see the weak defination above
377
				if( aiTextureTypeToString ){
378
					ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): loading " <<  aiTextureTypeToString((aiTextureType)d) << " image from \"" << texPath.data << "\"";
379
				}
380

381
				bool bWrap = (texMapMode[0]==aiTextureMapMode_Wrap);
382

383
				std::string texPathStr = texPath.C_Str();
384

385
				//deal with Blender putting "//" in front of local file paths
386
				if( texPathStr.size() > 2 && texPathStr.substr(0, 2) == "//" ){
387
					texPathStr = texPathStr.substr(2, texPathStr.size()-2);
388
				}
389

390
				//glb embedded texture file starts with *0
391
				bool bTryEmbed = false;
392
				if( texPathStr.size() >= 2 && texPathStr[0] == '*'){
393
					bTryEmbed = true;
394
				}
395

396
				//stuff for embedded textures
397
				auto ogPath = texPathStr;
398
				bool bHasEmbeddedTexture = false;
399

400
				auto modelFolder = ofFilePath::getEnclosingDirectory( file.path() );
401
				auto relTexPath = ofFilePath::getEnclosingDirectory(texPathStr,false);
402
				auto realPath = modelFolder / of::filesystem::path{ texPathStr };
403
				
404

405
#ifndef TARGET_LINUX_ARM
406
				if(bTryEmbed || ofFile::doesFileExist(realPath) == false) {
407
					auto embeddedTexture = scene->GetEmbeddedTexture(ogPath.c_str());
408
					if( embeddedTexture ){
409
						bHasEmbeddedTexture = true;
410
						ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource() texture " << realPath.filename() << " is embedded ";
411
					}else{
412
						ofLogError("ofxAssimpModelLoader") << "loadGLResource(): texture doesn't exist: \""
413
						<< file.getFileName() + "\" in \"" << realPath.string() << "\"";
414
					}
415
				}
416
#endif
417

418
				bool bTextureAlreadyExists = false;
419
				if(textures.count(realPath)){
420
					bTextureAlreadyExists = true;
421
				}
422

423
				if(bTextureAlreadyExists) {
424
					ofxAssimpTexture assimpTexture;
425

426
					assimpTexture.setup(*textures[realPath].get(), realPath, bWrap);
427
					assimpTexture.setTextureType((aiTextureType)d);
428
					meshHelper.addTexture(assimpTexture);
429

430
					ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture already loaded: \""
431
					<< file.getFileName() + "\" from \"" << realPath.string() << "\"" << " adding texture as " << assimpTexture.getTextureTypeAsString() ;
432
				} else {
433

434
					shared_ptr<ofTexture> texture = std::make_shared<ofTexture>();
435

436
					if( bHasEmbeddedTexture ){
437

438
#ifndef TARGET_LINUX_ARM
439
						auto embeddedTexture = scene->GetEmbeddedTexture(ogPath.c_str());
440

441
						//compressed texture
442
						if( embeddedTexture->mHeight == 0 && embeddedTexture->mWidth > 0){
443
							ofImage tmp;
444
							ofBuffer buffer;
445
							buffer.set((char *)embeddedTexture->pcData, embeddedTexture->mWidth);
446

447
							tmp.setUseTexture(false);
448
							tmp.load(buffer);
449

450
							ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource() texture size is " << tmp.getWidth() << "x" << tmp.getHeight();
451

452
							texture->loadData(tmp.getPixels());
453
						}else{
454
							//uncompressed texture - might need swizzling from argb to rgba?
455
							auto glFormat = getGLFormatFromAiFormat(embeddedTexture->achFormatHint);
456
							texture->loadData((const uint8_t *)embeddedTexture->pcData, embeddedTexture->mWidth, embeddedTexture->mHeight, glFormat);
457
						}
458
#endif
459
					}else{
460
						ofLoadImage(*texture.get(), realPath);
461
					}
462

463
					if(texture && texture->isAllocated()){
464
						ofxAssimpTexture tmpTex;
465
						tmpTex.setup(*texture.get(), realPath, bWrap);
466
						tmpTex.setTextureType((aiTextureType)d);
467
						textures[realPath] = texture;
468

469
						tmpTex.setTextureType((aiTextureType)d);
470
						meshHelper.addTexture( tmpTex );
471

472
						ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture " << tmpTex.getTextureTypeAsString() << " loaded, dimensions: " << texture->getWidth() << "x" << texture->getHeight();
473
					}else{
474
						ofLogError("ofxAssimpModelLoader") << "loadGLResource(): couldn't load texture: \""
475
						<< file.getFileName() + "\" from \"" << realPath.string() << "\"";
476
					}
477
				}
478
			}
479
		}
480

481
		meshHelper.mesh = mesh;
482
		aiMeshToOfMesh(mesh, meshHelper.cachedMesh, &meshHelper);
483
		meshHelper.cachedMesh.setMode(OF_PRIMITIVE_TRIANGLES);
484
		meshHelper.validCache = true;
485
		meshHelper.hasChanged = false;
486

487
		int numOfAnimations = scene->mNumAnimations;
488
		for (int i = 0; i<numOfAnimations; i++) {
489
			aiAnimation * animation = scene->mAnimations[i];
490
			animations.push_back(ofxAssimpAnimation(scene, animation));
491
		}
492

493
		if(hasAnimations()){
494
			meshHelper.animatedPos.resize(mesh->mNumVertices);
495
			if(mesh->HasNormals()){
496
				meshHelper.animatedNorm.resize(mesh->mNumVertices);
497
			}
498
		}
499

500

501
		int usage;
502
		if(getAnimationCount()){
503
#ifndef TARGET_OPENGLES
504
			if(!ofIsGLProgrammableRenderer()){
505
				usage = GL_STATIC_DRAW;
506
			}else{
507
				usage = GL_STREAM_DRAW;
508
			}
509
#else
510
			usage = GL_DYNAMIC_DRAW;
511
#endif
512
		}else{
513
			usage = GL_STATIC_DRAW;
514
		}
515

516
		meshHelper.vbo.setVertexData(&mesh->mVertices[0].x,3,mesh->mNumVertices,usage,sizeof(aiVector3D));
517
		if(mesh->HasVertexColors(0)){
518
			meshHelper.vbo.setColorData(&mesh->mColors[0][0].r,mesh->mNumVertices,GL_STATIC_DRAW,sizeof(aiColor4D));
519
		}
520
		if(mesh->HasNormals()){
521
			meshHelper.vbo.setNormalData(&mesh->mNormals[0].x,mesh->mNumVertices,usage,sizeof(aiVector3D));
522
		}
523
		if (meshHelper.cachedMesh.hasTexCoords()){
524
			meshHelper.vbo.setTexCoordData(&meshHelper.cachedMesh.getTexCoords()[0].x, mesh->mNumVertices,GL_STATIC_DRAW,sizeof(glm::vec2));
525
		}
526

527
		meshHelper.indices.resize(mesh->mNumFaces * 3);
528
		int j=0;
529
		for (unsigned int x = 0; x < mesh->mNumFaces; ++x){
530
			for (unsigned int a = 0; a < mesh->mFaces[x].mNumIndices; ++a){
531
				meshHelper.indices[j++]=mesh->mFaces[x].mIndices[a];
532
			}
533
		}
534

535
		meshHelper.vbo.setIndexData(&meshHelper.indices[0],meshHelper.indices.size(),GL_STATIC_DRAW);
536

537
		//modelMeshes.push_back(meshHelper);
538
	}
539
	ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): finished";
540
}
541

542
//-------------------------------------------
543
void ofxAssimpModelLoader::clear(){
544

545
	if( scene ){
546
		scene.reset();
547
		importer.FreeScene();
548
	}
549

550
	ofLogVerbose("ofxAssimpModelLoader") << "clear(): deleting GL resources";
551

552
	// clear out everything.
553
	modelMeshes.clear();
554
	animations.clear();
555
	pos = glm::vec3(0,0,0);
556
	scale = glm::vec3(1,1,1);
557
	rotAngle.clear();
558
	rotAxis.clear();
559
	lights.clear();
560

561
	scale = glm::vec3(1, 1, 1);
562
	normalizeScale = true;
563
	bUsingMaterials = true;
564
	bUsingNormals = true;
565
	bUsingTextures = true;
566
	bUsingColors = true;
567

568
	currentAnimation = -1;
569

570
	textures.clear();
571

572
	updateModelMatrix();
573
}
574

575
//------------------------------------------- update.
576
void ofxAssimpModelLoader::update() {
577
	if(!scene) return;
578
	updateAnimations();
579
	updateMeshes(scene->mRootNode, glm::mat4());
580
	if(hasAnimations() == false) {
581
		return;
582
	}
583
	updateBones();
584
	updateGLResources();
585
}
586

587
void ofxAssimpModelLoader::updateAnimations() {
588
	for(size_t i = 0; i < animations.size(); i++) {
589
		animations[i].update();
590
	}
591
}
592

593
void ofxAssimpModelLoader::updateMeshes(aiNode * node, glm::mat4 parentMatrix) {
594

595
	aiMatrix4x4 m = node->mTransformation;
596
	m.Transpose();
597
	ofMatrix4x4 matrix(m.a1, m.a2, m.a3, m.a4,
598
					   m.b1, m.b2, m.b3, m.b4,
599
					   m.c1, m.c2, m.c3, m.c4,
600
					   m.d1, m.d2, m.d3, m.d4);
601
	matrix *= parentMatrix;
602

603
	for(unsigned int i = 0; i < node->mNumMeshes; i++) {
604
		int meshIndex = node->mMeshes[i];
605
		ofxAssimpMeshHelper & mesh = modelMeshes[meshIndex];
606
		mesh.matrix = matrix;
607
	}
608

609
	for(unsigned int i = 0; i < node->mNumChildren; i++) {
610
		updateMeshes(node->mChildren[i], matrix);
611
	}
612
}
613

614
void ofxAssimpModelLoader::updateBones() {
615
	if (!hasAnimations()){
616
		return;
617
	}
618
	// update mesh position for the animation
619
	for(size_t i = 0; i < modelMeshes.size(); ++i) {
620
		// current mesh we are introspecting
621
		const aiMesh* mesh = modelMeshes[i].mesh;
622

623
		// calculate bone matrices
624
		vector<aiMatrix4x4> boneMatrices(mesh->mNumBones);
625
		for(unsigned int a = 0; a < mesh->mNumBones; ++a) {
626
			const aiBone* bone = mesh->mBones[a];
627

628
			// find the corresponding node by again looking recursively through the node hierarchy for the same name
629
			aiNode* node = scene->mRootNode->FindNode(bone->mName);
630

631
			// start with the mesh-to-bone matrix
632
			boneMatrices[a] = bone->mOffsetMatrix;
633
			// and now append all node transformations down the parent chain until we're back at mesh coordinates again
634
			const aiNode* tempNode = node;
635
			while(tempNode) {
636
				// check your matrix multiplication order here!!!
637
				boneMatrices[a] = tempNode->mTransformation * boneMatrices[a];
638
				// boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation;
639
				tempNode = tempNode->mParent;
640
			}
641
			modelMeshes[i].hasChanged = true;
642
			modelMeshes[i].validCache = false;
643
		}
644

645
		modelMeshes[i].animatedPos.assign(modelMeshes[i].animatedPos.size(), aiVector3D(0.0f));
646
		if(mesh->HasNormals()){
647
			modelMeshes[i].animatedNorm.assign(modelMeshes[i].animatedNorm.size(), aiVector3D(0.0f));
648
		}
649
		// loop through all vertex weights of all bones
650
		for(unsigned int a = 0; a < mesh->mNumBones; ++a) {
651
			const aiBone* bone = mesh->mBones[a];
652
			const aiMatrix4x4& posTrafo = boneMatrices[a];
653

654
			for(unsigned int b = 0; b < bone->mNumWeights; ++b) {
655
				const aiVertexWeight& weight = bone->mWeights[b];
656

657
				size_t vertexId = weight.mVertexId;
658
				const aiVector3D& srcPos = mesh->mVertices[vertexId];
659

660
				modelMeshes[i].animatedPos[vertexId] += weight.mWeight * (posTrafo * srcPos);
661
			}
662
			if(mesh->HasNormals()){
663
				// 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling
664
				aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo);
665
				for(unsigned int b = 0; b < bone->mNumWeights; ++b) {
666
					const aiVertexWeight& weight = bone->mWeights[b];
667
					size_t vertexId = weight.mVertexId;
668

669
					const aiVector3D& srcNorm = mesh->mNormals[vertexId];
670
					modelMeshes[i].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm);
671
				}
672
			}
673
		}
674
	}
675
}
676

677
void ofxAssimpModelLoader::updateGLResources(){
678
	// now upload the result position and normal along with the other vertex attributes into a dynamic vertex buffer, VBO or whatever
679
	for (unsigned int i = 0; i < modelMeshes.size(); ++i){
680
		if(modelMeshes[i].hasChanged){
681
			const aiMesh* mesh = modelMeshes[i].mesh;
682
			if(hasAnimations()){
683
				modelMeshes[i].vbo.updateVertexData(&modelMeshes[i].animatedPos[0].x,mesh->mNumVertices);
684
				if(mesh->HasNormals()){
685
					modelMeshes[i].vbo.updateNormalData(&modelMeshes[i].animatedNorm[0].x,mesh->mNumVertices);
686
				}
687
			}
688
			modelMeshes[i].hasChanged = false;
689
		}
690
	}
691
}
692

693
void ofxAssimpModelLoader::updateModelMatrix() {
694
	modelMatrix = glm::identity<glm::mat4>();
695
	modelMatrix = glm::translate(modelMatrix, toGlm(pos));
696
	modelMatrix = glm::rotate(modelMatrix, ofDegToRad(180), glm::vec3(0,0,1));
697

698
	if(normalizeScale) {
699
		modelMatrix = glm::scale(modelMatrix, glm::vec3(normalizedScale, normalizedScale, normalizedScale));
700
	}
701

702
	for(size_t i = 0; i < rotAngle.size(); i++){
703
		modelMatrix = glm::rotate(modelMatrix, ofDegToRad(rotAngle[i]), glm::vec3(rotAxis[i].x, rotAxis[i].y, rotAxis[i].z));
704
	}
705

706
	modelMatrix = glm::scale(modelMatrix, toGlm(scale));
707
}
708

709
//------------------------------------------- animations.
710
bool ofxAssimpModelLoader::hasAnimations() {
711
	return animations.size() > 0;
712
}
713

714
unsigned int ofxAssimpModelLoader::getAnimationCount(){
715
	return animations.size();
716
}
717

718
ofxAssimpAnimation & ofxAssimpModelLoader::getAnimation(int animationIndex) {
719
	animationIndex = ofClamp(animationIndex, 0, animations.size()-1);
720
	return animations[animationIndex];
721
}
722

723
void ofxAssimpModelLoader::playAllAnimations() {
724
	for(size_t i = 0; i < animations.size(); i++) {
725
		animations[i].play();
726
	}
727
}
728

729
void ofxAssimpModelLoader::stopAllAnimations() {
730
	for(size_t i = 0; i < animations.size(); i++) {
731
		animations[i].stop();
732
	}
733
}
734

735
void ofxAssimpModelLoader::resetAllAnimations() {
736
	for(size_t i = 0; i < animations.size(); i++) {
737
		animations[i].reset();
738
	}
739
}
740

741
void ofxAssimpModelLoader::setPausedForAllAnimations(bool pause) {
742
	for(size_t i = 0; i < animations.size(); i++) {
743
		animations[i].setPaused(pause);
744
	}
745
}
746

747
void ofxAssimpModelLoader::setLoopStateForAllAnimations(ofLoopType state) {
748
	for(size_t i = 0; i < animations.size(); i++) {
749
		animations[i].setLoopState(state);
750
	}
751
}
752

753
void ofxAssimpModelLoader::setPositionForAllAnimations(float position) {
754
	for(size_t i = 0; i < animations.size(); i++) {
755
		animations[i].setPosition(position);
756
	}
757
}
758

759
// DEPRECATED.
760
void ofxAssimpModelLoader::setAnimation(int animationIndex) {
761
	if(!hasAnimations()) {
762
		return;
763
	}
764
	currentAnimation = ofClamp(animationIndex, 0, getAnimationCount() - 1);
765
}
766

767
// DEPRECATED.
768
void ofxAssimpModelLoader::setNormalizedTime(float time) {
769
	if(!hasAnimations()) {
770
		return;
771
	}
772
	currentAnimation = ofClamp(currentAnimation, 0, getAnimationCount() - 1);
773
	ofxAssimpAnimation & animation = animations[currentAnimation];
774
	float realT = ofMap(time, 0.0, 1.0, 0.0, animation.getDurationInSeconds(), false);
775
	animation.setPosition(realT);
776
	update();
777
}
778

779
// DEPRECATED.
780
void ofxAssimpModelLoader::setTime(float time) {
781
	if(!hasAnimations()) {
782
		return;
783
	}
784
	currentAnimation = ofClamp(currentAnimation, 0, getAnimationCount() - 1);
785
	ofxAssimpAnimation & animation = animations[currentAnimation];
786
	animation.setPosition(time);
787
	update();
788
}
789

790
// DEPRECATED.
791
float ofxAssimpModelLoader::getDuration(int animationIndex) {
792
	if(!hasAnimations()) {
793
		return 0;
794
	}
795
	animationIndex = ofClamp(animationIndex, 0, getAnimationCount() - 1);
796
	float duration = animations[animationIndex].getDurationInSeconds();
797
	return duration;
798
}
799

800
//------------------------------------------- meshes.
801
bool ofxAssimpModelLoader::hasMeshes() {
802
	return modelMeshes.size() > 0;
803
}
804

805
unsigned int ofxAssimpModelLoader::getMeshCount() {
806
	return modelMeshes.size();
807
}
808

809
ofxAssimpMeshHelper & ofxAssimpModelLoader::getMeshHelper(int meshIndex) {
810
	meshIndex = ofClamp(meshIndex, 0, modelMeshes.size()-1);
811
	return modelMeshes[meshIndex];
812
}
813

814
//-------------------------------------------
815
void ofxAssimpModelLoader::getBoundingBoxWithMinVector( aiVector3D* min, aiVector3D* max )
816
{
817
	aiMatrix4x4 trafo;
818
	aiIdentityMatrix4(&trafo);
819

820
	min->x = min->y = min->z =  1e10f;
821
	max->x = max->y = max->z = -1e10f;
822

823
	for(auto & mesh: modelMeshes){
824
		this->getBoundingBoxForNode(mesh, min, max);
825
	}
826
}
827

828
//-------------------------------------------
829
void ofxAssimpModelLoader::getBoundingBoxForNode(const ofxAssimpMeshHelper & mesh, aiVector3D* min, aiVector3D* max){
830
	if (!hasAnimations()){
831
		for(unsigned int i = 0; i < mesh.mesh->mNumVertices; i++){
832
			auto vertex = mesh.mesh->mVertices[i];
833
			auto tmp = mesh.matrix * glm::vec4(vertex.x,vertex.y,vertex.z,1.0f);
834

835
			min->x = std::min(min->x,tmp.x);
836
			min->y = std::min(min->y,tmp.y);
837
			min->z = std::min(min->z,tmp.z);
838

839
			max->x = std::max(max->x,tmp.x);
840
			max->y = std::max(max->y,tmp.y);
841
			max->z = std::max(max->z,tmp.z);
842
		}
843
	} else {
844
		for (auto & animPos: mesh.animatedPos){
845
			auto tmp = mesh.matrix * glm::vec4(animPos.x,animPos.y,animPos.z,1.0f);
846

847
			min->x = std::min(min->x,tmp.x);
848
			min->y = std::min(min->y,tmp.y);
849
			min->z = std::min(min->z,tmp.z);
850

851
			max->x = std::max(max->x,tmp.x);
852
			max->y = std::max(max->y,tmp.y);
853
			max->z = std::max(max->z,tmp.z);
854
		}
855
	}
856
}
857

858
//-------------------------------------------
859
void ofxAssimpModelLoader::setPosition(float x, float y, float z){
860
	pos.x = x;
861
	pos.y = y;
862
	pos.z = z;
863

864
	updateModelMatrix();
865
}
866

867
//-------------------------------------------
868
void ofxAssimpModelLoader::setScale(float x, float y, float z){
869
	scale.x = x;
870
	scale.y = y;
871
	scale.z = z;
872

873
	updateModelMatrix();
874
}
875

876
//-------------------------------------------
877
void ofxAssimpModelLoader::setScaleNormalization(bool normalize) {
878
	normalizeScale = normalize;
879

880
	updateModelMatrix();
881
}
882

883
//-------------------------------------------
884
void ofxAssimpModelLoader::setRotation(int which, float angle, float rot_x, float rot_y, float rot_z){
885
	if(which + 1 > (int)rotAngle.size()){
886
		int diff = 1 + (which - rotAngle.size());
887
		for(int i = 0; i < diff; i++){
888
			rotAngle.push_back(0);
889
			rotAxis.push_back(glm::vec3(0.0,0.0,0.0));
890
		}
891
	}
892

893
	rotAngle[which]  = angle;
894
	rotAxis[which].x = rot_x;
895
	rotAxis[which].y = rot_y;
896
	rotAxis[which].z = rot_z;
897

898
	updateModelMatrix();
899
}
900

901
//--------------------------------------------------------------
902
void ofxAssimpModelLoader::drawWireframe(){
903
	draw(OF_MESH_WIREFRAME);
904
}
905

906
//--------------------------------------------------------------
907
void ofxAssimpModelLoader::drawFaces(){
908
	draw(OF_MESH_FILL);
909
}
910

911
//--------------------------------------------------------------
912
void ofxAssimpModelLoader::drawVertices(){
913
	draw(OF_MESH_POINTS);
914
}
915

916
//-------------------------------------------
917
void ofxAssimpModelLoader::enableCulling(int glCullType){
918
	mCullType = glCullType;
919
}
920

921
//-------------------------------------------
922
void ofxAssimpModelLoader::disableCulling(){
923
	mCullType = -1;
924
}
925

926
//-------------------------------------------
927
void ofxAssimpModelLoader::draw(ofPolyRenderMode renderType) {
928
	if(scene == NULL) {
929
		return;
930
	}
931

932
	ofPushStyle();
933

934
	ofPushMatrix();
935
	ofMultMatrix(modelMatrix);
936

937
#ifndef TARGET_OPENGLES
938
	glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType));
939
#endif
940

941
	for(size_t i = 0; i < modelMeshes.size(); i++) {
942
		ofxAssimpMeshHelper & mesh = modelMeshes[i];
943

944
		ofPushMatrix();
945
		ofMultMatrix(mesh.matrix);
946

947
		if(bUsingTextures){
948
			if(mesh.hasTexture(aiTextureType_DIFFUSE)) {
949
				mesh.getTextureRef(aiTextureType_DIFFUSE).bind();
950
			}
951
		}
952

953
		if(bUsingMaterials){
954
			mesh.material.begin();
955
		}
956

957
		//		this was broken / backwards
958
		if(!mesh.twoSided && mCullType >= 0) {
959
			glEnable(GL_CULL_FACE);
960
			glCullFace(GL_BACK);
961
			glFrontFace(mCullType);
962
		}
963
		else {
964
			glDisable(GL_CULL_FACE);
965
		}
966

967

968

969
		ofEnableBlendMode(mesh.blendMode);
970

971
#ifndef TARGET_OPENGLES
972
		mesh.vbo.drawElements(GL_TRIANGLES,mesh.indices.size());
973
#else
974
		switch(renderType){
975
			case OF_MESH_FILL:
976
				mesh.vbo.drawElements(GL_TRIANGLES,mesh.indices.size());
977
				break;
978
			case OF_MESH_WIREFRAME:
979
				//note this won't look the same as on non ES renderers.
980
				//there is no easy way to convert GL_TRIANGLES to outlines for each triangle
981
				mesh.vbo.drawElements(GL_LINES,mesh.indices.size());
982
				break;
983
			case OF_MESH_POINTS:
984
				mesh.vbo.drawElements(GL_POINTS,mesh.indices.size());
985
				break;
986
		}
987
#endif
988

989
		if(bUsingTextures){
990
			if(mesh.hasTexture(aiTextureType_DIFFUSE)) {
991
				mesh.getTextureRef(aiTextureType_DIFFUSE).unbind();
992
			}
993
		}
994

995
		if(!mesh.twoSided) {
996
			glDisable(GL_CULL_FACE);
997
		}
998

999
		if(bUsingMaterials){
1000
			mesh.material.end();
1001
		}
1002

1003
		ofPopMatrix();
1004
	}
1005

1006
#ifndef TARGET_OPENGLES
1007
	//set the drawing mode back to FILL if its drawn the model with a different mode.
1008
	if( renderType != OF_MESH_FILL ){
1009
		glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(OF_MESH_FILL));
1010
	}
1011
#endif
1012

1013
	ofPopMatrix();
1014
	ofPopStyle();
1015
}
1016

1017
//-------------------------------------------
1018
vector<string> ofxAssimpModelLoader::getMeshNames(){
1019
	if(!scene)return vector<string>();
1020

1021
	vector<string> names(scene->mNumMeshes);
1022
	for(unsigned int i=0; i< scene->mNumMeshes; i++){
1023
		names[i] = scene->mMeshes[i]->mName.data;
1024
	}
1025
	return names;
1026
}
1027

1028
//-------------------------------------------
1029
unsigned int ofxAssimpModelLoader::getNumMeshes(){
1030
	if( scene ){
1031
		return scene->mNumMeshes;
1032
	}
1033
	return 0;
1034
}
1035

1036
//-------------------------------------------
1037
ofMesh ofxAssimpModelLoader::getMesh(string name){
1038
	ofMesh ofm;
1039
	if( scene ){
1040
		// default to triangle mode
1041
		ofm.setMode(OF_PRIMITIVE_TRIANGLES);
1042
		aiMesh * aim = NULL;
1043
		for(unsigned int i=0; i < scene->mNumMeshes; i++){
1044
			if(string(scene->mMeshes[i]->mName.data)==name){
1045
				aim = scene->mMeshes[i];
1046
				break;
1047
			}
1048
		}
1049

1050
		if(!aim){
1051
			ofLogError("ofxAssimpModelLoader") <<"getMesh(): couldn't find mesh: \"" << name << "\"";
1052
			return ofm;
1053
		}
1054

1055
		aiMeshToOfMesh(aim,ofm);
1056
	}
1057
	return ofm;
1058
}
1059

1060
//-------------------------------------------
1061
ofMesh ofxAssimpModelLoader::getMesh(unsigned int num){
1062
	ofMesh ofm;
1063
	if( scene ){
1064
		if(scene->mNumMeshes <= num){
1065
			ofLogError("ofxAssimpModelLoader") << "getMesh(): mesh id " << num
1066
			<< " out of range for total num meshes: " << scene->mNumMeshes;
1067
			return ofm;
1068
		}
1069
		aiMeshToOfMesh(scene->mMeshes[num],ofm);
1070
	}
1071
	return ofm;
1072
}
1073

1074
//-------------------------------------------
1075
ofMesh ofxAssimpModelLoader::getCurrentAnimatedMesh(string name){
1076
	for(size_t i=0; i < modelMeshes.size(); i++){
1077
		if(string(modelMeshes[i].mesh->mName.data)==name){
1078
			if(!modelMeshes[i].validCache){
1079
				modelMeshes[i].cachedMesh.clearVertices();
1080
				modelMeshes[i].cachedMesh.clearNormals();
1081
				if(hasAnimations()){
1082
					modelMeshes[i].cachedMesh.addVertices(aiVecVecToOfVecVec(modelMeshes[i].animatedPos));
1083
					modelMeshes[i].cachedMesh.addNormals(aiVecVecToOfVecVec(modelMeshes[i].animatedNorm));
1084
				}
1085
				modelMeshes[i].validCache = true;
1086
			}
1087
			return modelMeshes[i].cachedMesh;
1088
		}
1089
	}
1090

1091
	ofLogError("ofxAssimpModelLoader") << "getCurrentAnimatedMesh(): couldn't find mesh: \"" + name << "\"";
1092
	return ofMesh();
1093

1094
}
1095

1096
//-------------------------------------------
1097
ofMesh ofxAssimpModelLoader::getCurrentAnimatedMesh(unsigned int num){
1098
	if(modelMeshes.size() <= num){
1099
		ofLogError("ofxAssimpModelLoader") << "getCurrentAnimatedMesh(): mesh id: " << num
1100
		<< "out of range for total num meshes: " << scene->mNumMeshes;
1101
		return ofMesh();
1102
	}
1103
	if(!modelMeshes[num].validCache){
1104
		modelMeshes[num].cachedMesh.clearVertices();
1105
		modelMeshes[num].cachedMesh.clearNormals();
1106
		modelMeshes[num].cachedMesh.addVertices(aiVecVecToOfVecVec(modelMeshes[num].animatedPos));
1107
		modelMeshes[num].cachedMesh.addNormals(aiVecVecToOfVecVec(modelMeshes[num].animatedNorm));
1108
		modelMeshes[num].validCache = true;
1109
	}
1110
	return modelMeshes[num].cachedMesh;
1111
}
1112

1113
//-------------------------------------------
1114
ofMaterial ofxAssimpModelLoader::getMaterialForMesh(string name){
1115
	for(size_t i = 0; i < modelMeshes.size(); i++){
1116
		if(string(modelMeshes[i].mesh->mName.data)==name){
1117
			return modelMeshes[i].material;
1118
		}
1119
	}
1120
	ofLogError("ofxAssimpModelLoader") << "getMaterialForMesh(): couldn't find mesh: \"" + name << "\"";
1121
	return ofMaterial();
1122
}
1123

1124
//-------------------------------------------
1125
ofMaterial ofxAssimpModelLoader::getMaterialForMesh(unsigned int num){
1126
	if(modelMeshes.size() <= num){
1127
		ofLogError("ofxAssimpModelLoader") << "getMaterialForMesh(): mesh id: " << num
1128
		<< "out of range for total num meshes: " << scene->mNumMeshes;
1129
		return ofMaterial();
1130
	}
1131
	return modelMeshes[num].material;
1132
}
1133

1134
//-------------------------------------------
1135
ofTexture ofxAssimpModelLoader::getTextureForMesh(string name){
1136
	for(size_t i = 0; i < modelMeshes.size(); i++){
1137
		if(string(modelMeshes[i].mesh->mName.data)==name){
1138
			if(modelMeshes[i].hasTexture()) {
1139
				return modelMeshes[i].getTextureRef();
1140
			}
1141
		}
1142
	}
1143
	ofLogError("ofxAssimpModelLoader") << "getTextureForMesh(): couldn't find mesh: \"" + name << "\"";
1144
	return ofTexture();
1145
}
1146

1147
//-------------------------------------------
1148
ofTexture ofxAssimpModelLoader::getTextureForMesh(unsigned int i){
1149
	if(i < modelMeshes.size()){
1150
		if(modelMeshes[i].hasTexture()) {
1151
			return modelMeshes[i].getTextureRef();
1152
		}
1153
	}
1154
	ofLogError("ofxAssimpModelLoader") << "getTextureForMesh(): mesh id: " << i
1155
	<< "out of range for total num meshes: " << scene->mNumMeshes;
1156
	return ofTexture();
1157
}
1158

1159
//-------------------------------------------
1160
glm::vec3 ofxAssimpModelLoader::getPosition(){
1161
	return pos;
1162
}
1163

1164
//-------------------------------------------
1165
glm::vec3 ofxAssimpModelLoader::getSceneCenter(){
1166
	return aiVecToOfVec(scene_center);
1167
}
1168

1169
//-------------------------------------------
1170
float ofxAssimpModelLoader::getNormalizedScale(){
1171
	return normalizedScale;
1172
}
1173

1174
//-------------------------------------------
1175
glm::vec3 ofxAssimpModelLoader::getScale(){
1176
	return scale;
1177
}
1178

1179
//-------------------------------------------
1180
glm::mat4 ofxAssimpModelLoader::getModelMatrix() {
1181
	return modelMatrix;
1182
}
1183

1184
//-------------------------------------------
1185
glm::vec3 ofxAssimpModelLoader::getSceneMin(bool bScaled ){
1186
	glm::vec3 sceneMin(scene_min.x, scene_min.y, scene_min.z);
1187
	if( bScaled ){
1188
		return sceneMin * scale;
1189
	}else{
1190
		return sceneMin;
1191
	}
1192
}
1193

1194
//-------------------------------------------
1195
glm::vec3 ofxAssimpModelLoader::getSceneMax(bool bScaled ){
1196
	glm::vec3 sceneMax(scene_max.x, scene_max.y, scene_max.z);
1197
	if( bScaled ){
1198
		return sceneMax * scale;
1199
	}else{
1200
		return sceneMax;
1201
	}
1202
}
1203

1204
//-------------------------------------------
1205
glm::vec3 ofxAssimpModelLoader::getSceneMinModelSpace(){
1206
	glm::vec3 sceneMax(scene_min.x, scene_min.y, scene_min.z);
1207
	return glm::vec3(modelMatrix * glm::vec4(scene_min.x, scene_min.y, scene_min.z, 1.0));
1208
}
1209

1210
//-------------------------------------------
1211
glm::vec3 ofxAssimpModelLoader::getSceneMaxModelSpace(){
1212
	glm::vec3 sceneMax(scene_max.x, scene_max.y, scene_max.z);
1213
	return glm::vec3(modelMatrix * glm::vec4(scene_max.x, scene_max.y, scene_max.z, 1.0));
1214
}
1215

1216
//-------------------------------------------
1217
glm::vec3 ofxAssimpModelLoader::getSceneCenterModelSpace(){
1218
	glm::vec3 center = getSceneCenter();
1219
	return glm::vec3(modelMatrix * glm::vec4(center.x, center.y, center.z, 1.0));
1220
}
1221

1222
//-------------------------------------------
1223
int ofxAssimpModelLoader::getNumRotations(){
1224
	return rotAngle.size();
1225
}
1226

1227
//-------------------------------------------
1228
glm::vec3 ofxAssimpModelLoader::getRotationAxis(int which){
1229
	if((int)rotAxis.size() > which){
1230
		return rotAxis[which];
1231
	}else{
1232
		return glm::vec3(0.0,0.0,0.0);
1233
	}
1234
}
1235

1236
//-------------------------------------------
1237
float ofxAssimpModelLoader::getRotationAngle(int which){
1238
	if((int)rotAngle.size() > which){
1239
		return rotAngle[which];
1240
	}else{
1241
		return 0.0;
1242
	}
1243
}
1244

1245
//-------------------------------------------
1246
const aiScene* ofxAssimpModelLoader::getAssimpScene(){
1247
	return scene.get();
1248
}
1249

1250
//--------------------------------------------------------------
1251
void ofxAssimpModelLoader::enableTextures(){
1252
	bUsingTextures = true;
1253
}
1254

1255
//--------------------------------------------------------------
1256
void ofxAssimpModelLoader::enableNormals(){
1257
	bUsingNormals = true;
1258
}
1259

1260
//--------------------------------------------------------------
1261
void ofxAssimpModelLoader::enableColors(){
1262
	bUsingColors = true;
1263
}
1264

1265
//--------------------------------------------------------------
1266
void ofxAssimpModelLoader::enableMaterials(){
1267
	bUsingMaterials = true;
1268
}
1269

1270
//--------------------------------------------------------------
1271
void ofxAssimpModelLoader::disableTextures(){
1272
	bUsingTextures = false;
1273
}
1274

1275
//--------------------------------------------------------------
1276
void ofxAssimpModelLoader::disableNormals(){
1277
	bUsingNormals = false;
1278
}
1279

1280
//--------------------------------------------------------------
1281
void ofxAssimpModelLoader::disableColors(){
1282
	bUsingColors = false;
1283
}
1284

1285
//--------------------------------------------------------------
1286
void ofxAssimpModelLoader::disableMaterials(){
1287
	bUsingMaterials = false;
1288
}
1289

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.