Недавно я освоил MonoGame, и мне нравится библиотека. Однако, я, кажется, возникли некоторые проблемы с нанесением кривых БезьеРисование кривых Безье в MonoGame (XNA) производит царапающие линии
В результате, что мой код производит выглядит примерно так
Посмотрите плохо, нет? Линии не являются гладкими.
Позвольте мне показать вам некоторые из кода:
//This is what I call to get all points between which to draw.
public static List<Point> computeCurvePoints(int steps)
{
List<Point> curvePoints = new List<Point>();
for (float x = 0; x < 1; x += 1/(float)steps)
{
curvePoints.Add(getBezierPointRecursive(x, pointsQ));
}
return curvePoints;
}
//Calculates a point on the bezier curve based on the timeStep.
private static Point getBezierPointRecursive(float timeStep, Point[] ps)
{
if (ps.Length > 2)
{
List<Point> newPoints = new List<Point>();
for (int x = 0; x < ps.Length-1; x++)
{
newPoints.Add(interpolatedPoint(ps[x], ps[x + 1], timeStep));
}
return getBezierPointRecursive(timeStep, newPoints.ToArray());
}
else
{
return interpolatedPoint(ps[0], ps[1], timeStep);
}
}
//Gets the linearly interpolated point at t between two given points (without manual rounding).
//Bad results!
private static Point interpolatedPoint(Point p1, Point p2, float t)
{
Vector2 roundedVector = (Vector2.Multiply(p2.ToVector2() - p1.ToVector2(), t) + p1.ToVector2());
return new Point((int)roundedVector.X, (int)roundedVector.Y);
}
//Method used to draw a line between two points.
public static void DrawLine(this SpriteBatch spriteBatch, Texture2D pixel, Vector2 begin, Vector2 end, Color color, int width = 1)
{
Rectangle r = new Rectangle((int)begin.X, (int)begin.Y, (int)(end - begin).Length() + width, width);
Vector2 v = Vector2.Normalize(begin - end);
float angle = (float)Math.Acos(Vector2.Dot(v, -Vector2.UnitX));
if (begin.Y > end.Y) angle = MathHelper.TwoPi - angle;
spriteBatch.Draw(pixel, r, null, color, angle, Vector2.Zero, SpriteEffects.None, 0);
}
//DrawLine() is called as following. "pixel" is just a Texture2D with a single black pixel.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
for(int x = 0; x < curvePoints.Count-1; x++)
{
DrawExtenstion.DrawLine(spriteBatch, pixel, curvePoints[x].ToVector2(), curvePoints[x + 1].ToVector2(), Color.Black, 2);
}
spriteBatch.End();
base.Draw(gameTime);
}
мне удалось сделать линию немного более гладкой, добавив некоторые ручной Math.Round() вызывает к моему методу interpolatedPoint
//Gets the linearly interpolated point at t between two given points (with manual rounding).
//Better results (but still not good).
private static Point interpolatedPoint(Point p1, Point p2, float t)
{
Vector2 roundedVector = (Vector2.Multiply(p2.ToVector2() - p1.ToVector2(), t) + p1.ToVector2());
return new Point((int)Math.Round(roundedVector.X), (int)Math.Round(roundedVector.Y));
}
Это дает следующий результат:
Мне пришлось удалить одно изображение, так как Stackoverflow не позволяет мне использовать более двух ссылок
Есть ли способы, чтобы эта кривая была абсолютно гладкой? Возможно, проблема с методом DrawLine?
Заранее спасибо.
EDIT:
Хорошо, я сумел сделать кривой выглядеть намного лучше, делая все расчеты с Vector2Ds и только преобразовав его в точку, в тот момент, когда он должен быть нарисован
он по-прежнему не является совершенным, хотя:/
что ссылка на втором изображении? мы можем его отредактировать. Тем не менее, трудно сказать, что вы считаете «идеальным». Когда вы занимаетесь такими вещами, никогда не обходитесь до самого последнего момента. И если ваша поверхность рисования может сделать рисунок подпикселя, даже не округлите ее в конце - пусть холст обрабатывает место размещения. (И обычно вместо рисования отдельных точек вы отслеживаете «текущую» и «предыдущую» точку, а вместо этого рисуете линии между ними) –
Выглядит хорошо. Вы, возможно, можете опубликовать свой ** текст ** в качестве ответа ниже. :) – MickyD
Вы изучали использование BasicEffect вместо SpriteBatch? Я думаю, что это лучший способ пойти на этот вопрос. – craftworkgames