/ celestia / celestia / src / celengine / model.h
Model is the standard geometry object in Celestia. A Model consists of a library of materials together with a list of meshes. Each mesh object contains a pool of vertices and a set of primitive groups. A primitive groups consists of a a primitive group type and a list of vertex indices. This structure is exactly the one used in Celestia model (.cmod) files.
DSC models are rendered with lighting disabled. In OpenGL, this means that a vertex is just assigned it's diffuse color, and no other material properties are considered. Unfortunately, this means the emissive color that makes a model appear self-luminous when it's referenced from an .ssc file will have no effect when the model is used in a .dsc file. If you want the model to show up when it's used in a .dsc, you need to specify the diffuse color instead of the emissive color--for testgrid.cmod, just change emissive to diffuse and everything will work.
This behavior is counterintuitive, but I honestly don't know what to do to make it better.
--Chris
/ celestia / celestia / src / celengine / modelfile.cpp
21 cjlaurel 1.4 /*! 22 This is an approximate Backus Naur form for the contents of ASCII cmod 23 files. For brevity, the categories <unsigned_int> and <float> aren't 24 defined here--they have the obvious definitions. 25 26 <modelfile> ::= <header> <model> 27 28 <header> ::= #celmodel__ascii 29 30 <model> ::= { <material_definition> } { <mesh_definition> } 31 32 <material_definition> ::= material 33 { <material_attribute> } 34 cjlaurel 1.5 end_material 35 cjlaurel 1.4 36 <material_attribute> ::= diffuse <color> | 37 specular <color> | 38 emissive <color> | 39 specpower <float> | 40 opacity <float> | 41 cjlaurel 1.5 texture0 <string> | 42 texture1 <string> 43 cjlaurel 1.4 44 <color> ::= <float> <float> <float> 45 46 <string> ::= """ { letter } """ 47 48 cjlaurel 1.5 <mesh_definition> ::= mesh 49 <vertex_description> 50 cjlaurel 1.4 <vertex_pool> 51 { <prim_group> } 52 cjlaurel 1.5 end_mesh 53 cjlaurel 1.4 54 <vertex_description> ::= vertexdesc 55 { <vertex_attribute> } 56 cjlaurel 1.5 end_vertexdesc 57 cjlaurel 1.4 58 <vertex_attribute> ::= <vertex_semantic> <vertex_format> 59 60 cjlaurel 1.5 <vertex_semantic> ::= position | normal | color0 | color1 | tangent | 61 texcoord0 | texcoord1 | texcoord2 | texcoord3 62 cjlaurel 1.4 63 <vertex_format> ::= f1 | f2 | f3 | f4 | ub4 64 65 <vertex_pool> ::= vertices <count> 66 { <float> } 67 68 <count> ::= <unsigned_int> 69 70 <prim_group> ::= <prim_group_type> <material_index> <count> 71 { <unsigned_int> } 72 73 <prim_group_type> ::= trilist | tristrip | trifan | 74 linelist | linestrip | points 75 76 <material_index> :: <unsigned_int> | -1 77 */ 78
(Quoted from a posting to the Developers' mailing list.)
Date: Tue, 17 Feb 2004 02:42:22 -0800 (PST)
From: Chris Laurel
Subject: [Celestia-developers] Big change -- meshes
I've been working for the last week on some fundamental changes to the way that Celestia handles meshes and finally checked in my modifications tonight. I've replaced the Mesh3DS/VertexList structure with a cleaner, more flexible, and more efficient structure called a Model in the Celestia code. Along with this checkin, I've added support for a new 3D file format, cmod (for Celestia model.) The new modules are model.cpp, modelfile.cpp, mesh.cpp, and rendcontext.cpp. There were quite a few other changes in the code, but these were mostly just renaming variables and functions from mesh to model. Please test my changes out with any meshes you have. 3DS files should look the same as before--it's probably a bug in the new code if they don't. I already take care of updating the Makefile.am and verifying that Celestia still builds on Linux. I didn't mess with the Visual Studio project files, so if you're using those to compile Celestia you'll have to add the new modules.
I'll give a quick overview of the Model class . . . A model consists of a library of materials and a set of meshes. Each mesh is a pool of vertices and a list of primitive groups. A primitive groups is just a list of indices into the vertex pool, together with a primitive group type identifier (triangle list, triangle strip, line list, etc.) and a material index. This structure is very hardware friendly. It's also the structure used in the cmod file format, meaning that cmod files can be loaded quickly, because very little processing is needed to get them into hardware-ready form.
Yes, there are a ton of 3D file formats out there already, and I'd certainly prefer to use an existing one and avoid the pain of writing a set of conversion tools. But, as I'd discussed on the forum a while ago, I didn't find any of them completely satisfactory. The main design goals for the cmod format were to be both quick to load and flexible enough to handle a wide range of vertex and materail data. A lot of the 3D formats out there require significant massaging before the data can be sent off to OpenGL for rendering. The 3DS format (and many others) don't store normals, so they must be generated at load time. Other formats separate index lists for each vertex attribute--the WaveFront obj format has an index for the position, an index for the texture coordinate, and an index for the normal. It's time consuming to convert this into hardware-friendly single index form. There are a couple hardware friendly formats out there, but they're too simplistic. The BMF format only allows a position, normal, and a 2D texture coordinate per vertex.
The cmod format will have both an ASCII and a binary version, though currently just the ASCII reader is working. The two versions of the format will share a common structure. Here's a sample ASCII cmod, commented heavily with explanations:
#celmodel__ascii # The above line is the 16-byte header; for binary files, it's # #celmodel_binary # material definitions follow--these must precede any meshes in the file material # index 0 emissive 0 1 0 opacity 0.5 end_material # A material with a texture. Texture filenames may use the wildcard # character, which behaves exactly as it does within a .ssc file. material # index 1 emissive 1 1 1 texture0 "tropical-beach.*" end_material # There may be one or more meshes in a model file--this file happens # to have just a single one mesh # The vertex description tells what attributes the vertices for this mesh # have. Each attribute in the description consists of a semantic and a # data format. vertexdesc position f3 normal f3 texcoord0 f2 end_vertexdesc # The vertex data--the number right after the keyword vertices is the # number of vertices in the pool. vertices 6 0 0 0 0 0 1 0 0 1 1 0 0 0 1 1 1 0 1 0 0 0 1 0 1 0 1 0 0 0 -1 0 1 1 1 0 0 0 -1 1 1 0 0 0 0 0 -1 0 0 # An arbitrary number of primitive groups follow # The primitive group type is followed by a material index, then # a count of the number of vertex indices in the group trilist 0 3 0 1 2 trilist 1 3 3 4 5 # End of the mesh end_mesh # ---- end of cmod file ----
The vertex attributes semantics recognized right now are: position - position (required) texcoord0 - primary texture coordinate texcoord1 ... texcoord3 - additional texture coordinates (for multitexturing) color0 ... color1 - primary and secondary colors tangent - surface tangents (for bump mapping) The vertex formats are: f1 - one float f2 - two floats (typical for texture coordinates) f3 - three floats (positions and normals) f4 - four floats ub4 - four unsigned bytes (the usual format for colors) The primitive types are: trilist tristrip trifan linelist linestrip points
Tristrips and trifans can be much more efficient than triangle lists. conversion tools should try to optimize meshes by generating strips and fans where possible.
I'd be happy to hear any suggestions on ways to improve the cmod format, or the new model code.
--Chris
Back to Contents.I've been working lately on improving the Celestia's rendering of meshes, which has for a long time lagged behind planet rendering and modern graphics hardware capabilities. I've implemented a lot of things which will make meshes look a lot better:
Here's demonstration of per-pixel specular lighting. This 'glossy Mars' is not meant to present a realistic example, although specular highlights can be very useful for visualization of surface relief. I anticipate that per-pixel specular lighting will be much more useful for meshes of spacecraft; I'm still in the process of creating a good demonstration.
[Images omitted. See http://www.shatters.net/forum/viewtopic.php?p=74169& ...s.]
In an ASCII cmod file, a full material definition looks like this:
material diffuse 0.5 0.5 0.2 specular 1 1 1 specpower 30 opacity 1 texture0 "basetex.jpg" normalmap "norm.png" specularmap "specmask.jpg" emissivemap "lights.jpg"All these attributes are also available in the binary format. I think that the 3DS file format may also have a place for a specular mask; if so, I can add it to the 3dstocmod converter so that there's a way to get use specular masks without hand editing ASCII cmod files. Do you have a modeling tool that can work with a specular mask?
The new lighting will be in the next prerelease. [after v1.4.1]
Per-pixel specular lighting requires a good amount of graphics power, especially with multiple light sources. But newer graphics hardware tears through even quite complex scenes like the third Mars image. My GeForce 7900 GTX renders it at 60Hz (refresh rate) even at the full monitor resolution of 2560x1600.
I should add that when using normal maps with specular highlights, you
need to be very careful about how you generate the normal map and its
mipmap levels. Normal map problems that were invisible with simple
diffuse lighting can look terrible when specular lighting is enabled.
This is not something particular to Celestia: specular highlights are
higher frequency than diffuse lighting, which changes very gradually
over a smooth surface. There are artifacts visible in Selden's image of
Mars rendered with the OGL 2.0 path. These are due to the fact that
Celestia's default Mars normal map is actually generated at run time
from an 8-bit source height map. We should instead include a normal map
generated from 16-bit source data. There are some other guidelines for
getting the best results with normal maps. I'll post them in the forum
soon.
--Chris
Back to Contents.
CMOD files now support point sprites. There is a new primitive type sprites which can be used in conjunction with the new attribute pointsize. texture0 of the current material becomes the sprite image. Here is a very simple example cmod with three point sprites:
#celmodel__ascii material diffuse 1 0 1 texture0 "flare.jpg" end_material mesh vertexdesc position f3 pointsize f1 end_vertexdesc vertices 3 0 -1 -1 0.5 0 1 1 0.1 0 -1 1 0.1 sprites 0 3 0 1 2 end_mesh
When using sprites in a cmod, the pointsize attribute must be present in addition to the position. The units of pointsize are the same as for vertex positions.
--Chris
A newly added feature to the cmod format are point sprites. These can be used for a variety of different volumetric rendering effects for phenomena such as nebula, accretion disks, volcanic plumes, or engine exhaust. To give a familiar example, Celestia's galaxies are rendered using point sprites (albeit with a level of detail feature not available for cmod point sprites.) First, some caveats:
The add-on can be found at
http://www.shatters.net/~claurel/celestia/files/spriteneb.zip
The changes to the cmod format relevant to point sprites are very minor. There's a new primitive type (sprites), and a new vertex attribute type (pointsize). The sprite texture is texture0 from the material definition. Here is a very basic example of a sprite cmod with three red sprites:
#celmodel__ascii material diffuse 1 0 0 texture0 "gaussian.jpg" end_material mesh vertexdesc position f3 pointsize f1 end_vertexdesc vertices 3 1 0 0 0.25 2 0 0 0.25 3 0 0 0.25 sprites 0 3 0 1 2 end_mesh
For nebula meshes, it may be useful to specify additive blending in the material definition by adding the line 'blend add'. This is especially appropriate for emission nebula, definitely not to be used for dark nebula like the Horsehead. Additively blended objects have the advantage of not needing to be depth sorted with respect to each other. Here's a slightly more complex sprite cmod that uses additive blending and per vertex colors so that each sprite has a different color:
#celmodel__ascii material diffuse 1 0 0 texture0 "gaussian.jpg" blend add end_material mesh vertexdesc position f3 pointsize f1 color f3 end_vertexdesc # row of sprites: red, green, blue vertices 3 1 0 0 0.25 1 0 0 2 0 0 0.25 0 1 0 3 0 0 0.25 0 0 1 sprites 0 3 0 1 2 end_mesh
The program GLNebula uses additively blended point sprites to show
nebula generated by the photoionization tool Cloudy-3D:
http://132.248.1.102/Cloudy_3D/.
An interesting project would be a
tool to convert output from Cloudy 3D into a cmod file.
--Chris
[/quote]
1-----2 1-----2 \ / \ / 3 1-----2 \ /\ \ / \ 3-----4 1-----2 \ /\ \ / \ 3-----4 \ / \ / 5
In general, for a trilist of T triangles we need 3*T entries, but for a tristrip of T triangles T+2 entries are enough. So for large meshes you are saving 2/3 of the resources. The same can be applied to linestrips:
1---2 1---2 / / 3 1---2 / / 3----4 1---2 / / 3----4 / / 5
If the above mesh is defined as a linelist: 1,2 2,3 3,4 4,5 (8 entries). If it is defined as a linestrip: 1,2,3,4,5 (5 entries) A linelist needs 2*L entries for a set of L lines. A linestrip only needs L+1 entries for the same set. For large meshes the saving is about 50% of resources.
The usual way to work with these primitives is to model the object as usual and then use an optimization utility to convert from raw triangles to tristrips, etc. I don't know of any free program/library that can do this, though. Surely Chris does.
1-------2 \ / \ / 3 1-------2 / \ / / \ / 4------ 3 5------ 1-------2 \ / \ / \ / \ / 4------ 3
Using trifans, the above mesh can be described as 1,2,3,4,5 Each tringle has the vertices [v0][v-1][v], where v0 is the first vertex of the set.
As you see, it's similar to a tristrip, but the first vertex is always the center of the trifan. You need T+2 entries to define T triangles, so it is as efficient as a tristrip (but often it can be used where a tristrip can't)
The advantage of using these primitives is that you save disk, bus and memory resources, because mesh descriptions are less voluminous.