ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/translat.txt
Revision: 1.3
Committed: Fri Feb 28 20:19:26 2003 UTC (21 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad4R2P2, rad5R0, rad5R1, rad3R7P2, rad3R7P1, rad4R2, rad4R1, rad4R0, rad3R5, rad3R6, rad3R6P1, rad3R8, rad3R9, rad4R2P1, rad5R3, HEAD
Changes since 1.2: +1 -1 lines
Log Message:
Fixed RCSid's

File Contents

# Content
1 TRANSLATING TO MGF FROM OTHER FORMATS
2 RCSid "$Id$"
3
4 The description of the parser and the MGF specification should provide
5 enough information to get you started using MGF scene files, but we
6 thought it would be helpful to also provide some hints and
7 suggestions for translating to MGF from other formats.
8 Specifically, we will discuss several issues that come up repeatedly
9 when converting from more usual computer graphics scene formats to
10 MGF, most of them having to do with materials. First, let's look at
11 some geometry-related issues.
12
13 Vertex Naming
14 =============
15 Many scene formats do not name vertices; many do not even share
16 vertices. Does it matter what names are given to vertices in MGF?
17 Not a lot, but it can affect memory and file size. In a way, vertex
18 sharing is nothing more than a form of file compression, and the
19 better you are at sharing vertex information, the smaller your file
20 will be. (Vertex sharing is also important for some rendering
21 algorithms, which depend on it for computing surface adjacency.)
22
23 If you are translating from a format that shares unnamed vertices,
24 such as Wavefront's .OBJ format, you will want to name your MGF
25 vertices according to some simple pattern. In most cases, a name
26 such as "v%d" will do, where %d is replaced by an incremented
27 integer.
28
29 If, on the other hand, you are translating from a format that does
30 not share vertices, you should do one of two things. You should
31 either select your MGF vertex names from a small, recycled pool of
32 names, or figure out some way to share vertices that were not shared
33 before. In the first case, you will just allocate as many vertex
34 names as you need for any given object, then reuse these names and
35 therefore the parser's memory for other objects. In the second case,
36 you will cache vertex names and values in some LRU table of
37 predetermined size, and use this table to merge vertices in the
38 file. (See rad2mgf.c as an example of how this can be done.)
39
40 For some objects, there may be little point in merging vertices, and
41 you may want to treat these surfaces separately. For example,
42 putting out an MGF ring means putting out a central vertex, which
43 must have both a position point and a normal direction. It is somewhat
44 unlikely that any other MGF entity will share this point, and quite
45 unlikely that it will share the normal direction, so there is little
46 sense in trying to merge or otherwise reuse it.
47
48 Points and Lines
49 ================
50 Although points and lines are really 3-d surfaces, many CAD
51 systems include them in their models. The question then is,
52 what do we do with these in MGF? If the idea is to produce a point
53 or line on the final display that is one or two pixels wide, there
54 is little one can do to guarantee such a thing will happen because
55 the pixel size is dependent on view and display parameters as well
56 as object location.
57
58 There are two ways of dealing with points and lines in MGF. The
59 first is to say, "Hey, these are 0 and 1 dimensional entities, so
60 they won't appear in 3 dimensions," and get rid of them. The second
61 approach is to assign some user-specified dimension for the "width"
62 of points and lines, and turn them into spheres and cylinders. It
63 might be best to instead create minimal polyhedron analogs, such as
64 tetrahedra for points and triangular prisms for lines. That way, an
65 itty-bitty point won't be converted into 200 polygons because the
66 translator reading in the MGF file can't handle curved surfaces.
67
68 Polygons with Holes
69 ===================
70 There is no explicit representation of holes in MGF. A hole must be
71 represented implicitly by connecting vertices to form "seams." For
72 example, a wall with a window in it might look like this:
73
74 v1.-----------------------------------------------.v4
75 | |
76 | v8.---------------.v5 |
77 | | | |
78 | | | |
79 | v7.---------------.v6 |
80 | |
81 | |
82 v2.-----------------------------------------------.v3
83
84 In many systems, the wall itself would be represented with the first
85 list of vertices, (v1,v2,v3,v4) and the hole associated with that
86 wall as a second set of vertices (v5,v6,v7,v8). In MGF, we must
87 give the whole thing as a single polygon, connecting the vertices so
88 as to create a "seam," thus:
89
90 v1.----------------------<------------------------.v4
91 | _____--><---'|
92 | v8.------->-------.v5 |
93 | | v |
94 v ^ | ^
95 | v7.-------<-------.v6 |
96 | |
97 | |
98 v2.---------------------->------------------------.v3
99
100 which could be written in MGF as "f v1 v2 v3 v4 v5 v6 v7 v8 v5 v4".
101
102 It is very important that the order of the hole be opposite to the
103 order of the outer perimeter, otherwise the polygon will be
104 "twisted" on top of itself. Note also that the seam was traversed
105 in both directions, once going from v4 to v5, and again returning
106 from v5 to v4. This is a necessary condition for a proper seam.
107 (The final edge from v4 back to v1 is implied in MGF.)
108
109 The choice of vertices to make into a seam is somewhat arbitrary, but
110 some rendering systems may not give sane results if you cross over a
111 hole with part of your seam. If we had chosen to create the seam
112 between v2 and v5 in the above example instead of v4 and v5, the seam
113 would cross our hole and may not render correctly. (For systems that
114 are sensitive to this, it is probably safest for their MGF
115 loader/translator re-expresses seams in terms of holes again, which can
116 be done easily so long as vertices are shared in the above fashion.)
117
118 Non-planar Polygons
119 ===================
120 Polygons in MGF should be planar. There is nothing about the format
121 that enforces this, but the rendering or modeling software on the other
122 end may have real problems if this requirement is violated. The parser
123 itself does not test for non-planar polygons, so when in doubt about a
124 model, it is safest to test for planarity and break a polygon into triangles
125 if it is even slightly non-planar.
126
127 NURBS, CSG, Blobbies, Etc.
128 ==========================
129 Sorry, folks, this is just plain hard. If and until MGF supports these
130 higher-order entities, it will be necessary for you to convert them to
131 smoothed triangle meshes. Fortunately, a lot of modeling software
132 already knows how to do this, so if you wrote the modeler, you probably
133 have access to the necessary code. (By the way, if you ever want to see
134 these primitives in MGF, you might just think about sharing the wealth,
135 because the MGF parser needs to mesh every primitive it supports.)
136
137 Materials
138 =========
139 The MGF material model was designed to accommodate most common
140 physical surfaces. Included are reasonable models for plastic
141 and metal, thin glass and translucent surfaces. Not included at
142 this time are surfaces with anisotropic reflection, refraction and/or
143 surface textures. These were deemed either unnecessary or too
144 difficult to standardize for the initial format. Also, light
145 sources are known only by the emissive nature of their surface(s),
146 and MGF itself only provides for diffuse emission. (As MGF is
147 destined to be part of the IES luminaire data standard, it was
148 assumed that this combined format would be used for such purposes as
149 describing light source output and geometry.)
150
151 The "sides" entity is used to control the number of sides a surface
152 should have. In the real world, a surface can have only one side,
153 defining the interface between one volume and another. Many
154 object-space rendering packages (e.g. z-buffer algorithms) take
155 advantage of this fact by culling back-facing polygons and thus saving
156 roughly 50% of the calculation time. However, many models rely on an
157 approximation whereby a single surface is used to represent a very thin
158 volume, such as a pane of glass, and this also can provide significant
159 calculational savings in an image-space algorithm (such as
160 ray-tracing). Since both types of surfaces are useful and both types
161 of rendering algorithms may ultimately be applied, MGF provides a way
162 to specify sidedness rather than picking one interpretation or the other.
163
164 So-called specular reflection and transmission are modeled using a
165 Gaussian distribution of surface normals. The "alpha_r" and
166 "alpha_t" parameters to the respective "rs" and "ts" entities specify
167 the root-mean-squared (RMS) surface facet slope, which varies from 0
168 for a perfectly smooth surface to around .2 for a fairly rough one.
169 The effect this will have on the reflected component distribution is
170 well-defined, but predicting the behavior of the transmitted
171 component requires further assumptions. We assume that the surface
172 scatters light passing through it just as much as it scatters
173 reflected light. This assumption is approximately correct for a
174 two-sided transparent material with an index of refraction of 1.5
175 (about that of glass) and both sides having the given RMS facet
176 slope.
177
178 Oftentimes, one is translating from a Phong exponent on the cosine
179 of the half-vector-to-normal angle to the more physical but less
180 familiar Gaussian model of MGF. The hardest part is translating
181 the specular power to a roughness value. For this, we recommend
182 the following approximation:
183
184 roughness = 0.6/sqrt(specular_power)
185
186 It's not a perfect correlation, but it's about as good as you can get.
187
188 Colors
189 ======
190 Unlike most graphics languages, MGF does not use an RGB color model,
191 simply because there is no recognized definition for this model.
192 It is based on computer monitor phosphors, which vary from one
193 CRT to the next. (There is an RGB standard defined in the TV
194 industry, but this has a rather poor correlation to most computer
195 monitors.)
196
197 MGF uses two alternative, well-defined standards. The first is the CIE
198 standard xy chromaticity coordinates. With this standard, any viewable
199 color may be exactly reproduced. Unfortunately, the interaction between
200 colors (i.e. colored light sources and interreflections) cannot be
201 specified exactly with any finite coordinate set, including CIE
202 chromaticities. So, MGF offers the ability to give reflectance,
203 transmittance or emittance as a function of wavelength over the visible
204 spectrum. This function is still discretized, but at a user-selectable
205 resolution. Furthermore, spectral colors may be mixed, providing (nearly)
206 arbitrary basis functions, which can produce more accurate results in
207 some cases and are merely a convenience for translation in others.
208
209 Conversion back and forth between CIE chromaticity coordinates and spectral
210 samples is provided within the MGF parser. Unfortunately, conversion
211 to and from RGB values depends on a particular RGB definition, and as we
212 have said, there is no recognized standard. We therefore recommend that
213 you decide yourself what chromaticity values to use for each RGB primary,
214 and adopt the following code to convert between CIE and RGB coordinates.
215
216 #ifdef NTSC
217 #define CIE_x_r 0.670 /* standard NTSC primaries */
218 #define CIE_y_r 0.330
219 #define CIE_x_g 0.210
220 #define CIE_y_g 0.710
221 #define CIE_x_b 0.140
222 #define CIE_y_b 0.080
223 #define CIE_x_w 0.3333 /* monitor white point */
224 #define CIE_y_w 0.3333
225 #else
226 #define CIE_x_r 0.640 /* nominal CRT primaries */
227 #define CIE_y_r 0.330
228 #define CIE_x_g 0.290
229 #define CIE_y_g 0.600
230 #define CIE_x_b 0.150
231 #define CIE_y_b 0.060
232 #define CIE_x_w 0.3333 /* monitor white point */
233 #define CIE_y_w 0.3333
234 #endif
235
236 #define CIE_D ( CIE_x_r*(CIE_y_g - CIE_y_b) + \
237 CIE_x_g*(CIE_y_b - CIE_y_r) + \
238 CIE_x_b*(CIE_y_r - CIE_y_g) )
239 #define CIE_C_rD ( (1./CIE_y_w) * \
240 ( CIE_x_w*(CIE_y_g - CIE_y_b) - \
241 CIE_y_w*(CIE_x_g - CIE_x_b) + \
242 CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g ) )
243 #define CIE_C_gD ( (1./CIE_y_w) * \
244 ( CIE_x_w*(CIE_y_b - CIE_y_r) - \
245 CIE_y_w*(CIE_x_b - CIE_x_r) - \
246 CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r ) )
247 #define CIE_C_bD ( (1./CIE_y_w) * \
248 ( CIE_x_w*(CIE_y_r - CIE_y_g) - \
249 CIE_y_w*(CIE_x_r - CIE_x_g) + \
250 CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r ) )
251
252 #define CIE_rf (CIE_y_r*CIE_C_rD/CIE_D)
253 #define CIE_gf (CIE_y_g*CIE_C_gD/CIE_D)
254 #define CIE_bf (CIE_y_b*CIE_C_bD/CIE_D)
255
256 float xyz2rgbmat[3][3] = { /* XYZ to RGB */
257 {(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g)/CIE_C_rD,
258 (CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b)/CIE_C_rD,
259 (CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g)/CIE_C_rD},
260 {(CIE_y_b - CIE_y_r - CIE_y_b*CIE_x_r + CIE_y_r*CIE_x_b)/CIE_C_gD,
261 (CIE_x_r - CIE_x_b - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r)/CIE_C_gD,
262 (CIE_x_b*CIE_y_r - CIE_x_r*CIE_y_b)/CIE_C_gD},
263 {(CIE_y_r - CIE_y_g - CIE_y_r*CIE_x_g + CIE_y_g*CIE_x_r)/CIE_C_bD,
264 (CIE_x_g - CIE_x_r - CIE_x_g*CIE_y_r + CIE_x_r*CIE_y_g)/CIE_C_bD,
265 (CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r)/CIE_C_bD}
266 };
267
268 float rgb2xyzmat[3][3] = { /* RGB to XYZ */
269 {CIE_x_r*CIE_C_rD/CIE_D,CIE_x_g*CIE_C_gD/CIE_D,CIE_x_b*CIE_C_bD/CIE_D},
270 {CIE_y_r*CIE_C_rD/CIE_D,CIE_y_g*CIE_C_gD/CIE_D,CIE_y_b*CIE_C_bD/CIE_D},
271 {(1.-CIE_x_r-CIE_y_r)*CIE_C_rD/CIE_D,
272 (1.-CIE_x_g-CIE_y_g)*CIE_C_gD/CIE_D,
273 (1.-CIE_x_b-CIE_y_b)*CIE_C_bD/CIE_D}
274 };
275
276
277 cie_rgb(rgbcolor, ciecolor) /* convert CIE to RGB */
278 register float *rgbcolor, *ciecolor;
279 {
280 register int i;
281
282 for (i = 0; i < 3; i++) {
283 rgbcolor[i] = xyz2rgbmat[i][0]*ciecolor[0] +
284 xyz2rgbmat[i][1]*ciecolor[1] +
285 xyz2rgbmat[i][2]*ciecolor[2] ;
286 if (rgbcolor[i] < 0.0)
287 rgbcolor[i] = 0.0;
288 }
289 }
290
291
292 rgb_cie(ciecolor, rgbcolor) /* convert RGB to CIE */
293 register float *ciecolor, *rgbcolor;
294 {
295 register int i;
296
297 for (i = 0; i < 3; i++)
298 ciecolor[i] = rgb2xyzmat[i][0]*rgbcolor[0] +
299 rgb2xyzmat[i][1]*rgbcolor[1] +
300 rgb2xyzmat[i][2]*rgbcolor[2] ;
301 }
302
303 An alternative to adopting the above code is to use the MGF "cmix"
304 entity to convert from RGB directly by naming the three primaries in
305 terms of their chromaticities, e.g:
306
307 c r =
308 cxy 0.640 0.330
309 c g =
310 cxy 0.290 0.600
311 c b =
312 cxy 0.150 0.060
313
314 Then, converting from RGB to MGF colors is as simple as multiplying each
315 component by its relative luminance in a cmix statement, for instance:
316
317 c white =
318 cmix 0.265 r 0.670 g 0.065 b
319
320 For the chosen RGB standard, the above specification would result a pure
321 white. The reason the coefficients are not all 1 as you might expect is
322 that cmix uses relative luminance as the standard for its weights. Since
323 blue is less luminous for the same energy than red, which is in turn
324 less luminous than green, the weights cannot be the same to achieve an
325 even spectral balance. Unfortunately, computing these relative weights
326 is not straightforward, though it is given in the above macros as CIE_rf,
327 CIE_gf and CIE_bf. (The common factors in these macros may of course
328 be removed for simplification purposes.)