Added color filtering for raytrace transparency.

http://www.blender3d.org/cms/Transparent_filtering.514.0.html

Choice was for using a single (new) filter value and have it working OK
with existing alpha.
This commit is contained in:
Ton Roosendaal
2005-01-24 14:08:06 +00:00
parent 93319a28a8
commit e44b07d828
6 changed files with 108 additions and 76 deletions

View File

@@ -64,6 +64,7 @@ typedef struct Material {
float translucency;
float fresnel_mir, fresnel_mir_i;
float fresnel_tra, fresnel_tra_i;
float filter, pad0; /* filter added, for raytrace transparency */
short ray_depth, ray_depth_tra;
short har;
char seed1, seed2;

View File

@@ -1457,7 +1457,9 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen
if(depth>0) {
if(shi.mat->mode & (MA_RAYTRANSP|MA_ZTRA) && shr.alpha!=1.0) {
float f, f1, refract[3], tracol[3];
float f, f1, refract[3], tracol[4];
tracol[3]= col[3]; // we pass on and accumulate alpha
if(shi.mat->mode & MA_RAYTRANSP) {
/* odd depths: use normal facing viewer, otherwise flip */
@@ -1478,16 +1480,21 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen
traceray(depth-1, shi.co, shi.view, tracol, shi.vlr, shi.mask, osatex, 0);
f= shr.alpha; f1= 1.0-f;
shr.diff[0]= f*shr.diff[0] + f1*tracol[0];
shr.diff[1]= f*shr.diff[1] + f1*tracol[1];
shr.diff[2]= f*shr.diff[2] + f1*tracol[2];
fr= 1.0+ shi.mat->filter*(shi.r-1.0);
fg= 1.0+ shi.mat->filter*(shi.g-1.0);
fb= 1.0+ shi.mat->filter*(shi.b-1.0);
shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0];
shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1];
shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2];
shr.spec[0] *=f;
shr.spec[1] *=f;
shr.spec[2] *=f;
shr.alpha= 1.0;
col[3]= f1*tracol[3] + f;
}
else
col[3]= 1.0;
if(shi.mat->mode & MA_RAYMIRROR) {
f= shi.ray_mirror;
@@ -1496,9 +1503,10 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen
else f= 0.0;
if(f!=0.0) {
float mircol[4];
reflection(ref, shi.vn, shi.view, NULL);
traceray(depth-1, shi.co, ref, col, shi.vlr, shi.mask, osatex, 0);
traceray(depth-1, shi.co, ref, mircol, shi.vlr, shi.mask, osatex, 0);
f1= 1.0-f;
@@ -1512,9 +1520,9 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen
fg= shi.mirg;
fb= shi.mirb;
col[0]= f*fr*(1.0-shr.spec[0])*col[0] + f1*shr.diff[0] + shr.spec[0];
col[1]= f*fg*(1.0-shr.spec[1])*col[1] + f1*shr.diff[1] + shr.spec[1];
col[2]= f*fb*(1.0-shr.spec[2])*col[2] + f1*shr.diff[2] + shr.spec[2];
col[0]= f*fr*(1.0-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0];
col[1]= f*fg*(1.0-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1];
col[2]= f*fb*(1.0-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2];
}
else {
col[0]= shr.diff[0] + shr.spec[0];
@@ -1530,7 +1538,6 @@ static void traceray(short depth, float *start, float *vec, float *col, VlakRen
}
else { /* sky */
VECCOPY(shi.view, vec);
Normalise(shi.view);
@@ -1676,7 +1683,7 @@ static float *jitter_plane(LampRen *lar, int xs, int ys)
void ray_trace(ShadeInput *shi, ShadeResult *shr)
{
VlakRen *vlr;
float i, f, f1, fr, fg, fb, vec[3], mircol[3], tracol[3];
float i, f, f1, fr, fg, fb, vec[3], mircol[4], tracol[4];
int do_tra, do_mir;
do_tra= ((shi->mat->mode & (MA_RAYTRANSP|MA_ZTRA)) && shr->alpha!=1.0);
@@ -1686,6 +1693,8 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr)
if(do_tra) {
float refract[3];
tracol[3]= shr->alpha;
if(shi->mat->mode & MA_RAYTRANSP) {
refraction(refract, shi->vn, shi->view, shi->ang);
traceray(shi->mat->ray_depth_tra, shi->co, refract, tracol, shi->vlr, shi->mask, 0, RAY_TRA|RAY_TRAFLIP);
@@ -1694,10 +1703,14 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr)
traceray(shi->mat->ray_depth_tra, shi->co, shi->view, tracol, shi->vlr, shi->mask, 0, 0);
f= shr->alpha; f1= 1.0-f;
shr->diff[0]= f*shr->diff[0] + f1*tracol[0];
shr->diff[1]= f*shr->diff[1] + f1*tracol[1];
shr->diff[2]= f*shr->diff[2] + f1*tracol[2];
shr->alpha= 1.0;
fr= 1.0+ shi->mat->filter*(shi->r-1.0);
fg= 1.0+ shi->mat->filter*(shi->g-1.0);
fb= 1.0+ shi->mat->filter*(shi->b-1.0);
shr->diff[0]= f*shr->diff[0] + f1*fr*tracol[0];
shr->diff[1]= f*shr->diff[1] + f1*fg*tracol[1];
shr->diff[2]= f*shr->diff[2] + f1*fb*tracol[2];
shr->alpha= tracol[3];
}
if(do_mir) {
@@ -1727,29 +1740,31 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr)
}
}
/* no premul here! */
static void addAlphaLight(float *old, float *over)
/* color 'shadfac' passes through 'col' with alpha and filter */
/* filter is only applied on alpha defined transparent part */
static void addAlphaLight(float *shadfac, float *col, float alpha, float filter)
{
float div= old[3]+over[3];
if(div > 0.0001) {
old[0]= (over[3]*over[0] + old[3]*old[0])/div;
old[1]= (over[3]*over[1] + old[3]*old[1])/div;
old[2]= (over[3]*over[2] + old[3]*old[2])/div;
}
old[3]= over[3] + (1-over[3])*old[3];
float fr, fg, fb;
fr= 1.0+ filter*(col[0]-1.0);
fg= 1.0+ filter*(col[1]-1.0);
fb= 1.0+ filter*(col[2]-1.0);
shadfac[0]= alpha*col[0] + fr*(1.0-alpha)*shadfac[0];
shadfac[1]= alpha*col[1] + fg*(1.0-alpha)*shadfac[1];
shadfac[2]= alpha*col[2] + fb*(1.0-alpha)*shadfac[2];
shadfac[3]= (1.0-alpha)*shadfac[3];
}
static void ray_trace_shadow_tra(Isect *is, int depth)
{
/* ray to lamp, find first face that intersects, check alpha properties,
if it has alpha<1 continue. exit when alpha is full */
if it has col[3]>0.0 continue. so exit when alpha is full */
ShadeInput shi;
ShadeResult shr;
if( d3dda(is)) {
float col[4];
/* we got a face */
shi.mask= 1;
@@ -1758,12 +1773,10 @@ static void ray_trace_shadow_tra(Isect *is, int depth)
shade_ray(is, &shi, &shr);
/* add color */
VECCOPY(col, shr.diff);
col[3]= shr.alpha;
addAlphaLight(is->col, col);
if(depth>0 && is->col[3]<1.0) {
/* mix colors based on shadfac (rgb + amount of light factor) */
addAlphaLight(is->col, shr.diff, shr.alpha, shi.mat->filter);
if(depth>0 && is->col[3]>0.0) {
/* adapt isect struct */
VECCOPY(is->start, shi.co);
@@ -1771,8 +1784,6 @@ static void ray_trace_shadow_tra(Isect *is, int depth)
ray_trace_shadow_tra(is, depth-1);
}
else if(is->col[3]>1.0) is->col[3]= 1.0;
}
}
@@ -2102,17 +2113,13 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
VECCOPY(isec.end, lampco);
if(isec.mode==DDA_SHADOW_TRA) {
/* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
isec.col[0]= isec.col[1]= isec.col[2]= 1.0;
isec.col[3]= 0.0; //alpha
isec.col[3]= 1.0;
ray_trace_shadow_tra(&isec, DEPTH_SHADOW_TRA);
VECCOPY(shadfac, isec.col);
// alpha to 'light'
shadfac[3]= 1.0-isec.col[3];
shadfac[0]= shadfac[3]+shadfac[0]*isec.col[3];
shadfac[1]= shadfac[3]+shadfac[1]*isec.col[3];
shadfac[2]= shadfac[3]+shadfac[2]*isec.col[3];
QUATCOPY(shadfac, isec.col);
//printf("shadfac %f %f %f %f\n", shadfac[0], shadfac[1], shadfac[2], shadfac[3]);
}
else if( d3dda(&isec)) shadfac[3]= 0.0;
}

View File

@@ -2189,9 +2189,15 @@ void *shadepixel(float x, float y, int z, int facenr, int mask, float *col)
else alpha= 1.0;
if(shr.alpha!=1.0 || alpha!=1.0) {
fac= alpha*(shr.alpha);
col[3]= fac;
if(shi.mat->mode & MA_RAYTRANSP) {
// sky was applied allready for ray transp, only do mist
col[3]= shr.alpha;
fac= alpha;
}
else {
fac= alpha*(shr.alpha);
col[3]= fac;
}
col[0]*= fac;
col[1]*= fac;
col[2]*= fac;
@@ -2233,10 +2239,15 @@ void *shadepixel(float x, float y, int z, int facenr, int mask, float *col)
static void shadepixel_sky(float x, float y, int z, int facenr, int mask, float *colf)
{
VlakRen *vlr;
float collector[4];
shadepixel(x, y, z, facenr, mask, colf);
vlr= shadepixel(x, y, z, facenr, mask, colf);
if(colf[3] != 1.0) {
/* bail out when raytrace transparency (sky included already) */
if(vlr && (R.r.mode & R_RAYTRACE))
if(vlr->mat->mode & MA_RAYTRANSP) return;
renderSkyPixelFloat(collector, x, y);
addAlphaOverFloat(collector, colf);
QUATCOPY(colf, collector);

View File

@@ -2316,7 +2316,7 @@ void abufsetrow(float *acolrow, int y)
APixstr *ap, *apn;
float *col, fcol[4], tempcol[4], sampcol[16*4], *scol, accumcol[4];
float ys, fac, alpha[32];
int x, part, a, zrow[100][3], totvlak, nr;
int x, part, a, zrow[100][3], totface, nr;
int sval;
if(y<0) return;
@@ -2363,22 +2363,22 @@ void abufsetrow(float *acolrow, int y)
for(x=0; x<R.rectx; x++, col+=4, ap++) {
if(ap->p[0]) {
/* sort in z */
totvlak= 0;
totface= 0;
apn= ap;
while(apn) {
for(a=0; a<4; a++) {
if(apn->p[a]) {
zrow[totvlak][0]= apn->z[a];
zrow[totvlak][1]= apn->p[a];
zrow[totvlak][2]= apn->mask[a];
totvlak++;
if(totvlak>99) totvlak= 99;
zrow[totface][0]= apn->z[a];
zrow[totface][1]= apn->p[a];
zrow[totface][2]= apn->mask[a];
totface++;
if(totface>99) totface= 99;
}
else break;
}
apn= apn->next;
}
if(totvlak==1) {
if(totface==1) {
shadetrapixel((float)x, (float)y, ap->z[0], ap->p[0], ap->mask[0], fcol);
@@ -2399,7 +2399,7 @@ void abufsetrow(float *acolrow, int y)
}
else {
if(totvlak==2) {
if(totface==2) {
if(zrow[0][0] < zrow[1][0]) {
a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a;
a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a;
@@ -2407,31 +2407,31 @@ void abufsetrow(float *acolrow, int y)
}
}
else { /* totvlak>2 */
qsort(zrow, totvlak, sizeof(int)*3, vergzvlak);
else { /* totface>2 */
qsort(zrow, totface, sizeof(int)*3, vergzvlak);
}
/* join when pixels are adjacent */
while(totvlak>0) {
totvlak--;
while(totface>0) {
totface--;
shadetrapixel((float)x, (float)y, zrow[totvlak][0], zrow[totvlak][1], zrow[totvlak][2], fcol);
shadetrapixel((float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol);
a= count_mask(zrow[totvlak][2]);
a= count_mask(zrow[totface][2]);
if( (R.r.mode & R_OSA ) && a<R.osa) {
if(totvlak>0) {
if(totface>0) {
memset(sampcol, 0, 4*sizeof(float)*R.osa);
sval= addtosampcol(sampcol, fcol, zrow[totvlak][2]);
sval= addtosampcol(sampcol, fcol, zrow[totface][2]);
/* sval==0: alpha completely full */
while( (sval != 0) && (totvlak>0) ) {
a= count_mask(zrow[totvlak-1][2]);
while( (sval != 0) && (totface>0) ) {
a= count_mask(zrow[totface-1][2]);
if(a==R.osa) break;
totvlak--;
totface--;
shadetrapixel((float)x, (float)y, zrow[totvlak][0], zrow[totvlak][1], zrow[totvlak][2], fcol);
sval= addtosampcol(sampcol, fcol, zrow[totvlak][2]);
shadetrapixel((float)x, (float)y, zrow[totface][0], zrow[totface][1], zrow[totface][2], fcol);
sval= addtosampcol(sampcol, fcol, zrow[totface][2]);
}
scol= sampcol;
accumcol[0]= scol[0]; accumcol[1]= scol[1];

View File

@@ -2789,7 +2789,10 @@ static void material_panel_tramir(Material *ma)
uiDefButF(block, NUMSLI, B_MATPRV, "Fac ", 170,140,140,20, &(ma->fresnel_mir_i), 1.0, 5.0, 10, 2, "Blending factor for Fresnel");
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_DIFF, "Zoffs:", 10,110,100,20, &(ma->zoffs), 0.0, 10.0, 0, 0, "Gives faces an artificial offset in the Z buffer for Ztransp option");
if(ma->mode & MA_RAYTRANSP)
uiDefButF(block, NUM, B_MATPRV, "Filt:", 10,110,100,20, &(ma->filter), 0.0, 1.0, 0, 0, "Amount of filtering for transparent raytrace");
else
uiDefButF(block, NUM, B_DIFF, "Zoffs:", 10,110,100,20, &(ma->zoffs), 0.0, 10.0, 0, 0, "Gives faces an artificial offset in the Z buffer for Ztransp option");
uiDefButI(block, TOG|BIT|6, B_MATZTRANSP,"ZTransp", 110,110,100,20, &(ma->mode), 0, 0, 0, 0, "Enables Z-Buffering of transparent faces");
uiDefButI(block, TOG|BIT|17, B_MATRAYTRANSP,"Ray Transp",210,110,100,20, &(ma->mode), 0, 0, 0, 0, "Enables raytracing for transparency rendering");

View File

@@ -994,9 +994,19 @@ static void shade_preview_pixel(ShadeInput *shi, float *vec, int x, int y,char *
tracol= (1.0-alpha)*tracol;
rect[0]= tracol+ (rect[0]*alpha) ;
rect[1]= tracol+ (rect[1]*alpha) ;
rect[2]= tracol+ (rect[2]*alpha) ;
if((mat->mode & MA_RAYTRANSP) && mat->filter!=0.0) {
float fr= 1.0+ mat->filter*(shi->r-1.0);
rect[0]= fr*tracol+ (rect[0]*alpha) ;
fr= 1.0+ mat->filter*(shi->g-1.0);
rect[1]= fr*tracol+ (rect[1]*alpha) ;
fr= 1.0+ mat->filter*(shi->b-1.0);
rect[2]= fr*tracol+ (rect[2]*alpha) ;
}
else {
rect[0]= tracol+ (rect[0]*alpha) ;
rect[1]= tracol+ (rect[1]*alpha) ;
rect[2]= tracol+ (rect[2]*alpha) ;
}
}
}