Reputation: 64874
How do I draw a filled circle with openGl on iPhone ?
I've found many solutions but none of them work. Probably because there are many ways to do it. But what's the method with shortest code ?
Upvotes: 4
Views: 8183
Reputation: 3383
Here is a super fast way using shaders... Just make a Quad with a vertex buffer and set the UV's from -1 to 1 for each corner of the quad.
The vertex buffer in floats should look like: NOTE: this needs a index buffer too.
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
Upvotes: 0
Reputation: 3389
To get the verices of a circle:
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;
}
Draw it as GL10.GL_LINES if you want a empty circle
gl.glDrawArrays(GL10.GL_LINES, 0, verts.length / 2);
Or draw it as GL10.GL_TRIANGLE_FAN if you want a filled one
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, verts.length / 2);
Its java but it is really easy to convert to c++/objc
Upvotes: 1
Reputation: 170317
For a truly smooth circle, you're going to want a custom fragment shader. For example, the following vertex shader:
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
and fragment shader:
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;
}
will draw a smooth red circle within a square that you draw to the screen. You'll need to supply vertices for your square to the position
attribute and coordinates that range from 0.0 to 1.0 in X and Y to the inputTextureCoordinate
attribute, but this will draw a circle that's as sharp as your viewport's resolution allows and do so very quickly.
Upvotes: 17
Reputation: 1477
One way would be to use GL_POINTS:
glPointSize(radius);
glBegin(GL_POINTS);
glVertex2f(x,y);
glEnd();
Another alternative would be to use 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();
Upvotes: 2