Recently, I’m spending a lot of time in the atrium of the Sponza palace.
No, I didn’t move to Dubrovnik, Croatia, nor I’m on vacation: it’s just that the Sponza atrium model, originally created for a rendering contest, has been adopted by the computer graphics community as a test model (especially in the global illumination field), and who am I, working on my master thesis on rendering, to pick something else?
The original model dates back to 2002, but what I’m using is the updated and enhanced version made available by Crytek in 2010.
It features textures, normal maps, specular maps and opacity maps, so there’s plenty of data to be used while rendering.
I’m using Assimp to load models, and I stumbled into a couple problems. I googled about them and found nothing, so I tought that a little post on the subject was worth writing. I mean: if you get lucky and find something not yet on the Internet, you are morally obliged to blog about it before someone else does it! It works like that, right?
Anyway, enough blabbering: the two problems reside in the materials file, sponza.mtl.
- a texture is missing
- the material 16___Default refers to gi_flag.tga, not included in the textures archive
- the specular maps are unreferenced
- the textures pack features some specular maps (the files named *_spec.tga), but they are never referenced by the materials file
Let’s fix them…
Lenna, save us from the missing texture
Obviously, the missing texture is the one of the only untextured object in the scene: the big vertical drape. Copying some other drape texture as gi_flag.tga (or changing the filename in sponza.mtl, of course) gives visually acceptable results.
But didn’t make me happy. What was the original texture like? What if it featured a secret message of some sort? What if it was selected between hundreds, by Crytek professionals, to show some effect I could not even imagine? What if this “I WANT THE RIGHT TEXTURE” thing is just some form of OCD and I must see someone?
I googled for the misterious missing texture, gi_flag.tga but had no luck finding it. I found files named gi_flag.tga in some code repositories using the Sponza model, as I am, but after checking them out, the included gi_flag.tga was always some bogus file put there just to make the asset loader happy.
This poor guy on Stackoverflow asked for the misterious texture too, but had no luck, either.
Finally, my investigations brought me watching this amazing Crytek video, where they use the Sponza model at the beginning and around 2:30.
(also, the video humiliated me and my test renderer a lot)
It somehow solved the mistery: the missing texture is a quite boring red stuff with borders. Yawn.
Disappointement, and I still didn’t have the damn file – but it was time to move on, leaving the gi_flag.tga failure behind me. So, as you may imagine, after some hours of flying around with the camera, testing the shaders, looking if the alpha blending is done correctly, if the normal maps are applied properly, etc, the Sponza palace slowly becomes a boring place. Lion heads. RGB Drapes. Bricks. Plants. More bricks. All static, dead. Depression is around the corner, especially when you waste 3 hours ’cause you forgot to transpose a matrix, or something like that.
Consequently, I tought that selecting missing texture could be an occasion to make the place happier. How? Suddenly, the right answer came to my mind: Lenna.
This picture of Lenna Söderberg, scanned in 1973 from a Playboy issue (to be used as test image for a scientific paper), became a standard test image for compression algorithms and image processing.
I encourage you to visit http://www.lenna.org for the full story.
So, I put a computer graphics iconic image into a computer graphics standard test model.
And the iconic image is a naked woman, turning a bitter failure into an epic win. Hey, that’s how I see it.
Of course, you’re welcome to spread the usage as gi_flag.tga of this Lenna texture I prepared.
- download gi_flag_lenna_full.tga (full body version, minimal cut of the original image)
- download gi_flag_lenna.tga (zoomed on the upper part – more face, less legs)
- download a zip of both (I admire your wiseness)
Get your favourite version (I know, it’s a difficult choice) and rename as gi_flag.tga, put in the textures folder of the Sponza model, and be happy. It’s 2048×2048, you might want to scale it down to 1024×1024 or 512×512.
I properly cutted the original image to let it fit the drape geometry: I’m a gentleman, and gentlemen never let texture get stretched improperly – that could make women on them look fat.
Where are my specular maps?
This is not interesting and not funny: sponza.mtl is missing the “map_Ks” entries used in the .mtl file format to refer to specular maps. I tought it was some other Assimp quirk (for example, it loads the normal maps as height maps), but when I checked the sponza.mtl file I found no reference at all to the *spec.tga files, so Assimp was innocent.
Luckily, the files are consistently named, so a specular map named “sponza_thorn_spec.tga” can be tied to the material that refers to the “sponza_thorn_diff.tga” texture.
That’s what I did, assigning all the provided specular maps to the appropriate materials.
And here you are the updated sponza.mtl file, so you don’t have to repeat the boring file editing process:
With this, I made the post concretely useful for other people, so I’m forgiven for all the Lenna delirium.
… you now what? I’m dating this post April 1st, I can post whatever I want and still pretend to be a serious person.
Hey, this article really helped me a lot, I can’t thank you enough.
However, I think there are two things that still needed to be fixed in the material file and I just thought I’d bring it to your attention…
1) The bricks bump map is set to the diffuse map by mistake (line 99: map_bump should be spnza_bricks_a_ddn.tga not spnza_bricks_a_diff.tga)
2) newmtl_vase was missing the bump map (line 373: map_bump vase_ddn.tga)
Thanks for your comment Rohit, I can’t check what you pointed out and update the file in this moment, but hopefully your comment will help other readers!
What assimp ai flags do you use for loading the mesh. I use the following code, but in a result I’m getting wrongs UV’s (http://imgur.com/b3cqX6b):
aiPropertyStore* props = aiCreatePropertyStore();
aiSetImportPropertyInteger(props, AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
aiSetImportPropertyFloat(props, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f);
aiSetImportPropertyInteger(props, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
aiSetImportPropertyInteger(props, AI_CONFIG_GLOB_MEASURE_TIME, 1);
unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible
aiProcess_JoinIdenticalVertices | // join identical vertices/ optimize indexing
aiProcess_ValidateDataStructure | // perform a full validation of the loader’s output
aiProcess_ImproveCacheLocality | // improve the cache locality of the output vertices
aiProcess_RemoveRedundantMaterials | // remove redundant materials
aiProcess_FindDegenerates | // remove degenerated polygons from the import
aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors
aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs
aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation …)
aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master
aiProcess_LimitBoneWeights | // limit bone weights to 4 per vertex
aiProcess_OptimizeMeshes | // join small meshes, if possible;
aiProcess_SplitByBoneCount | // split meshes with too many bones. Necessary for our (limited) hardware skinning shader
const aiScene* scene = aiImportFileExWithProperties(fileName.c_str(),
ppsteps | /* configurable pp steps */
aiProcess_GenSmoothNormals | // generate smooth normal vectors if not existing
aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
aiProcess_Triangulate | // triangulate polygons with more than 3 edges
//aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
aiProcess_SortByPType | // make ‘clean’ meshes which consist of a single typ of primitives
hopefully I’ll soon manage to publish my full sandbox on GitHub.
Anyway, I don’t do anything fancy with Assimp flags, I use one of the presets:
const aiScene *scene = importer.ReadFile( pFile, aiProcessPreset_TargetRealtime_Quality);
Are you sure it’s a loading issue? Maybe you got something wrong in your shaders?
Fixed. The problem was with the GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T. It was set to GL_CLAMP_TO_EDGE. Renders normally when GL_REPEAT is used.
I just got this problem, and googling led me here. This is almost a wonderful easter egg, I’ll use the image you provided! Thanks