使用OpenGLES绘制圆形笔触

时间:2019-08-13 02:36:17

标签: android opengl-es opengl-es-2.0

我要画一个这样的笔划圆:

enter image description here

我尝试使用普通的顶点着色器和片段着色器,例如google samples,顶点坐标为364点:

vertices = new float[364 * 3];
vertices[0] = 0;
vertices[1] = 0;
vertices[2] = 0;

for (int i =1; i <364; i++){
    vertices[(i * 3)+ 0] = (float) (0.5 * Math.cos((3.14/180) * (float)i ));
    vertices[(i * 3)+ 1] = (float) (0.5 * Math.sin((3.14/180) * (float)i ));
    vertices[(i * 3)+ 2] = 0;
}

然后使用以下方法绘制:

int COORDS_PER_VERTEX = 3;
int vertexCount = 364 * 3 / COORDS_PER_VERTEX;
int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

GLES20.glDrawArrays(GLES20.GL_LINE_LOOP, 1, vertexCount - 1);

但是结果与预期不符,我的圈子中有4个缺失的部分。

enter image description here

如何像上面的示例一样绘制笔划的圆?

2 个答案:

答案 0 :(得分:2)

问题是实现glLineWidth的方式。根据{{​​3}}:

  

宽度非一个的非抗锯齿线段通过在短方向上偏移来栅格化(对于x主线,次方向为y,对于y主线,次方向为x)并沿次要方向复制片段(见图3.3)。

这4个缺失部分对应于您的圆线从x-主要变为y-主要的位置。如果仔细看,您会发现随着x-major和y-major之间的切换,圆也变细了。

最好的选择是放弃画线,而改用三角带渲染实心带。即spec中的“三角线”示例也提出了一些更高级的解决方案。

答案 1 :(得分:0)

大多数库使用“三角线”,我认为这是绘制笔触线的最佳方法,因为您可以设置渐变颜色,控制线的不同部分的线宽并绘制平滑线。

但是,如果您想用单色创建笔划圆,您可以做的一招是创建 strokeWidth 1f 的多个圆,然后改变其半径使得每个下一个圆的半径比上一个圆大+(1f / 2)。

enter image description here

我创建了一个OpenGL library,它可以创建多种类型的形状,例如三角形,圆形,三角形等。以下是使用library生成多个圆圈的代码,其结果如上图所示。

     lateinit var circles: Circles // OpenGL circles object

     fun createCircles() {

        val coordinatesInfo = generateCoordinateInfo(400f, 400f, 100f, 20)

        // set object for the OpenGL circles
        circles = Circles(
            // in format: [cx1,cy1,radius1,angle1,  cx2,cy2,radius2,angle2,...]
            coordinatesInfo = coordinatesInfo,
            colors = intArrayOf(Color.RED),
            style = STYLE_STROKE,
            strokeWidth = 1f,
            preloadProgram = program,
            gestureDetector = mainGestureDetector,
            useSingleColor = true
        )
     }

    /**
     * Get the coordinates for the stroke circles
     * @param x x coordinate of the circle
     * @param y y coordinate of the circle
     * @param r radius of the circle
     * @param strokeWidth stroke width of the circle
     */
    fun generateCoordinateInfo(x: Float, y: Float, r: Float, strokeWidth: Int = 20): FloatArray {

        val coordinatesInfo = FloatArray((strokeWidth * 2) * 4)

        for (i in 0 until strokeWidth) {
            val j = i * 4
            coordinatesInfo[j] = x                // x
            coordinatesInfo[j + 1] = y            // y
            coordinatesInfo[j + 2] = r - i / 2f   // radius
            coordinatesInfo[j + 3] = 0f           // angle
        }

        for (i in 0 until strokeWidth) {
            val j = (strokeWidth + i) * 4
            coordinatesInfo[j] = x                // x
            coordinatesInfo[j + 1] = y            // y
            coordinatesInfo[j + 2] = r + i / 2f   // radius
            coordinatesInfo[j + 3] = 0f           // angle
        }

        return coordinatesInfo
    }

    fun draw(transformedMatrixOpenGL: FloatArray) {

        // draw circles
        if (::circles.isInitialized) {
            circles.draw(transformedMatrixOpenGL)
        } 
    }