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:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user