Reputation: 97
I have a 2D scene in Monogame with some primitives and sprites (i.e. in PrimitiveBatches and SpriteBatches) and I would like to create a magnifying glass effect with a circular lens showing a zoomed view of the content under it. How do I do that?
Thanks.
Upvotes: 0
Views: 160
Reputation: 51855
I do not use your environment but I always did this effect with pixel displacement. If you got pixel access to rendered scene (ideally while still in a back-buffer so it does not flicker) then just move the pixels inside your lens to the outward positions. Either use constant displacement or even better is when you move more (bigger zoom) in the middle and less near the edges.
Typical implementation looks like this:
temp
buffer(x,y)
through lens arear
of processed pixel from lens center (x0,y0)
ignore pixels outside lens area (r>R)
compute actual zoom m
of processed pixel
I like to use cos
for this like this:
m=1.0+(1.5*cos(0.5*M_PI*double(r)/double(r0))); // M_PI=3.1415...
you can play with the 1.0,1.5
constants. They determine minimal (1.0)
and maximal (1.0+1.5)
zoom. Also this is for cos
taking angle in [rad]
so if yours need [deg]
instead change the 0.5*M_PI
with 90.0
copy pixel from temp
to backbuffer or screen
backbuffer(x,y)=temp(x0+(x-x0)/m,y0+(y-y0)/m)
Here C++/VCL example:
void TMain::draw()
{
// clear bmp (if image not covering whole area)
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
// copy background image
bmp->Canvas->Draw(0,0,jpg); // DWORD pxy[ys][xs] is bmp direct pixel access, (xs,ys) is bmp size
// here comes the important stuff:
int x0=mx,y0=my; // position = mouse
const int r0=50; // radius
DWORD tmp[2*r0+3][2*r0+3]; // temp buffer
double m;
int r,x,y,xx,yy,xx0,xx1,yy0,yy1;
// zoom area bounding box
xx0=x0-r0; if (xx0< 0) xx0=0;
xx1=x0+r0; if (xx1>=xs) xx1=xs-1;
yy0=y0-r0; if (yy0< 0) yy0=0;
yy1=y0+r0; if (yy1>=ys) yy1=ys-1;
// copy bmp to tmp
for (y=yy0;y<=yy1;y++)
for (x=xx0;x<=xx1;x++)
tmp[y-yy0][x-xx0]=pyx[y][x];
// render zoomed area
for (y=yy0;y<=yy1;y++)
for (x=xx0;x<=xx1;x++)
{
// compute radius
xx=x-x0;
yy=y-y0;
r=sqrt((xx*xx)+(yy*yy));
if (r>r0) continue;
if (r==r0) { pyx[y][x]=clWhite; continue; }
// compute zoom: 2.5 on center, 1.0 at eges
m=1.0+(1.5*cos(0.5*M_PI*double(r)/double(r0))); // M_PI=3.1415...
// compute displacement
xx=double(double(xx)/m)+x0;
yy=double(double(yy)/m)+y0;
// copy
if ((xx>=xx0)&&(yy>=yy0)&&(xx<=xx1)&&(yy<=yy1))
pyx[y][x]=tmp[yy-yy0][xx-xx0];
}
// just refresh screen with backbuffer
Canvas->Draw(0,0,bmp);
}
And here animated GIF preview (quality and fps is lowered by GIF encoding):
If you need help with understanding the gfx access in my code see:
Upvotes: 1