【问题标题】:Draw an arc in opengl GL10在opengl GL10中画一条弧线
【发布时间】:2015-12-09 05:05:48
【问题描述】:

我想在 opengl surfaceview 上使用中心点、起点、终点绘制弧线。到目前为止,我已经尝试过下面给出的代码。如果我们手动指定 start_line_angleend_line_angle 的值(如 start_line_angle=0 和 end_line_angle,此函数将绘制预期的弧线>=90) 度数。

但我需要用给定的坐标(中心点、起点、终点)绘制一条弧线,并以编程方式计算 start_line_angleend_line_angle。 这个给定的函数用给定的参数绘制一条弧线,但没有给出期望的结果。我为此浪费了 2 天时间。提前致谢。

 private void drawArc(GL10 gl, float radius, float cx, float cy, float start_point_x, float start_point_y, float end_point_x, float end_point_y) {
        gl.glLineWidth(1);
        int start_line_angle;
        double sLine = Math.toDegrees(Math.atan((cy - start_point_y) / (cx - start_point_x)));   //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line first
        double eLine = Math.toDegrees(Math.atan((cy - end_point_y) / (cx - end_point_x)));         //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line second

        //cast from double to int after round
        int start_line_Slope = (int) (sLine + 0.5);


        /**
         * mapping the tiriogonometric angle system to glsurfaceview angle system
         * since angle system in trigonometric system starts in anti clockwise
         * but in opengl glsurfaceview angle system starts in clock wise and the starting angle is 90 degree of general trigonometric angle system
         **/
        if (start_line_Slope <= 90) {
            start_line_angle = 90 - start_line_Slope;
        } else {
            start_line_angle = 360 - start_line_Slope + 90;
        }

//        int start_line_angle = 270;
//        int end_line_angle = 36;

        //casting from double to int
        int end_line_angle = (int) (eLine + 0.5);

        if (start_line_angle > end_line_angle) {
            start_line_angle = start_line_angle - 360;

        }
        int nCount = 0;

        float[] stVertexArray = new float[2 * (end_line_angle - start_line_angle)];

        float[] newStVertextArray;
        FloatBuffer sampleBuffer;

//        stVertexArray[0] = cx;
//        stVertexArray[1] = cy;

        for (int nR = start_line_angle; nR < end_line_angle; nR++) {
            float fX = (float) (cx + radius * Math.sin((float) nR * (1 * (Math.PI / 180))));
            float fY = (float) (cy + radius * Math.cos((float) nR * (1 * (Math.PI / 180))));

            stVertexArray[nCount * 2] = fX;
            stVertexArray[nCount * 2 + 1] = fY;
            nCount++;
        }

        //taking making the stVertextArray's data in reverse order
        reverseArray = new float[stVertexArray.length];//-2 so that no repeatation occurs of first value and end value
        int count = 0;


        for (int i = (stVertexArray.length) / 2; i > 0; i--) {
            reverseArray[count] = stVertexArray[(i - 1) * 2 + 0];
            count++;
            reverseArray[count] = stVertexArray[(i - 1) * 2 + 1];
            count++;
        }

        //reseting the counter to initial value
        count = 0;
        int finalArraySize = stVertexArray.length + reverseArray.length;
        newStVertextArray = new float[finalArraySize];

        /**Now adding all the values to the single newStVertextArray to draw an arc**/

        //adding stVertextArray to newStVertextArray
        for (float d : stVertexArray) {
            newStVertextArray[count++] = d;
        }

        //adding reverseArray to newStVertextArray
        for (float d : reverseArray) {
            newStVertextArray[count++] = d;
        }

        Log.d("stArray", stVertexArray.length + "");
        Log.d("reverseArray", reverseArray.length + "");
        Log.d("newStArray", newStVertextArray.length + "");

        ByteBuffer bBuff = ByteBuffer.allocateDirect(newStVertextArray.length * 4);
        bBuff.order(ByteOrder.nativeOrder());
        sampleBuffer = bBuff.asFloatBuffer();
        sampleBuffer.put(newStVertextArray);
        sampleBuffer.position(0);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(2, GL10.GL_FLOAT, 0, sampleBuffer);
        gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, nCount * 2);
        gl.glLineWidth(1);
    }

