ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/bsdf_m.c
(Generate patch)

Comparing ray/src/common/bsdf_m.c (file contents):
Revision 3.28 by greg, Fri Mar 21 17:49:53 2014 UTC vs.
Revision 3.29 by greg, Thu Apr 2 16:40:32 2015 UTC

# Line 13 | Line 13 | static const char RCSid[] = "$Id$";
13  
14   #define _USE_MATH_DEFINES
15   #include "rtio.h"
16 #include <stdlib.h>
16   #include <math.h>
17   #include <ctype.h>
18   #include "ezxml.h"
# Line 65 | Line 64 | ANGLE_BASIS    abase_list[MAXABASES] = {
64  
65   int             nabases = 3;            /* current number of defined bases */
66  
67 + C_COLOR mtx_RGB_prim[3];                /* our RGB primaries  */
68 + float   mtx_RGB_coef[3];                /* corresponding Y coefficients */
69 +
70 + enum {mtx_Y, mtx_X, mtx_Z};             /* matrix components (mtx_Y==0) */
71 +
72 + /* check if two real values are near enough to equal */
73   static int
74   fequal(double a, double b)
75   {
# Line 73 | Line 78 | fequal(double a, double b)
78          return (a <= 1e-6) & (a >= -1e-6);
79   }
80  
81 < /* Returns the given tag's character content or empty string if none */
77 < #ifdef ezxml_txt
78 < #undef ezxml_txt
79 < static char *
80 < ezxml_txt(ezxml_t xml)
81 < {
82 <        if (xml == NULL)
83 <                return "";
84 <        return xml->txt;
85 < }
86 < #endif
87 <
88 < /* Convert error to standard BSDF code */
81 > /* convert error to standard BSDF code */
82   static SDError
83   convert_errcode(int ec)
84   {
# Line 106 | Line 99 | convert_errcode(int ec)
99          return SDEunknown;
100   }
101  
102 < /* Allocate a BSDF matrix of the given size */
102 > /* allocate a BSDF matrix of the given size */
103   static SDMat *
104   SDnewMatrix(int ni, int no)
105   {
# Line 130 | Line 123 | SDnewMatrix(int ni, int no)
123   }
124  
125   /* Free a BSDF matrix */
126 < #define SDfreeMatrix            free
126 > void
127 > SDfreeMatrix(void *ptr)
128 > {
129 >        SDMat   *mp = (SDMat *)ptr;
130  
131 +        if (mp->chroma != NULL) free(mp->chroma);
132 +        free(ptr);
133 + }
134 +
135   /* Get vector for this angle basis index (front exiting) */
136   int
137   fo_getvec(FVECT v, double ndxr, void *p)
# Line 288 | Line 288 | fi_getndx(const FVECT v, void *p)
288          return fo_getndx(v2, p);
289   }
290  
291 + /* Get color or grayscale value for BSDF for the given direction pair */
292 + int
293 + mBSDF_color(float coef[], const SDMat *dp, int i, int o)
294 + {
295 +        C_COLOR cxy;
296 +
297 +        coef[0] = mBSDF_value(dp, i, o);
298 +        if (dp->chroma == NULL)
299 +                return 1;       /* grayscale */
300 +
301 +        c_decodeChroma(&cxy, dp->chroma[o*dp->ninc + i]);
302 +        c_toSharpRGB(&cxy, coef[0], coef);
303 +        coef[0] *= mtx_RGB_coef[0];
304 +        coef[1] *= mtx_RGB_coef[1];
305 +        coef[2] *= mtx_RGB_coef[2];
306 +        return 3;               /* RGB color */
307 + }
308 +
309   /* load custom BSDF angle basis */
310   static int
311   load_angle_basis(ezxml_t wab)
# Line 380 | Line 398 | get_extrema(SDSpectralDF *df)
398  
399   /* load BSDF distribution for this wavelength */
400   static int
401 < load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
401 > load_bsdf_data(SDData *sd, ezxml_t wdb, int ct, int rowinc)
402   {
403          SDSpectralDF    *df;
404          SDMat           *dp;
# Line 395 | Line 413 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
413           * Remember that front and back are reversed from WINDOW 6 orientations
414           */
415          if (!strcasecmp(sdata, "Transmission Front")) {
416 <                if (sd->tb != NULL)
399 <                        SDfreeSpectralDF(sd->tb);
400 <                if ((sd->tb = SDnewSpectralDF(1)) == NULL)
416 >                if (sd->tb == NULL && (sd->tb = SDnewSpectralDF(3)) == NULL)
417                          return RC_MEMERR;
418                  df = sd->tb;
419          } else if (!strcasecmp(sdata, "Transmission Back")) {
420 <                if (sd->tf != NULL)
405 <                        SDfreeSpectralDF(sd->tf);
406 <                if ((sd->tf = SDnewSpectralDF(1)) == NULL)
420 >                if (sd->tf == NULL && (sd->tf = SDnewSpectralDF(3)) == NULL)
421                          return RC_MEMERR;
422                  df = sd->tf;
423          } else if (!strcasecmp(sdata, "Reflection Front")) {
424 <                if (sd->rb != NULL)
411 <                        SDfreeSpectralDF(sd->rb);
412 <                if ((sd->rb = SDnewSpectralDF(1)) == NULL)
424 >                if (sd->rb == NULL && (sd->rb = SDnewSpectralDF(3)) == NULL)
425                          return RC_MEMERR;
426                  df = sd->rb;
427          } else if (!strcasecmp(sdata, "Reflection Back")) {
428 <                if (sd->rf != NULL)
417 <                        SDfreeSpectralDF(sd->rf);
418 <                if ((sd->rf = SDnewSpectralDF(1)) == NULL)
428 >                if (sd->rf == NULL && (sd->rf = SDnewSpectralDF(3)) == NULL)
429                          return RC_MEMERR;
430                  df = sd->rf;
431          } else
432                  return RC_FAIL;
433 <        /* XXX should also check "ScatteringDataType" for consistency? */
433 >                                        /* free previous matrix if any */
434 >        if (df->comp[ct].dist != NULL) {
435 >                SDfreeMatrix(df->comp[ct].dist);
436 >                df->comp[ct].dist = NULL;
437 >        }
438                                          /* get angle bases */
439          sdata = ezxml_txt(ezxml_child(wdb,"ColumnAngleBasis"));
440          if (!sdata || !*sdata) {
# Line 477 | Line 491 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
491          }
492          dp->ib_ohm = &io_getohm;
493          dp->ob_ohm = &io_getohm;
494 <        df->comp[0].cspec[0] = c_dfcolor; /* XXX monochrome for now */
495 <        df->comp[0].dist = dp;
482 <        df->comp[0].func = &SDhandleMtx;
494 >        df->comp[ct].dist = dp;
495 >        df->comp[ct].func = &SDhandleMtx;
496                                          /* read BSDF data */
497          sdata = ezxml_txt(ezxml_child(wdb, "ScatteringData"));
498          if (!sdata || !*sdata) {
# Line 509 | Line 522 | load_bsdf_data(SDData *sd, ezxml_t wdb, int rowinc)
522                          dp->bsdf[i] = val;
523                  sdata = sdnext;
524          }
525 <        return get_extrema(df);
525 >        return (ct == mtx_Y) ? get_extrema(df) : RC_GOOD;
526   }
527  
528 < /* Subtract minimum (diffuse) scattering amount from BSDF */
528 > /* copy our RGB (x,y) primary chromaticities */
529 > static void
530 > copy_RGB_prims(C_COLOR cspec[])
531 > {
532 >        if (mtx_RGB_coef[1] < .001) {   /* need to initialize */
533 >                int     i = 3;
534 >                while (i--) {
535 >                        float   rgb[3];
536 >                        rgb[0] = rgb[1] = rgb[2] = .0f;
537 >                        rgb[i] = 1.f;
538 >                        mtx_RGB_coef[i] = c_fromSharpRGB(rgb, &mtx_RGB_prim[i]);
539 >                }
540 >        }
541 >        memcpy(cspec, mtx_RGB_prim, sizeof(mtx_RGB_prim));
542 > }
543 >
544 > /* encode chromaticity if XYZ -- reduce to one channel in any case */
545 > static SDSpectralDF *
546 > encode_chroma(SDSpectralDF *df)
547 > {
548 >        SDMat   *mpx, *mpy, *mpz;
549 >        int     n;
550 >
551 >        if (df == NULL || df->ncomp != 3)
552 >                return df;
553 >
554 >        mpy = (SDMat *)df->comp[mtx_Y].dist;
555 >        if (mpy == NULL) {
556 >                free(df);
557 >                return NULL;
558 >        }
559 >        mpx = (SDMat *)df->comp[mtx_X].dist;
560 >        mpz = (SDMat *)df->comp[mtx_Z].dist;
561 >        if (mpx == NULL || (mpx->ninc != mpy->ninc) | (mpx->nout != mpy->nout))
562 >                goto done;
563 >        if (mpz == NULL || (mpz->ninc != mpy->ninc) | (mpz->nout != mpy->nout))
564 >                goto done;
565 >        mpy->chroma = (C_CHROMA *)malloc(sizeof(C_CHROMA)*mpy->ninc*mpy->nout);
566 >        if (mpy->chroma == NULL)
567 >                goto done;              /* XXX punt */
568 >                                        /* encode chroma values */
569 >        for (n = mpy->ninc*mpy->nout; n--; ) {
570 >                const double    sum = mpx->bsdf[n] + mpy->bsdf[n] + mpz->bsdf[n];
571 >                C_COLOR         cxy;
572 >                if (sum > .0)
573 >                        c_cset(&cxy, mpx->bsdf[n]/sum, mpy->bsdf[n]/sum);
574 >                else
575 >                        c_cset(&cxy, 1./3., 1./3.);
576 >                mpy->chroma[n] = c_encodeChroma(&cxy);
577 >        }
578 > done:                                   /* free X & Z channels */
579 >        if (mpx != NULL) SDfreeMatrix(mpx);
580 >        if (mpz != NULL) SDfreeMatrix(mpz);
581 >        if (mpy->chroma == NULL)        /* grayscale after all? */
582 >                df->comp[0].cspec[0] = c_dfcolor;
583 >        else                            /* else copy RGB primaries */
584 >                copy_RGB_prims(df->comp[0].cspec);
585 >        df->ncomp = 1;                  /* return resized struct */
586 >        return (SDSpectralDF *)realloc(df, sizeof(SDSpectralDF));
587 > }
588 >
589 > /* subtract minimum (diffuse) scattering amount from BSDF */
590   static double
591 < subtract_min(SDMat *sm)
591 > subtract_min(C_COLOR *cs, SDMat *sm)
592   {
593 <        float   minv = sm->bsdf[0];
594 <        int     n = sm->ninc*sm->nout;
595 <        int     i;
593 >        const int       ncomp = 1 + 2*(sm->chroma != NULL);
594 >        float           min_coef[3], coef[3];
595 >        int             i, o, c;
596          
597 <        for (i = n; --i; )
598 <                if (sm->bsdf[i] < minv)
599 <                        minv = sm->bsdf[i];
600 <        
601 <        if (minv <= FTINY)
597 >        min_coef[0] = min_coef[1] = min_coef[2] = FHUGE;
598 >        for (i = 0; i < sm->ninc; i++)
599 >                for (o = 0; o < sm->nout; o++) {
600 >                        c = mBSDF_color(coef, sm, i, o);
601 >                        while (c--)
602 >                                if (coef[c] < min_coef[c])
603 >                                        min_coef[c] = coef[c];
604 >                }
605 >        for (c = ncomp; c--; )
606 >                if (min_coef[c] > FTINY)
607 >                        break;
608 >        if (c < 0)
609                  return .0;
610 +        if (ncomp == 1) {               /* subtract grayscale minimum */
611 +                for (i = sm->ninc*sm->nout; i--; )
612 +                        sm->bsdf[i] -= min_coef[0];
613 +                *cs = c_dfcolor;
614 +                return min_coef[0]*M_PI;
615 +        }
616 +                                        /* else subtract colored minimum */
617 +        for (i = 0; i < sm->ninc; i++)
618 +                for (o = 0; o < sm->nout; o++) {
619 +                        C_COLOR cxy;
620 +                        c = mBSDF_color(coef, sm, i, o);
621 +                        while (c--)
622 +                                coef[c] = (coef[c] - min_coef[c]) /
623 +                                                mtx_RGB_coef[c];
624 +                        c_fromSharpRGB(coef, &cxy);
625 +                        sm->chroma[o*sm->ninc + i] = c_encodeChroma(&cxy);
626 +                        mBSDF_value(sm,i,o) -= min_coef[0]+min_coef[1]+min_coef[2];
627 +                }
628  
629 <        for (i = n; i--; )
630 <                sm->bsdf[i] -= minv;
629 >                                        /* return colored minimum */
630 >        c_cmix(cs, min_coef[0], &mtx_RGB_prim[0], min_coef[1], &mtx_RGB_prim[1]);
631 >        c_cmix(cs, min_coef[0]+min_coef[1], cs, min_coef[2], &mtx_RGB_prim[2]);
632  
633 <        return minv*M_PI;               /* be sure to include multiplier */
633 >        return (min_coef[0]+min_coef[1]+min_coef[2])*M_PI;
634   }
635  
636 < /* Extract and separate diffuse portion of BSDF */
637 < static void
636 > /* Extract and separate diffuse portion of BSDF & convert color */
637 > static SDSpectralDF *
638   extract_diffuse(SDValue *dv, SDSpectralDF *df)
639   {
540        int     n;
640  
641 +        df = encode_chroma(df);         /* reduce XYZ to Y + chroma */
642          if (df == NULL || df->ncomp <= 0) {
643                  dv->spec = c_dfcolor;
644                  dv->cieY = .0;
645 <                return;
645 >                return df;
646          }
647 <        dv->spec = df->comp[0].cspec[0];
648 <        dv->cieY = subtract_min((SDMat *)df->comp[0].dist);
549 <                                        /* in case of multiple components */
550 <        for (n = df->ncomp; --n; ) {
551 <                double  ymin = subtract_min((SDMat *)df->comp[n].dist);
552 <                c_cmix(&dv->spec, dv->cieY, &dv->spec, ymin, &df->comp[n].cspec[0]);
553 <                dv->cieY += ymin;
554 <        }
647 >                                        /* subtract minimum value */
648 >        dv->cieY = subtract_min(&dv->spec, (SDMat *)df->comp[0].dist);
649          df->maxHemi -= dv->cieY;        /* adjust maximum hemispherical */
650                                          /* make sure everything is set */
651          c_ccvt(&dv->spec, C_CSXY+C_CSSPEC);
652 +        return df;
653   }
654  
655   /* Load a BSDF matrix from an open XML file */
# Line 594 | Line 689 | SDloadMtx(SDData *sd, ezxml_t wtl)
689                                          /* load BSDF components */
690          for (wld = ezxml_child(wtl, "WavelengthData");
691                                  wld != NULL; wld = wld->next) {
692 <                if (strcasecmp(ezxml_txt(ezxml_child(wld,"Wavelength")),
693 <                                "Visible"))
694 <                        continue;       /* just visible for now */
692 >                const char      *cnm = ezxml_txt(ezxml_child(wld,"Wavelength"));
693 >                int             ct = -1;
694 >                if (!strcasecmp(cnm, "Visible"))
695 >                        ct = mtx_Y;
696 >                else if (!strcasecmp(cnm, "CIE-X"))
697 >                        ct = mtx_X;
698 >                else if (!strcasecmp(cnm, "CIE-Z"))
699 >                        ct = mtx_Z;
700 >                else
701 >                        continue;
702                  for (wdb = ezxml_child(wld, "WavelengthDataBlock");
703                                          wdb != NULL; wdb = wdb->next)
704 <                        if ((rval = load_bsdf_data(sd, wdb, rowIn)) < 0)
704 >                        if ((rval = load_bsdf_data(sd, wdb, ct, rowIn)) < 0)
705                                  return convert_errcode(rval);
706          }
707                                          /* separate diffuse components */
708 <        extract_diffuse(&sd->rLambFront, sd->rf);
709 <        extract_diffuse(&sd->rLambBack, sd->rb);
708 >        sd->rf = extract_diffuse(&sd->rLambFront, sd->rf);
709 >        sd->rb = extract_diffuse(&sd->rLambBack, sd->rb);
710          if (sd->tf != NULL)
711 <                extract_diffuse(&sd->tLamb, sd->tf);
711 >                sd->tf = extract_diffuse(&sd->tLamb, sd->tf);
712          if (sd->tb != NULL)
713 <                extract_diffuse(&sd->tLamb, sd->tb);
713 >                sd->tb = extract_diffuse(&sd->tLamb, sd->tb);
714                                          /* return success */
715          return SDEnone;
716   }
# Line 634 | Line 736 | SDgetMtxBSDF(float coef[SDmaxCh], const FVECT outVec,
736          }
737          if ((i_ndx < 0) | (o_ndx < 0))
738                  return 0;               /* nothing from this component */
739 <        coef[0] = mBSDF_value(dp, i_ndx, o_ndx);
740 <        return 1;                       /* XXX monochrome for now */
739 >
740 >        return mBSDF_color(coef, dp, i_ndx, o_ndx);
741   }
742  
743   /* Query solid angle for vector(s) */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines