Bounding box clipping in the render engine.

Now bounding boxes are computed per object, and checked first before
zbuffering objects. For strands, bounding boxes are computed per
original face in the mesh. Overall the speed improvement from this 
is quite small (zbuffering is rarely the bottleneck), but it seems a
sensible thing to do anyway.
This commit is contained in:
Brecht Van Lommel 2008-01-29 12:20:42 +00:00
parent 5bf5b030e5
commit 8e94028ed5
8 changed files with 211 additions and 97 deletions

@ -780,6 +780,21 @@ void *exec_distribution(void *data)
return 0;
}
/* not thread safe, but qsort doesn't take userdata argument */
static int *COMPARE_ORIG_INDEX = NULL;
static int compare_orig_index(const void *p1, const void *p2)
{
int index1 = COMPARE_ORIG_INDEX[*(const int*)p1];
int index2 = COMPARE_ORIG_INDEX[*(const int*)p2];
if(index1 < index2)
return -1;
else if(index1 == index2)
return 0;
else
return 1;
}
/* creates a distribution of coordinates on a DerivedMesh */
/* */
/* 1. lets check from what we are emitting */
@ -1157,6 +1172,13 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm
MEM_freeN(sum);
/* for hair, sort by origindex, allows optimizations in rendering */
if(part->type == PART_HAIR) {
COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
if(COMPARE_ORIG_INDEX)
qsort(index, totpart, sizeof(int), compare_orig_index);
}
/* weights are no longer used except for FROM_PARTICLE, which needs them zeroed for indexing */
if(from==PART_FROM_PARTICLE){
for(i=0; i<tot; i++)

@ -247,13 +247,15 @@ typedef struct ObjectRen {
struct Scene *sce;
int index, psysindex, flag, lay;
float boundbox[2][3];
int totvert, totvlak, totstrand, tothalo;
int vertnodeslen, vlaknodeslen, strandnodeslen, blohalen;
struct VertTableNode *vertnodes;
struct VlakTableNode *vlaknodes;
struct StrandTableNode *strandnodes;
struct HaloRen **bloha;
ListBase strandbufs;
struct StrandBuffer *strandbuf;
char (*mtface)[32];
char (*mcol)[32];
@ -346,7 +348,7 @@ typedef struct StrandSurface {
int (*face)[4];
float (*co)[3];
/* for occlusion caching */
float (*col)[3]; /* for occlusion */
float (*col)[3];
/* for speedvectors */
float (*prevco)[3], (*nextco)[3];
int totvert, totface;
@ -354,13 +356,14 @@ typedef struct StrandSurface {
typedef struct StrandBound {
int start, end;
float bbox[2][3];
float boundbox[2][3];
} StrandBound;
typedef struct StrandBuffer {
struct StrandBuffer *next, *prev;
struct StrandVert *vert;
int totvert;
struct StrandBound *bound;
int totvert, totbound;
struct ObjectRen *obr;
struct Material *ma;

@ -85,6 +85,7 @@ void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
void set_normalflags(struct Render *re, struct ObjectRen *obr);
void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs, int do_buckets);
int clip_render_object(float boundbox[][3], float *bounds, float mat[][4]);
/* functions are not exported... so wrong names */

@ -93,6 +93,7 @@ typedef struct StrandShadeCache StrandShadeCache;
void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
void render_strand_segment(struct Render *re, float winmat[][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg);
void strand_minmax(struct StrandRen *strand, float *min, float *max);
struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[][4], int timeoffset);
void free_strand_surface(struct Render *re);

@ -111,6 +111,7 @@
#include "strand.h"
#include "texture.h"
#include "sss.h"
#include "strand.h"
#include "zbuf.h"
#ifndef DISABLE_YAFRAY /* disable yafray */
@ -1482,6 +1483,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
ParticleCacheKey *cache=0;
StrandBuffer *strandbuf=0;
StrandVert *svert=0;
StrandBound *sbound= 0;
StrandRen *strand=0;
RNG *rng= 0;
float loc[3],loc1[3],loc0[3],vel[3],mat[4][4],nmat[3][3],co[3],nor[3],time;
@ -1491,6 +1493,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0, dosurfacecache = 0;
int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild;
int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0}, num;
int totface, *origindex = 0;
char **uv_name=0;
/* 1. check that everything is ok & updated */
@ -1653,6 +1656,18 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
else if((re->wrld.mode & WO_AMB_OCC) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
if(ma->amb != 0.0f)
dosurfacecache= 1;
totface= psmd->dm->getNumFaces(psmd->dm);
origindex= psmd->dm->getFaceDataArray(psmd->dm, CD_ORIGINDEX);
if(origindex) {
for(a=0; a<totface; a++)
strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]);
strandbuf->totbound++;
}
strandbuf->totbound++;
strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
sbound= strandbuf->bound;
sbound->start= sbound->end= 0;
}
}
}
@ -1802,6 +1817,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
cache = psys->childcache[a-totpart];
max_k = (int)cache->steps;
}
if(strandbuf) {
if(origindex[cpa->num]+1 > sbound - strandbuf->bound) {
sbound= strandbuf->bound + origindex[cpa->num]+1;
sbound->start= sbound->end= obr->totstrand;
}
}
}
/* surface normal shading setup */
@ -1845,6 +1867,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
}
}
sbound->end++;
}
/* strandco computation setup */
@ -3841,6 +3865,11 @@ static void check_non_flat_quads(ObjectRen *obr)
static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
VertRen *ver= NULL;
StrandRen *strand= NULL;
StrandBound *sbound= NULL;
float min[3], max[3], smin[3], smax[3];
int a, b;
if(obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) {
/* the exception below is because displace code now is in init_render_mesh call,
@ -3858,6 +3887,36 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
check_non_flat_quads(obr);
set_fullsample_flag(re, obr);
/* compute bounding boxes for clipping */
INIT_MINMAX(min, max);
for(a=0; a<obr->totvert; a++) {
if((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
else ver++;
DO_MINMAX(ver->co, min, max);
}
if(obr->strandbuf) {
sbound= obr->strandbuf->bound;
for(b=0; b<obr->strandbuf->totbound; b++, sbound++) {
INIT_MINMAX(smin, smax);
for(a=sbound->start; a<sbound->end; a++) {
strand= RE_findOrAddStrand(obr, a);
strand_minmax(strand, smin, smax);
}
VECCOPY(sbound->boundbox[0], smin);
VECCOPY(sbound->boundbox[1], smax);
DO_MINMAX(smin, min, max);
DO_MINMAX(smax, min, max);
}
}
VECCOPY(obr->boundbox[0], min);
VECCOPY(obr->boundbox[1], max);
}
}
}
@ -4674,7 +4733,7 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
}
if(obr->strandnodes) {
strandbuf= obr->strandbufs.first;
strandbuf= obr->strandbuf;
mesh= (strandbuf)? strandbuf->surface: NULL;
/* compute speed vectors at surface vertices */

@ -711,7 +711,7 @@ StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
strandbuf->totvert= totvert;
strandbuf->obr= obr;
BLI_addtail(&obr->strandbufs, strandbuf);
obr->strandbuf= strandbuf;
return strandbuf;
}
@ -842,9 +842,12 @@ void free_renderdata_tables(Render *re)
obr->strandnodeslen= 0;
}
for(strandbuf=obr->strandbufs.first; strandbuf; strandbuf=strandbuf->next)
strandbuf= obr->strandbuf;
if(strandbuf) {
if(strandbuf->vert) MEM_freeN(strandbuf->vert);
BLI_freelistN(&obr->strandbufs);
if(strandbuf->bound) MEM_freeN(strandbuf->bound);
MEM_freeN(strandbuf);
}
if(obr->mtface)
MEM_freeN(obr->mtface);
@ -1342,13 +1345,11 @@ void RE_makeRenderInstances(Render *re)
re->instancetable= newlist;
}
#if 0
int clip_render_object(ObjectInstanceRen *obi, float *bounds, float winmat[][4])
int clip_render_object(float boundbox[][3], float *bounds, float winmat[][4])
{
float mat[4][4], vec[4], max, min, (*boundbox)[3];
float mat[4][4], vec[4];
int a, fl, flag= -1;
boundbox= obi->obr->boundbox;
Mat4CpyMat4(mat, winmat);
for(a=0; a<8; a++) {
@ -1374,22 +1375,10 @@ int clip_render_object(ObjectInstanceRen *obi, float *bounds, float winmat[][4])
if(vec[2] < -vec[3]) fl |= 16;
if(vec[2] > vec[3]) fl |= 32;
#if 0
max= vec[3];
min= -vec[3];
wco= ho[3];
if(vec[0] < min) fl |= 1;
if(vec[0] > max) fl |= 2;
if(vec[1] < min) fl |= 4;
if(vec[1] > max) fl |= 8;
#endif
flag &= fl;
if(flag==0) return 0;
}
return flag;
}
#endif

