1 //////////////////////////////////////////////////////////////////////
2 //
3 // Pixie
4 //
5 // Copyright � 1999 - 2003, Okan Arikan
6 //
7 // Contact: okan@cs.utexas.edu
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 ///////////////////////////////////////////////////////////////////////
24 ///////////////////////////////////////////////////////////////////////
25 //
26 // File : object.cpp
27 // Classes : CGeometry
28 // Description : Implementation
29 //
30 ////////////////////////////////////////////////////////////////////////
31 #include <math.h>
32
33 #include "object.h"
34 #include "error.h"
35 #include "ri.h"
36 #include "shading.h"
37 #include "stats.h"
38 #include "memory.h"
39 #include "surface.h"
40 #include "rendererContext.h"
41 #include "renderer.h"
42 #include "random.h"
43
44
45
46
47
48
49
50
51
52
53 ///////////////////////////////////////////////////////////////////////
54 // Class : CObject
55 // Method : CObject
56 // Description : Ctor
57 // Return Value : -
58 // Comments :
CObject(CAttributes * a,CXform * x)59 CObject::CObject(CAttributes *a,CXform *x) {
60 atomicIncrement(&stats.numObjects);
61
62 flags = 0;
63 attributes = a;
64 xform = x;
65
66 attributes->attach();
67 xform->attach();
68
69 children = NULL;
70 sibling = NULL;
71 }
72
73
74 ///////////////////////////////////////////////////////////////////////
75 // Class : CObject
76 // Method : ~CObject
77 // Description : Dtor
78 // Return Value : -
79 // Comments :
~CObject()80 CObject::~CObject() {
81 atomicDecrement(&stats.numObjects);
82
83 attributes->detach();
84 xform->detach();
85 }
86
87
88 ///////////////////////////////////////////////////////////////////////
89 // Class : CObject
90 // Method : dice
91 // Description : Dice the children objects
92 // Return Value : -
93 // Comments :
dice(CShadingContext * rasterizer)94 void CObject::dice(CShadingContext *rasterizer) {
95 CObject *cObject,*nObject;
96 for (cObject=children;cObject!=NULL;cObject=nObject) {
97 nObject = cObject->sibling;
98
99 cObject->attach();
100
101 rasterizer->drawObject(cObject);
102
103 cObject->detach();
104 }
105 }
106
107
getDisp(const float * mat,float disp)108 static float getDisp(const float *mat,float disp) {
109 float tmp[4],tmp2[4];
110 int i;
111 float alpha;
112
113 tmp[0] = _urand();
114 tmp[1] = _urand();
115 tmp[2] = _urand();
116 tmp[3] = _urand();
117
118 for (i=0;i<10;i++) {
119 mulmp4(tmp2,mat,tmp);
120
121 alpha = max(absf(tmp2[0]),absf(tmp2[1]));
122 alpha = max(alpha,absf(tmp2[2]));
123 alpha = max(alpha,absf(tmp2[3]));
124
125 tmp[0] = tmp2[0] / alpha;
126 tmp[1] = tmp2[1] / alpha;
127 tmp[2] = tmp2[2] / alpha;
128 tmp[3] = tmp2[3] / alpha;
129 }
130
131 return alpha;
132
133 #undef urand
134 }
135
136
137 ///////////////////////////////////////////////////////////////////////
138 // Class : CObject
139 // Method : cluster
140 // Description : Cluster the objects
141 // Return Value :
142 // Comments :
cluster(CShadingContext * context)143 void CObject::cluster(CShadingContext *context) {
144 int numChildren;
145 CObject *cObject;
146
147 // Count the number of children
148 for (numChildren=0,cObject=children;cObject!=NULL;cObject=cObject->sibling,numChildren++);
149
150 // If we have too few children, continue
151 if (numChildren <= 2) return;
152
153 // These are the two children
154 CObject *front,*frontChildren;
155 CObject *back,*backChildren;
156
157 // Begin a memory page
158 memBegin(context->threadMemory);
159
160 // Cluster the midpoints of the objects
161 float *P = (float *) ralloc(numChildren*3*sizeof(float),context->threadMemory);
162 int *indices = (int *) ralloc(numChildren*sizeof(int),context->threadMemory);
163
164
165 // For 5 iterations
166 for (int iteration=0;iteration<15;iteration++) {
167
168 // Compute a slightly jittered center position for the object
169 for (numChildren=0,cObject=children;cObject!=NULL;cObject=cObject->sibling,numChildren++) {
170 initv(P + numChildren*3 , (cObject->bmax[0] - cObject->bmin[0])*(context->urand()*0.2f + 0.4f) + cObject->bmin[0]
171 , (cObject->bmax[1] - cObject->bmin[1])*(context->urand()*0.2f + 0.4f) + cObject->bmin[1]
172 , (cObject->bmax[2] - cObject->bmin[2])*(context->urand()*0.2f + 0.4f) + cObject->bmin[2]);
173 indices[numChildren] = -1;
174 }
175
176 // The random cluster centers
177 vector P1,P2;
178 initv(P1, (bmax[0] - bmin[0])*context->urand() + bmin[0]
179 , (bmax[1] - bmin[1])*context->urand() + bmin[1]
180 , (bmax[2] - bmin[2])*context->urand() + bmin[2]);
181 initv(P2, (bmax[0] - bmin[0])*context->urand() + bmin[0]
182 , (bmax[1] - bmin[1])*context->urand() + bmin[1]
183 , (bmax[2] - bmin[2])*context->urand() + bmin[2]);
184
185 // The main clustering loop
186 int done;
187 for (done=FALSE;done==FALSE;) {
188 int i;
189 vector nP1,nP2;
190 int num1,num2;
191
192 done = TRUE;
193
194 initv(nP1,0);
195 initv(nP2,0);
196 num1 = 0;
197 num2 = 0;
198 for (i=0;i<numChildren;i++) {
199 vector D1,D2;
200
201 subvv(D1,P + i*3,P1);
202 subvv(D2,P + i*3,P2);
203 if (dotvv(D1,D1) < dotvv(D2,D2)) {
204 if (indices[i] != 0) {
205 done = FALSE;
206 indices[i] = 0;
207 }
208
209 addvv(nP1,P+i*3);
210 num1++;
211 } else {
212 if (indices[i] != 1) {
213 done = FALSE;
214 indices[i] = 1;
215 }
216
217 addvv(nP2,P+i*3);
218 num2++;
219 }
220 }
221
222 if ((num1 == 0) || (num2 == 0)) break;
223
224 mulvf(P1,nP1,1/(float) num1);
225 mulvf(P2,nP2,1/(float) num2);
226 }
227
228 if (done == TRUE) break;
229 }
230
231
232 // Cluster the rest of the objects
233 front = new CDummyObject(attributes,xform);
234 back = new CDummyObject(attributes,xform);
235 initv(front->bmin,C_INFINITY);
236 initv(front->bmax,-C_INFINITY);
237 initv(back->bmin,C_INFINITY);
238 initv(back->bmax,-C_INFINITY);
239
240 frontChildren = NULL;
241 backChildren = NULL;
242
243 // Create the clusters
244 for (numChildren=0,cObject=children;cObject!=NULL;numChildren++) {
245 CObject *nObject = cObject->sibling;
246
247 if (indices[numChildren] == 0) {
248 cObject->sibling = frontChildren;
249 frontChildren = cObject;
250 addBox(front->bmin,front->bmax,cObject->bmin);
251 addBox(front->bmin,front->bmax,cObject->bmax);
252 } else {
253 cObject->sibling = backChildren;
254 backChildren = cObject;
255 addBox(back->bmin,back->bmax,cObject->bmin);
256 addBox(back->bmin,back->bmax,cObject->bmax);
257 }
258
259 cObject = nObject;
260 }
261
262 memEnd(context->threadMemory);
263
264 // Recurse
265 front->children = frontChildren;
266 back->children = backChildren;
267
268 front->attach();
269 back->attach();
270
271 front->sibling = back;
272 back->sibling = NULL;
273 children = front;
274 }
275
276 ///////////////////////////////////////////////////////////////////////
277 // Class : CObject
278 // Method : setChildren
279 // Description : Set the children objects
280 // Return Value :
281 // Comments :
setChildren(CShadingContext * context,CObject * allChildren)282 void CObject::setChildren(CShadingContext *context,CObject *allChildren) {
283
284 // If raytraced, attach to the children
285 if (raytraced()) {
286 for (CObject *cObject=allChildren;cObject!=NULL;cObject=cObject->sibling) cObject->attach();
287 }
288
289 children = allChildren;
290 }
291
292 ///////////////////////////////////////////////////////////////////////
293 // Class : CObject
294 // Method : destroy
295 // Description : Destroy the entire tree
296 // Return Value :
297 // Comments :
destroy()298 void CObject::destroy() {
299 if (sibling != NULL) sibling->destroy();
300 if (children != NULL) children->destroy();
301
302 delete this;
303 }
304
305 ///////////////////////////////////////////////////////////////////////
306 // Class : CObject
307 // Method : makeBound
308 // Description : Make sure we do not have empty bounding box
309 // Return Value :
310 // Comments :
makeBound(float * bmin,float * bmax) const311 void CObject::makeBound(float *bmin,float *bmax) const {
312 vector D;
313 float maxD;
314 float maxDisp = attributes->maxDisplacement;
315
316 subvv(D,bmax,bmin);
317 maxD = D[0];
318 maxD = max(D[1],maxD);
319 maxD = max(D[2],maxD);
320 maxD *= attributes->bexpand;
321
322 // Add the displacement amount of the surface
323 if (attributes->maxDisplacementSpace != NULL) {
324 const float *from,*to;
325 ECoordinateSystem sys;
326
327 if (CRenderer::findCoordinateSystem(attributes->maxDisplacementSpace,from,to,sys)) {
328 maxDisp = attributes->maxDisplacement * getDisp(from,attributes->maxDisplacement);
329 }
330
331 free(attributes->maxDisplacementSpace);
332 attributes->maxDisplacementSpace = NULL;
333 }
334
335 maxD += maxDisp;
336
337 // Expand the bound accordingly
338 subvf(bmin,maxD);
339 addvf(bmax,maxD);
340 }
341
342 ///////////////////////////////////////////////////////////////////////
343 // Class : CObject
344 // Method : estimateDicing
345 // Description : Estimate the dicing size on the screen
346 // Return Value :
347 // Comments : P must be in pixels
estimateDicing(float * P,int udiv,int vdiv,int & nudiv,int & nvdiv,float shadingRate,int nonrasterorient)348 void CObject::estimateDicing(float *P,int udiv,int vdiv,int &nudiv,int &nvdiv,float shadingRate,int nonrasterorient) {
349 float uMin,vMin; // The minimum edge length
350 float uMax,vMax; // The maximum edge length
351 int i,j;
352 const float *cP,*nP,*tP;
353 float dx,dy;
354
355 uMax = vMax = 0;
356 uMin = vMin = C_INFINITY;
357
358 if (!nonrasterorient) {
359
360 // Project to pixels
361 camera2pixels((udiv+1)*(vdiv+1),P);
362
363 // U stats
364 cP = P;
365 for (j=(vdiv+1);j>0;--j) {
366
367 float total = 0;
368 for (i=udiv;i>0;--i,cP+=3) {
369 dx = cP[3 + COMP_X] - cP[COMP_X];
370 dy = cP[3 + COMP_Y] - cP[COMP_Y];
371 total += sqrtf(dx*dx + dy*dy);
372 }
373 cP += 3;
374 uMax = max(uMax,total);
375 uMin = min(uMin,total);
376 }
377
378 // V stats
379 cP = P;
380 for (i=(udiv+1);i>0;--i,cP+=3) {
381 nP = cP;
382 tP = nP + (udiv+1)*3;
383 float total = 0;
384 for (j=vdiv;j>0;--j,nP=tP,tP+=(udiv+1)*3) {
385 dx = tP[COMP_X] - nP[COMP_X];
386 dy = tP[COMP_Y] - nP[COMP_Y];
387 total += sqrtf(dx*dx + dy*dy);
388 }
389
390 vMax = max(vMax,total);
391 vMin = min(vMin,total);
392 }
393 } else { // non raster oriented
394 vector tmp;
395
396 float maxDim = max(CRenderer::dPixeldx,CRenderer::dPixeldy);
397 if(CRenderer::projection == OPTIONS_PROJECTION_PERSPECTIVE) {
398 for (j=0;j<(vdiv+1)*(udiv+1);++j) {
399 float x,y;
400 x = (CRenderer::imagePlane*P[j*3+COMP_X]/P[j*3+COMP_Z]);
401 y = (CRenderer::imagePlane*P[j*3+COMP_Y]/P[j*3+COMP_Z]);
402 initv(tmp,x-P[j*3+COMP_X],y-P[j*3+COMP_Y],P[j*3+COMP_Z]-1);
403 P[j*3+COMP_X] = x*maxDim;
404 P[j*3+COMP_Y] = y*maxDim;
405 P[j*3+COMP_Z] = lengthv(tmp)*maxDim;
406 }
407 } else {
408 for (j=0;j<(vdiv+1)*(udiv+1);++j) {
409 P[j*3+COMP_X] = P[j*3+COMP_X]*CRenderer::dPixeldx;
410 P[j*3+COMP_Y] = P[j*3+COMP_Y]*CRenderer::dPixeldy;
411 P[j*3+COMP_Z] *= maxDim;
412 }
413 }
414
415 // U stats
416 cP = P;
417 for (j=(vdiv+1);j>0;--j) {
418
419 float total = 0;
420 for (i=udiv;i>0;--i,cP+=3) {
421 subvv(tmp,cP+3,cP);
422 total += lengthv(tmp);
423 }
424 cP += 3;
425 uMax = max(uMax,total);
426 uMin = min(uMin,total);
427 }
428
429 // V stats
430 cP = P;
431 for (i=(udiv+1);i>0;--i,cP+=3) {
432 nP = cP;
433 tP = nP + (udiv+1)*3;
434 float total = 0;
435 for (j=vdiv;j>0;--j,nP=tP,tP+=(udiv+1)*3) {
436 subvv(tmp,tP,nP);
437 total += lengthv(tmp);
438 }
439
440 vMax = max(vMax,total);
441 vMin = min(vMin,total);
442 }
443 }
444 float udivf,vdivf;
445
446 // Compute the new grid size based on the maximum size
447 udivf = uMax / shadingRate;
448 vdivf = vMax / shadingRate;
449
450 // Clamp the division amount
451 udivf = max(1,udivf);
452 vdivf = max(1,vdivf);
453 udivf = min(10000,udivf);
454 vdivf = min(10000,vdivf);
455
456 // Estimate the dicing amount
457 if (attributes->flags & ATTRIBUTES_FLAGS_BINARY_DICE) {
458 const double log2 = log(2.0);
459
460 nudiv = 1 << (unsigned int) (ceil(log(udivf) / log2));
461 nvdiv = 1 << (unsigned int) (ceil(log(vdivf) / log2));
462 } else {
463 nudiv = (int) ceil(udivf);
464 nvdiv = (int) ceil(vdivf);
465 }
466 }
467
468
469
470
471
472
473
474 ///////////////////////////////////////////////////////////////////////
475 // Class : CDummyObject
476 // Method : CDummyObject
477 // Description : Ctor
478 // Return Value :
479 // Comments :
CDummyObject(CAttributes * a,CXform * x)480 CDummyObject::CDummyObject(CAttributes *a,CXform *x) : CObject(a,x) {
481 flags |= OBJECT_DUMMY;
482 }
483
484 ///////////////////////////////////////////////////////////////////////
485 // Class : CDummyObject
486 // Method : ~CDummyObject
487 // Description : Dtor
488 // Return Value :
489 // Comments :
~CDummyObject()490 CDummyObject::~CDummyObject() {
491 }
492
493 ///////////////////////////////////////////////////////////////////////
494 // Class : CDummyObject
495 // Method : intersect
496 // Description : Intersect a ray
497 // Return Value :
498 // Comments :
intersect(CShadingContext *,CRay *)499 void CDummyObject::intersect(CShadingContext *,CRay *) {
500 // Should never reach this point
501 //assert(FALSE);
502 }
503
504
505
506
507
508
509
510
511
512 ///////////////////////////////////////////////////////////////////////
513 // Class : CSurface
514 // Method : intersect
515 // Description : Intersect the surface
516 // Return Value :
517 // Comments :
intersect(CShadingContext * context,CRay * cRay)518 void CSurface::intersect(CShadingContext *context,CRay *cRay) {
519
520 if (! (cRay->flags & attributes->flags) ) return;
521
522 if (attributes->flags & ATTRIBUTES_FLAGS_LOD) {
523 const float importance = attributes->lodImportance;
524 if (importance >= 0) {
525 if (cRay->jimp > importance) return;
526 } else {
527 if ((1-cRay->jimp) >= -importance) return;
528 }
529 }
530
531 // Do we have a grid ?
532 if (children == NULL) {
533 // Intersect with our bounding box
534 float t = nearestBox(bmin,bmax,cRay->from,cRay->invDir,cRay->tmin,cRay->t);
535
536 // Bail out if the hit point is already further than the ray got
537 // Note: this avoids unneeded top level tesselations
538 if (!(t < cRay->t)) return;
539
540 // We must lock the tesselateMutex so that the list of known tesselation patches
541 // is maintained in a thread safe manner
542 osLock(CRenderer::tesselateMutex);
543
544 if (children == NULL) {
545
546 CTesselationPatch *tesselation = new CTesselationPatch(attributes,xform,this,0,1,0,1,0,0,-1);
547
548 tesselation->initTesselation(context);
549 tesselation->attach();
550 children = tesselation;
551 }
552
553 osUnlock(CRenderer::tesselateMutex);
554 }
555 }
556
557 ///////////////////////////////////////////////////////////////////////
558 // Class : CSurface
559 // Method : dice
560 // Description : Dice the object into smaller ones
561 // Return Value :
562 // Comments :
dice(CShadingContext * rasterizer)563 void CSurface::dice(CShadingContext *rasterizer) {
564
565 int minU,minV;
566 int minSplits = max(attributes->minSplits,getDicingStats(0,minU,minV));
567
568 CPatch *cSurface = new CPatch(attributes,xform,this,0,1,0,1,0,minSplits);
569 cSurface->attach();
570 cSurface->dice(rasterizer);
571 cSurface->detach();
572
573 // Note we tesselate for raytracing on demand - so we do not automatically emit a CTesselationPatch here
574 }
575
576 ///////////////////////////////////////////////////////////////////////
577 // Class : CSurface
578 // Method : moving
579 // Description : TRUE if the object is moving
580 // Return Value :
581 // Comments :
moving() const582 int CSurface::moving() const {
583 return FALSE;
584 }
585
586 ///////////////////////////////////////////////////////////////////////
587 // Class : CSurface
588 // Method : sample
589 // Description : Sample a bunch of points on the surface
590 // Return Value : TRUE if the sampling was done and shaders need to be executed
591 // Comments :
sample(int,int,float **,float ***,unsigned int &) const592 void CSurface::sample(int,int,float **,float ***,unsigned int &) const {
593 error(CODE_BUG,"An object is missing the \"sample\" function\n");
594 assert(FALSE);
595 }
596
597 ///////////////////////////////////////////////////////////////////////
598 // Class : CSurface
599 // Method : interpolate
600 // Description : Interpolate the varying data and set the uniform data
601 // Return Value :
602 // Comments :
interpolate(int,float **,float ***) const603 void CSurface::interpolate(int,float **,float ***) const {
604 error(CODE_BUG,"An object is missing the \"interpolate\" function\n");
605 assert(FALSE);
606 }
607
608
609 ///////////////////////////////////////////////////////////////////////
610 // Class : CSurface
611 // Method : split
612 // Description : Split an object
613 // Return Value :
614 // Comments :
shade(CShadingContext * context,int numRays,CRay ** rays)615 void CSurface::shade(CShadingContext *context,int numRays,CRay **rays) {
616 float **varying = context->currentShadingState->varying;
617 float *u = varying[VARIABLE_U];
618 float *v = varying[VARIABLE_V];
619 float *time = varying[VARIABLE_TIME];
620 float *I = varying[VARIABLE_I];
621 float *du = varying[VARIABLE_DU];
622 int i;
623
624 for (i=numRays;i>0;i--) {
625 const CRay *cRay = *rays++;
626
627 *u++ = cRay->u; // The intersection u
628 *v++ = cRay->v; // The intersection v
629 *time++ = cRay->time; // The intersection time
630 *du++ = cRay->da*cRay->t + cRay->db; // The ray differential
631 mulvf(I,cRay->dir,cRay->t); // Compute the I vector
632 I += 3;
633 }
634
635 context->shade(this,numRays,1,SHADING_2D,0);
636 }
637
638
639
640