[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