New stuff & fixes in Blender OSA filtering.

While investigating alternative filters (Mitchell), I found two small
errors in the Gauss code, it clipped wrong and multiplied wrong, causing
settings other than filter size 1.0 to not work properly.

Took the last-minute liberty to add more filter types in Blender too.
Also wrote an extensive log about how sampling & filtering in Blender
works.

http://www.blender3d.org/cms/Samples_and_Filtering.723.0.html
This commit is contained in:
Ton Roosendaal 2005-11-23 15:20:45 +00:00
parent 65a824879c
commit 622f914776
16 changed files with 199 additions and 69 deletions

@ -5018,6 +5018,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Scene *sce= main->scene.first;
Camera *cam= main->camera.first;
Material *ma= main->mat.first;
int set_passepartout= 0;
/* deformflag is local in modifier now */
for(ob=main->object.first; ob; ob= ob->id.next) {
@ -5040,33 +5041,37 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if (arm->ghostsize==0) arm->ghostsize=1;
}
while(sce) {
for(;sce;sce= sce->id.next) {
/* make 'innervert' the default subdivide type, for backwards compat */
sce->toolsettings->cornertype=1;
while(cam) {
/* convert the passepartout scene flag to a camera flag */
if(sce->r.scemode & R_PASSEPARTOUT) {
cam->flag |= CAM_SHOWPASSEPARTOUT;
/* now disable it from the scene*/
sce->r.scemode &= ~R_PASSEPARTOUT;
}
/* make sure old cameras have title safe on */
/* *** to be uncommented before 2.40 release! *** */
/*
if (!(cam->flag & CAM_SHOWTITLESAFE))
cam->flag |= CAM_SHOWTITLESAFE;
*/
/* set an appropriate camera passepartout alpha */
if (!(cam->passepartalpha)) cam->passepartalpha = 0.2f;
cam= cam->id.next;
if(sce->r.scemode & R_PASSEPARTOUT) {
set_passepartout= 1;
sce->r.scemode &= ~R_PASSEPARTOUT;
}
/* gauss is filter variable now */
if(sce->r.mode & R_GAUSS) {
sce->r.filtertype= R_FILTER_GAUSS;
sce->r.mode &= ~R_GAUSS;
}
sce= sce->id.next;
}
for(;cam; cam= cam->id.next) {
if(set_passepartout)
cam->flag |= CAM_SHOWPASSEPARTOUT;
/* make sure old cameras have title safe on */
/* *** to be uncommented before 2.40 release! *** */
/*
if (!(cam->flag & CAM_SHOWTITLESAFE))
cam->flag |= CAM_SHOWTITLESAFE;
*/
/* set an appropriate camera passepartout alpha */
if (!(cam->passepartalpha)) cam->passepartalpha = 0.2f;
}
for(; ma; ma= ma->id.next) {
if(ma->strand_sta==0.0f) {
ma->strand_sta= ma->strand_end= 1.0f;

@ -518,4 +518,7 @@ void quicktime_exit(void);
Called by schrijfplaatje() in toets.c */
short imb_savehdr_fromfloat(float *fbuf, char *name, int width, int height);
/* intern/dynlibtiff.c */
void libtiff_exit(void);
#endif

@ -62,16 +62,16 @@
* LOCAL DEFINITIONS *
*********************/
PILdynlib *libtiff = NULL;
void libtiff_loadlibtiff();
void libtiff_loadlibtiff(void);
void* libtiff_findsymbol(char*);
int libtiff_load_symbols();
int libtiff_load_symbols(void);
/**************************
* LIBRARY INITIALIZATION *
**************************/
void libtiff_loadlibtiff()
void libtiff_loadlibtiff(void)
{
char *filename;
libtiff = NULL;
@ -111,7 +111,7 @@ void *libtiff_findsymbol(char *name)
return symbol;
}
void libtiff_init()
void libtiff_init(void)
{
if (libtiff != NULL) {
printf("libtiff_init: Attempted to load libtiff twice!\n");
@ -121,7 +121,7 @@ void libtiff_init()
G.have_libtiff = ((libtiff != NULL) && (libtiff_load_symbols()));
}
void libtiff_exit()
void libtiff_exit(void)
{
if (libtiff != NULL) {
PIL_dynlib_close(libtiff);
@ -130,7 +130,7 @@ void libtiff_exit()
}
int libtiff_load_symbols()
int libtiff_load_symbols(void)
{
/* Attempt to load TIFFClientOpen */
libtiff_TIFFClientOpen = libtiff_findsymbol("TIFFClientOpen");

@ -300,13 +300,9 @@ void test_idbutton_cb(void *namev, void *arg2_unused);
#define B_SET_EDGE 1643
#define B_SET_ZBLUR 1644
#ifdef __NLA
/* *********************** */
enum {
B_ARMATUREBUTS = 1800,
B_POSE = 1701
};
#endif
#define B_ARMATUREBUTS 1800
#define B_POSE 1701
/* *********************** */
#define B_COMMONEDITBUTS 2049

@ -117,7 +117,7 @@ typedef struct RenderData {
short dimensionspreset; /* for the dimensions presets menu */
short pad[2];
short filtertype, pad; /* filter is box, tent, gauss, mitch, etc */
short size, maximsize; /* size in %, max in Kb */
@ -351,11 +351,20 @@ typedef struct Scene {
#define R_MBLUR 0x4000
#define R_UNIFIED 0x8000
#define R_RAYTRACE 0x10000
/* R_GAUSS is obsolete, but used to retrieve setting from old files */
#define R_GAUSS 0x20000
#define R_FBUF 0x40000
#define R_THREADS 0x80000
#define R_ZBLUR 0x100000
/* filtertype */
#define R_FILTER_BOX 0
#define R_FILTER_TENT 1
#define R_FILTER_QUAD 2
#define R_FILTER_CUBIC 3
#define R_FILTER_CATROM 4
#define R_FILTER_GAUSS 5
#define R_FILTER_MITCH 6
/* yafray: renderer flag (not only exclusive to yafray) */
#define R_INTERN 0
@ -364,7 +373,8 @@ typedef struct Scene {
/* scemode */
#define R_DOSEQ 0x0001
#define R_BG_RENDER 0x0002
#define R_PASSEPARTOUT 0x0004 /* keep this for backward compatibility */
/* passepartout is camera option now, keep this for backward compatibility */
#define R_PASSEPARTOUT 0x0004
#define R_EXTENSION 0x0010
#define R_OGL 0x0020

@ -1361,6 +1361,10 @@ PyObject *RenderData_EnableGaussFilter( BPy_RenderData * self,
{
return M_Render_BitToggleInt( args, R_GAUSS,
&self->renderContext->mode );
/* note, this now is obsolete (ton) */
/* we now need a call like RenderData_SetFilter() or so */
/* choices are listed in DNA_scene_types.h (search filtertype) */
}
//------------------------------------RenderData.EnableBorderRender() ---

@ -82,7 +82,8 @@ typedef struct ShadeInput
/* texture coordinates */
float lo[3], gl[3], uv[3], ref[3], orn[3], winco[3], sticky[3], vcol[3], rad[3];
float vn[3], facenor[3], view[3], refcol[4], displace[3], strand;
float vn[3], facenor[3], view[3], refcol[4], displace[3], strand, tang[3];
/* dx/dy OSA coordinates */
float dxco[3], dyco[3];
float dxlo[3], dylo[3], dxgl[3], dygl[3], dxuv[3], dyuv[3];

@ -206,7 +206,8 @@ static void envmap_renderdata(EnvMap *env)
R.xstart= R.ystart= -R.afmx;
R.xend= R.yend= R.xstart+R.rectx-1;
R.r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR | R_GAUSS);
R.r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
R.r.filtertype= 0;
R.r.xparts= R.r.yparts= 1;
R.r.bufflag= 0;
R.r.size= 100;

@ -119,14 +119,61 @@ void init_filt_mask(void);
/* ****************** GAMMA, MASKS and LUTS **************** */
static float filt_quadratic(float x)
{
if (x < 0.0f) x = -x;
if (x < 0.5f) return 0.75f-(x*x);
if (x < 1.5f) return 0.50f*(x-1.5f)*(x-1.5f);
return 0.0f;
}
static float filt_cubic(float x)
{
float x2= x*x;
if (x < 0.0f) x = -x;
if (x < 1.0f) return 0.5*x*x2 - x2 + 2.0f/3.0f;
if (x < 2.0f) return (2.0-x)*(2.0-x)*(2.0-x)/6.0f;
return 0.0f;
}
static float filt_catrom(float x)
{
float x2= x*x;
if (x < 0.0f) x = -x;
if (x < 1.0f) return 1.5f*x2*x - 2.5f*x2 + 1.0f;
if (x < 2.0f) return -0.5f*x2*x + 2.5*x2 - 4.0f*x + 2.0f;
return 0.0f;
}
static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
{
float b = 1.0f/3.0f, c = 1.0f/3.0f;
float p0 = ( 6.0 - 2.0*b ) / 6.0;
float p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0;
float p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0;
float q0 = ( 8.0*b + 24.0*c) / 6.0;
float q1 = ( - 12.0*b - 48.0*c) / 6.0;
float q2 = ( 6.0*b + 30.0*c) / 6.0;
float q3 = ( - b - 6.0*c) / 6.0;
if (x<-2.0) return 0.0;
if (x<-1.0) return (q0-x*(q1-x*(q2-x*q3)));
if (x< 0.0) return (p0+x*x*(p2-x*p3));
if (x< 1.0) return (p0+x*x*(p2+x*p3));
if (x< 2.0) return (q0+x*(q1+x*(q2+x*q3)));
return 0.0;
}
static float calc_weight(float *weight, int i, int j)
{
float x, y, dist, totw= 0.0, fac;
float x, y, dist, totw= 0.0;
int a;
fac= R.r.gauss*R.r.gauss;
fac*= fac;
for(a=0; a<R.osa; a++) {
x= jit[a][0] + i;
y= jit[a][1] + j;
@ -134,17 +181,40 @@ static float calc_weight(float *weight, int i, int j)
weight[a]= 0.0;
/* gaussian weighting */
if(R.r.mode & R_GAUSS) {
if(dist<R.r.gauss) {
x = dist*R.r.gauss;
weight[a]= (1.0/exp(x*x) - 1.0/exp(fac));
}
}
else {
/* Weighting choices */
switch(R.r.filtertype) {
case R_FILTER_BOX:
if(i==0 && j==0) weight[a]= 1.0;
break;
case R_FILTER_TENT:
if(dist < R.r.gauss)
weight[a]= R.r.gauss - dist;
break;
case R_FILTER_GAUSS:
x = dist*R.r.gauss;
weight[a]= (1.0/exp(x*x) - 1.0/exp(R.r.gauss*R.r.gauss*2.25));
break;
case R_FILTER_MITCH:
weight[a]= filt_mitchell(dist*R.r.gauss);
break;
case R_FILTER_QUAD:
weight[a]= filt_quadratic(dist*R.r.gauss);
break;
case R_FILTER_CUBIC:
weight[a]= filt_cubic(dist*R.r.gauss);
break;
case R_FILTER_CATROM:
weight[a]= filt_catrom(dist*R.r.gauss);
break;
}
totw+= weight[a];
}
@ -157,8 +227,8 @@ void init_filt_mask(void)
{
static int firsttime=1;
static int lastosa=0;
static int lastgauss=0;
static float lastgamma= 0.0;
static int lastfilter= -1;
static float lastgamma= 0.0f, lastgaussdist=0.0f;
float gamma, igamma, flweight[32], fmask[256];
float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
int i, j, a;
@ -233,10 +303,11 @@ void init_filt_mask(void)
}
}
if(R.osa && (lastosa!=R.osa || lastgauss != (R.r.mode & R_GAUSS)) ) {
if(R.osa && (lastosa!=R.osa || lastfilter != (R.r.filtertype) || lastgaussdist!=R.r.gauss)) {
lastosa= R.osa;
lastgauss= R.r.mode & R_GAUSS;
lastfilter= R.r.filtertype;
lastgaussdist= R.r.gauss;
val= 1.0/((float)R.osa);
for(a=0; a<256; a++) {
fmask[a]= ((float)cmask[a])*val;
@ -683,8 +754,8 @@ static void initparts(void)
}
if(pa->x>0 && pa->y>0) {
/* Gauss needs 1 pixel extra to work */
if((R.r.mode & R_GAUSS)) {
/* Non-box filters might need 1 pixel extra to work */
if((R.r.filtertype)) {
pa->minx-= 1;
pa->miny-= 1;
pa->maxx+= 1;
@ -728,7 +799,7 @@ static void addparttorect(Part *pa)
copylen=len= pa->x;
height= pa->y;
if(R.r.mode & R_GAUSS) {
if(R.r.filtertype) { /* filters added 1 pixel extra */
rtp+= 1+len;
if(rzp) rzp+= 1+len;
@ -1031,7 +1102,7 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
if( (R.r.mode & R_BORDER) && (R.r.mode & R_MOVIECROP));
else {
/* HANDLE PART OR BORDER */
if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.mode & R_GAUSS)) {
if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.filtertype)) {
pa->rect= R.rectot;
R.rectot= NULL;
@ -1055,7 +1126,7 @@ static void mainRenderLoop(void) /* here the PART and FIELD loops */
if(R.r.mode & R_PANORAMA) R.rectx*= R.r.xparts;
if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.mode & R_GAUSS)) {
if(totparts>1 || (R.r.mode & R_BORDER) || (R.r.filtertype)) {
int a;
if(R.rectot) MEM_freeN(R.rectot);
@ -1313,7 +1384,7 @@ void RE_initrender(struct View3D *ogl_render_view3d)
/* just prevents cpu cycles for larger render and copying */
if((R.r.mode & R_OSA)==0)
R.r.mode &= ~R_GAUSS;
R.r.filtertype= 0;
renderloop_setblending(); // alpha, sky, gamma

@ -2751,7 +2751,7 @@ void zbufshadeDA(void) /* Delta Accum Pixel Struct */
do_renderlineDA(&rl2);
SDL_WaitThread(thread, NULL);
if(R.r.mode & R_GAUSS) {
if(R.r.filtertype) {
float *rb1= rowbuf1, *rb2= rowbuf2, *rb1a= rowbuf1a, *rb2a= rowbuf2a;
a= 4*(R.rectx + 4);
while(a--) {

@ -1576,7 +1576,7 @@ void zBufShadeAdvanced()
SDL_WaitThread(thread, NULL);
if(R.r.mode & R_GAUSS) {
if(R.r.filtertype) {
float *rb1= AColourBuffer1, *rb2= AColourBuffer2, *rb1a= AColourBuffer1a, *rb2a= AColourBuffer2a;
int a= 4*(R.rectx + 4);
while(a--) {

@ -1090,7 +1090,7 @@ static void render_panel_output(void)
static void render_panel_render(void)
{
uiBlock *block;
char str[256];
block= uiNewBlock(&curarea->uiblocks, "render_panel_render", UI_EMBOSS, UI_HELV, curarea->win);
if(uiNewPanel(curarea, block, "Render", "Render", 320, 0, 318, 204)==0) return;
@ -1148,8 +1148,9 @@ static void render_panel_render(void)
uiDefButBitI(block, TOG, R_ODDFIELD, 0,"Odd", 627,55,39,20,&G.scene->r.mode, 0, 0, 0, 0, "Enables Odd field first rendering (Default: Even field)");
uiDefButBitI(block, TOG, R_FIELDSTILL, 0,"X", 668,55,19,20,&G.scene->r.mode, 0, 0, 0, 0, "Disables time difference in field calculations");
uiDefButBitI(block, TOG, R_GAUSS, 0,"Gauss", 565,34,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Enable Gaussian sampling filter for antialiasing");
uiDefButF(block, NUM,B_DIFF,"", 627,34,60,20,&G.scene->r.gauss,0.5, 1.5, 100, 2, "Sets the Gaussian filter size");
sprintf(str, "Filter%%t|Box %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
uiDefButS(block, MENU, B_DIFF,str, 565,34,60,20, &G.scene->r.filtertype, 0, 0, 0, 0, "Set sampling filter for antialiasing");
uiDefButF(block, NUM,B_DIFF,"", 627,34,60,20,&G.scene->r.gauss,0.5, 1.5, 10, 2, "Sets the filter size");
uiDefButBitI(block, TOG, R_BORDER, REDRAWVIEWCAM, "Border", 565,13,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Render a small cut-out of the image");
uiDefButBitI(block, TOG, R_GAMMA, B_REDR, "Gamma", 627,13,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Enable gamma correction");

@ -950,7 +950,45 @@ static void drawviewborder(void)
BIF_ThemeColor(TH_WIRE);
glRectf(x1, y1, x2, y2);
{
extern float jit[64][2];
int a, i, j;
BIF_ThemeColor(TH_BACK);
glBegin(GL_LINES);
glVertex2f(x1 + (x2-x1)/3, y1);
glVertex2f(x1 + (x2-x1)/3, y2);
glVertex2f(x1 + 2*(x2-x1)/3, y1);
glVertex2f(x1 + 2*(x2-x1)/3, y2);
glVertex2f(x1, y1 + (y2-y1)/3);
glVertex2f(x2, y1 + (y2-y1)/3);
glVertex2f(x1, y1 + 2*(y2-y1)/3);
glVertex2f(x2, y1 + 2*(y2-y1)/3);
glEnd();
glPointSize(4);
glBegin(GL_POINTS);
for(i= -1; i<2; i++) {
for(j= -1; j<2; j++) {
if(i==0 && j==0)
glColor3ub(255, 255, 255);
else
glColor3ub(150, 150, 150);
for(a=0; a<R.osa; a++) {
glVertex2f(i*(x2-x1)/3 + (x1+x2)/2 + jit[a][0]*(x2-x1)/3.0, j*(y2-y1)/3 + (y1+y2)/2 + jit[a][1]*(y2-y1)/3.0);
}
}
}
glEnd();
glPointSize(1.0);
}
/* camera name */
if (ca && (ca->flag & CAM_SHOWNAME)) {
glRasterPos2f(x1, y1-15);

@ -507,7 +507,6 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
the orientation where %s is (logically).
*/
void setUserConstraint(TransInfo *t, int mode, const char ftext[]) {
float mtx[3][3];
char text[40];
short twmode= (t->spacetype==SPACE_VIEW3D)? G.vd->twmode: V3D_MANIP_GLOBAL;

@ -74,6 +74,7 @@
#include "BKE_utildefines.h"
#include "BSE_view.h"
#include "BDR_unwrapper.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"

@ -114,7 +114,7 @@
#include "blendef.h"
#include "radio.h"
#include "render.h" // RE_ free stuff
#include "render.h" /* RE_ free stuff */
#include "datatoc.h"
#include "SYS_System.h"