B样条曲线渲染及生成全景图
采用OpenGL场景中渲染B样条曲线,曲线控制点给生成全景图算法,生成全景图,创建过程:
- 场景中B样条曲线,需要渲染的部分:B样条的控制点controlPoint,及由控制点B样条算法生成的曲线上的点linePoint;这些点通过坐标转换,将屏幕坐标转换为世界坐标。曲线外面矩形框点,固定的点,世界坐标。
- 全景图中B样条算法中需要的控制点,需要的是像素坐标。因此,曲线actor中传给B样条算法的点需要像素坐标,而曲线需要B样条计算出来的点转换为世界坐标。
传给BSpline算法:
double dTheta = m_fRotateAngle / 180f * Math.PI;
float[] fMatrix = { (float)Math.Cos(dTheta), (float)Math.Sin(dTheta),0,
-(float)Math.Sin(dTheta),(float)Math.Cos(dTheta),0,
m_fCenterX,m_fCenterY,1};
visMat3f mvisMat3f = new visMat3f(fMatrix);
visMat3f mvisMat3fInvert = mvisMat3f.GetInvert();
float fNewNodeX = (mvisMat3fInvert.f00 * fMouseX + mvisMat3fInvert.f10 * fMouseY + mvisMat3fInvert.f20)
/ m_fScaleX;
float fNewNodeY = (mvisMat3fInvert.f01 * fMouseX + mvisMat3fInvert.f11 * fMouseY + mvisMat3fInvert.f21)
/ m_fScaleY;
visVec3f visV3fNewPosition = new visVec3f(fNewNodeX, fNewNodeY);
m_lv3fNodePoints.Insert(m_nWhichPointIsSelected, visV3fNewPosition);
m_lv3fNodePoints.RemoveAt(m_nWhichPointIsSelected + 1);
float fPixelX = 0;
float fPixelY = 0;
CoordWorldToPixel(fNewNodeX, fNewNodeY, ref fPixelX, ref fPixelY);
m_algoBSpline.MoveNodePoint(fPixelX, fPixelY, m_nWhichPointIsSelected);
B样条算法传给actor的linePoint
List<visVec3f> listV3fLineStrip = new List<visVec3f>();
m_algoBSpline.GetPanoLineStrip(listV3fLineStrip);
m_lv3fPanoLine.Clear();
foreach (visVec3f v3fPixel in listV3fLineStrip)
{
float fWolrdX = 0;
float fWolrdY = 0;
CoordPixelToWorld(v3fPixel.x, v3fPixel.y, ref fWolrdX, ref fWolrdY);
m_lv3fPanoLine.Add(new visVec3f(fWolrdX, fWolrdY));
}
- 以上可以看出actor中B样条算法BSpline,与生成全景图需要的B样条算法BSpline所需控制点均为像素坐标。
- 另在编辑整个图形时,核心主要以下几点:
1)移动外面边框时,actor曲线上的点(controlpoint 及linepoint)坐标均不变,在渲染时,已经将框的平移及缩放量计算;
GL.PushMatrix();
GL.Translate(m_fCenterX, m_fCenterY, 0);
GL.Rotate(m_fRotateAngle, 0, 0, 1);
GL.Scale(m_fScaleX, m_fScaleY, 0f);
2) 移动控制点时,actor本身控制点坐标需改变,全景算法中B样条控制点同样需要改变,见3
double dTheta = m_fRotateAngle / 180f * Math.PI;
float[] fMatrix = { (float)Math.Cos(dTheta), (float)Math.Sin(dTheta),0,
-(float)Math.Sin(dTheta),(float)Math.Cos(dTheta),0,
m_fCenterX,m_fCenterY,1};
visMat3f mvisMat3f = new visMat3f(fMatrix);
visMat3f mvisMat3fInvert = mvisMat3f.GetInvert();
float fNewNodeX = (mvisMat3fInvert.f00 * fMouseX + mvisMat3fInvert.f10 * fMouseY + mvisMat3fInvert.f20)
/ m_fScaleX;
float fNewNodeY = (mvisMat3fInvert.f01 * fMouseX + mvisMat3fInvert.f11 * fMouseY + mvisMat3fInvert.f21)
/ m_fScaleY;
visVec3f visV3fNewPosition = new visVec3f(fNewNodeX, fNewNodeY);
m_lv3fNodePoints.Insert(m_nWhichPointIsSelected, visV3fNewPosition);
m_lv3fNodePoints.RemoveAt(m_nWhichPointIsSelected + 1);
float fPixelX = 0;
float fPixelY = 0;
CoordWorldToPixel(fNewNodeX, fNewNodeY, ref fPixelX, ref fPixelY);
m_algoBSpline.MoveNodePoint(fPixelX, fPixelY, m_nWhichPointIsSelected);
3)结束移动时,无论是移动点还是框,传给生成全景图的B样条算法的控制点需要计算成绝对的坐标:
#region 只修改传给全景算法的控制点,actor本身的控制点不修改
float fPointX, fPointY;
double dTheta = MathHelper.DegreesToRadians(m_fRotateAngle);
float fPixelX = 0, fPixelY = 0;
m_algoBSplineForP.ClearNodePoint();
for (int i = 0; i < m_lv3fNodePoints.Count; i++)
{
//需要先将目前的点坐标转换为变换后的坐标
fPointX = m_lv3fNodePoints[i].x * m_fScaleX * (float)Math.Cos(dTheta)
- m_lv3fNodePoints[i].y * m_fScaleX * (float)Math.Sin(dTheta) + m_fCenterX / 2;
fPointY = m_lv3fNodePoints[i].x * m_fScaleY * (float)Math.Sin(dTheta)
+ m_lv3fNodePoints[i].y * m_fScaleY * (float)Math.Cos(dTheta) + m_fCenterY / 2;
CoordWorldToPixel(fPointX, fPointY, ref fPixelX, ref fPixelY);
m_algoBSplineForP.AddNodePoint(new visVec3f(fPixelX, fPixelY, 0));
}
UpdateManualPanoramicCurve();
#endregion