[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17316] branches/projection-paint/source/ blender/src/imagepaint.c: optional uv seem bleed so painting across seams wont give artifacts ( like with baking), no UI yet, set to 2 by default.

Campbell Barton ideasman42 at gmail.com
Tue Nov 4 06:29:37 CET 2008


Revision: 17316
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17316
Author:   campbellbarton
Date:     2008-11-04 06:29:36 +0100 (Tue, 04 Nov 2008)

Log Message:
-----------
optional uv seem bleed so painting across seams wont give artifacts (like with baking), no UI yet, set to 2 by default.

Does not work yet with perspective view yet, there are still some issue with pixel alignment.

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-11-04 05:17:02 UTC (rev 17315)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-04 05:29:36 UTC (rev 17316)
@@ -185,7 +185,7 @@
 	short projectIsOcclude;		/* Use raytraced occlusion? - ortherwise will paint right through to the back*/
 	short projectIsBackfaceCull;	/* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
 	short projectIsOrtho;
-	short projectIsSeamBleed;
+	float projectSeamBleed;
 	
 	float projectMat[4][4];		/* Projection matrix, use for getting screen coords */
 	float viewMat[4][4];
@@ -369,7 +369,6 @@
 
 static int project_paint_BucketOffset(ProjectPaintState *ps, float *projCo2D)
 {
-	
 	/* If we were not dealing with screenspace 2D coords we could simple do...
 	 * ps->projectBuckets[x + (y*ps->bucketsY)] */
 	
@@ -650,23 +649,265 @@
 static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
 {
 	if (is_quad) {
-		ps->projectFaceFlags[face_index] = 
+		ps->projectFaceFlags[face_index] |= 
 			(check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
 			(check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
 			(check_seam(ps, face_index, 2,3) ? PROJ_FACE_SEAM3 : 0) |
 			(check_seam(ps, face_index, 3,0) ? PROJ_FACE_SEAM4 : 0);
 	} else {
-		ps->projectFaceFlags[face_index] = 
+		ps->projectFaceFlags[face_index] |= 
 			(check_seam(ps, face_index, 0,1) ? PROJ_FACE_SEAM1 : 0) |
 			(check_seam(ps, face_index, 1,2) ? PROJ_FACE_SEAM2 : 0) |
 			(check_seam(ps, face_index, 2,0) ? PROJ_FACE_SEAM3 : 0);
 	}
 }
 
+static float angleToLength(float angle)
+{
+	float x,y, fac;
+	
+	// Alredy accounted for
+	if (angle < 0.000001)
+		return 1.0;
+	
+	angle = (2.0*M_PI/360.0) * angle;
+	x = cos(angle);
+	y = sin(angle);
+	
+	// print "YX", x,y
+	// 0 d is hoz to the right.
+	// 90d is vert upward.
+	fac = 1.0/x;
+	x = x*fac;
+	y = y*fac;
+	return sqrt((x*x)+(y*y));
+}
+
+/* return zero if there is no area in the returned rectangle */
+static int uv_image_rect(float *uv1, float *uv2, float *uv3, float *uv4, int *min_px, int *max_px, int x_px, int y_px, int is_quad)
+{
+	float min_uv[2], max_uv[2]; /* UV bounds */
+	int i;
+	
+	INIT_MINMAX2(min_uv, max_uv);
+	
+	DO_MINMAX2(uv1, min_uv, max_uv);
+	DO_MINMAX2(uv2, min_uv, max_uv);
+	DO_MINMAX2(uv3, min_uv, max_uv);
+	if (is_quad)
+		DO_MINMAX2(uv4, min_uv, max_uv);
+	
+	min_px[0] = (int)(x_px * min_uv[0]);
+	min_px[1] = (int)(y_px * min_uv[1]);
+	
+	max_px[0] = (int)(x_px * max_uv[0]) +1;
+	max_px[1] = (int)(y_px * max_uv[1]) +1;
+	
+	/*printf("%d %d %d %d \n", min_px[0], min_px[1], max_px[0], max_px[1]);*/
+	CLAMP(min_px[0], 0, x_px);
+	CLAMP(max_px[0], 0, x_px);
+	
+	CLAMP(min_px[1], 0, y_px);
+	CLAMP(max_px[1], 0, y_px);
+	
+	/* face uses no UV area when quantized to pixels? */
+	return (min_px[0] == max_px[0] || min_px[1] == max_px[1]) ? 0 : 1;
+}
+
+/* takes a faces UV's and assigns outset coords to outset_uv */
+static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float scaler, int x_px, int y_px, int is_quad)
+{
+	float a1,a2,a3,a4=0.0;
+	float puv[4][2]; /* pixelspace uv's */
+	float no1[2], no2[2], no3[2], no4[2]; /* normals */
+	float dir1[2], dir2[2], dir3[2], dir4[2];
+	
+	/* make UV's in pixel space so we can */
+	puv[0][0] = orig_uv[0][0] * x_px;
+	puv[0][1] = orig_uv[0][1] * y_px;
+	
+	puv[1][0] = orig_uv[1][0] * x_px;
+	puv[1][1] = orig_uv[1][1] * y_px;
+	
+	puv[2][0] = orig_uv[2][0] * x_px;
+	puv[2][1] = orig_uv[2][1] * y_px;
+	
+	if (is_quad) {
+		puv[3][0] = orig_uv[3][0] * x_px;
+		puv[3][1] = orig_uv[3][1] * y_px;
+	}
+	
+	/* face edge directions */
+	Vec2Subf(dir1, puv[1], puv[0]);
+	Vec2Subf(dir2, puv[2], puv[1]);
+	Normalize2(dir1);
+	Normalize2(dir2);
+	
+	if (is_quad) {
+		Vec2Subf(dir3, puv[3], puv[2]);
+		Vec2Subf(dir4, puv[0], puv[3]);
+		Normalize2(dir3);
+		Normalize2(dir4);
+	} else {
+		Vec2Subf(dir3, puv[0], puv[2]);
+		Normalize2(dir3);
+	}
+	
+	if (is_quad) {
+		a1 = NormalizedVecAngle2_2D(dir4, dir1);
+		a2 = NormalizedVecAngle2_2D(dir1, dir2);
+		a3 = NormalizedVecAngle2_2D(dir2, dir3);
+		a4 = NormalizedVecAngle2_2D(dir3, dir4);
+	} else {
+		a1 = NormalizedVecAngle2_2D(dir3, dir1);
+		a2 = NormalizedVecAngle2_2D(dir1, dir2);
+		a3 = NormalizedVecAngle2_2D(dir2, dir3);
+	}
+	
+	a1 = angleToLength(a1);
+	a2 = angleToLength(a2);
+	a3 = angleToLength(a3);
+	if (is_quad)
+		a4 = angleToLength(a4);
+	
+	if (is_quad) {
+		Vec2Subf(no1, dir4, dir1);
+		Vec2Subf(no2, dir1, dir2);
+		Vec2Subf(no3, dir2, dir3);
+		Vec2Subf(no4, dir3, dir4);
+		Normalize2(no1);
+		Normalize2(no2);
+		Normalize2(no3);
+		Normalize2(no4);
+		Vec2Mulf(no1, a1*scaler);
+		Vec2Mulf(no2, a2*scaler);
+		Vec2Mulf(no3, a3*scaler);
+		Vec2Mulf(no4, a4*scaler);
+		Vec2Addf(outset_uv[0], puv[0], no1);
+		Vec2Addf(outset_uv[1], puv[1], no2);
+		Vec2Addf(outset_uv[2], puv[2], no3);
+		Vec2Addf(outset_uv[3], puv[3], no4);
+		outset_uv[0][0] /= x_px;
+		outset_uv[0][1] /= y_px;
+		
+		outset_uv[1][0] /= x_px;
+		outset_uv[1][1] /= y_px;
+		
+		outset_uv[2][0] /= x_px;
+		outset_uv[2][1] /= y_px;
+		
+		outset_uv[3][0] /= x_px;
+		outset_uv[3][1] /= y_px;
+	} else {
+		Vec2Subf(no1, dir3, dir1);
+		Vec2Subf(no2, dir1, dir2);
+		Vec2Subf(no3, dir2, dir3);
+		Normalize2(no1);
+		Normalize2(no2);
+		Normalize2(no3);
+		Vec2Mulf(no1, a1*scaler);
+		Vec2Mulf(no2, a2*scaler);
+		Vec2Mulf(no3, a3*scaler);
+		Vec2Addf(outset_uv[0], puv[0], no1);
+		Vec2Addf(outset_uv[1], puv[1], no2);
+		Vec2Addf(outset_uv[2], puv[2], no3);
+		outset_uv[0][0] /= x_px;
+		outset_uv[0][1] /= y_px;
+		
+		outset_uv[1][0] /= x_px;
+		outset_uv[1][1] /= y_px;
+		
+		outset_uv[2][0] /= x_px;
+		outset_uv[2][1] /= y_px;
+	}
+}
+
+/* TODO - move to arithb.c */
+
+/* little sister we only need to know lambda */
+static float lambda_cp_line2(float p[2], float l1[2], float l2[2])
+{
+	float h[2],u[2];
+	Vec2Subf(u, l2, l1);
+	Vec2Subf(h, p, l1);
+	return(Inp2f(u,h)/Inp2f(u,u));
+}
+
+
+#define pixel_size 4
+static void project_paint_uvpixel_init(
+		ProjectPaintState *ps, ProjectScanline *sc, ImBuf *ibuf, float *uv,
+		float *v1co, float *v2co, float *v3co,
+		float *uv1co, float *uv2co, float *uv3co,
+		int x, int y, int face_index,
+		float *pixelScreenCo /* can provide own own coords, use for seams when we want to bleed our from the original location */
+) {
+	float pixelScreenCo_own[3]; /* for testing occlusion we need the depth too, but not for saving into ProjectPixel */
+	int bucket_index;
+	
+	ProjectPixel *projPixel;
+	
+	
+	/* pixelScreenCo not provided? - calculate our own */
+	if (pixelScreenCo==NULL) {
+		float w1, w2, w3, wtot; /* weights for converting the pixel into 3d worldspace coords */
+
+		pixelScreenCo = pixelScreenCo_own;
+		/* Get the world coord for the point in uv space */
+		if (ps->projectIsOrtho) {
+			w1 = AreaF2Dfl(uv2co, uv3co, uv);
+			w2 = AreaF2Dfl(uv3co, uv1co, uv);
+			w3 = AreaF2Dfl(uv1co, uv2co, uv);
+		} else { /* prespective mode needs an interpolation */
+			w1 = AreaF2Dfl(uv2co, uv3co, uv) / v1co[2];
+			w2 = AreaF2Dfl(uv3co, uv1co, uv) / v2co[2];
+			w3 = AreaF2Dfl(uv1co, uv2co, uv) / v3co[2];
+		}
+		
+		wtot = w1 + w2 + w3;
+		w1 /= wtot; w2 /= wtot; w3 /= wtot;
+		
+		pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
+		pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
+		pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;
+	}
+	
+	bucket_index = project_paint_BucketOffset(ps, pixelScreenCo);
+	
+	/* even though it should be clamped, in some cases it can still run over */
+	if (bucket_index < 0 || bucket_index >= ps->bucketsX * ps->bucketsY)
+		return;
+	
+	/* Use viewMin2D to make (0,0) the bottom left of the bounds 
+	 * Then this can be used to index the bucket array */
+	
+	/* Is this UV visible from the view? - raytrace */
+	if (ps->projectIsOcclude==0 || !project_bucket_point_occluded(ps, bucket_index, face_index, pixelScreenCo)) {
+		/* done with view3d_project_float inline */
+		projPixel = (ProjectPixel *)BLI_memarena_alloc( ps->projectArena, sizeof(ProjectPixel) );
+		
+		/* screenspace unclamped */
+		VECCOPY2D(projPixel->projCo2D, pixelScreenCo);
+		
+		projPixel->pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * pixel_size);
+		
+#ifdef PROJ_DEBUG_PAINT
+		projPixel->pixel[1] = 0;
+#endif
+		projPixel->image_index = ps->image_index;
+		
+		BLI_linklist_prepend_arena(
+			&ps->projectBuckets[ bucket_index ],
+			projPixel,
+			ps->projectArena
+		);
+	}
+}
+
 static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf *ibuf)
 {
 	/* Projection vars, to get the 3D locations into screen space  */
-	ProjectPixel *projPixel;
+	
 	MFace *mf = ps->dm_mface + face_index;
 	MTFace *tf = ps->dm_mtface + face_index;
 	
@@ -674,11 +915,10 @@
 	int x; /* Image X-Pixel */
 	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 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 */
+	
+	int min_px[2], max_px[2]; /* UV Bounds converted to int's for pixel */
 	float *v1co, *v2co, *v3co; /* for convenience only, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
+	float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
 	int i, j;
 	
 	/* scanlines since quads can have 2 triangles intersecting the same vertical location */
@@ -686,102 +926,185 @@
 	ProjectScanline *sc;
 	int totscanlines; /* can only be 1 or 2, oh well */
 	
-	float pixelScreenCo[3]; /* for testing occlusion we need the depth too, but not for saving into ProjectPixel */
-	int bucket_index;
-	
-	
-	INIT_MINMAX2(min_uv, max_uv);
-	
-	i = mf->v4 ? 3:2;
-	do {
-		DO_MINMAX2(tf->uv[i], min_uv, max_uv);
-	} while (i--);
-	
-	xmini = (int)(ibuf->x * min_uv[0]);
-	ymini = (int)(ibuf->y * min_uv[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);*/
-	CLAMP(xmini, 0, ibuf->x);
-	CLAMP(xmaxi, 0, ibuf->x);
-	
-	CLAMP(ymini, 0, ibuf->y);
-	CLAMP(ymaxi, 0, ibuf->y);
-	
-	/* face uses no UV area when quanticed to pixels? */

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list