@ -750,12 +750,13 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand
ZSpan zspan;
StrandRen *strand=0;
StrandVert *svert;
StrandBound *sbound;
StrandPart spart;
StrandSegment sseg;
StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
MemArena *memarena;
float z[4], bounds[4], winmat[4][4];
int a, b, i, totsegment, clip[4];
int a, b, c, i, totsegment, clip[4];
if(re->test_break())
return 0;
@ -800,58 +801,66 @@ int zbuffer_strands_abuf(Render *re, RenderPart *pa, RenderLayer *rl, APixstrand
sortseg= sortsegments;
totsegment= 0;
/* for all object instances */
for(obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
obr= obi->obr;
if(!obr->strandbuf || !(obr->strandbuf->lay & rl->lay))
continue;
/* compute matrix and try clipping whole object */
if(obi->flag & R_TRANSFORMED)
zbuf_make_winmat(re, obi->mat, winmat);
else
zbuf_make_winmat(re, NULL, winmat);
for(a=0; a<obr->totstrand; a++) {
if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
else strand++;
if(clip_render_object(obi->obr->boundbox, bounds, winmat))
continue;
if(re->test_break())
break;
if(!(strand->buffer->lay & rl->lay))
/* for each bounding box containing a number of strands */
sbound= obr->strandbuf->bound;
for(c=0; c<obr->strandbuf->totbound; c++, sbound++) {
if(clip_render_object(sbound->boundbox, bounds, winmat))
continue;
svert= strand->vert;
/* for each strand in this bounding box */
for(a=sbound->start; a<sbound->end; a++) {
strand= RE_findOrAddStrand(obr, a);
svert= strand->vert;
/* keep clipping and z depth for 4 control points */
clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]);
clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]);
clip[0]= clip[1]; z[0]= z[1];
for(b=0; b<strand->totvert-1; b++, svert++) {
/* compute 4th point clipping and z depth */
if(b < strand->totvert-2) {
clip[3]= strand_test_clip(winmat, &zspan, bounds, (svert+2)->co, &z[3]);
}
else {
clip[3]= clip[2]; z[3]= z[2];
}
/* check clipping and add to sortsegments buffer */
if(!(clip[0] & clip[1] & clip[2] & clip[3])) {
sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
sortseg->obi= i;
sortseg->strand= strand->index;
sortseg->segment= b;
sortseg->z= 0.5f*(z[1] + z[2]);
sortseg->next= firstseg;
firstseg= sortseg;
totsegment++;
}
/* shift clipping and z depth */
/* keep clipping and z depth for 4 control points */
clip[1]= strand_test_clip(winmat, &zspan, bounds, svert->co, &z[1]);
clip[2]= strand_test_clip(winmat, &zspan, bounds, (svert+1)->co, &z[2]);
clip[0]= clip[1]; z[0]= z[1];
clip[1]= clip[2]; z[1]= z[2];
clip[2]= clip[3]; z[2]= z[3];
for(b=0; b<strand->totvert-1; b++, svert++) {
/* compute 4th point clipping and z depth */
if(b < strand->totvert-2) {
clip[3]= strand_test_clip(winmat, &zspan, bounds, (svert+2)->co, &z[3]);
}
else {
clip[3]= clip[2]; z[3]= z[2];
}
/* check clipping and add to sortsegments buffer */
if(!(clip[0] & clip[1] & clip[2] & clip[3])) {
sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
sortseg->obi= i;
sortseg->strand= strand->index;
sortseg->segment= b;
sortseg->z= 0.5f*(z[1] + z[2]);
sortseg->next= firstseg;
firstseg= sortseg;
totsegment++;
}
/* shift clipping and z depth */
clip[0]= clip[1]; z[0]= z[1];
clip[1]= clip[2]; z[1]= z[2];
clip[2]= clip[3]; z[2]= z[3];
}
}
}
}
@ -973,3 +982,12 @@ void free_strand_surface(Render *re)
BLI_freelistN(&re->strandsurface);
}
void strand_minmax(StrandRen *strand, float *min, float *max)
{
StrandVert *svert;
int a;
for(a=0, svert=strand->vert; a<strand->totvert; a++, svert++)
DO_MINMAX(svert->co, min, max)
}

