我正在为 HTML5 Canvas 编写内容,将其用作视口,在其中保持中心原点和缩放级别。我想要跟踪并缩放到一个区域,但遇到了自然发生的效果,破坏了我试图获得的外观。这个问题涉及我如何在保持自然效果的同时减轻这种情况。
想象我在天花板上安装了一个向下的摄像头,而地板上的某个地方有一张纸。我沿着天花板以恒定的速度移动相机,直到它位于纸张上方,同时以线性速率缩放,以便纸张最终填充渲染的图像。这些动作同时发生。
执行此操作时,可以观察到纸张在返回中心之前滑出框架的效果。这可能最好用视觉来解释,并保持二维:
这看起来不太好看。考虑用户请求专注于某件事。他们的概念是,实体正在进入视野,奇怪的是,它似乎在靠近之前先离开了。
我希望的效果是目标物体只接近画面的中心,并且永远不会后退。我想答案是以某种方式改变缩放速率(或移动速率,尽管我不喜欢这个) )大概是所涉及距离的函数,或者人为调整缩放以使页面保持在框架中。我更希望获得与前一种方法类似的解决方案的帮助。
哦,所以你得到了一个不涉及硬件相机的软件实现....
我指的是真正的倾斜效果,英文称为滚动快门:如果您通过移动真实的硬件扫描线相机获取图像(没有TDI技术),那么滑动扫描时会出现倾斜+模糊效果线条...尝试从行驶中的汽车的侧窗拍摄照片,图像会倾斜。
您所描述的效果与偏斜无关,它只是一个数学“奇点”,抱歉我没有任何名称。
由于您的相机是 SW,只有您可以根据自己的喜好影响平移和缩放,因此我只需根据相机
FOV和
zoom
位置计算 pan
。我看是这样的:
所以:
I. a = FOV / zoom
II. tan(0.5*a) = (x1-x0) / h
------------------------
zoom = 0.5*FOV/atan( (x1-x0) / h )
其中
h
是天花板高度,x0
是相机(平移)位置,x0
是纸张边缘位置,FOV
是非变焦相机的视野...
[编辑1]将纸张滑入并动画...
我最终得到了这个:
这里是 C++/VCL 代码:
//---------------------------------------------------------------------------
double x0,x1,w=50,h=200,FOVx=60.0*M_PI/180.0,zoom,pan;
double t=0; // animation parameter <0,1>
//---------------------------------------------------------------------------
void TMain::draw()
{
if (!_redraw) return;
// clear buffer
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
double y0,y1,dx;
// position side view onto screen based on its size xs,ys
y0=0.5*(ys-h);
y1=y0+h;
x0=0.5*xs;
x1=x0+(h*tan(0.5*FOVx));
// compute zoom,pan from t
pan=(x1-x0+(0.5*w))*t;
zoom=0.5*FOVx/atan(((1.0-t)*(x1-x0)+(0.5*w*t))/h);
// scene
bmp->Canvas->Pen->Color=clBlue;
bmp->Canvas->MoveTo( 0,y0);
bmp->Canvas->LineTo(xs,y0);
bmp->Canvas->MoveTo( 0,y1);
bmp->Canvas->LineTo(xs,y1);
// paper
bmp->Canvas->Pen->Color=clRed;
bmp->Canvas->MoveTo(x1,y1);
bmp->Canvas->LineTo(x1+w,y1);
// FOVx
dx=h*tan(0.5*FOVx/zoom);
bmp->Canvas->Pen->Color=clAqua;
bmp->Canvas->MoveTo(x0+pan-dx,y1);
bmp->Canvas->LineTo(x0+pan,y0);
bmp->Canvas->LineTo(x0+pan+dx,y1);
// points
dx=4;
bmp->Canvas->Pen->Color=clAqua;
bmp->Canvas->Brush->Color=clBlue;
bmp->Canvas->Ellipse(x0-dx,y0-dx,x0+dx,y0+dx);
bmp->Canvas->Ellipse(x0+pan-dx,y0-dx,x0+pan+dx,y0+dx);
bmp->Canvas->Ellipse(x1-dx,y1-dx,x1+dx,y1+dx);
bmp->Canvas->Font->Color=clYellow;
bmp->Canvas->Brush->Style=bsClear;
bmp->Canvas->TextOutA(x0,y0-20,"x0");
bmp->Canvas->TextOutA(x0+pan+20,y0+5,"x0+pan");
bmp->Canvas->TextOutA(x1,y1+5,"x1");
bmp->Canvas->Brush->Style=bsSolid;
// render backbuffer
Main->Canvas->Draw(0,0,bmp);
_redraw=false;
}
//---------------------------------------------------------------------------
如果您忽略渲染内容,这对您来说很重要:
pan=(x1-x0+(0.5*w))*t;
zoom=0.5*FOVx/atan(((1.0-t)*(x1-x0)+(0.5*w*t))/h);
所以我稍微改变了
x1
(它是纸张的另一边)的含义,而不是上面原始方程中的x1
,我使用了x1+w*t
,这意味着纸张在开始时不在视图中(t=0
) )但是它从外面接触它并且当(t=1)
时它完全在视野中。剩下的只是替换的结果...
w
是纸张宽度,t=<0.0,1.0>
是动画参数,其他值没有改变意义...
动画只是在我的 GIF 编码器记录的 150 毫秒计时器中将
t
增加 0.02
(这就是它如此不稳定的原因)