From 7b2172cb0b4afaada3f59f90f694847cfc61c43d Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Fri, 17 May 2013 11:13:46 +0000 Subject: 3D Viewport rendering (Blender Internal) Added incremental re-render on view changes. That means all data preprocessing only needs to be done once on view changes, quite faster that way. Also fixed a bug in raytracing strands with soft shadows, was wrongly changing coordinates in a static array. Note: proper signals for re-renders is still on the todo. Many button options don't signal a re-render yet. Work around: press G+ESC for quick full renders. --- source/blender/render/intern/include/envmap.h | 2 +- .../render/intern/include/rayintersection.h | 4 + .../blender/render/intern/include/renderdatabase.h | 3 + .../blender/render/intern/source/convertblender.c | 2 +- source/blender/render/intern/source/envmap.c | 80 +++++--- source/blender/render/intern/source/rayshade.c | 210 ++++++++------------- 6 files changed, 142 insertions(+), 159 deletions(-) (limited to 'source/blender/render') diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h index 79233a5d625..c813e88c656 100644 --- a/source/blender/render/intern/include/envmap.h +++ b/source/blender/render/intern/include/envmap.h @@ -48,7 +48,7 @@ struct ImagePool; void make_envmaps(struct Render *re); int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool); -void env_rotate_scene(struct Render *re, float mat[4][4], int mode); +void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate); #endif /* __ENVMAP_H__ */ diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h index 4dceae56a4c..3607e66a237 100644 --- a/source/blender/render/intern/include/rayintersection.h +++ b/source/blender/render/intern/include/rayintersection.h @@ -64,6 +64,10 @@ typedef struct Isect { float dir[3]; float dist; + /* for envmap and incremental view update renders */ + float origstart[3]; + float origdir[3]; + /* precomputed values to accelerate bounding box intersection */ int bv_index[6]; float idot_axis[3]; diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index 1e81ca20d03..9e48299ed9a 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -140,6 +140,9 @@ struct VlakRen *RE_vlakren_copy(struct ObjectRen *obr, struct VlakRen *vlr); void RE_set_customdata_names(struct ObjectRen *obr, struct CustomData *data); +void area_lamp_vectors(struct LampRen *lar); + + /* haloren->type: flags */ #define HA_ONLYSKY 1 #define HA_VECT 2 diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 976be755532..2be3c118ec8 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3765,7 +3765,7 @@ static void initshadowbuf(Render *re, LampRen *lar, float mat[4][4]) shb->compressthresh= lar->compressthresh; } -static void area_lamp_vectors(LampRen *lar) +void area_lamp_vectors(LampRen *lar) { float xsize= 0.5f*lar->area_size, ysize= 0.5f*lar->area_sizey, multifac; diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 6423bfa9486..419c3d8ee23 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -45,6 +45,7 @@ #include "DNA_group_types.h" #include "DNA_image_types.h" +#include "DNA_lamp_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" @@ -163,6 +164,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env) /* view stuff in env render */ viewscale = (env->type == ENV_PLANE) ? env->viewscale : 1.0f; RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend); + copy_m4_m4(envre->viewmat_orig, re->viewmat_orig); /* callbacks */ envre->display_draw = re->display_draw; @@ -265,23 +267,27 @@ static void env_set_imats(Render *re) /* ------------------------------------------------------------------------- */ -void env_rotate_scene(Render *re, float mat[4][4], int mode) +void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) { GroupObject *go; ObjectRen *obr; ObjectInstanceRen *obi; LampRen *lar = NULL; HaloRen *har = NULL; - float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4]; + float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4]; int a; - if (mode == 0) { + if (do_rotate == 0) { invert_m4_m4(tmat, mat); copy_m3_m4(imat, tmat); + + copy_m4_m4(mat_inverse, mat); } else { copy_m4_m4(tmat, mat); copy_m3_m4(imat, mat); + + invert_m4_m4(mat_inverse, tmat); } for (obi = re->instancetable.first; obi; obi = obi->next) { @@ -290,7 +296,7 @@ void env_rotate_scene(Render *re, float mat[4][4], int mode) copy_m4_m4(tmpmat, obi->mat); mult_m4_m4m4(obi->mat, tmat, tmpmat); } - else if (mode == 1) + else if (do_rotate == 1) copy_m4_m4(obi->mat, tmat); else unit_m4(obi->mat); @@ -300,10 +306,12 @@ void env_rotate_scene(Render *re, float mat[4][4], int mode) transpose_m3(obi->nmat); /* indicate the renderer has to use transform matrices */ - if (mode == 0) + if (do_rotate == 0) obi->flag &= ~R_ENV_TRANSFORMED; - else + else { obi->flag |= R_ENV_TRANSFORMED; + copy_m4_m4(obi->imat, mat_inverse); + } } @@ -319,32 +327,50 @@ void env_rotate_scene(Render *re, float mat[4][4], int mode) for (go = re->lights.first; go; go = go->next) { lar = go->lampren; - /* removed here some horrible code of someone in NaN who tried to fix - * prototypes... just solved by introducing a correct cmat[3][3] instead - * of using smat. this works, check square spots in reflections (ton) */ - copy_m3_m3(cmat, lar->imat); - mul_m3_m3m3(lar->imat, cmat, imat); - - mul_m3_v3(imat, lar->vec); - mul_m4_v3(tmat, lar->co); - - lar->sh_invcampos[0] = -lar->co[0]; - lar->sh_invcampos[1] = -lar->co[1]; - lar->sh_invcampos[2] = -lar->co[2]; - mul_m3_v3(lar->imat, lar->sh_invcampos); - lar->sh_invcampos[2] *= lar->sh_zfac; + /* copy from add_render_lamp */ + if (do_rotate == 1) + mult_m4_m4m4(tmpmat, re->viewmat, go->ob->obmat); + else + mult_m4_m4m4(tmpmat, re->viewmat_orig, go->ob->obmat); + invert_m4_m4(go->ob->imat, tmpmat); - if (lar->shb) { - if (mode == 1) { - invert_m4_m4(pmat, mat); - mult_m4_m4m4(smat, lar->shb->viewmat, pmat); - mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat); + copy_m3_m4(lar->mat, tmpmat); + + copy_m3_m4(lar->imat, go->ob->imat); + + lar->vec[0]= -tmpmat[2][0]; + lar->vec[1]= -tmpmat[2][1]; + lar->vec[2]= -tmpmat[2][2]; + normalize_v3(lar->vec); + lar->co[0]= tmpmat[3][0]; + lar->co[1]= tmpmat[3][1]; + lar->co[2]= tmpmat[3][2]; + + if (lar->type == LA_AREA) { + area_lamp_vectors(lar); + } + else if (lar->type == LA_SPOT) { + normalize_v3(lar->imat[0]); + normalize_v3(lar->imat[1]); + normalize_v3(lar->imat[2]); + + lar->sh_invcampos[0] = -lar->co[0]; + lar->sh_invcampos[1] = -lar->co[1]; + lar->sh_invcampos[2] = -lar->co[2]; + mul_m3_v3(lar->imat, lar->sh_invcampos); + lar->sh_invcampos[2] *= lar->sh_zfac; + + if (lar->shb) { + if (do_rotate == 1) { + mult_m4_m4m4(smat, lar->shb->viewmat, mat_inverse); + mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat); + } + else mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat); } - else mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat); } } - if (mode) { + if (do_rotate) { init_render_world(re); env_set_imats(re); } diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 387004527c0..e77920dde26 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -499,7 +499,37 @@ static void shade_ray_set_derivative(ShadeInput *shi) } +/* four functions to facilitate envmap rotation for raytrace */ +static void ray_env_rotate_start(Isect *is, float imat[4][4]) +{ + copy_v3_v3(is->origstart, is->start); + mul_m4_v3(imat, is->start); +} + +static void ray_env_rotate_dir(Isect *is, float imat[4][4]) +{ + float end[3]; + + copy_v3_v3(is->origdir, is->dir); + add_v3_v3v3(end, is->origstart, is->dir); + + mul_m4_v3(imat, end); + sub_v3_v3v3(is->dir, end, is->start); +} + +static void ray_env_rotate(Isect *is, float imat[4][4]) +{ + ray_env_rotate_start(is, imat); + ray_env_rotate_dir(is, imat); +} +static void ray_env_rotate_restore(Isect *is) +{ + copy_v3_v3(is->start, is->origstart); + copy_v3_v3(is->dir, is->origdir); +} + +/* main ray shader */ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr) { ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob; @@ -716,11 +746,18 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con isec.orig.ob = obi; isec.orig.face = vlr; RE_RC_INIT(isec, shi); + + /* database is in original view, obi->imat transforms current position back to original */ + if (origshi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate(&isec, origshi->obi->imat); if (RE_rayobject_raycast(R.raytree, &isec)) { ShadeResult shr= {{0}}; float d= 1.0f; + if (origshi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_restore(&isec); + /* for as long we don't have proper dx/dy transform for rays we copy over original */ copy_v3_v3(shi.dxco, origshi->dxco); copy_v3_v3(shi.dyco, origshi->dyco); @@ -1621,6 +1658,9 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int shi.lay= origshi->lay; shi.nodes= origshi->nodes; + if (origshi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_restore(is); + shade_ray(is, &shi, &shr); if (shi.mat->material_type == MA_TYPE_SURFACE) { const float d= (traflag & RAY_TRA) ? @@ -1654,78 +1694,6 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int } } -/* not used, test function for ambient occlusion (yaf: pathlight) */ -/* main problem; has to be called within shading loop, giving unwanted recursion */ -static int UNUSED_FUNCTION(ray_trace_shadow_rad)(ShadeInput *ship, ShadeResult *shr) -{ - static int counter=0, only_one= 0; - extern float hashvectf[]; - Isect isec; - ShadeInput shi; - ShadeResult shr_t; - float vec[3], accum[3], div= 0.0f; - int a; - - assert(0); - - if (only_one) { - return 0; - } - only_one= 1; - - accum[0]= accum[1]= accum[2]= 0.0f; - isec.mode= RE_RAY_MIRROR; - isec.orig.ob = ship->obi; - isec.orig.face = ship->vlr; - isec.hint = 0; - - copy_v3_v3(isec.start, ship->co); - - RE_RC_INIT(isec, shi); - - for (a=0; a<8*8; a++) { - - counter+=3; - counter %= 768; - copy_v3_v3(vec, hashvectf+counter); - if (dot_v3v3(ship->vn, vec) > 0.0f) { - vec[0]-= vec[0]; - vec[1]-= vec[1]; - vec[2]-= vec[2]; - } - - copy_v3_v3(isec.dir, vec); - isec.dist = RE_RAYTRACE_MAXDIST; - - if (RE_rayobject_raycast(R.raytree, &isec)) { - float fac; - - /* Warning, This is not that nice, and possibly a bit slow for every ray, - * however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */ - memset(&shi, 0, sizeof(ShadeInput)); - /* end warning! - Campbell */ - - shade_ray(&isec, &shi, &shr_t); - /* fac= isec.dist*isec.dist; */ - fac= 1.0f; - accum[0]+= fac*(shr_t.diff[0]+shr_t.spec[0]); - accum[1]+= fac*(shr_t.diff[1]+shr_t.spec[1]); - accum[2]+= fac*(shr_t.diff[2]+shr_t.spec[2]); - div+= fac; - } - else div+= 1.0f; - } - - if (div!=0.0f) { - shr->diff[0]+= accum[0]/div; - shr->diff[1]+= accum[1]/div; - shr->diff[2]+= accum[2]/div; - } - shr->alpha= 1.0f; - - only_one= 0; - return 1; -} /* aolight: function to create random unit sphere vectors for total random sampling */ static void RandomSpherical(RNG *rng, float v[3]) @@ -1909,6 +1877,10 @@ static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3]) isec.lay= -1; copy_v3_v3(isec.start, shi->co); + + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_start(&isec, shi->obi->imat); + RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start); isec.hint = &point_hint; @@ -1961,12 +1933,15 @@ static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3]) dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]); normalize_v3(dir); - + isec.dir[0] = -dir[0]; isec.dir[1] = -dir[1]; isec.dir[2] = -dir[2]; isec.dist = maxdist; + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_dir(&isec, shi->obi->imat); + prev = fac; if (RE_rayobject_raycast(R.raytree, &isec)) { @@ -2049,6 +2024,9 @@ static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3]) isec.lay= -1; copy_v3_v3(isec.start, shi->co); + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_start(&isec, shi->obi->imat); + RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start); isec.hint = &point_hint; @@ -2106,6 +2084,9 @@ static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3]) isec.dir[2] = -vec[2]; isec.dist = maxdist; + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_dir(&isec, shi->obi->imat); + /* do the trace */ if (RE_rayobject_raycast(R.raytree, &isec)) { if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac); @@ -2214,7 +2195,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float colsq[4]; float adapt_thresh = lar->adapt_thresh; int min_adapt_samples=4, max_samples = lar->ray_totsamp; - float *co; + float start[3]; int do_soft = TRUE, full_osa = FALSE, i; float min[3], max[3]; @@ -2257,6 +2238,10 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], for (i = 0; i < totjitco; i++) { minmax_v3v3_v3(min, max, jitco[i]); } + if (shi->obi->flag & R_ENV_TRANSFORMED) { + mul_m4_v3(shi->obi->imat, min); + mul_m4_v3(shi->obi->imat, max); + } RE_rayobject_hint_bb(R.raytree, &bb_hint, min, max); isec->hint = &bb_hint; @@ -2272,7 +2257,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], /* manually jitter the start shading co-ord per sample * based on the pre-generated OSA texture sampling offsets, * for anti-aliasing sharp shadow edges. */ - co = jitco[samples % totjitco]; + copy_v3_v3(start, jitco[samples % totjitco]); if (do_soft) { /* sphere shadow source */ @@ -2280,7 +2265,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float ru[3], rv[3], v[3], s[3]; /* calc tangent plane vectors */ - sub_v3_v3v3(v, co, lampco); + sub_v3_v3v3(v, start, lampco); normalize_v3(v); ortho_basis_v3v3_v3(ru, rv, v); @@ -2314,20 +2299,23 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float jitbias= 0.5f*(len_v3(shi->dxco) + len_v3(shi->dyco)); float v[3]; - sub_v3_v3v3(v, co, end); + sub_v3_v3v3(v, start, end); normalize_v3(v); - co[0] -= jitbias*v[0]; - co[1] -= jitbias*v[1]; - co[2] -= jitbias*v[2]; + start[0] -= jitbias*v[0]; + start[1] -= jitbias*v[1]; + start[2] -= jitbias*v[2]; } - - copy_v3_v3(isec->start, co); + + copy_v3_v3(isec->start, start); isec->dir[0] = end[0]-isec->start[0]; isec->dir[1] = end[1]-isec->start[1]; isec->dir[2] = end[2]-isec->start[2]; isec->dist = normalize_v3(isec->dir); + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate(isec, shi->obi->imat); + /* trace the ray */ if (isec->mode==RE_RAY_SHADOW_TRA) { float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -2404,6 +2392,9 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[ else if (a==9) mask |= (mask>>9); copy_v3_v3(isec->start, shi->co); + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_start(isec, shi->obi->imat); + isec->orig.ob = shi->obi; isec->orig.face = shi->vlr; RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, isec->start); @@ -2429,6 +2420,10 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[ isec->dir[0] = vec[0]+lampco[0]-isec->start[0]; isec->dir[1] = vec[1]+lampco[1]-isec->start[1]; isec->dir[2] = vec[2]+lampco[2]-isec->start[2]; + + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate_dir(isec, shi->obi->imat); + isec->dist = 1.0f; isec->check = RE_CHECK_VLR_RENDER; isec->skip = RE_SKIP_VLR_NEIGHBOUR; @@ -2528,6 +2523,9 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]) sub_v3_v3v3(isec.dir, lampco, isec.start); isec.dist = normalize_v3(isec.dir); + if (shi->obi->flag & R_ENV_TRANSFORMED) + ray_env_rotate(&isec, shi->obi->imat); + if (isec.mode==RE_RAY_SHADOW_TRA) { /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -2550,51 +2548,3 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]) } -#if 0 -/* only when face points away from lamp, in direction of lamp, trace ray and find first exit point */ -static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float co[3]) -{ - Isect isec; - float lampco[3]; - - assert(0); - - /* setup isec */ - RE_RC_INIT(isec, *shi); - isec.mode= RE_RAY_SHADOW_TRA; - isec.hint = 0; - - if (lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1; - - if (lar->type==LA_SUN || lar->type==LA_HEMI) { - lampco[0]= shi->co[0] - RE_RAYTRACE_MAXDIST*lar->vec[0]; - lampco[1]= shi->co[1] - RE_RAYTRACE_MAXDIST*lar->vec[1]; - lampco[2]= shi->co[2] - RE_RAYTRACE_MAXDIST*lar->vec[2]; - } - else { - copy_v3_v3(lampco, lar->co); - } - - isec.orig.ob = shi->obi; - isec.orig.face = shi->vlr; - - /* set up isec.dir */ - copy_v3_v3(isec.start, shi->co); - copy_v3_v3(isec.end, lampco); - - if (RE_rayobject_raycast(R.raytree, &isec)) { - /* we got a face */ - - /* render co */ - co[0]= isec.start[0]+isec.dist*(isec.dir[0]); - co[1]= isec.start[1]+isec.dist*(isec.dir[1]); - co[2]= isec.start[2]+isec.dist*(isec.dir[2]); - - *distfac= len_v3(isec.dir); - } - else - *distfac= 0.0f; -} - -#endif - -- cgit v1.2.3