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 Object;
struct BGpic; struct BGpic;
struct rcti; struct rctf;
struct ScrArea; struct ScrArea;
struct ImBuf; struct ImBuf;
@@ -61,7 +61,7 @@ void drawview3dspace(struct ScrArea *sa, void *spacedata);
void drawview3d_render(struct View3D *v3d, int winx, int winy); void drawview3d_render(struct View3D *v3d, int winx, int winy);
int update_time(void); 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); void view3d_set_1_to_1_viewborder(struct View3D *v3d);
int view3d_test_clipping(struct View3D *v3d, float *vec); int view3d_test_clipping(struct View3D *v3d, float *vec);

View File

@@ -108,6 +108,7 @@ struct Render
rcti disprect; /* part within winx winy */ rcti disprect; /* part within winx winy */
rctf viewplane; /* mapped on winx winy */ rctf viewplane; /* mapped on winx winy */
float viewdx, viewdy; /* size of 1 pixel */ 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) */ /* final picture width and height (within disprect) */
int rectx, recty; int rectx, recty;
@@ -120,7 +121,6 @@ struct Render
/* values for viewing */ /* values for viewing */
float lens, ycor, viewfac; float lens, ycor, viewfac;
float bluroffsx, bluroffsy;
float panophi, panosi, panoco, panodxp, panodxv; float panophi, panosi, panoco, panodxp, panodxv;
/* Matrices */ /* Matrices */

View File

