- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我最近开始使用 MonoGame,我喜欢这个库。但是,我似乎在绘制贝塞尔曲线时遇到了一些问题
我的代码产生的结果看起来像这样
看起来很糟糕,不是吗?线条一点也不流畅。
让我向您展示一些代码:
//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);
}
通过向我的 interpolatedPoint 方法添加一些手动 Math.Round() 调用,我设法使线条更平滑一些
//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 方法有问题?
提前致谢。
编辑:
好吧,通过使用 Vector2D 进行所有计算并仅在需要绘制时将其转换为点,我设法使曲线看起来好多了
虽然还不够完美:/
最佳答案
正如 Mike 'Pomax' Kamermans 所说,这似乎是 2D 表面不允许子像素绘制并因此导致舍入问题的问题
根据 craftworkgames 的建议,我调整了算法以使用 BasicEffect 在 3D 中绘制曲线。这也允许抗锯齿,从而使曲线平滑很多。
结果如下:
好多了!
非常感谢您提供有用的建议!
编辑:
这是我用来执行此操作的代码。
我还想补充一点,这个网页 ( http://gamedevelopment.tutsplus.com/tutorials/create-a-glowing-flowing-lava-river-using-bezier-curves-and-shaders--gamedev-919 ) 在编写这段代码时帮助了我很多。
另外,请注意,我用于定义方法的一些名称可能没有实际意义或可能令人困惑。这是我在一个晚上快速整理的东西。
//Used for generating the mesh for the curve
//First object is vertex data, second is indices (both as arrays)
public static object[] computeCurve3D(int steps)
{
List<VertexPositionTexture> path = new List<VertexPositionTexture>();
List<int> indices = new List<int>();
List<Vector2> curvePoints = new List<Vector2>();
for (float x = 0; x < 1; x += 1 / (float)steps)
{
curvePoints.Add(getBezierPointRecursive(x, points3D));
}
float curveWidth = 0.003f;
for(int x = 0; x < curvePoints.Count; x++)
{
Vector2 normal;
if(x == 0)
{
//First point, Take normal from first line segment
normal = getNormalizedVector(getLineNormal(curvePoints[x+1] - curvePoints[x]));
}
else if (x + 1 == curvePoints.Count)
{
//Last point, take normal from last line segment
normal = getNormalizedVector(getLineNormal(curvePoints[x] - curvePoints[x-1]));
} else
{
//Middle point, interpolate normals from adjacent line segments
normal = getNormalizedVertexNormal(getLineNormal(curvePoints[x] - curvePoints[x - 1]), getLineNormal(curvePoints[x + 1] - curvePoints[x]));
}
path.Add(new VertexPositionTexture(new Vector3(curvePoints[x] + normal * curveWidth, 0), new Vector2()));
path.Add(new VertexPositionTexture(new Vector3(curvePoints[x] + normal * -curveWidth, 0), new Vector2()));
}
for(int x = 0; x < curvePoints.Count-1; x++)
{
indices.Add(2 * x + 0);
indices.Add(2 * x + 1);
indices.Add(2 * x + 2);
indices.Add(2 * x + 1);
indices.Add(2 * x + 3);
indices.Add(2 * x + 2);
}
return new object[] {
path.ToArray(),
indices.ToArray()
};
}
//Recursive algorithm for getting the bezier curve points
private static Vector2 getBezierPointRecursive(float timeStep, Vector2[] ps)
{
if (ps.Length > 2)
{
List<Vector2> newPoints = new List<Vector2>();
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 interpolated Vector2 based on t
private static Vector2 interpolatedPoint(Vector2 p1, Vector2 p2, float t)
{
return Vector2.Multiply(p2 - p1, t) + p1;
}
//Gets the normalized normal of a vertex, given two adjacent normals (2D)
private static Vector2 getNormalizedVertexNormal(Vector2 v1, Vector2 v2) //v1 and v2 are normals
{
return getNormalizedVector(v1 + v2);
}
//Normalizes the given Vector2
private static Vector2 getNormalizedVector(Vector2 v)
{
Vector2 temp = new Vector2(v.X, v.Y);
v.Normalize();
return v;
}
//Gets the normal of a given Vector2
private static Vector2 getLineNormal(Vector2 v)
{
Vector2 normal = new Vector2(v.Y, -v.X);
return normal;
}
//Drawing method in main Game class
//curveData is a private object[] that is initialized in the constructor (by calling computeCurve3D)
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
var camPos = new Vector3(0, 0, 0.1f);
var camLookAtVector = Vector3.Forward;
var camUpVector = Vector3.Up;
effect.View = Matrix.CreateLookAt(camPos, camLookAtVector, camUpVector);
float aspectRatio = graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
float fieldOfView = MathHelper.PiOver4;
float nearClip = 0.1f;
float farClip = 200f;
//Orthogonal
effect.Projection = Matrix.CreateOrthographic(480 * aspectRatio, 480, nearClip, farClip);
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
effect.World = Matrix.CreateScale(200);
graphics.GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList,
(VertexPositionTexture[])curveData[0],
0,
((VertexPositionTexture[])curveData[0]).Length,
(int[])curveData[1],
0,
((int[])curveData[1]).Length/3);
}
base.Draw(gameTime);
}
此外,这张图片可能能够更好地显示代码的作用
关于c# - 在 MonoGame (XNA) 中绘制贝塞尔曲线会产生划痕线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33977226/
所以我目前正在尝试使用 MonoGame 在 Visual Studio (C#) 中制作游戏,但是当我尝试双击 Content Folder 中的 Content 文件时 MPT 没有打开。在我观看
我在 Mac OS X Yosemite 上使用 Xamarin 5.9.1。我构建了一个运行 Xamarin.iOS 的 iOS 游戏。我能够从 NuGet 成功地将 MonoGame.Framew
我已经下载并安装了适用于 Linux 的 Monogame,如下所示:http://www.monogame.net/documentation/?page=Setting_Up_MonoGame_L
当我下载 MonoGame(我将使用它代替 XNA,因为我在 Mac 上)并解压缩它时,所有 MonoDevelop 解决方案文件都被命名为 MonoGame.Framework.[PLATFORM
我知道之前曾有人问过这个问题,但我是通过 Mono游戏来完成的,而我使用的编程语言是 C#。 我制作了一款游戏,其目的是克服障碍,每遇到一个障碍,您都可以赚取积分。现在,我正在尝试添加点睛之笔。我已经
我正在尝试使用Monogame引擎对一些旧的Arcade游戏进行C#编程。但是,我遇到了一个问题。 由于我的代码有些混乱,因此当玩家成功完成游戏时,我通常不花力气重置所有内容。相反,我只是关闭当前的G
我正在使用 Window Project (在MonoGame 3.2中),该项目使用 DirectX 而不是OpenGL。 如果我运行游戏,那么它将显示给我: "Could not load win
我不明白如何设置 monogame 内容项目。请帮助我 :)我试图阅读这些东西:https://github.com/mono/MonoGame/wiki/MonoGame-Content-Proce
我正在为比赛编写游戏,我们必须创建直接从 CD 运行的游戏,而无需在计算机上安装任何组件。 MonoGame 看起来是一个不错的候选者,因为它是跨平台的,我想使用 C# ,但我无法确定它是否需要安装任
我在游戏中遇到 2D 碰撞检测问题。 问题是我的播放器的矩形没有正确地注册与其他对象的矩形的交点。 我想知道我用来旋转播放器的 origin 变量是否与我的问题有任何关系,以及如何解决它。 我会更详细
我刚刚开始使用 MonoGame(以及一般的游戏编程)并且无法运行任何程序。我不断收到此异常消息 An unhandled exception of type 'System.DllNotFoundE
在MonoGame中,如何以字符串形式读取按下的是哪个键盘键? 我试过 String pressedKey = Keyboard.GetState().ToString();,但它给了我“Micros
我正在构建一个 2D 平台游戏。但是制作视频的人只是展示了如何创建 map 和图 block 类并从他制作的数组中加载关卡。我听说这是一种不好的做法,人们应该从文件中加载关卡...我知道如何使用流阅读
我正在开发游戏并开发“主菜单”,在那里有一个设置场景。该场景包含一些选项卡,对于“视频”选项卡,我想要一个允许切换分辨率的下拉菜单。现在,我了解了后一部分的逻辑,但是使用XNA框架时,我无法理解下拉菜
我正在创建一个基于小行星的 2D 游戏。在那场比赛中,我需要将船推向一个方向。 我可以画出这艘船,让它掉头。但是当谈到推进它时,我的问题出现了。 我似乎无法理解这个问题。 (整个制作游戏的过程对我来说
前几天,我启动了我的 monogame 项目并启动它来进行快速游戏测试。这是行不通的。我遇到了 2 个错误。 Error 1 The command "SETX MONOGAME_PLATFORM "
我正在用 Monogame 制作游戏。 我使用 2 台计算机进行编程,都是 Windows 8 x64 和 VS 2013 Pro在我的一台电脑上,我没有任何问题。声音很好用(我使用的是 DX 版本)
我正在写一个小 Monogame,我想知道如何绘制一条由某些公式生成的曲线,然后我想用某种颜色填充该曲线下方的所有内容,我想在顶部生成东西并放下他们下来,直到他们与曲线相撞。查看图片以更好地了解我的问
我正在开发一款全屏 Windows 游戏。今天我看到一个独立游戏(用 XNA 制作)有以下行为:当它是焦点窗口时,它会 Update() 和 Draw() 但是当它得到最小化它停止这两个并等待用户再次
好的,所以我将我一直在开发的游戏移植到 Monogame,但是现在移植后我遇到了着色器问题。这是一个奇怪的错误,因为它适用于我的旧 XNA 项目,而且我第一次在新的 monogame 项目中使用它时它
我是一名优秀的程序员,十分优秀!