|
Blender
V2.59
|
00001 /* 00002 * $Id: strand.c 37667 2011-06-20 15:17:02Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: none of this file. 00024 * 00025 * Contributors: Brecht Van Lommel. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <math.h> 00036 #include <string.h> 00037 #include <stdlib.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_key_types.h" 00042 #include "DNA_material_types.h" 00043 #include "DNA_meshdata_types.h" 00044 00045 #include "BLI_math.h" 00046 #include "BLI_blenlib.h" 00047 #include "BLI_utildefines.h" 00048 #include "BLI_ghash.h" 00049 #include "BLI_memarena.h" 00050 #include "BLI_rand.h" 00051 00052 #include "BKE_DerivedMesh.h" 00053 #include "BKE_key.h" 00054 00055 00056 #include "render_types.h" 00057 #include "initrender.h" 00058 #include "rendercore.h" 00059 #include "renderdatabase.h" 00060 #include "renderpipeline.h" 00061 #include "pixelblending.h" 00062 #include "shading.h" 00063 #include "strand.h" 00064 #include "zbuf.h" 00065 00066 /* to be removed */ 00067 void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco); 00068 void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) ); 00069 void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, float *ho1, float *ho2); 00070 00071 /* *************** */ 00072 00073 static float strand_eval_width(Material *ma, float strandco) 00074 { 00075 float fac; 00076 00077 strandco= 0.5f*(strandco + 1.0f); 00078 00079 if(ma->strand_ease!=0.0f) { 00080 if(ma->strand_ease<0.0f) 00081 fac= pow(strandco, 1.0+ma->strand_ease); 00082 else 00083 fac= pow(strandco, 1.0/(1.0f-ma->strand_ease)); 00084 } 00085 else fac= strandco; 00086 00087 return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end); 00088 } 00089 00090 void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) 00091 { 00092 Material *ma; 00093 StrandBuffer *strandbuf; 00094 float *simplify; 00095 float p[4][3], data[4], cross[3], crosslen, w, dx, dy, t; 00096 int type; 00097 00098 strandbuf= sseg->buffer; 00099 ma= sseg->buffer->ma; 00100 t= spoint->t; 00101 type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; 00102 00103 VECCOPY(p[0], sseg->v[0]->co); 00104 VECCOPY(p[1], sseg->v[1]->co); 00105 VECCOPY(p[2], sseg->v[2]->co); 00106 VECCOPY(p[3], sseg->v[3]->co); 00107 00108 if(sseg->obi->flag & R_TRANSFORMED) { 00109 mul_m4_v3(sseg->obi->mat, p[0]); 00110 mul_m4_v3(sseg->obi->mat, p[1]); 00111 mul_m4_v3(sseg->obi->mat, p[2]); 00112 mul_m4_v3(sseg->obi->mat, p[3]); 00113 } 00114 00115 if(t == 0.0f) { 00116 VECCOPY(spoint->co, p[1]); 00117 spoint->strandco= sseg->v[1]->strandco; 00118 00119 spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); 00120 if(sseg->v[0] != sseg->v[1]) 00121 spoint->dtstrandco *= 0.5f; 00122 } 00123 else if(t == 1.0f) { 00124 VECCOPY(spoint->co, p[2]); 00125 spoint->strandco= sseg->v[2]->strandco; 00126 00127 spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); 00128 if(sseg->v[3] != sseg->v[2]) 00129 spoint->dtstrandco *= 0.5f; 00130 } 00131 else { 00132 key_curve_position_weights(t, data, type); 00133 spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; 00134 spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; 00135 spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; 00136 spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; 00137 } 00138 00139 key_curve_tangent_weights(t, data, type); 00140 spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; 00141 spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; 00142 spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; 00143 00144 VECCOPY(spoint->tan, spoint->dtco); 00145 normalize_v3(spoint->tan); 00146 00147 VECCOPY(spoint->nor, spoint->co); 00148 VECMUL(spoint->nor, -1.0f); 00149 normalize_v3(spoint->nor); 00150 00151 spoint->width= strand_eval_width(ma, spoint->strandco); 00152 00153 /* simplification */ 00154 simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); 00155 spoint->alpha= (simplify)? simplify[1]: 1.0f; 00156 00157 /* outer points */ 00158 cross_v3_v3v3(cross, spoint->co, spoint->tan); 00159 00160 w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; 00161 dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; 00162 dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; 00163 w= sqrt(dx*dx + dy*dy); 00164 00165 if(w > 0.0f) { 00166 if(strandbuf->flag & R_STRAND_B_UNITS) { 00167 crosslen= len_v3(cross); 00168 w= 2.0f*crosslen*strandbuf->minwidth/w; 00169 00170 if(spoint->width < w) { 00171 spoint->alpha= spoint->width/w; 00172 spoint->width= w; 00173 } 00174 00175 if(simplify) 00176 /* squared because we only change width, not length */ 00177 spoint->width *= simplify[0]*simplify[0]; 00178 00179 mul_v3_fl(cross, spoint->width*0.5f/crosslen); 00180 } 00181 else 00182 mul_v3_fl(cross, spoint->width/w); 00183 } 00184 00185 sub_v3_v3v3(spoint->co1, spoint->co, cross); 00186 add_v3_v3v3(spoint->co2, spoint->co, cross); 00187 00188 VECCOPY(spoint->dsco, cross); 00189 } 00190 00191 /* *************** */ 00192 00193 static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v) 00194 { 00195 v[0]= negt*v1[0] + t*v2[0]; 00196 } 00197 00198 static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v) 00199 { 00200 v[0]= negt*v1[0] + t*v2[0]; 00201 v[1]= negt*v1[1] + t*v2[1]; 00202 v[2]= negt*v1[2] + t*v2[2]; 00203 } 00204 00205 static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v) 00206 { 00207 v[0]= negt*v1[0] + t*v2[0]; 00208 v[1]= negt*v1[1] + t*v2[1]; 00209 v[2]= negt*v1[2] + t*v2[2]; 00210 v[3]= negt*v1[3] + t*v2[3]; 00211 } 00212 00213 static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag) 00214 { 00215 float negt= 1.0f - t; 00216 00217 interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined); 00218 00219 if(addpassflag & SCE_PASS_VECTOR) { 00220 interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed); 00221 } 00222 /* optim... */ 00223 if(addpassflag & ~(SCE_PASS_VECTOR)) { 00224 if(addpassflag & SCE_PASS_Z) 00225 interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z); 00226 if(addpassflag & SCE_PASS_RGBA) 00227 interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col); 00228 if(addpassflag & SCE_PASS_NORMAL) { 00229 interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor); 00230 normalize_v3(shr->nor); 00231 } 00232 if(addpassflag & SCE_PASS_EMIT) 00233 interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit); 00234 if(addpassflag & SCE_PASS_DIFFUSE) 00235 interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff); 00236 if(addpassflag & SCE_PASS_SPEC) 00237 interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec); 00238 if(addpassflag & SCE_PASS_SHADOW) 00239 interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad); 00240 if(addpassflag & SCE_PASS_AO) 00241 interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao); 00242 if(addpassflag & SCE_PASS_ENVIRONMENT) 00243 interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env); 00244 if(addpassflag & SCE_PASS_INDIRECT) 00245 interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect); 00246 if(addpassflag & SCE_PASS_REFLECT) 00247 interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl); 00248 if(addpassflag & SCE_PASS_REFRACT) 00249 interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr); 00250 if(addpassflag & SCE_PASS_MIST) 00251 interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist); 00252 } 00253 } 00254 00255 static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha) 00256 { 00257 if(alpha < 1.0f) { 00258 shr->combined[0] *= alpha; 00259 shr->combined[1] *= alpha; 00260 shr->combined[2] *= alpha; 00261 shr->combined[3] *= alpha; 00262 00263 shr->col[0] *= alpha; 00264 shr->col[1] *= alpha; 00265 shr->col[2] *= alpha; 00266 shr->col[3] *= alpha; 00267 00268 shr->alpha *= alpha; 00269 } 00270 } 00271 00272 static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint) 00273 { 00274 ShadeInput *shi= ssamp->shi; 00275 ShadeResult *shr= ssamp->shr; 00276 VlakRen vlr; 00277 int seed; 00278 00279 memset(&vlr, 0, sizeof(vlr)); 00280 vlr.flag= R_SMOOTH; 00281 if(sseg->buffer->ma->mode & MA_TANGENT_STR) 00282 vlr.flag |= R_TANGENT; 00283 00284 shi->vlr= &vlr; 00285 shi->v1= NULL; 00286 shi->v2= NULL; 00287 shi->v3= NULL; 00288 shi->strand= sseg->strand; 00289 shi->obi= sseg->obi; 00290 shi->obr= sseg->obi->obr; 00291 00292 /* cache for shadow */ 00293 shi->samplenr= re->shadowsamplenr[shi->thread]++; 00294 00295 /* all samples */ 00296 shi->mask= 0xFFFF; 00297 00298 /* seed RNG for consistent results across tiles */ 00299 seed = shi->strand->index + (svert - shi->strand->vert); 00300 BLI_thread_srandom(shi->thread, seed); 00301 00302 shade_input_set_strand(shi, sseg->strand, spoint); 00303 shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint); 00304 00305 /* init material vars */ 00306 shade_input_init_material(shi); 00307 00308 /* shade */ 00309 shade_samples_do_AO(ssamp); 00310 shade_input_do_shade(shi, shr); 00311 00312 /* apply simplification */ 00313 strand_apply_shaderesult_alpha(shr, spoint->alpha); 00314 00315 /* include lamphalos for strand, since halo layer was added already */ 00316 if(re->flag & R_LAMPHALO) 00317 if(shi->layflag & SCE_LAY_HALO) 00318 renderspothalo(shi, shr->combined, shr->combined[3]); 00319 00320 shi->strand= NULL; 00321 } 00322 00323 /* *************** */ 00324 00325 struct StrandShadeCache { 00326 GHash *resulthash; 00327 GHash *refcounthash; 00328 MemArena *memarena; 00329 }; 00330 00331 StrandShadeCache *strand_shade_cache_create(void) 00332 { 00333 StrandShadeCache *cache; 00334 00335 cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache"); 00336 cache->resulthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "strand_shade_cache_create1 gh"); 00337 cache->refcounthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "strand_shade_cache_create2 gh"); 00338 cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena"); 00339 00340 return cache; 00341 } 00342 00343 void strand_shade_cache_free(StrandShadeCache *cache) 00344 { 00345 BLI_ghash_free(cache->refcounthash, NULL, NULL); 00346 BLI_ghash_free(cache->resulthash, NULL, (GHashValFreeFP)MEM_freeN); 00347 BLI_memarena_free(cache->memarena); 00348 MEM_freeN(cache); 00349 } 00350 00351 static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert) 00352 { 00353 ShadeResult *hashshr; 00354 StrandPoint p; 00355 int *refcount; 00356 00357 hashshr= BLI_ghash_lookup(cache->resulthash, svert); 00358 refcount= BLI_ghash_lookup(cache->refcounthash, svert); 00359 00360 if(!hashshr) { 00361 /* not shaded yet, shade and insert into hash */ 00362 p.t= (sseg->v[1] == svert)? 0.0f: 1.0f; 00363 strand_eval_point(sseg, &p); 00364 strand_shade_point(re, ssamp, sseg, svert, &p); 00365 00366 hashshr= MEM_callocN(sizeof(ShadeResult), "HashShadeResult"); 00367 *hashshr= ssamp->shr[0]; 00368 BLI_ghash_insert(cache->resulthash, svert, hashshr); 00369 } 00370 else 00371 /* already shaded, just copy previous result from hash */ 00372 ssamp->shr[0]= *hashshr; 00373 00374 /* lower reference count and remove if not needed anymore by any samples */ 00375 (*refcount)--; 00376 if(*refcount == 0) { 00377 BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN); 00378 BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL); 00379 } 00380 } 00381 00382 void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag) 00383 { 00384 ShadeResult shr1, shr2; 00385 00386 /* get shading for two endpoints and interpolate */ 00387 strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]); 00388 shr1= ssamp->shr[0]; 00389 strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]); 00390 shr2= ssamp->shr[0]; 00391 00392 interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag); 00393 00394 /* apply alpha along width */ 00395 if(sseg->buffer->widthfade != 0.0f) { 00396 s = 1.0f - pow(fabs(s), sseg->buffer->widthfade); 00397 00398 strand_apply_shaderesult_alpha(ssamp->shr, s); 00399 } 00400 } 00401 00402 void strand_shade_unref(StrandShadeCache *cache, StrandVert *svert) 00403 { 00404 int *refcount; 00405 00406 /* lower reference count and remove if not needed anymore by any samples */ 00407 refcount= BLI_ghash_lookup(cache->refcounthash, svert); 00408 00409 (*refcount)--; 00410 if(*refcount == 0) { 00411 BLI_ghash_remove(cache->resulthash, svert, NULL, (GHashValFreeFP)MEM_freeN); 00412 BLI_ghash_remove(cache->refcounthash, svert, NULL, NULL); 00413 } 00414 } 00415 00416 static void strand_shade_refcount(StrandShadeCache *cache, StrandVert *svert) 00417 { 00418 int *refcount= BLI_ghash_lookup(cache->refcounthash, svert); 00419 00420 if(!refcount) { 00421 refcount= BLI_memarena_alloc(cache->memarena, sizeof(int)); 00422 *refcount= 1; 00423 BLI_ghash_insert(cache->refcounthash, svert, refcount); 00424 } 00425 else 00426 (*refcount)++; 00427 } 00428 00429 /* *************** */ 00430 00431 typedef struct StrandPart { 00432 Render *re; 00433 ZSpan *zspan; 00434 00435 APixstrand *apixbuf; 00436 int *totapixbuf; 00437 int *rectz; 00438 int *rectmask; 00439 intptr_t *rectdaps; 00440 int rectx, recty; 00441 int sample; 00442 int shadow; 00443 float (*jit)[2]; 00444 00445 StrandSegment *segment; 00446 float t[3], s[3]; 00447 00448 StrandShadeCache *cache; 00449 } StrandPart; 00450 00451 typedef struct StrandSortSegment { 00452 struct StrandSortSegment *next; 00453 int obi, strand, segment; 00454 float z; 00455 } StrandSortSegment; 00456 00457 static int compare_strand_segment(const void *poin1, const void *poin2) 00458 { 00459 const StrandSortSegment *seg1= (const StrandSortSegment*)poin1; 00460 const StrandSortSegment *seg2= (const StrandSortSegment*)poin2; 00461 00462 if(seg1->z < seg2->z) 00463 return -1; 00464 else if(seg1->z == seg2->z) 00465 return 0; 00466 else 00467 return 1; 00468 } 00469 00470 static void do_strand_point_project(float winmat[][4], ZSpan *zspan, float *co, float *hoco, float *zco) 00471 { 00472 projectvert(co, winmat, hoco); 00473 hoco_to_zco(zspan, zco, hoco); 00474 } 00475 00476 static void strand_project_point(float winmat[][4], float winx, float winy, StrandPoint *spoint) 00477 { 00478 float div; 00479 00480 projectvert(spoint->co, winmat, spoint->hoco); 00481 00482 div= 1.0f/spoint->hoco[3]; 00483 spoint->x= spoint->hoco[0]*div*winx*0.5f; 00484 spoint->y= spoint->hoco[1]*div*winy*0.5f; 00485 } 00486 00487 static APixstrand *addpsmainAstrand(ListBase *lb) 00488 { 00489 APixstrMain *psm; 00490 00491 psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA"); 00492 BLI_addtail(lb, psm); 00493 psm->ps= MEM_callocN(4096*sizeof(APixstrand),"pixstr"); 00494 00495 return psm->ps; 00496 } 00497 00498 static APixstrand *addpsAstrand(ZSpan *zspan) 00499 { 00500 /* make new PS */ 00501 if(zspan->apstrandmcounter==0) { 00502 zspan->curpstrand= addpsmainAstrand(zspan->apsmbase); 00503 zspan->apstrandmcounter= 4095; 00504 } 00505 else { 00506 zspan->curpstrand++; 00507 zspan->apstrandmcounter--; 00508 } 00509 return zspan->curpstrand; 00510 } 00511 00512 #define MAX_ZROW 2000 00513 00514 static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z) 00515 { 00516 StrandPart *spart= (StrandPart*)handle; 00517 StrandShadeCache *cache= spart->cache; 00518 StrandSegment *sseg= spart->segment; 00519 APixstrand *apn, *apnew; 00520 float t, s; 00521 int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0; 00522 00523 offset = y*spart->rectx + x; 00524 obi= sseg->obi - spart->re->objectinstance; 00525 strnr= sseg->strand->index + 1; 00526 seg= sseg->v[1] - sseg->strand->vert; 00527 mask= (1<<spart->sample); 00528 00529 /* check against solid z-buffer */ 00530 zverg= (int)z; 00531 00532 if(spart->rectdaps) { 00533 /* find the z of the sample */ 00534 PixStr *ps; 00535 intptr_t *rd= spart->rectdaps + offset; 00536 00537 bufferz= 0x7FFFFFFF; 00538 if(spart->rectmask) maskz= 0x7FFFFFFF; 00539 00540 if(*rd) { 00541 for(ps= (PixStr *)(*rd); ps; ps= ps->next) { 00542 if(mask & ps->mask) { 00543 bufferz= ps->z; 00544 if(spart->rectmask) 00545 maskz= ps->maskz; 00546 break; 00547 } 00548 } 00549 } 00550 } 00551 else { 00552 bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF; 00553 if(spart->rectmask) 00554 maskz= spart->rectmask[offset]; 00555 } 00556 00557 #define CHECK_ADD(n) \ 00558 if(apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \ 00559 { if(!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } 00560 #define CHECK_ASSIGN(n) \ 00561 if(apn->p[n]==0) \ 00562 {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } 00563 00564 /* add to pixel list */ 00565 if(zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) { 00566 if(!spart->rectmask || zverg > maskz) { 00567 t = u*spart->t[0] + v*spart->t[1] + (1.0f-u-v)*spart->t[2]; 00568 s = fabs(u*spart->s[0] + v*spart->s[1] + (1.0f-u-v)*spart->s[2]); 00569 00570 apn= spart->apixbuf + offset; 00571 while(apn) { 00572 CHECK_ADD(0); 00573 CHECK_ADD(1); 00574 CHECK_ADD(2); 00575 CHECK_ADD(3); 00576 CHECK_ASSIGN(0); 00577 CHECK_ASSIGN(1); 00578 CHECK_ASSIGN(2); 00579 CHECK_ASSIGN(3); 00580 00581 apnew= addpsAstrand(spart->zspan); 00582 SWAP(APixstrand, *apnew, *apn); 00583 apn->next= apnew; 00584 CHECK_ASSIGN(0); 00585 } 00586 00587 if(cache) { 00588 strand_shade_refcount(cache, sseg->v[1]); 00589 strand_shade_refcount(cache, sseg->v[2]); 00590 } 00591 spart->totapixbuf[offset]++; 00592 } 00593 } 00594 } 00595 00596 /* width is calculated in hoco space, to ensure strands are visible */ 00597 static int strand_test_clip(float winmat[][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy) 00598 { 00599 float hoco[4]; 00600 int clipflag= 0; 00601 00602 projectvert(co, winmat, hoco); 00603 00604 /* we compare z without perspective division for segment sorting */ 00605 *zcomp= hoco[2]; 00606 00607 if(hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1; 00608 else if(hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2; 00609 00610 if(hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4; 00611 else if(hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8; 00612 00613 clipflag |= testclip(hoco); 00614 00615 return clipflag; 00616 } 00617 00618 static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample) 00619 { 00620 float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy; 00621 00622 VECCOPY(jco1, co1); 00623 VECCOPY(jco2, co2); 00624 VECCOPY(jco3, co3); 00625 VECCOPY(jco4, co4); 00626 00627 if(spart->jit) { 00628 jx= -spart->jit[sample][0]; 00629 jy= -spart->jit[sample][1]; 00630 00631 jco1[0] += jx; jco1[1] += jy; 00632 jco2[0] += jx; jco2[1] += jy; 00633 jco3[0] += jx; jco3[1] += jy; 00634 jco4[0] += jx; jco4[1] += jy; 00635 00636 /* XXX mblur? */ 00637 } 00638 00639 spart->sample= sample; 00640 00641 spart->t[0]= t-dt; 00642 spart->s[0]= -1.0f; 00643 spart->t[1]= t-dt; 00644 spart->s[1]= 1.0f; 00645 spart->t[2]= t; 00646 spart->s[2]= 1.0f; 00647 zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac); 00648 spart->t[0]= t-dt; 00649 spart->s[0]= -1.0f; 00650 spart->t[1]= t; 00651 spart->s[1]= 1.0f; 00652 spart->t[2]= t; 00653 spart->s[2]= -1.0f; 00654 zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac); 00655 } 00656 00657 static void strand_render(Render *re, StrandSegment *sseg, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2) 00658 { 00659 if(spart) { 00660 float t= p2->t; 00661 float dt= p2->t - p1->t; 00662 int a; 00663 00664 if(re->osa) { 00665 for(a=0; a<re->osa; a++) 00666 do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a); 00667 } 00668 else 00669 do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, 0); 00670 } 00671 else { 00672 float hoco1[4], hoco2[4]; 00673 int a, obi, index; 00674 00675 obi= sseg->obi - re->objectinstance; 00676 index= sseg->strand->index; 00677 00678 projectvert(p1->co, winmat, hoco1); 00679 projectvert(p2->co, winmat, hoco2); 00680 00681 00682 for(a=0; a<totzspan; a++) { 00683 #if 0 00684 /* render both strand and single pixel wire to counter aliasing */ 00685 zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2); 00686 #endif 00687 /* only render a line for now, which makes the shadow map more 00688 similiar across frames, and so reduces flicker */ 00689 zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2); 00690 } 00691 } 00692 } 00693 00694 static int strand_segment_recursive(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth) 00695 { 00696 StrandPoint p; 00697 StrandBuffer *buffer= sseg->buffer; 00698 float dot, d1[2], d2[2], len1, len2; 00699 00700 if(depth == buffer->maxdepth) 00701 return 0; 00702 00703 p.t= (p1->t + p2->t)*0.5f; 00704 strand_eval_point(sseg, &p); 00705 strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p); 00706 00707 d1[0]= (p.x - p1->x); 00708 d1[1]= (p.y - p1->y); 00709 len1= d1[0]*d1[0] + d1[1]*d1[1]; 00710 00711 d2[0]= (p2->x - p.x); 00712 d2[1]= (p2->y - p.y); 00713 len2= d2[0]*d2[0] + d2[1]*d2[1]; 00714 00715 if(len1 == 0.0f || len2 == 0.0f) 00716 return 0; 00717 00718 dot= d1[0]*d2[0] + d1[1]*d2[1]; 00719 if(dot*dot > sseg->sqadaptcos*len1*len2) 00720 return 0; 00721 00722 if(spart) { 00723 do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1); 00724 do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2); 00725 } 00726 else { 00727 #if 0 00728 projectvert(p.co1, winmat, p.hoco1); 00729 projectvert(p.co2, winmat, p.hoco2); 00730 p.clip1= testclip(p.hoco1); 00731 p.clip2= testclip(p.hoco2); 00732 #endif 00733 } 00734 00735 if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1)) 00736 strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p); 00737 if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1)) 00738 strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2); 00739 00740 return 1; 00741 } 00742 00743 void render_strand_segment(Render *re, float winmat[][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg) 00744 { 00745 StrandBuffer *buffer= sseg->buffer; 00746 StrandPoint *p1= &sseg->point1; 00747 StrandPoint *p2= &sseg->point2; 00748 00749 p1->t= 0.0f; 00750 p2->t= 1.0f; 00751 00752 strand_eval_point(sseg, p1); 00753 strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1); 00754 strand_eval_point(sseg, p2); 00755 strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2); 00756 00757 if(spart) { 00758 do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1); 00759 do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2); 00760 do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1); 00761 do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2); 00762 } 00763 else { 00764 #if 0 00765 projectvert(p1->co1, winmat, p1->hoco1); 00766 projectvert(p1->co2, winmat, p1->hoco2); 00767 projectvert(p2->co1, winmat, p2->hoco1); 00768 projectvert(p2->co2, winmat, p2->hoco2); 00769 p1->clip1= testclip(p1->hoco1); 00770 p1->clip2= testclip(p1->hoco2); 00771 p2->clip1= testclip(p2->hoco1); 00772 p2->clip2= testclip(p2->hoco2); 00773 #endif 00774 } 00775 00776 if(!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0)) 00777 strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2); 00778 } 00779 00780 /* render call to fill in strands */ 00781 int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[][4], int winx, int winy, int UNUSED(sample), float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache) 00782 { 00783 ObjectRen *obr; 00784 ObjectInstanceRen *obi; 00785 ZSpan zspan; 00786 StrandRen *strand=0; 00787 StrandVert *svert; 00788 StrandBound *sbound; 00789 StrandPart spart; 00790 StrandSegment sseg; 00791 StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg; 00792 MemArena *memarena; 00793 float z[4], bounds[4], obwinmat[4][4]; 00794 int a, b, c, i, totsegment, clip[4]; 00795 00796 if(re->test_break(re->tbh)) 00797 return 0; 00798 if(re->totstrand == 0) 00799 return 0; 00800 00801 /* setup StrandPart */ 00802 memset(&spart, 0, sizeof(spart)); 00803 00804 spart.re= re; 00805 spart.rectx= pa->rectx; 00806 spart.recty= pa->recty; 00807 spart.apixbuf= apixbuf; 00808 spart.zspan= &zspan; 00809 spart.rectdaps= pa->rectdaps; 00810 spart.rectz= pa->rectz; 00811 spart.rectmask= pa->rectmask; 00812 spart.cache= cache; 00813 spart.shadow= shadow; 00814 spart.jit= jit; 00815 00816 zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop); 00817 00818 /* needed for transform from hoco to zbuffer co */ 00819 zspan.zmulx= ((float)winx)/2.0; 00820 zspan.zmuly= ((float)winy)/2.0; 00821 00822 zspan.zofsx= -pa->disprect.xmin; 00823 zspan.zofsy= -pa->disprect.ymin; 00824 00825 /* to center the sample position */ 00826 if(!shadow) { 00827 zspan.zofsx -= 0.5f; 00828 zspan.zofsy -= 0.5f; 00829 } 00830 00831 zspan.apsmbase= apsmbase; 00832 00833 /* clipping setup */ 00834 bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx; 00835 bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx; 00836 bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy; 00837 bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy; 00838 00839 memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena"); 00840 firstseg= NULL; 00841 sortseg= sortsegments; 00842 totsegment= 0; 00843 00844 /* for all object instances */ 00845 for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) { 00846 Material *ma; 00847 float widthx, widthy; 00848 00849 obr= obi->obr; 00850 00851 if(!obr->strandbuf || !(obr->strandbuf->lay & lay)) 00852 continue; 00853 00854 /* compute matrix and try clipping whole object */ 00855 if(obi->flag & R_TRANSFORMED) 00856 mul_m4_m4m4(obwinmat, obi->mat, winmat); 00857 else 00858 copy_m4_m4(obwinmat, winmat); 00859 00860 /* test if we should skip it */ 00861 ma = obr->strandbuf->ma; 00862 00863 if(shadow && !(ma->mode & MA_SHADBUF)) 00864 continue; 00865 else if(!shadow && (ma->mode & MA_ONLYCAST)) 00866 continue; 00867 00868 if(clip_render_object(obi->obr->boundbox, bounds, obwinmat)) 00869 continue; 00870 00871 widthx= obr->strandbuf->maxwidth*obwinmat[0][0]; 00872 widthy= obr->strandbuf->maxwidth*obwinmat[1][1]; 00873 00874 /* for each bounding box containing a number of strands */ 00875 sbound= obr->strandbuf->bound; 00876 for(c=0; c<obr->strandbuf->totbound; c++, sbound++) { 00877 if(clip_render_object(sbound->boundbox, bounds, obwinmat)) 00878 continue; 00879 00880 /* for each strand in this bounding box */ 00881 for(a=sbound->start; a<sbound->end; a++) { 00882 strand= RE_findOrAddStrand(obr, a); 00883 svert= strand->vert; 00884 00885 /* keep clipping and z depth for 4 control points */ 00886 clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy); 00887 clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy); 00888 clip[0]= clip[1]; z[0]= z[1]; 00889 00890 for(b=0; b<strand->totvert-1; b++, svert++) { 00891 /* compute 4th point clipping and z depth */ 00892 if(b < strand->totvert-2) { 00893 clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy); 00894 } 00895 else { 00896 clip[3]= clip[2]; z[3]= z[2]; 00897 } 00898 00899 /* check clipping and add to sortsegments buffer */ 00900 if(!(clip[0] & clip[1] & clip[2] & clip[3])) { 00901 sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment)); 00902 sortseg->obi= i; 00903 sortseg->strand= strand->index; 00904 sortseg->segment= b; 00905 00906 sortseg->z= 0.5f*(z[1] + z[2]); 00907 00908 sortseg->next= firstseg; 00909 firstseg= sortseg; 00910 totsegment++; 00911 } 00912 00913 /* shift clipping and z depth */ 00914 clip[0]= clip[1]; z[0]= z[1]; 00915 clip[1]= clip[2]; z[1]= z[2]; 00916 clip[2]= clip[3]; z[2]= z[3]; 00917 } 00918 } 00919 } 00920 } 00921 00922 if(!re->test_break(re->tbh)) { 00923 /* convert list to array and sort */ 00924 sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment"); 00925 for(a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next) 00926 sortsegments[a]= *sortseg; 00927 qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment); 00928 } 00929 00930 BLI_memarena_free(memarena); 00931 00932 spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf"); 00933 00934 if(!re->test_break(re->tbh)) { 00935 /* render segments in sorted order */ 00936 sortseg= sortsegments; 00937 for(a=0; a<totsegment; a++, sortseg++) { 00938 if(re->test_break(re->tbh)) 00939 break; 00940 00941 obi= &re->objectinstance[sortseg->obi]; 00942 obr= obi->obr; 00943 00944 sseg.obi= obi; 00945 sseg.strand= RE_findOrAddStrand(obr, sortseg->strand); 00946 sseg.buffer= sseg.strand->buffer; 00947 sseg.sqadaptcos= sseg.buffer->adaptcos; 00948 sseg.sqadaptcos *= sseg.sqadaptcos; 00949 00950 svert= sseg.strand->vert + sortseg->segment; 00951 sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert; 00952 sseg.v[1]= svert; 00953 sseg.v[2]= svert+1; 00954 sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1; 00955 sseg.shaded= 0; 00956 00957 spart.segment= &sseg; 00958 00959 render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg); 00960 } 00961 } 00962 00963 if(sortsegments) 00964 MEM_freeN(sortsegments); 00965 MEM_freeN(spart.totapixbuf); 00966 00967 zbuf_free_span(&zspan); 00968 00969 return totsegment; 00970 } 00971 00972 /* *************** */ 00973 00974 StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[][4], int timeoffset) 00975 { 00976 StrandSurface *mesh; 00977 MFace *mface; 00978 MVert *mvert; 00979 float (*co)[3]; 00980 int a, totvert, totface; 00981 00982 totvert= dm->getNumVerts(dm); 00983 totface= dm->getNumFaces(dm); 00984 00985 for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) 00986 if(mesh->obr.ob == obr->ob && mesh->obr.par == obr->par 00987 && mesh->obr.index == obr->index && mesh->totvert==totvert && mesh->totface==totface) 00988 break; 00989 00990 if(!mesh) { 00991 mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface"); 00992 mesh->obr= *obr; 00993 mesh->totvert= totvert; 00994 mesh->totface= totface; 00995 mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); 00996 mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO"); 00997 mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv"); 00998 mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect"); 00999 BLI_addtail(&re->strandsurface, mesh); 01000 } 01001 01002 if(timeoffset == -1 && !mesh->prevco) 01003 mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); 01004 else if(timeoffset == 0 && !mesh->co) 01005 mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); 01006 else if(timeoffset == 1 && !mesh->nextco) 01007 mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo"); 01008 else 01009 return mesh; 01010 01011 mvert= dm->getVertArray(dm); 01012 for(a=0; a<mesh->totvert; a++, mvert++) { 01013 VECCOPY(co[a], mvert->co); 01014 mul_m4_v3(mat, co[a]); 01015 } 01016 01017 mface= dm->getFaceArray(dm); 01018 for(a=0; a<mesh->totface; a++, mface++) { 01019 mesh->face[a][0]= mface->v1; 01020 mesh->face[a][1]= mface->v2; 01021 mesh->face[a][2]= mface->v3; 01022 mesh->face[a][3]= mface->v4; 01023 } 01024 01025 return mesh; 01026 } 01027 01028 void free_strand_surface(Render *re) 01029 { 01030 StrandSurface *mesh; 01031 01032 for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) { 01033 if(mesh->co) MEM_freeN(mesh->co); 01034 if(mesh->prevco) MEM_freeN(mesh->prevco); 01035 if(mesh->nextco) MEM_freeN(mesh->nextco); 01036 if(mesh->ao) MEM_freeN(mesh->ao); 01037 if(mesh->env) MEM_freeN(mesh->env); 01038 if(mesh->indirect) MEM_freeN(mesh->indirect); 01039 if(mesh->face) MEM_freeN(mesh->face); 01040 } 01041 01042 BLI_freelistN(&re->strandsurface); 01043 } 01044 01045 void strand_minmax(StrandRen *strand, float *min, float *max, float width) 01046 { 01047 StrandVert *svert; 01048 float vec[3], width2= 2.0f*width; 01049 int a; 01050 01051 for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++) { 01052 VECCOPY(vec, svert->co); 01053 DO_MINMAX(vec, min, max); 01054 01055 if(width!=0.0f) { 01056 vec[0]+= width; vec[1]+= width; vec[2]+= width; 01057 DO_MINMAX(vec, min, max); 01058 vec[0]-= width2; vec[1]-= width2; vec[2]-= width2; 01059 DO_MINMAX(vec, min, max); 01060 } 01061 } 01062 } 01063