Bugreport #4787 mentioned subpixel render issues, especially for small

images (like used for rendering icons).

When working during Orange on new render pipeline, I've left this topic
alone for a while... subpixel precision testing is very time consuming and
needs concentration for a while. :)

This commit brings back precision as it was for 2.41. Below a short
explanation of the solved issues.

- the window matrix for rendering is kept constant during all OSA passes,
  this to ensure clipping happens for each pass identically.
- a subpixel offset is only applied on filling in the z-buffer
- this offset is inverse corrected for shadepixel code, only on 2 places

Another nasty issue is that for filtered rendering (gauss etc), the tiles
(or entire image) is temporally increased 2 pixel in size. This caused a
'dark' (or sky color) edge on the rendering. During Orange that was solved
with a hardcoded clipping offset value, which only corrected for larger
pictures (like > 500 pixels in size).
Now this clipping offset is correctly calculated, based on render size.

Last issue: the view border in 3d window was calculated using integers,
giving small errors in display too. Now it uses float, so visually the
view border is more close to what a render shows.
This commit is contained in:
2006-08-12 11:27:00 +00:00
parent 3be0a5ad70
commit e47137ff42
8 changed files with 49 additions and 40 deletions

View File

@@ -35,7 +35,7 @@
struct Object;
struct BGpic;
struct rcti;
struct rctf;
struct ScrArea;
struct ImBuf;
@@ -61,7 +61,7 @@ void drawview3dspace(struct ScrArea *sa, void *spacedata);
void drawview3d_render(struct View3D *v3d, int winx, int winy);
int update_time(void);
void calc_viewborder(struct View3D *v3d, struct rcti *viewborder_r);
void calc_viewborder(struct View3D *v3d, struct rctf *viewborder_r);
void view3d_set_1_to_1_viewborder(struct View3D *v3d);
int view3d_test_clipping(struct View3D *v3d, float *vec);

View File

@@ -108,6 +108,7 @@ struct Render
rcti disprect; /* part within winx winy */
rctf viewplane; /* mapped on winx winy */
float viewdx, viewdy; /* size of 1 pixel */
float clipcrop; /* 2 pixel boundary to prevent clip when filter used */
/* final picture width and height (within disprect) */
int rectx, recty;
@@ -120,7 +121,6 @@ struct Render
/* values for viewing */
float lens, ycor, viewfac;
float bluroffsx, bluroffsy;
float panophi, panosi, panoco, panodxp, panodxv;
/* Matrices */

View File

