libgdx绘制圆弧曲线
libgdx drawing arc curve
libgdx的圆弧函数不是画圆弧而是画饼图(即有2条线连接到圆弧的原点)
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.arc(x, y, radius, 30, 120);
shapeRenderer.end();
有没有办法解决这个问题,让libgdx可以画出类似于html5 canvas弧函数的圆弧曲线?
阅读源代码,这似乎是内置行为:
/** Draws an arc using {@link ShapeType#Line} or {@link ShapeType#Filled}. */
public void arc (float x, float y, float radius, float start, float degrees, int segments) {
if (segments <= 0) throw new IllegalArgumentException("segments must be > 0.");
float colorBits = color.toFloatBits();
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
if (shapeType == ShapeType.Line) {
check(ShapeType.Line, ShapeType.Filled, segments * 2 + 2);
renderer.color(colorBits);
renderer.vertex(x, y, 0); <b><--- CENTER</b>
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0); <b><--- LINE TO START POINT</b>
for (int i = 0; i < segments; i++) {
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
}
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0); <b><-- LINE TO END POINT</b>
...
最简单的方法可能是复制整个函数并至少删除我标记的两行:CENTER
和 LINE TO END POINT
,以及每个上方随附的 renderer.color(..
行。
(您也可以删除 LINE TO START POINT
– 它 出现 以设置曲线的起点,但那是实际上也是在循环内完成的,所以它是多余的。)
该函数的第二部分用于填充 "arc"(我同意,它应该正确命名为 "pie" 或 "wedge"),但您在这里不需要因为它会完全一样。
如果你让它工作,你可以将它推荐给 libgdx 的维护者,例如在 libgdx's Contributions Forum.
最后我对 ShapeRenderer 进行了子分类 Class
public class Arc extends ShapeRenderer{
private final ImmediateModeRenderer renderer;
private final Color color = new Color(1, 1, 1, 1);
public Arc(){
renderer = super.getRenderer();
}
/** Draws an arc using {@link ShapeType#Line} or {@link ShapeType#Filled}. */
public void arc (float x, float y, float radius, float start, float degrees) {
int segments = (int)(6 * (float)Math.cbrt(radius) * (degrees / 360.0f));
if (segments <= 0) throw new IllegalArgumentException("segments must be > 0.");
float colorBits = color.toFloatBits();
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
for (int i = 0; i < segments; i++) {
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
}
}
}
然后这样调用
Arc a = new Arc();
a.setProjectionMatrix(cam.combined);
a.begin(ShapeType.Line);
a.arc(10, 10, 10, 30, 120);
a.end();
角度很奇怪,无法正确,不确定这是我的代码还是 libGDX
我认为您和其他响应者已经发布了当前最佳解决方案。 "hack"
的人的另一种选择
- 不太关心性能
- 有静态背景
将在用相同绘制的背景色线条绘制的 2 条线上进行渲染,以在之后将它们遮盖起来。是的,它是蹩脚但快速而肮脏的小代码解决方案。
这是一个使用 kotlin 扩展的简单解决方案。
/** Draws an arc with 'stroke' of given width */
fun ShapeRenderer.strokeArc(strokeWidth: Float, x: Float, y: Float, radius: Float, start: Float, degrees: Float, sampling: Float = 2f, color: Color = Color.WHITE) {
val segments = ((6 * Math.cbrt(radius.toDouble()) * (Math.abs(degrees) / 360.0f)) * sampling).toInt()
val colorBits = color.toFloatBits()
for (i in 0 until segments) {
val x1 = radius * MathUtils.cosDeg(start + (degrees / segments) * i)
val y1 = radius * MathUtils.sinDeg(start + (degrees / segments) * i)
val x2 = (radius - strokeWidth) * MathUtils.cosDeg(start + (degrees / segments) * i)
val y2 = (radius - strokeWidth) * MathUtils.sinDeg(start + (degrees / segments) * i)
val x3 = radius * MathUtils.cosDeg(start + (degrees / segments) * (i + 1))
val y3 = radius * MathUtils.sinDeg(start + (degrees / segments) * (i + 1))
val x4 = (radius - strokeWidth) * MathUtils.cosDeg(start + (degrees / segments) * (i + 1))
val y4 = (radius - strokeWidth) * MathUtils.sinDeg(start + (degrees / segments) * (i + 1))
renderer.color(colorBits)
renderer.vertex(x + x1, y + y1, 0f)
renderer.color(colorBits)
renderer.vertex(x + x3, y + y3, 0f)
renderer.color(colorBits)
renderer.vertex(x + x2, y + y2, 0f)
renderer.color(colorBits)
renderer.vertex(x + x3, y + y3, 0f)
renderer.color(colorBits)
renderer.vertex(x + x2, y + y2, 0f)
renderer.color(colorBits)
renderer.vertex(x + x4, y + y4, 0f)
}
}
为了更好地理解这一点以及内置解决方案为何如此行事。 ShapeRenderer 绘制三角形(就像 OpenGL 所做的那样)所以你需要 3 个顶点来绘制三角形。在这里,我们一次绘制一个线段。每段由 2 个三角形组成一个矩形。足够多的矩形开始看起来像一个光滑的圆圈。
内置 ShapeRenderer.arc 的绘制方式很像馅饼。如果你有足够多的直边切片,它开始看起来像一个完整的馅饼,而不是中心的一堆三角形。
我希望这有一定的意义,并允许其他人绘制自己的自定义形状并为将来学习!
libgdx的圆弧函数不是画圆弧而是画饼图(即有2条线连接到圆弧的原点)
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.arc(x, y, radius, 30, 120);
shapeRenderer.end();
有没有办法解决这个问题,让libgdx可以画出类似于html5 canvas弧函数的圆弧曲线?
阅读源代码,这似乎是内置行为:
/** Draws an arc using {@link ShapeType#Line} or {@link ShapeType#Filled}. */
public void arc (float x, float y, float radius, float start, float degrees, int segments) {
if (segments <= 0) throw new IllegalArgumentException("segments must be > 0.");
float colorBits = color.toFloatBits();
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
if (shapeType == ShapeType.Line) {
check(ShapeType.Line, ShapeType.Filled, segments * 2 + 2);
renderer.color(colorBits);
renderer.vertex(x, y, 0); <b><--- CENTER</b>
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0); <b><--- LINE TO START POINT</b>
for (int i = 0; i < segments; i++) {
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
}
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0); <b><-- LINE TO END POINT</b>
...
最简单的方法可能是复制整个函数并至少删除我标记的两行:CENTER
和 LINE TO END POINT
,以及每个上方随附的 renderer.color(..
行。
(您也可以删除 LINE TO START POINT
– 它 出现 以设置曲线的起点,但那是实际上也是在循环内完成的,所以它是多余的。)
该函数的第二部分用于填充 "arc"(我同意,它应该正确命名为 "pie" 或 "wedge"),但您在这里不需要因为它会完全一样。
如果你让它工作,你可以将它推荐给 libgdx 的维护者,例如在 libgdx's Contributions Forum.
最后我对 ShapeRenderer 进行了子分类 Class
public class Arc extends ShapeRenderer{
private final ImmediateModeRenderer renderer;
private final Color color = new Color(1, 1, 1, 1);
public Arc(){
renderer = super.getRenderer();
}
/** Draws an arc using {@link ShapeType#Line} or {@link ShapeType#Filled}. */
public void arc (float x, float y, float radius, float start, float degrees) {
int segments = (int)(6 * (float)Math.cbrt(radius) * (degrees / 360.0f));
if (segments <= 0) throw new IllegalArgumentException("segments must be > 0.");
float colorBits = color.toFloatBits();
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
for (int i = 0; i < segments; i++) {
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
renderer.color(colorBits);
renderer.vertex(x + cx, y + cy, 0);
}
}
}
然后这样调用
Arc a = new Arc();
a.setProjectionMatrix(cam.combined);
a.begin(ShapeType.Line);
a.arc(10, 10, 10, 30, 120);
a.end();
角度很奇怪,无法正确,不确定这是我的代码还是 libGDX
我认为您和其他响应者已经发布了当前最佳解决方案。 "hack"
的人的另一种选择- 不太关心性能
- 有静态背景
将在用相同绘制的背景色线条绘制的 2 条线上进行渲染,以在之后将它们遮盖起来。是的,它是蹩脚但快速而肮脏的小代码解决方案。
这是一个使用 kotlin 扩展的简单解决方案。
/** Draws an arc with 'stroke' of given width */
fun ShapeRenderer.strokeArc(strokeWidth: Float, x: Float, y: Float, radius: Float, start: Float, degrees: Float, sampling: Float = 2f, color: Color = Color.WHITE) {
val segments = ((6 * Math.cbrt(radius.toDouble()) * (Math.abs(degrees) / 360.0f)) * sampling).toInt()
val colorBits = color.toFloatBits()
for (i in 0 until segments) {
val x1 = radius * MathUtils.cosDeg(start + (degrees / segments) * i)
val y1 = radius * MathUtils.sinDeg(start + (degrees / segments) * i)
val x2 = (radius - strokeWidth) * MathUtils.cosDeg(start + (degrees / segments) * i)
val y2 = (radius - strokeWidth) * MathUtils.sinDeg(start + (degrees / segments) * i)
val x3 = radius * MathUtils.cosDeg(start + (degrees / segments) * (i + 1))
val y3 = radius * MathUtils.sinDeg(start + (degrees / segments) * (i + 1))
val x4 = (radius - strokeWidth) * MathUtils.cosDeg(start + (degrees / segments) * (i + 1))
val y4 = (radius - strokeWidth) * MathUtils.sinDeg(start + (degrees / segments) * (i + 1))
renderer.color(colorBits)
renderer.vertex(x + x1, y + y1, 0f)
renderer.color(colorBits)
renderer.vertex(x + x3, y + y3, 0f)
renderer.color(colorBits)
renderer.vertex(x + x2, y + y2, 0f)
renderer.color(colorBits)
renderer.vertex(x + x3, y + y3, 0f)
renderer.color(colorBits)
renderer.vertex(x + x2, y + y2, 0f)
renderer.color(colorBits)
renderer.vertex(x + x4, y + y4, 0f)
}
}
为了更好地理解这一点以及内置解决方案为何如此行事。 ShapeRenderer 绘制三角形(就像 OpenGL 所做的那样)所以你需要 3 个顶点来绘制三角形。在这里,我们一次绘制一个线段。每段由 2 个三角形组成一个矩形。足够多的矩形开始看起来像一个光滑的圆圈。
内置 ShapeRenderer.arc 的绘制方式很像馅饼。如果你有足够多的直边切片,它开始看起来像一个完整的馅饼,而不是中心的一堆三角形。
我希望这有一定的意义,并允许其他人绘制自己的自定义形状并为将来学习!