@@ -456,8 +456,6 @@ void RE_SetCamera(Render *re, Object *camera)
rctf viewplane; rctf viewplane;
float pixsize, clipsta, clipend; float pixsize, clipsta, clipend;
float lens; float lens;
float xd, yd;
int blursample= 0; /* make new call for that */
/* question mark */ /* question mark */
re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp); 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; viewplane.ymax+= .5*re->ycor;
} }
} }
/* the window matrix is used for clipping, and not changed during OSA steps */
xd= yd= 0.0; /* using an offset of +0.5 here would give clip errors on edges */
if(blursample != -1 && re->osa != 0 ) { viewplane.xmin= pixsize*(viewplane.xmin);
re->bluroffsx= xd= re->jit[blursample % re->osa][0]; viewplane.xmax= pixsize*(viewplane.xmax);
re->bluroffsy= yd= re->ycor*re->jit[blursample % re->osa][1]; viewplane.ymin= pixsize*(viewplane.ymin);
} viewplane.ymax= pixsize*(viewplane.ymax);
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);
re->viewdx= pixsize; re->viewdx= pixsize;
re->viewdy= re->ycor*pixsize; re->viewdy= re->ycor*pixsize;
@@ -562,7 +554,8 @@ void RE_SetCamera(Render *re, Object *camera)
else else
RE_SetWindow(re, &viewplane, clipsta, clipend); 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 fx= 2.0/(R.winx*R.winmat[0][0]);
float fy= 2.0/(R.winy*R.winmat[1][1]); 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[0]= (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[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 */ /* using a*x + b*y + c*z = d equation, (a b c) is normal */
if(shi.facenor[2]!=0.0f) 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 fx= 2.0/(R.rectx*R.winmat[0][0]);
float fy= 2.0/(R.recty*R.winmat[1][1]); 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[0]= (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[1]= (y - 0.5*R.recty)*fy - R.winmat[3][1]/R.winmat[1][1];
} }
calc_view_vector(shi.view, x, y); 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; VlakRen *vlr;
float collector[4], rco[3]; 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); vlr= shadepixel(shpi, x, y, z, facenr, mask, rco);
if(shpi->shr.combined[3] != 1.0) { 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]; v13= v1[3];
} }
else { else {
dw= 1.005f*(v2[3]-v1[3]); dw= R.clipcrop*(v2[3]-v1[3]);
v13= 1.005f*v1[3]; v13= R.clipcrop*v1[3];
} }
/* according the original article by Liang&Barsky, for clipping of /* according the original article by Liang&Barsky, for clipping of
* homogenous coordinates with viewplane, the value of "0" is used instead of "-w" . * 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, f1);
hoco_to_zco(zspan, vez+4, f2); hoco_to_zco(zspan, vez+4, f2);
hoco_to_zco(zspan, vez+8, f3); hoco_to_zco(zspan, vez+8, f3);
zspan->zbuffunc(zspan, zvlnr, vez,vez+4,vez+8, NULL); 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 */ /* needed for transform from hoco to zbuffer co */
zspan.zmulx= ((float)R.winx)/2.0; zspan.zmulx= ((float)R.winx)/2.0;
zspan.zmuly= ((float)R.winy)/2.0; zspan.zmuly= ((float)R.winy)/2.0;
if(R.osa) { if(R.osa) {
zspan.zofsx= -pa->disprect.xmin - R.jit[pa->sample][0]; zspan.zofsx= -pa->disprect.xmin - R.jit[pa->sample][0];
zspan.zofsy= -pa->disprect.ymin - R.jit[pa->sample][1]; 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.zofsx= -pa->disprect.xmin;
zspan.zofsy= -pa->disprect.ymin; zspan.zofsy= -pa->disprect.ymin;
} }
/* to centre the sample position */
zspan.zofsx -= 0.5f;
zspan.zofsy -= 0.5f;
/* the buffers */ /* the buffers */
zspan.rectz= pa->rectz; 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); zbuf_alloc_span(&zspan, vw->rectx, vw->recty);
zspan.zmulx= ((float)vw->rectx)/2.0; zspan.zmulx= ((float)vw->rectx)/2.0;
zspan.zmuly= ((float)vw->recty)/2.0; zspan.zmuly= ((float)vw->recty)/2.0;
zspan.zofsx= 0; zspan.zofsx= -0.5f;
zspan.zofsy= 0; zspan.zofsy= -0.5f;
/* the buffers */ /* the buffers */
zspan.rectz= vw->rectz; 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 */ /* needed for transform from hoco to zbuffer co */
zspan.zmulx= ((float)R.winx)/2.0; zspan.zmulx= ((float)R.winx)/2.0;
zspan.zmuly= ((float)R.winy)/2.0; zspan.zmuly= ((float)R.winy)/2.0;
zspan.zofsx= -pa->disprect.xmin;
zspan.zofsy= -pa->disprect.ymin;
/* the buffers */ /* the buffers */
zspan.arectz= MEM_mallocT(sizeof(int)*pa->rectx*pa->recty, "Arectz"); 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; zspan.mask= 1<<zsample;
if(R.osa) { if(R.osa) {
zspan.zofsx= -pa->disprect.xmin-R.jit[zsample][0]; zspan.zofsx= -pa->disprect.xmin - R.jit[zsample][0];
zspan.zofsy= -pa->disprect.ymin-R.jit[zsample][1]; zspan.zofsy= -pa->disprect.ymin - R.jit[zsample][1];
} }
else if(R.i.curblur) { else if(R.i.curblur) {
zspan.zofsx= -pa->disprect.xmin - R.jit[R.i.curblur-1][0]; zspan.zofsx= -pa->disprect.xmin - R.jit[R.i.curblur-1][0];
zspan.zofsy= -pa->disprect.ymin - R.jit[R.i.curblur-1][1]; 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++) { for(v=0; v<R.totvlak; v++) {
if((v & 255)==0) 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)); printf("error in shadetrapixel nr: %d\n", (facenr & RE_QUAD_MASK));
return; return;
} }
/* correction back for zbuffer filling in */
x+= 0.5f;
y+= 0.5f;
if(R.osa) { if(R.osa) {
VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & RE_QUAD_MASK); VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & RE_QUAD_MASK);
float accumcol[4]={0,0,0,0}, tot=0.0; 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) { if(G.vd->persp==2) {
rcti vb; rctf vb;
calc_viewborder(G.vd, &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 zoomfac, size[2];
float dx= 0.0f, dy= 0.0f; float dx= 0.0f, dy= 0.0f;
@@ -964,7 +964,7 @@ static void drawviewborder(void)
float fac, a; float fac, a;
float x1, x2, y1, y2; float x1, x2, y1, y2;
float x3, y3, x4, y4; float x3, y3, x4, y4;
rcti viewborder; rctf viewborder;
Camera *ca= NULL; Camera *ca= NULL;
if(G.vd->camera==NULL) if(G.vd->camera==NULL)

View File

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

View File

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