我在使用 OpenGL 繪制橢圓物件時遇到問題(確切地說是 sharpgl,因為它與 WPF 配合得很好)。
現在我正在使用這段代碼(角度以度為單位):
gl.Begin(OpenGL.GL_LINE_STRIP);
gl.Color(colorR, colorG, colorB, alfa);
for (double i = angleStart; i <= angleEnd; i)
{
double angleCurrent = Math.PI * i / 180;
double dx = radiusX * Math.Cos(angleCurrent);
double dy = radiusY * Math.Sin(angleCurrent);
gl.Vertex(dx ellipseMiddleCoordX, dy ellipseMiddleCoordY, 0);
}
gl.End();
它在繪制角度為 0、90、180、270、360 ( ) 的圓(即radiusX = radiusY
)和橢圓時可以 100% 正常作業radiusX != radiusY
。
但是,radiusX != radiusY
例如,它并不能很好地完成作業angleStart = 30; angleEnd = 70
。
它對上面的例子做了什么,它首先畫一個圓,應用角度,然后重新計算 X/Y 半徑。這給出了不正確的結果,因為我期望這樣的事情:
其中紅色 = 預期行為,黃色 = 上面的代碼,灰色 = 角度的附加線
我對如何解決這個問題感到很迷茫。
PS
是的 - 我知道那些gl.Begin/gl.End
是過時的函式,但我仍然無法掌握 OGL 的完整概念,而且我的大部分程式只是數學。
uj5u.com熱心網友回復:
這是因為橢圓引數角不是幾何角,因為它被每個軸上的不同比例(半徑)扭曲。請參閱這些相關的 QA 以獲得一些靈感:
如您所見,角度在整個圓周上匹配(藍色弧線與黃線對齊)......
The function
float ellipse_angle(float rx,float ry,float ang)
will return elliptic parametric angle that corresponds to geometric angleang
on axis aligned ellipse with half axisesrx,ry
.There are quite a few things that can improve speed of this like using
rx/ry
and scaling just one axis, precompute the angle constants etc.[Edit1] slightly better code
using aspect ratio and render is changed too for better visual check
//--------------------------------------------------------------------------- const float pi2=2.0*M_PI; const float deg=M_PI/180.0; //--------------------------------------------------------------------------- float ellipse_angle(float rx,float ry,float ang) // geometrical angle [rad] -> ellipse parametric angle [rad] { float da,ea,ga,aspect; aspect=rx/ry; // aspect ratio for speed up ang=fmod(ang,pi2); // normalize to <0,pi2> ea=ang; // start elliptic angle ga=atan2(sin(ea),aspect*cos(ea)); // compute geometrical angle from it if (ga<0.0) ga =pi2; // normalize to <0,pi2> if (ga<=ang) // ea >= ang { da=90.0*deg-fmod(ang,90.0*deg); // range to search da*=0.5; for (ea=ang;da>1e-10;da*=0.5) // binary search { ea =da; // test next elliptic angle ga=atan2(sin(ea),aspect*cos(ea)); // compute geometrical angle from it if (ga<0.0) ga =pi2; // normalize to <0,pi2> if (ga>ang) ea-=da; // restore original angle if too big } } else{ // ea <= ang da=fmod(ang,90.0*deg); // range to search da*=0.5; for (ea=ang;da>1e-10;da*=0.5) // binary search { ea-=da; // test next elliptic angle ga=atan2(sin(ea),aspect*cos(ea)); // compute geometrical angle from it if (ga<0.0) ga =pi2; // normalize to <0,pi2> if (ga<ang) ea =da; // restore original angle if too small } } return ea; } //--------------------------------------------------------------------------- void gl_draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glScalef(1.0,float(xs)/float(ys),1.0); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); int i,n=100; float rx=0.95,ry=0.35; float x,y,a,dd,da,a0,a1,ea0,ea1; // test whole circumference for (dd=10.0*deg,a0=0.0,a1=a0 0.75*dd;a1<pi2;a0 =dd,a1 =dd) { // render geometric angle pies (for visual check) glBegin(GL_TRIANGLES); glColor3f(0.1,0.1,0.1); glVertex2f(cos(a0),sin(a0)); glVertex2f(0.0,0.0); glVertex2f(cos(a1),sin(a1)); glEnd(); // get parametric angles (rx,ry) ea0=ellipse_angle(rx,ry,a0); ea1=ellipse_angle(rx,ry,a1); // render elliptic arc (rx,ry) glBegin(GL_LINE_STRIP); glColor3f(0.3,0.7,1.0); for (a=ea0,da=(ea1-ea0)/float(n-1),i=0;i<n;i ,a =da) { x=rx*cos(a); y=ry*sin(a); glVertex2f(x,y); } glEnd(); // get parametric angles (ry,rx) ea0=ellipse_angle(ry,rx,a0); ea1=ellipse_angle(ry,rx,a1); // render elliptic arc (ry,rx) glBegin(GL_LINE_STRIP); glColor3f(1.0,0.7,0.3); for (a=ea0,da=(ea1-ea0)/float(n-1),i=0;i<n;i ,a =da) { x=ry*cos(a); y=rx*sin(a); glVertex2f(x,y); } glEnd(); } glFlush(); SwapBuffers(hdc); } //---------------------------------------------------------------------------
There still room for improvement like get rid of
atan2
completely and use cross product instead like I did in here:Here C code:
//--------------------------------------------------------------------------- const float pi2=2.0*M_PI; const float deg=M_PI/180.0; //--------------------------------------------------------------------------- float ellipse_angle(float rx,float ry,float ang) // geometrical angle [rad] -> ellipse parametric angle [rad] { float x,y,t,aa,bb,ea; x=cos(ang); // axis direction at angle ang y=sin(ang); aa=rx*rx; bb=ry*ry; // intersection between ellipse and axis t=aa*bb/((x*x*bb) (y*y*aa)); x*=t; y*=t; y*=rx/ry; // convert to circle ea=atan2(y,x); // compute elliptic angle if (ea<0.0) ea =pi2; // normalize to <0,pi2> return ea; } //---------------------------------------------------------------------------
上一篇:將數字增加或減少“x”百分比