Revision: 17247
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17247
Author:   campbellbarton
Date:     2008-10-31 18:12:45 +0100 (Fri, 31 Oct 2008)

Log Message:
-----------
speedup occlusion by removing octree raytracing method and use the bucket's 
face list.

Modified Paths:
--------------
    branches/projection-paint/source/blender/src/imagepaint.c

Modified: branches/projection-paint/source/blender/src/imagepaint.c
===================================================================
--- branches/projection-paint/source/blender/src/imagepaint.c   2008-10-31 
16:33:42 UTC (rev 17246)
+++ branches/projection-paint/source/blender/src/imagepaint.c   2008-10-31 
17:12:45 UTC (rev 17247)
@@ -88,8 +88,6 @@
 #include "BDR_imagepaint.h"
 #include "BDR_vpaint.h"
 
-#include "RE_raytrace.h" /* For projection painting occlusion */
-
 #include "GPU_draw.h"
 
 #include "GHOST_Types.h"
@@ -136,7 +134,6 @@
 /* testing options */
 #define PROJ_BUCKET_DIV 128 /* TODO - test other values, this is a guess, 
seems ok */
 
-#define PROJ_LAZY_INIT 1
 // #define PROJ_PAINT_DEBUG 1
 
 /* projectFaceFlags options */
@@ -167,11 +164,10 @@
        /* projection painting only */
        MemArena *projectArena;         /* use for alocating many pixel structs 
and link-lists */
        LinkNode **projectBuckets;      /* screen sized 2D array, each pixel 
has a linked list of ImagePaintProjectPixel's */
-#ifdef PROJ_LAZY_INIT
        LinkNode **projectFaces;        /* projectBuckets alligned array 
linkList of faces overlapping each bucket */
        char *projectBucketFlags;       /* store if the bucks have been 
initialized  */
        char *projectFaceFlags;         /* store info about faces, if they are 
initialized etc*/
-#endif
+       
        int bucketsX;                           /* The size of the bucket grid, 
the grid span's viewMin2D/viewMax2D so you can paint outsize the screen or with 
2 brushes at once */
        int bucketsY;
        
@@ -179,27 +175,20 @@
        int projectImageTotal;          /* size of projectImages array */
        int image_index;                        /* current image, use for 
context switching */
        
-       float (*projectVertCos2D)[2];   /* verts projected into floating point 
screen space */
+       float (*projectVertScreenCos)[3];       /* verts projected into 
floating point screen space */
        
-       RayTree *projectRayTree;        /* ray tracing acceleration structure */
-       Isect isec;                                     /* re-use ray 
intersection var */
-       
        /* options for projection painting */
        short projectOcclude;           /* Use raytraced occlusion? - 
ortherwise will paint right through to the back*/
        short projectBackfaceCull;      /* ignore faces with normals pointing 
away, skips a lot of raycasts if your normals are correctly flipped */
        
        float projectMat[4][4];         /* Projection matrix, use for getting 
screen coords */
        float viewMat[4][4];
-       float viewPoint[3];                     /* Use only when in perspective 
mode with projectOcclude, the point we are viewing from, cast rays to this */
        float viewDir[3];                       /* View vector, use for 
projectBackfaceCull and for ray casting with an ortho viewport  */
        
        float viewMin2D[2];                     /* 2D bounds for mesh verts on 
the screen's plane (screenspace) */
        float viewMax2D[2]; 
        float viewWidth;                        /* Calculated from viewMin2D & 
viewMax2D */
        float viewHeight;
-       
-       
-       
 } ProjectPaintState;
 
 typedef struct ImagePaintProjectPixel {
@@ -367,21 +356,6 @@
 }
 
 