@ -2081,6 +2081,9 @@ void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart*,
else
zbuf_make_winmat(&R, NULL, winmat);
if(clip_render_object(obi->obr->boundbox, bounds, winmat))
continue;
zbuf_project_cache_clear(cache, obr->totvert);
for(v=0; v<obr->totvlak; v++) {
@ -2337,8 +2340,9 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
StrandSegment sseg;
StrandRen *strand= NULL;
StrandVert *svert;
StrandBound *sbound;
float obwinmat[4][4], ho1[4], ho2[4], ho3[4], ho4[4];
int a, b, i, c1, c2, c3, c4, ok=1, lay= -1;
int a, b, c, i, c1, c2, c3, c4, ok=1, lay= -1;
if(lar->mode & LA_LAYER) lay= lar->lay;
@ -2374,6 +2378,9 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
else
Mat4CpyMat4(obwinmat, winmat);
if(clip_render_object(obi->obr->boundbox, NULL, obwinmat))
continue;
zbuf_project_cache_clear(cache, obr->totvert);
/* faces */
@ -2417,45 +2424,54 @@ void zbuffer_shadow(Render *re, float winmat[][4], LampRen *lar, int *rectz, int
}
/* strands */
for(a=0; a<obr->totstrand; a++) {
if((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
else strand++;
if(obr->strandbuf) {
/* for each bounding box containing a number of strands */
sbound= obr->strandbuf->bound;
for(c=0; c<obr->strandbuf->totbound; c++, sbound++) {
if(clip_render_object(sbound->boundbox, NULL, obwinmat))
continue;
sseg.obi= obi;
sseg.buffer= strand->buffer;
sseg.sqadaptcos= sseg.buffer->adaptcos;
sseg.sqadaptcos *= sseg.sqadaptcos;
sseg.strand= strand;
svert= strand->vert;
/* for each strand in this bounding box */
for(a=sbound->start; a<sbound->end; a++) {
strand= RE_findOrAddStrand(obr, a);
/* note, these conditions are copied in shadowbuf_autoclip() */
if(sseg.buffer->ma!= ma) {
ma= sseg.buffer->ma;
ok= 1;
if((ma->mode & MA_SHADBUF)==0) ok= 0;
}
sseg.obi= obi;
sseg.buffer= strand->buffer;
sseg.sqadaptcos= sseg.buffer->adaptcos;
sseg.sqadaptcos *= sseg.sqadaptcos;
sseg.strand= strand;
svert= strand->vert;
if(ok && (sseg.buffer->lay & lay)) {
zbuf_project_cache_clear(cache, strand->totvert);
/* note, these conditions are copied in shadowbuf_autoclip() */
if(sseg.buffer->ma!= ma) {
ma= sseg.buffer->ma;
ok= 1;
if((ma->mode & MA_SHADBUF)==0) ok= 0;
}
for(b=0; b<strand->totvert-1; b++, svert++) {
sseg.v[0]= (b > 0)? (svert-1): svert;
sseg.v[1]= svert;
sseg.v[2]= svert+1;
sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1;
if(ok && (sseg.buffer->lay & lay)) {
zbuf_project_cache_clear(cache, strand->totvert);
c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1);
c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2);
c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3);
c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4);
for(b=0; b<strand->totvert-1; b++, svert++) {
sseg.v[0]= (b > 0)? (svert-1): svert;
sseg.v[1]= svert;
sseg.v[2]= svert+1;
sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1;
if(!(c1 & c2 & c3 & c4))
render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg);
c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1);
c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2);
c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3);
c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4);
if(!(c1 & c2 & c3 & c4))
render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg);
}
}
if((a & 255)==255 && re->test_break())
break;
}
}
if((a & 255)==255 && re->test_break())
break;
}
if(re->test_break())
@ -2599,6 +2615,9 @@ void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(vo
else
zbuf_make_winmat(&R, NULL, winmat);
if(clip_render_object(obi->obr->boundbox, bounds, winmat))
continue;
zbuf_project_cache_clear(cache, obr->totvert);
for(v=0; v<obr->totvlak; v++) {
@ -3286,7 +3305,6 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
/* to center the sample position */
zspan->zofsx -= 0.5f;
zspan->zofsy -= 0.5f;
}
/* we use this to test if nothing was filled in */
@ -3303,6 +3321,9 @@ static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, un
else
zbuf_make_winmat(&R, NULL, winmat);
if(clip_render_object(obi->obr->boundbox, bounds, winmat))
continue;
zbuf_project_cache_clear(cache, obr->totvert);
for(v=0; v<obr->totvlak; v++) {