如何在iPhone上使用OpenGL ES绘制实心圆?

4

如何在iPhone上使用openGl绘制实心圆?

我找到了很多解决方案,但都没有成功。可能是因为有很多方法可以做到。但是哪种方法的代码最短?


它们都不起作用?哦,怎么回事? - genpfault
很有趣听到你找到的解决方案以及你迄今为止尝试过的方法。如果它们都不起作用,我怀疑你的实现中存在一些错误! - kroneml
4个回答

17

如果您想要一个真正平滑的圆,您需要编写一个自定义片段着色器。例如以下顶点着色器:

 attribute vec4 position;
 attribute vec4 inputTextureCoordinate;

 varying vec2 textureCoordinate;

 void main()
 {
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
 }

和片元着色器:

 varying highp vec2 textureCoordinate;

 const highp vec2 center = vec2(0.5, 0.5);
 const highp float radius = 0.5;

 void main()
 {
     highp float distanceFromCenter = distance(center, textureCoordinate);
     lowp float checkForPresenceWithinCircle = step(distanceFromCenter, radius);

     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * checkForPresenceWithinCircle;     
 }

此代码将在你绘制到屏幕的正方形内画出一个平滑的红色圆。你需要提供正方形的顶点给position属性,并且对于inputTextureCoordinate属性,需要提供范围为0.0至1.0的X和Y坐标,但这样做将绘制一个尖锐度取决于视口分辨率的圆,并且速度非常快。


我也认为这是最好的解决方案。请注意,您可以使用(三角形)广告牌绘制正方形,也可以只使用正确的点大小绘制一个点。第二种解决方案的优点是您只需要传输点位置和半径(即一个vec4)。如果您有一个3D场景,您也不必担心您的正方形面向相机。 - kroneml
但是如何避免绘制正方形的黑色部分呢? 例如,如果您想在屏幕上绘制几个这样的球体,并且它们重叠,则正方形的“黑色”部分将覆盖其他球体,就像这张图片中一样:http://imgur.com/e7Z4ugb - OMH
1
@OMH - 上述代码中该部分是透明绘制的,您需要启用混合以确保在球体边缘不仅得到不透明的黑色。对于重叠的球体,您还需要进行深度渲染预处理以生成深度查找纹理,以确定何时拒绝被其他合并到此球体中的球体阻挡的片段。我在这里描述了这个过程:http://www.sunsetlakesoftware.com/2011/05/08/enhancing-molecules-using-opengl-es-20和https://dev59.com/Qm025IYBdhLWcg3wW0yx。 - Brad Larson
2
为了得到更加平滑的圆形,将以下代码行:'lowp float checkForPresenceWithinCircle = step(distanceFromCenter, radius);' 替换为 'highp float checkForPresenceWithinCircle = 1.0 - smoothstep(radius-0.05, radius+0.05, distanceFromCenter);'。这个改变会产生一个快速而简单的抗锯齿效果。 - Andy Shiue

2

一种方法是使用GL_POINTS:

glPointSize(radius);
glBegin(GL_POINTS); 
glVertex2f(x,y); 
glEnd(); 

另一种选择是使用GL_TRIANGLE_FAN:

radius = 1.0;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x, y);
for(int angle = 1; angle <= 360; angle = angle + 1)
glVertex2f(x + sind(angle) * radius, y + cosd(angle) * radius);
glEnd();

谢谢,我收到了“在c99中glBegin函数的隐式声明无效”的警告。这是什么意思? - aneuryzm
我们确实需要看到你的代码才能确定你出了什么问题。 - StuGrey
iOS似乎不支持glBegin调用。请记住这是ES2,并且他们已经淘汰了一些函数。也没有似乎有glEnd函数。 - user1401452

1
获取一个圆的顶点:
     float[] verts=MakeCircle2d(1,100,0,0)

     public static float[] MakeCircle2d(float rad,int points,float x,float y)//x,y  ofsets
     {
            float[] verts=new float[points*2+2];
            boolean first=true;
            float fx=0;
            float fy=0;
            int c=0;
            for (int i = 0; i < points; i++)
            {
                    float fi = 2*Trig.PI*i/points;
                    float xa = rad*Trig.sin(fi + Trig.PI)+x ;
                    float ya = rad*Trig.cos(fi + Trig.PI)+y ;
                    if(first)
                    {
                        first=false;
                        fx=xa;
                        fy=ya;
                    }
                    verts[c]=xa;
                    verts[c+1]=ya;
                    c+=2;
            }
            verts[c]=fx;
            verts[c+1]=fy;
            return verts;
      }

如果你想要一个空心圆,可以使用GL10.GL_LINES进行绘制

 gl.glDrawArrays(GL10.GL_LINES, 0, verts.length / 2);

如果你想要一个填充的图形,可以使用GL10.GL_TRIANGLE_FAN进行绘制

 gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, verts.length / 2);

这是Java,但非常容易转换为C++/Objc。


0

这里有一个使用着色器的超快速方法...只需使用一个顶点缓冲创建一个四边形,并为四边形的每个角设置UV从-1到1。

浮点数中的顶点缓冲应如下所示: 注意:还需要一个索引缓冲。

var verts = new float[20]
{
    -1, -1, 0,   -1, -1,
    -1, 1, 0,   -1, 1,
    1, 1, 0,   1, 1,
    1, -1, 0,   1, -1,
};


#VS
attribute vec3 Position0;
attribute vec2 Texcoord0;

varying vec4 Position_VSPS;
varying vec2 Texcoord_VSPS;

uniform vec2 Location;

void main()
{
    vec3 loc = vec3(Position0.xy + Location, Position0.z);
    gl_Position = Position_VSPS = vec4(loc, 1);
    Texcoord_VSPS = loc.xy;
}
#END

#PS
varying vec4 Position_VSPS;
varying vec2 Texcoord_VSPS;

uniform vec2 Location;

void main()
{
    float dis = distance(Location, Texcoord_VSPS);
    if (.1 - dis < 0.0) discard;

    gl_FragData[0] = vec4(0, 0, 1, 1);
}
#END

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接