-static MVert * mvert_static = NULL;
-static void project_paint_begin_coords_func(RayFace *face, float **v1, float 
**v2, float **v3, float **v4)
-{
-       MFace *mface= (MFace*)face;
-
-       *v1= mvert_static[mface->v1].co;
-       *v2= mvert_static[mface->v2].co;
-       *v3= mvert_static[mface->v3].co;
-       *v4= (mface->v4)? mvert_static[mface->v4].co: NULL;
-}
-
-static int project_paint_begin_check_func(Isect *is, int ob, RayFace *face)
-{
-       return 1;
-}
 static int project_paint_BucketOffset(ProjectPaintState *ps, float *projCo2D)
 {
        
@@ -399,10 +373,107 @@
                (       (       (int)(( (projCo2D[1] - ps->viewMin2D[1])  / 
ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
 }
 
-static void project_paint_face_init(ProjectPaintState *ps, MFace *mf, MTFace 
*tf, ImBuf *ibuf)
+/* return...
+ * 0   : no occlusion
+ * -1  : no occlusion but 2D intersection is true (avoid testing the other 
half of a quad)
+ * 1   : occluded */
+
+static int screenco_tri_pt_occlude(float *pt, float *v1, float *v2, float *v3)
 {
+       float w1, w2, w3, wtot; /* weights for converting the pixel into 3d 
worldspace coords */
+       
+       /* if all are behind us, return false */
+       if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
+               return 0;
+               
+       /* do a 2D point in try intersection */
+       if ( !IsectPT2Df(pt, v1, v2, v3) )
+               return 0; /* we know there is  */
+       
+       /* From here on we know there IS an intersection */
+       
+       /* if ALL of the verts are infront of us then we know it intersects ? */
+       if(     v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
+               return 1;
+       } else {
+               /* we intersect? - find the exact depth at the point of 
intersection */
+               w1 = AreaF2Dfl(v2, v3, pt);
+               w2 = AreaF2Dfl(v3, v1, pt);
+               w3 = AreaF2Dfl(v1, v2, pt);
+               wtot = w1 + w2 + w3;
+               
+               if ((v1[2]*w1/wtot) + (v2[2]*w2/wtot) + (v3[2]*w3/wtot) < 
pt[2]) {
+                       return 1; /* This point is occluded by another face */
+               }
+       }
+       return -1;
+}
+
+
+/* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be 
used for comparison */
+static int project_bucket_point_occluded(ProjectPaintState *ps, int 
bucket_index, int orig_face, float pixelScreenCo[3])
+{
+       LinkNode *node = ps->projectFaces[bucket_index];
+       LinkNode *prev_node = NULL;
+       MFace *mf;
+       int face_index;
+       int isect_ret;
+       
+       while (node) {
+               face_index = (int)node->link;
+               
+               if (orig_face != face_index) {
+                       
+                       mf = ps->dm_mface + face_index;
+                       
+                       isect_ret = screenco_tri_pt_occlude(
+                                       pixelScreenCo,
+                                       ps->projectVertScreenCos[mf->v1],
+                                       ps->projectVertScreenCos[mf->v2],
+                                       ps->projectVertScreenCos[mf->v3]);
+                       
+                       /* Note, if isect_ret==-1 then we dont want to test the 
other side of the quad */
+                       if (isect_ret==0 && mf->v4) {
+                               isect_ret = screenco_tri_pt_occlude(
+                                               pixelScreenCo,
+                                               
ps->projectVertScreenCos[mf->v1],
+                                               
ps->projectVertScreenCos[mf->v3],
+                                               
ps->projectVertScreenCos[mf->v4]);
+                       }
+                       
+                       if (isect_ret==1) {
+                               /* Cheap Optimization!
+                                * This function runs for every UV Screen pixel,
+                                * therefor swapping the swapping the faces for 
this buckets list helps because
+                                * the next ~5 to ~200 runs will can hit the 
first face each time. */
+                               if (ps->projectFaces[bucket_index] != node) {
+                                       /* SWAP(void *, 
ps->projectFaces[bucket_index]->link, node->link); */
+                                       
+                                       /* dont need to use swap since we 
alredy have face_index */
+                                       node->link = 
ps->projectFaces[bucket_index]->link; /* move the value item to the current 
value */
+                                       ps->projectFaces[bucket_index]->link = 
(void *) face_index;
+                                       
+                                       /*printf("swapping %d %d\n", 
(int)node->link, face_index);*/
+                               } /*else {
+                                       printf("first hit %d\n", face_index);
+                               }*/
+                               
+                               return 1; 
+                       }
+               }
+               prev_node = node;
+               node = node->next;
+       }
+       
+       return 0;
+}
+
+static void project_paint_face_init(ProjectPaintState *ps, int face_index, 
ImBuf *ibuf)
+{
        /* Projection vars, to get the 3D locations into screen space  */
        ImagePaintProjectPixel *projPixel;
+       MFace *mf = ps->dm_mface + face_index;
+       MTFace *tf = ps->dm_mtface + face_index;
        
        float pxWorldCo[3];
        float pxProjCo[4];
@@ -412,31 +483,25 @@
        int y;/* Image Y-Pixel */
        float uv[2]; /* Image floating point UV - same as x,y but from 0.0-1.0 
*/
        int pixel_size = 4;     /* each pixel is 4 x 8-bits packed in unsigned 
int */
-       float xmin, ymin, xmax, ymax; /* UV bounds */
+       float min_uv[2], max_uv[2]; /* UV bounds */
        int xmini, ymini, xmaxi, ymaxi; /* UV Bounds converted to int's for 
pixel */
        float w1, w2, w3, wtot; /* weights for converting the pixel into 3d 
worldspace coords */
        float *v1co, *v2co, *v3co, *v4co; /* for convenience only */
        
        int i;
        
-       /* clamp to 0-1 for now */
-       xmin = ymin = 1.0f;
-       xmax = ymax = 0.0f;
+       INIT_MINMAX2(min_uv, max_uv);
        
        i = mf->v4 ? 3:2;
        do {
-               xmin = MIN2(xmin, tf->uv[i][0]);
-               ymin = MIN2(ymin, tf->uv[i][1]);
-               
-               xmax = MAX2(xmax, tf->uv[i][0]);
-               ymax = MAX2(ymax, tf->uv[i][1]);
+               DO_MINMAX2(tf->uv[i], min_uv, max_uv);
        } while (i--);
        
-       xmini = (int)(ibuf->x * xmin);
-       ymini = (int)(ibuf->y * ymin);
+       xmini = (int)(ibuf->x * min_uv[0]);
+       ymini = (int)(ibuf->y * min_uv[1]);
        
-       xmaxi = (int)(ibuf->x * xmax) +1;
-       ymaxi = (int)(ibuf->y * ymax) +1;
+       xmaxi = (int)(ibuf->x * max_uv[0]) +1;
+       ymaxi = (int)(ibuf->y * max_uv[1]) +1;
        
        /*printf("%d %d %d %d \n", xmini, ymini, xmaxi, ymaxi);*/
        
@@ -458,6 +523,10 @@
        
        for (y = ymini; y < ymaxi; y++) {
                uv[1] = (((float)y)+0.5) / (float)ibuf->y;
+
+               /* IsectPT2Df works fine but is too slow
+                * rather then IsectPT2Df's all the time we can do somthing 
more like scanlines */
+
                for (x = xmini; x < xmaxi; x++) {
                        uv[0] = (((float)x)+0.5) / (float)ibuf->x;
                        
@@ -491,43 +560,39 @@
                                        pxWorldCo[i] = v1co[i]*w1 + v3co[i]*w2 
+ v4co[i]*w3;
                                } while (i--);
                        }
-                       
+
                        /* view3d_project_float(curarea, vec, projCo2D, 
s->projectMat);
                        if (projCo2D[0]==IS_CLIPPED)
                                continue;*/
                        if (wtot != -1.0) {
-                               
                                /* Inline, a bit faster */
                                VECCOPY(pxProjCo, pxWorldCo);
                                pxProjCo[3] = 1.0;
                                
                                Mat4MulVec4fl(ps->projectMat, pxProjCo);
                                
+
                                if( pxProjCo[3] > 0.001 ) {
+                                       float pixelScreenCo[3]; /* for testing 
occlusion we need the depth too, but not for saving into ImagePaintProjectPixel 
*/
+                                       int bucket_index;
+                                       
+                                       pixelScreenCo[0] = 
(float)(curarea->winx/2.0)+(curarea->winx/2.0)*pxProjCo[0]/pxProjCo[3];
+                                       pixelScreenCo[1] = 
(float)(curarea->winy/2.0)+(curarea->winy/2.0)*pxProjCo[1]/pxProjCo[3];
+                                       pixelScreenCo[2] = 
pxProjCo[2]/pxProjCo[3]; /* Only for depth test */
+                                       
+                                       bucket_index = 
project_paint_BucketOffset(ps, pixelScreenCo);
+                                       
                                        /* Use viewMin2D to make (0,0) the 
bottom left of the bounds 
                                         * Then this can be used to index the 
bucket array */
                                        
-                                       if (ps->projectOcclude) {
-                                               VECCOPY(ps->isec.start, 
pxWorldCo);
-                                               
-                                               if (G.vd->persp==V3D_ORTHO) {
-                                                       VecAddf(ps->isec.end, 
pxWorldCo, ps->viewDir);
-                                               } else { /* value dosnt change 
but it is modified by RE_ray_tree_intersect() - keep this line */
-                                                       VECCOPY(ps->isec.end, 
ps->viewPoint);
-                                               }
-
-                                               ps->isec.faceorig = mf;
-                                       }
-                                       
                                        /* Is this UV visible from the view? - 
raytrace */
-                                       if (ps->projectOcclude==0 || 
!RE_ray_tree_intersect(ps->projectRayTree, &ps->isec)) {
+                                       if (ps->projectOcclude==0 || 
!project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
                                                
                                                /* done with 
view3d_project_float inline */
                                                projPixel = 
(ImagePaintProjectPixel *)BLI_memarena_alloc( ps->projectArena, 
sizeof(ImagePaintProjectPixel) );
                                                
                                                /* screenspace unclamped */

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to