【问题讨论】:

  • 你想用 3 个点画什么样的弧?这是圆弧还是椭圆弧?还是贝塞尔曲线?究竟是什么?我看到你在一个半径范围内经过;这似乎违背了使用 3 分的目的。
  • 老实说我不想使用半径,因为如果我们有起点和中心点,我们也可以计算半径。我们可以忽略半径,但在这个计算圆上的点的函数中,我们也需要半径,所以我使用了这个。我需要圆弧。我不知道如何达到结果。我也是opengl-es的新手:(
  • OpenGL ES 部分本质上是无关的;只要您可以绘制线段,问题就是要绘制哪些线段来形成您的弧线。问题是一个中心和 2 个点不形成 弧。您必须将两个点限制为都在圆圈上。
  • 先生,您有没有实现这个目标的示例源代码:)

标签: java android opengl-es automatic-ref-counting


【解决方案1】:

从三角函数开始,您不能简单地使用atan 来求角度的度数。您需要检查向量在哪个象限,并增加或减少从atan 获得的结果。最好使用atan2,它应该同时包含dxdy,并为您完成这项工作。

您似乎创建了缓冲区,以便每度创建一个点。这不是最好的解决方案,因为大半径可能太小,而对于小半径,这太多了。镶嵌也应该包括半径,这样N 的点数是N = abs((int)(deltaAngle*radius*tessellationFactor)),然后使用angleFragment = deltaAngle/N,但要确保N 大于0 (N = N?N:1)。然后缓冲区大小为2*(N+1) 的浮点数,如果为for(int i=0; i&lt;=N; i++) angle = startAngle + angleFragment*i;,则为迭代。

正如已经指出的,您需要定义圆弧的半径。以您的方式使用外部源并简单地将其强制为该值是很正常的,但使用 3 个点作为中心和两个边界。其他一些通常有意义的选项是:

  • 从起点获取半径
  • 从两条线中较短的一条线获取半径
  • 求两者的平均值
  • 对两者进行插值得到椭圆曲线(如下所述)

要插入半径,您需要获得两个半径 startRadiusendRadius。然后你需要找到上面已经用作deltaAngle的整体半径(计算这个时要小心,它看起来更复杂,例如从320度绘制到10度导致deltaAngle = 50)。无论如何,特定点的半径就是radius = startRadius + (endRadius-startRadius)*abs((angleFragment*i)/deltaAngle)。这代表了极坐标系中的简单线性插值,通常用于对矩阵中的向量进行插值,是获得漂亮动画的核心功能。

还有其他一些获取弧点的方法可能会更好地提高性能,但我不会建议它们,除非并且直到您需要优化您的代码,这应该在生产中很晚。您可以简单地继续向下一个点前进并修正半径(这只是一个概念):

        vec2 start, end, center; // input values
        float radius; // input value

        // making the start and end relative to center
        start -= center;
        end -= center;

        vec2 current = start/length(start) * radius;  // current position starts in first vector

        vec2 target = end/length(end) * radius; // should be the last point

        outputBuffer[0] = current+center; // insert the first point
        for(int i=1;; i++) { // "break" will need to exit the loop, we need index only for the buffer
            vec2 step = vec2(current.y, -(current.x)); // a tangential vector from current start point according to center
            step = step/length(step) / tessellationScale; // normalize and apply tessellation

            vec2 next = current + step; // move tangentially
            next = next/length(next) * radius; // normalize and set the

            if(dot(current-target, next-target) > .0) { // when we passed the target vector
                current = next; // set the current point
                outputBuffer[i] = current+center; // insert into buffer
            }
            else {
                current = target; // simply use the target now
                outputBuffer[i] = current+center; // insert into buffer
                break; // exit
            }
        }

【讨论】:

  • 我通过简单地修改这些行来解决这个问题: double sLine = Math.abs(Math.toDegrees(Math.atan((cy - start_point_y) / (cx - start_point_x))));双 eLine = Math.abs(Math.toDegrees(Math.atan((cy - end_point_y) / (cx - end_point_x)))); int tStart = (int) (sLine + 0.5); int tEnd = (int) (eLine + 0.5);
  • 最后是这个:int start_line_angle = 90 - tStart; int end_line_angle = 90 - tEnd; int temp = start_line_angle; /** * 因为凝视角度总是小于结束角度 */ if (start_line_angle > end_line_angle) { start_line_angle = end_line_angle; end_line_angle = 温度; }
  • 我希望你对所有象限都做了测试。例如 start = (-.1, -1.0) end = (-.1, 1.0) center = (0,0)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多