@@ -456,8 +456,6 @@ void RE_SetCamera(Render *re, Object *camera)
rctf viewplane;
float pixsize, clipsta, clipend;
float lens;
float xd, yd;
int blursample= 0; /* make new call for that */
/* question mark */
re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp);
@@ -541,18 +539,12 @@ void RE_SetCamera(Render *re, Object *camera)
viewplane.ymax+= .5*re->ycor;
}
}
xd= yd= 0.0;
if(blursample != -1 && re->osa != 0 ) {
re->bluroffsx= xd= re->jit[blursample % re->osa][0];
re->bluroffsy= yd= re->ycor*re->jit[blursample % re->osa][1];
}
else re->bluroffsx=re->bluroffsy= 0.0f;
viewplane.xmin= pixsize*(viewplane.xmin+xd);
viewplane.xmax= pixsize*(viewplane.xmax+xd);
viewplane.ymin= pixsize*(viewplane.ymin+yd);
viewplane.ymax= pixsize*(viewplane.ymax+yd);
/* the window matrix is used for clipping, and not changed during OSA steps */
/* using an offset of +0.5 here would give clip errors on edges */
viewplane.xmin= pixsize*(viewplane.xmin);
viewplane.xmax= pixsize*(viewplane.xmax);
viewplane.ymin= pixsize*(viewplane.ymin);
viewplane.ymax= pixsize*(viewplane.ymax);
re->viewdx= pixsize;
re->viewdy= re->ycor*pixsize;
@@ -562,7 +554,8 @@ void RE_SetCamera(Render *re, Object *camera)
else
RE_SetWindow(re, &viewplane, clipsta, clipend);
//printmatrix4("win", re->winmat);
/* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
re->clipcrop= 1.0f + 2.0f/(float)(re->winx>re->winy?re->winy:re->winx);
}

View File

@@ -2453,8 +2453,8 @@ void *shadepixel(ShadePixelInfo *shpi, float x, float y, int z, volatile int fac
float fx= 2.0/(R.winx*R.winmat[0][0]);
float fy= 2.0/(R.winy*R.winmat[1][1]);
shi.co[0]= (0.5 + x - 0.5*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
shi.co[1]= (0.5 + y - 0.5*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
shi.co[0]= (x - 0.5*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
shi.co[1]= (y - 0.5*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
/* using a*x + b*y + c*z = d equation, (a b c) is normal */
if(shi.facenor[2]!=0.0f)
@@ -2675,8 +2675,8 @@ void *shadepixel(ShadePixelInfo *shpi, float x, float y, int z, volatile int fac
float fx= 2.0/(R.rectx*R.winmat[0][0]);
float fy= 2.0/(R.recty*R.winmat[1][1]);
shi.co[0]= (0.5 + x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0];
shi.co[1]= (0.5 + y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1];
shi.co[0]= (x - 0.5*R.rectx)*fx - R.winmat[3][0]/R.winmat[0][0];
shi.co[1]= (y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1];
}
calc_view_vector(shi.view, x, y);
@@ -2697,6 +2697,10 @@ static void shadepixel_sky(ShadePixelInfo *shpi, float x, float y, int z, int fa
VlakRen *vlr;
float collector[4], rco[3];
/* correction back for zbuffer filling in */
x+= 0.5f;
y+= 0.5f;
vlr= shadepixel(shpi, x, y, z, facenr, mask, rco);
if(shpi->shr.combined[3] != 1.0) {

View File

@@ -1307,8 +1307,8 @@ static void clippyra(float *labda, float *v1, float *v2, int *b2, int *b3, int a
v13= v1[3];
}
else {
dw= 1.005f*(v2[3]-v1[3]);
v13= 1.005f*v1[3];
dw= R.clipcrop*(v2[3]-v1[3]);
v13= R.clipcrop*v1[3];
}
/* according the original article by Liang&Barsky, for clipping of
* homogenous coordinates with viewplane, the value of "0" is used instead of "-w" .
@@ -1527,7 +1527,6 @@ void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1,
hoco_to_zco(zspan, vez, f1);
hoco_to_zco(zspan, vez+4, f2);
hoco_to_zco(zspan, vez+8, f3);
zspan->zbuffunc(zspan, zvlnr, vez,vez+4,vez+8, NULL);
}
@@ -1628,6 +1627,7 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag)
/* needed for transform from hoco to zbuffer co */
zspan.zmulx= ((float)R.winx)/2.0;
zspan.zmuly= ((float)R.winy)/2.0;
if(R.osa) {
zspan.zofsx= -pa->disprect.xmin - R.jit[pa->sample][0];
zspan.zofsy= -pa->disprect.ymin - R.jit[pa->sample][1];
@@ -1640,6 +1640,9 @@ void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag)
zspan.zofsx= -pa->disprect.xmin;
zspan.zofsy= -pa->disprect.ymin;
}
/* to centre the sample position */
zspan.zofsx -= 0.5f;
zspan.zofsy -= 0.5f;
/* the buffers */
zspan.rectz= pa->rectz;
@@ -1752,8 +1755,8 @@ void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem, Re
zbuf_alloc_span(&zspan, vw->rectx, vw->recty);
zspan.zmulx= ((float)vw->rectx)/2.0;
zspan.zmuly= ((float)vw->recty)/2.0;
zspan.zofsx= 0;
zspan.zofsy= 0;
zspan.zofsx= -0.5f;
zspan.zofsy= -0.5f;
/* the buffers */
zspan.rectz= vw->rectz;
@@ -2409,8 +2412,6 @@ static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, u
/* needed for transform from hoco to zbuffer co */
zspan.zmulx= ((float)R.winx)/2.0;
zspan.zmuly= ((float)R.winy)/2.0;
zspan.zofsx= -pa->disprect.xmin;
zspan.zofsy= -pa->disprect.ymin;
/* the buffers */
zspan.arectz= MEM_mallocT(sizeof(int)*pa->rectx*pa->recty, "Arectz");
@@ -2430,13 +2431,20 @@ static void zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, u
zspan.mask= 1<<zsample;
if(R.osa) {
zspan.zofsx= -pa->disprect.xmin-R.jit[zsample][0];
zspan.zofsy= -pa->disprect.ymin-R.jit[zsample][1];
zspan.zofsx= -pa->disprect.xmin - R.jit[zsample][0];
zspan.zofsy= -pa->disprect.ymin - R.jit[zsample][1];
}
else if(R.i.curblur) {
zspan.zofsx= -pa->disprect.xmin - R.jit[R.i.curblur-1][0];
zspan.zofsy= -pa->disprect.ymin - R.jit[R.i.curblur-1][1];
}
else {
zspan.zofsx= -pa->disprect.xmin;
zspan.zofsy= -pa->disprect.ymin;
}
/* to centre the sample position */
zspan.zofsx -= 0.5f;
zspan.zofsy -= 0.5f;
for(v=0; v<R.totvlak; v++) {
if((v & 255)==0)
@@ -2605,6 +2613,10 @@ static void shadetrapixel(ShadePixelInfo *shpi, float x, float y, int z, int fac
printf("error in shadetrapixel nr: %d\n", (facenr & RE_QUAD_MASK));
return;
}
/* correction back for zbuffer filling in */
x+= 0.5f;
y+= 0.5f;
if(R.osa) {
VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & RE_QUAD_MASK);
float accumcol[4]={0,0,0,0}, tot=0.0;

View File

@@ -393,7 +393,7 @@ static void draw_bgpic(void)
}
if(G.vd->persp==2) {
rcti vb;
rctf vb;
calc_viewborder(G.vd, &vb);
@@ -864,7 +864,7 @@ static void view3d_get_viewborder_size(View3D *v3d, float size_r[2])
}
}
void calc_viewborder(struct View3D *v3d, rcti *viewborder_r)
void calc_viewborder(struct View3D *v3d, rctf *viewborder_r)
{
float zoomfac, size[2];
float dx= 0.0f, dy= 0.0f;
@@ -964,7 +964,7 @@ static void drawviewborder(void)
float fac, a;
float x1, x2, y1, y2;
float x3, y3, x4, y4;
rcti viewborder;
rctf viewborder;
Camera *ca= NULL;
if(G.vd->camera==NULL)

View File

@@ -247,7 +247,7 @@ int get_border(rcti *rect, short flag)
BMF_DrawString(G.fonts, str);
}
else if(G.vd->persp==2) {
rcti vb;
rctf vb;
calc_viewborder(G.vd, &vb);

View File

@@ -1980,14 +1980,14 @@ void set_render_border(void)
val= get_border(&rect, 3);
if(val) {
rcti vb;
rctf vb;
calc_viewborder(G.vd, &vb);
G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
G.scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
G.scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
G.scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
G.scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
CLAMP(G.scene->r.border.ymin, 0.0, 1.0);