Fix [#22418] Displace Node also makes entire image fuzzy
Changed displace node sampling to use EWA filtering, and removed old hacks for calculating derivatives - I think it should be generated correctly now.
This commit is contained in:
@@ -44,94 +44,83 @@ static bNodeSocketType cmp_node_displace_out[]= {
|
||||
{ -1, 0, "" }
|
||||
};
|
||||
|
||||
static float *vecbuf_get_pixel(CompBuf *vecbuf, float *veccol, int x, int y)
|
||||
{
|
||||
/* the x-xrad stuff is a bit weird, but i seem to need it otherwise
|
||||
* my returned pixels are offset weirdly */
|
||||
return compbuf_get_pixel(vecbuf, veccol, x-vecbuf->xrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad);
|
||||
}
|
||||
/* minimum distance (in pixels) a pixel has to be displaced
|
||||
* in order to take effect */
|
||||
#define DISPLACE_EPSILON 0.01
|
||||
|
||||
static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *veccol, float *xscale, float *yscale)
|
||||
{
|
||||
ImBuf *ibuf;
|
||||
float dx=0.0, dy=0.0;
|
||||
float dspx, dspy;
|
||||
float uv[2], col[4], colnext[4], colprev[4];
|
||||
float *vp, *vpnext, *vpprev;
|
||||
float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect;
|
||||
int x, y, vx, vy, sx, sy;
|
||||
int x, y;
|
||||
float p_dx, p_dy; /* main displacement in pixel space */
|
||||
float d_dx, d_dy;
|
||||
float dxt, dyt;
|
||||
float u, v;
|
||||
float vec[3], vecdx[3], vecdy[3];
|
||||
float col[3];
|
||||
|
||||
/* ibuf needed for sampling */
|
||||
ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
|
||||
ibuf->rect_float= cbuf->rect;
|
||||
|
||||
vec = vecbuf->rect;
|
||||
|
||||
sx= stackbuf->x;
|
||||
sy= stackbuf->y;
|
||||
|
||||
QUATCOPY(col, veccol);
|
||||
QUATCOPY(colnext, veccol);
|
||||
QUATCOPY(colprev, veccol);
|
||||
|
||||
for(y=0; y<sy; y++) {
|
||||
for(x= 0; x< sx; x++, out+=4, in+=4, vec+=3) {
|
||||
for(y=0; y < stackbuf->y; y++) {
|
||||
for(x=0; x < stackbuf->x; x++) {
|
||||
/* calc pixel coordinates */
|
||||
qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof, vec);
|
||||
p_dx = vec[0] * xscale[0];
|
||||
p_dy = vec[1] * yscale[0];
|
||||
|
||||
vp = vecbuf_get_pixel(vecbuf, col, x, y);
|
||||
|
||||
/* this happens in compbuf_get_pixel, need to make sure the following
|
||||
* check takes them into account */
|
||||
vx= x-vecbuf->xof;
|
||||
vy= y-vecbuf->yof;
|
||||
|
||||
/* find the new displaced co-ords, also correcting for translate offset */
|
||||
dspx = vx - (*xscale * vp[0]);
|
||||
dspy = vy - (*yscale * vp[1]);
|
||||
|
||||
/* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */
|
||||
uv[0] = dspx / (float)sx;
|
||||
uv[1] = dspy / (float)sy;
|
||||
|
||||
if(vx>0 && vx< vecbuf->x-1 && vy>0 && vy< vecbuf->y-1) {
|
||||
/* adaptive sampling, X and Y channel.
|
||||
* we call vecbuf_get_pixel for every pixel since the input
|
||||
* might be a procedural, and then we can't use offsets */
|
||||
vpprev = vecbuf_get_pixel(vecbuf, colprev, x-1, y);
|
||||
vpnext = vecbuf_get_pixel(vecbuf, colnext, x+1, y);
|
||||
dx= 0.5f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0]));
|
||||
|
||||
vpprev = vecbuf_get_pixel(vecbuf, colprev, x, y-1);
|
||||
vpnext = vecbuf_get_pixel(vecbuf, colnext, x, y+1);
|
||||
dy= 0.5f*(fabs(vp[1]-vpnext[1]) + fabs(vp[1]-vpprev[1]));
|
||||
|
||||
vpprev = vecbuf_get_pixel(vecbuf, colprev, x-1, y-1);
|
||||
vpnext = vecbuf_get_pixel(vecbuf, colnext, x-1, y+1);
|
||||
dx+= 0.25f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0]));
|
||||
dy+= 0.25f*(fabs(vp[1]-vpprev[1]) + fabs(vp[1]-vpnext[1]));
|
||||
|
||||
vpprev = vecbuf_get_pixel(vecbuf, colprev, x+1, y-1);
|
||||
vpnext = vecbuf_get_pixel(vecbuf, colnext, x+1, y+1);
|
||||
dx+= 0.25f*(fabs(vp[0]-vpprev[0]) + fabs(vp[0]-vpnext[0]));
|
||||
dy+= 0.25f*(fabs(vp[1]-vpprev[1]) + fabs(vp[1]-vpnext[1]));
|
||||
|
||||
/* scaled down to prevent blurriness */
|
||||
/* 8: magic number, provides a good level of sharpness without getting too aliased */
|
||||
dx /= 8;
|
||||
dy /= 8;
|
||||
/* if no displacement, then just copy this pixel */
|
||||
if (p_dx < DISPLACE_EPSILON && p_dy < DISPLACE_EPSILON) {
|
||||
qd_getPixel(cbuf, x-cbuf->xof, y-cbuf->yof, col);
|
||||
qd_setPixel(stackbuf, x, y, col);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* should use mipmap */
|
||||
if(dx > 0.006f) dx= 0.006f;
|
||||
if(dy > 0.006f) dy= 0.006f;
|
||||
if ((vp[0]> 0.0) && (dx < 0.004)) dx = 0.004;
|
||||
if ((vp[1]> 0.0) && (dy < 0.004)) dy = 0.004;
|
||||
|
||||
|
||||
ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
|
||||
/* displaced pixel in uv coords, for image sampling */
|
||||
u = (x - cbuf->xof - p_dx + 0.5f) / (float)stackbuf->x;
|
||||
v = (y - cbuf->yof - p_dy + 0.5f) / (float)stackbuf->y;
|
||||
|
||||
|
||||
/* calc derivatives */
|
||||
qd_getPixel(vecbuf, x-vecbuf->xof+1, y-vecbuf->yof, vecdx);
|
||||
qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof+1, vecdy);
|
||||
d_dx = vecdx[0] * xscale[0];
|
||||
d_dy = vecdy[0] * yscale[0];
|
||||
|
||||
/* clamp derivatives to minimum displacement distance in UV space */
|
||||
dxt = MAX2(p_dx - d_dx, DISPLACE_EPSILON)/(float)stackbuf->x;
|
||||
dyt = MAX2(p_dy - d_dy, DISPLACE_EPSILON)/(float)stackbuf->y;
|
||||
|
||||
ibuf_sample(ibuf, u, v, dxt, dyt, col);
|
||||
qd_setPixel(stackbuf, x, y, col);
|
||||
}
|
||||
}
|
||||
|
||||
IMB_freeImBuf(ibuf);
|
||||
IMB_freeImBuf(ibuf);
|
||||
|
||||
|
||||
/* simple method for reference, linear interpolation */
|
||||
/*
|
||||
int x, y;
|
||||
float dx, dy;
|
||||
float u, v;
|
||||
float vec[3];
|
||||
float col[3];
|
||||
|
||||
for(y=0; y < stackbuf->y; y++) {
|
||||
for(x=0; x < stackbuf->x; x++) {
|
||||
qd_getPixel(vecbuf, x, y, vec);
|
||||
|
||||
dx = vec[0] * (xscale[0]);
|
||||
dy = vec[1] * (yscale[0]);
|
||||
|
||||
u = (x - dx + 0.5f) / (float)stackbuf->x;
|
||||
v = (y - dy + 0.5f) / (float)stackbuf->y;
|
||||
|
||||
qd_getPixelLerp(cbuf, u*cbuf->x - 0.5f, v*cbuf->y - 0.5f, col);
|
||||
qd_setPixel(stackbuf, x, y, col);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -586,49 +586,19 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
|
||||
}
|
||||
}
|
||||
|
||||
void image_sample(Image *ima, float fx, float fy, float dx, float dy, float *result)
|
||||
{
|
||||
TexResult texres;
|
||||
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
|
||||
|
||||
if(ibuf==NULL) {
|
||||
result[0]= result[1]= result[2]= result[3]= 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
|
||||
ibuf->rect+= (ibuf->x*ibuf->y);
|
||||
|
||||
boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1, 0);
|
||||
result[0]= texres.tr;
|
||||
result[1]= texres.tg;
|
||||
result[2]= texres.tb;
|
||||
result[3]= texres.ta;
|
||||
|
||||
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
|
||||
ibuf->rect-= (ibuf->x*ibuf->y);
|
||||
}
|
||||
|
||||
void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result)
|
||||
{
|
||||
TexResult texres;
|
||||
|
||||
if(ibuf==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&texres, 0, sizeof(texres));
|
||||
boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1, 0);
|
||||
result[0]= texres.tr;
|
||||
result[1]= texres.tg;
|
||||
result[2]= texres.tb;
|
||||
result[3]= texres.ta;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
// from here, some functions only used for the new filtering
|
||||
|
||||
// anisotropic filters, data struct used instead of long line of (possibly unused) func args
|
||||
typedef struct afdata_t {
|
||||
float dxt[2], dyt[2];
|
||||
int intpol, extflag;
|
||||
// feline only
|
||||
float majrad, minrad, theta;
|
||||
int iProbes;
|
||||
float dusc, dvsc;
|
||||
} afdata_t;
|
||||
|
||||
// this only used here to make it easier to pass extend flags as single int
|
||||
enum {TXC_XMIR=1, TXC_YMIR, TXC_REPT, TXC_EXTD};
|
||||
|
||||
@@ -713,16 +683,6 @@ static int ibuf_get_color_clip_bilerp(float *col, ImBuf *ibuf, float u, float v,
|
||||
return ibuf_get_color_clip(col, ibuf, (int)u, (int)v, extflag);
|
||||
}
|
||||
|
||||
// anisotropic filters, data struct used instead of long line of (possibly unused) func args
|
||||
typedef struct afdata_t {
|
||||
float dxt[2], dyt[2];
|
||||
int intpol, extflag;
|
||||
// feline only
|
||||
float majrad, minrad, theta;
|
||||
int iProbes;
|
||||
float dusc, dvsc;
|
||||
} afdata_t;
|
||||
|
||||
static void area_sample(TexResult* texr, ImBuf* ibuf, float fx, float fy, afdata_t* AFD)
|
||||
{
|
||||
int xs, ys, clip = 0;
|
||||
@@ -1775,3 +1735,53 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *DXT, f
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void image_sample(Image *ima, float fx, float fy, float dx, float dy, float *result)
|
||||
{
|
||||
TexResult texres;
|
||||
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
|
||||
|
||||
if(ibuf==NULL) {
|
||||
result[0]= result[1]= result[2]= result[3]= 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
|
||||
ibuf->rect+= (ibuf->x*ibuf->y);
|
||||
|
||||
boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1, 0);
|
||||
result[0]= texres.tr;
|
||||
result[1]= texres.tg;
|
||||
result[2]= texres.tb;
|
||||
result[3]= texres.ta;
|
||||
|
||||
if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
|
||||
ibuf->rect-= (ibuf->x*ibuf->y);
|
||||
}
|
||||
|
||||
void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result)
|
||||
{
|
||||
TexResult texres;
|
||||
afdata_t AFD;
|
||||
|
||||
if(ibuf==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
AFD.dxt[0] = dx; AFD.dxt[1] = dx;
|
||||
AFD.dyt[0] = dy; AFD.dyt[1] = dy;
|
||||
//copy_v2_v2(AFD.dxt, dx);
|
||||
//copy_v2_v2(AFD.dyt, dy);
|
||||
|
||||
AFD.intpol = 1;
|
||||
AFD.extflag = TXC_EXTD;
|
||||
|
||||
memset(&texres, 0, sizeof(texres));
|
||||
ewa_eval(&texres, ibuf, fx, fy, &AFD);
|
||||
|
||||
|
||||
result[0]= texres.tr;
|
||||
result[1]= texres.tg;
|
||||
result[2]= texres.tb;
|
||||
result[3]= texres.ta;
|
||||
}
|
||||
Reference in New Issue
Block a user