我是OpenGL ES 2中的新手,我已经阅读了很多关于如何在Android上的OpenGL ES 2中绘制圆圈的主题。根据{{3}}和Drawing Shapes,我可以绘制三角形和quares,但我仍然不知道如何绘制圆。我现在有三种绘制圆圈的方法:
但我该如何实施呢?
答案 0 :(得分:17)
我绝对不建议通过几何体渲染圆圈。它有两个主要缺点:
还有另一种方法,我个人在每个图形API中使用它。渲染至少三角形或sqare / quad并使用片段着色器仅使得disired(基于等式)像素可见。这很容易理解。它灵活而快速。它需要混合,但这并不是很难开始工作。
步骤:
使用数据初始化缓冲区。您需要顶点的顶点缓冲区,索引的索引缓冲区(如果您使用的是方形几何体)和textureCoord缓冲区(纹理坐标)。 对于正方形,我建议使用-1.0作为最低,1.0作为最高纹理坐标,因为那时你可以使用单位圆方程。
在片段着色器中,使用以下内容:
if ((textureCoord.x * textureCoord.x) + (textureCoord.y * textureCoord.y) <= 1.0)
{
// Render colored and desired transparency
}
else
{
// Render with 0.0 in alpha channel
}
虽然(textureCoord.x * textureCoord.x)+(textureCoord.y * textureCoord.y)&lt; = 1.0是不等式,因为你需要一个圆,你必须渲染该范围内的每个像素,而不仅仅是边界。您可以对其进行更改,以便为您提供所需的输出。
就是这样。实现起来不是很复杂,所以我在这里不提供任何基本的渲染代码。您需要的只是在片段着色器中发生。
答案 1 :(得分:12)
如果要为圆创建几何体,请执行以下操作:
int vertexCount = 30;
float radius = 1.0f;
float center_x = 0.0f;
float center_y = 0.0f;
// Create a buffer for vertex data
float buffer[] = new float[vertexCount*2]; // (x,y) for each vertex
int idx = 0;
// Center vertex for triangle fan
buffer[idx++] = center_x;
buffer[idx++] = center_y;
// Outer vertices of the circle
int outerVertexCount = vertexCount-1;
for (int i = 0; i < outerVertexCount; ++i){
float percent = (i / (float) (outerVertexCount-1));
float rad = percent * 2*Math.PI;
//Vertex position
float outer_x = center_x + radius * cos(rad);
float outer_y = center_y + radius * sin(rad);
buffer[idx++] = outer_x;
buffer[idx++] = outer_y;
}
//Create VBO from buffer with glBufferData()
然后你可以使用glDrawArrays()绘制为:
// Draw circle contours (skip center vertex at start of the buffer)
glDrawArrays(GL_LINE_LOOP, 2, outerVertexCount);
// Draw circle as a filled shape
glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
答案 2 :(得分:9)
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
import android.util.Log;
public class Circle {
private int mProgram, mPositionHandle, mColorHandle, mMVPMatrixHandle ;
private FloatBuffer mVertexBuffer;
private float vertices[] = new float[364 * 3];
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
Circle(){
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;
}
Log.v("Thread",""+vertices[0]+","+vertices[1]+","+vertices[2]);
ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
vertexByteBuffer.order(ByteOrder.nativeOrder());
mVertexBuffer = vertexByteBuffer.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram);
}
public static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
public void draw (float[] mvpMatrix){
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,12
,mVertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 364);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
答案 3 :(得分:4)
这是上述答案的修改版本。它还包括为圆圈着色的代码。大多数功能都用作OpenGL ES1。注意上厕所,LOL的命名惯例。如果你需要我渲染OpenGL的其他类的代码,请告诉我。
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Toilet {
// Circle variables
int circlePoints = 30;
float radius = 1.0f;
float center_x = 0.0f;
float center_y = 0.0f;
// Outer vertices of the circle i.e. excluding the center_x, center_y
int circumferencePoints = circlePoints-1;
// Circle vertices and buffer variables
int vertices = 0;
float circleVertices[] = new float[circlePoints*2];
private FloatBuffer toiletBuff; // 4 bytes per float
// Color values
private float rgbaValues[] = {
1, 1, 0, .5f,
.25f, 0, .85f, 1,
0, 1, 1, 1
};
private FloatBuffer colorBuff;
public Toilet()
{
// The initial buffer values
circleVertices[vertices++] = center_x;
circleVertices[vertices++] = center_y;
// Set circle vertices values
for (int i = 0; i < circumferencePoints; i++)
{
float percent = (i / (float) (circumferencePoints - 1));
float radians = (float) (percent * 2 * Math.PI);
// Vertex position
float outer_x = (float) (center_x + radius * Math.cos(radians));
float outer_y = (float) (center_y + radius * Math.sin(radians));
circleVertices[vertices++] = outer_x;
circleVertices[vertices++] = outer_y;
}
// Float buffer short has four bytes
ByteBuffer toiletByteBuff = ByteBuffer
.allocateDirect(circleVertices.length * 4);
// Garbage collector won't throw this away
toiletByteBuff.order(ByteOrder.nativeOrder());
toiletBuff = toiletByteBuff.asFloatBuffer();
toiletBuff.put(circleVertices);
toiletBuff.position(0);
// Float buffer short has four bytes
ByteBuffer clrBuff = ByteBuffer.allocateDirect(rgbaValues.length * 4);
// garbage collector wont throw this away
clrBuff.order(ByteOrder.nativeOrder());
colorBuff = clrBuff.asFloatBuffer();
colorBuff.put(rgbaValues);
colorBuff.position(0);
}
// Draw methods
public void draw(GL10 gl) {
// Get the front face
gl.glFrontFace(GL10.GL_CW); // Front facing is clockwise
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Enable color array
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// Pointer to the buffer
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, toiletBuff);
// Pointer to color
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuff);
// Draw hollow circle
//gl.glDrawArrays(GL10.GL_LINE_LOOP, 1, circumferencePoints);
// Draw circle as filled shape
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, circlePoints);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
答案 4 :(得分:1)
https://gist.github.com/beetsolutions/9c343f86ec44987de4550cada118e560
您可以在此处找到完整的工作示例: https://github.com/beetsolutions/opengl_circle
完美且优化得很好
答案 5 :(得分:0)
我在'球门柱上发现的一个主要缺陷:你无法改变圆圈的位置。
这是修复。注意'for'循环中前两行的结尾。
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[0]);
vertices[(i * 3)+ 1] = (float) (0.5 * Math.sin((3.14/180) * (float)i ) + vertices[1]);
vertices[(i * 3)+ 2] = 0;
}