[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17247] branches/projection-paint/source/ blender/src/imagepaint.c: speedup occlusion by removing octree raytracing method and use the bucket' s face list.
Campbell Barton
ideasman42 at gmail.com
Fri Oct 31 18:12:46 CET 2008
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. @@
More information about the Bf-blender-cvs
mailing list