我正试图在Android上的openGL ES 2.0中绘制一个球体。我已经查看过相关问题,并尝试了一些代码,但我仍然无法使用它。
根据Android developer examples和this code found on gamedev.net,我提出了以下代码。但它没有正确绘制;使用glDrawArrays()
渲染工作但结果不正确时,使用glDrawElements()
时出现GL_INVALID_OPERATION
错误。我在下面列出了我的缓冲区的内容。
Sphere.java
public class Sphere
{
private int stacks;
private int slices;
private float radius;
//Buffers
private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private ShortBuffer indexBuffer;
//Buffer sizes in aantal bytes
private int vertexBufferSize;
private int colorBufferSize;
private int indexBufferSize;
private int vertexCount;
private int program;
static final int FLOATS_PER_VERTEX = 3; // Het aantal floats in een vertex (x, y, z)
static final int FLOATS_PER_COLOR = 4; // Het aantal floats in een kleur (r, g, b, a)
static final int SHORTS_PER_INDEX = 2;
static final int BYTES_PER_FLOAT = 4;
static final int BYTES_PER_SHORT = 2;
static final int BYTES_PER_VERTEX = FLOATS_PER_VERTEX * BYTES_PER_FLOAT;
static final int BYTES_PER_COLOR = FLOATS_PER_COLOR * BYTES_PER_FLOAT;
static final int BYTES_PER_INDEX_ENTRY = SHORTS_PER_INDEX * BYTES_PER_SHORT;
// Set color with red, green, blue and alpha (opacity) values
private float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Sphere(float radius, int stacks, int slices)
{
this.stacks = stacks;
this.slices = slices;
this.radius = radius;
vertexCount = (stacks+1) * (slices+1);
vertexBufferSize = vertexCount * BYTES_PER_VERTEX;
colorBufferSize = vertexCount * BYTES_PER_COLOR;
indexBufferSize = vertexCount * BYTES_PER_INDEX_ENTRY;
program = GLHelpers.createProgram();
if (program == 0) {
return;
}
GLHelpers.checkGlError("program");
// Setup vertex-array buffer. Vertices in float. A float has 4 bytes.
vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize).order(ByteOrder.nativeOrder()).asFloatBuffer();
colorBuffer = ByteBuffer.allocateDirect(colorBufferSize).order(ByteOrder.nativeOrder()).asFloatBuffer();
indexBuffer = ByteBuffer.allocateDirect(indexBufferSize).order(ByteOrder.nativeOrder()).asShortBuffer();
generateSphereCoords(radius, stacks, slices);
vertexBuffer.position(0);
colorBuffer.position(0);
indexBuffer.position(0);
}
public void draw(float[] modelViewProjectionMatrix)
{
GLES20.glUseProgram(program);
GLHelpers.checkGlError("useprogram");
int positionHandle = GLES20.glGetAttribLocation(program, "a_Position");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, BYTES_PER_VERTEX, vertexBuffer);
GLHelpers.checkGlError("pos");
//int colorHandle = GLES20.glGetAttribLocation(program, "a_Color");
//GLES20.glEnableVertexAttribArray(colorHandle);
//GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, BYTES_PER_COLOR, colorBuffer);
//GLHelpers.checkGlError("color");
int matrixHandle = GLES20.glGetUniformLocation(program, "u_Matrix");
GLES20.glUniformMatrix4fv(matrixHandle, 1, false, modelViewProjectionMatrix, 0);
/*
* When using glDrawArrays rendering works but the results are not correct, when using glDrawElements I get an GL_INVALID_OPERATION error.
*/
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexBuffer.capacity(), GLES20.GL_SHORT, indexBuffer);
//GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
GLHelpers.checkGlError("draw");
// Disable vertex array
GLES20.glDisableVertexAttribArray(positionHandle);
//GLES20.glDisableVertexAttribArray(colorHandle);
}
private void generateSphereCoords(float radius, int stacks, int slices)
{
for (int stackNumber = 0; stackNumber <= stacks; ++stackNumber)
{
for (int sliceNumber = 0; sliceNumber < slices; ++sliceNumber)
{
float theta = (float) (stackNumber * Math.PI / stacks);
float phi = (float) (sliceNumber * 2 * Math.PI / slices);
float sinTheta = FloatMath.sin(theta);
float sinPhi = FloatMath.sin(phi);
float cosTheta = FloatMath.cos(theta);
float cosPhi = FloatMath.cos(phi);
vertexBuffer.put(new float[]{radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta});
}
}
for (int stackNumber = 0; stackNumber < stacks; ++stackNumber)
{
for (int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber)
{
indexBuffer.put((short) ((stackNumber * slices) + (sliceNumber % slices)));
indexBuffer.put((short) (((stackNumber + 1) * slices) + (sliceNumber % slices)));
}
}
}
}
GLHelpers.java
public class GLHelpers
{
private static final String TAG = "GLHelpers";
private static final String VERTEX_SHADER_CODE =
"uniform mat4 u_Matrix;" +
"attribute vec4 a_Position;" +
"attribute vec4 a_Color;" +
"varying vec4 v_Color;" +
"void main() {" +
" v_Color = a_Color;" +
" gl_Position = a_Position * u_Matrix;" +
"}";
private static final String FRAGMENT_SHADER_CODE =
"precision mediump float;" +
"varying vec4 v_Color;" +
"void main() {" +
" gl_FragColor = v_Color;" +
"}";
private static int loadShader(int shaderType, String source)
{
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0)
{
Log.e(TAG, "Could not compile shader " + shaderType + ":");
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
public static int createProgram()
{
int vertexShader = GLHelpers.loadShader(GLES20.GL_VERTEX_SHADER, GLHelpers.VERTEX_SHADER_CODE);
if (vertexShader == 0)
return 0;
int pixelShader = GLHelpers.loadShader(GLES20.GL_FRAGMENT_SHADER, GLHelpers.FRAGMENT_SHADER_CODE);
if (pixelShader == 0)
return 0;
int program = GLES20.glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
GLHelpers.checkGlError("glAttachShader");
GLES20.glAttachShader(program, pixelShader);
GLHelpers.checkGlError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE)
{
Log.e(TAG, "Could not link program: ");
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
public static void checkGlError(String glOperation)
{
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
{
Log.e(TAG, glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
vertexBuffer
X Y Z
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
-0.0, 0.0, 1.0,
-0.0, -0.0, 1.0,
0.0, -0.0, 1.0,
0.58778524, 0.0, 0.809017,
0.18163562, 0.559017, 0.809017,
-0.4755283, 0.34549147, 0.809017,
-0.4755282, -0.34549156, 0.809017,
0.18163571, -0.55901694, 0.809017,
0.95105654, 0.0, 0.30901697,
0.29389262, 0.90450853, 0.30901697,
-0.769421, 0.55901694, 0.30901697,
-0.76942086, -0.5590171, 0.30901697,
0.29389274, -0.9045085, 0.30901697,
0.9510565, 0.0, -0.30901703,
0.2938926, 0.9045085, -0.30901703,
-0.7694209, 0.5590169, -0.30901703,
-0.7694208, -0.55901706, -0.30901703,
0.29389274, -0.9045084, -0.30901703,
0.5877852, 0.0, -0.80901706,
0.1816356, 0.55901694, -0.80901706,
-0.47552824, 0.3454914, -0.80901706,
-0.47552818, -0.34549153, -0.80901706,
0.1816357, -0.5590169, -0.80901706,
-8.742278E-8, -0.0, -1.0,
-2.7015123E-8, -8.3144E-8, -1.0,
7.0726514E-8, -5.138581E-8, -1.0,
7.072651E-8, 5.138583E-8, -1.0,
-2.7015135E-8, 8.3143995E-8, -1.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0
indexBuffer
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
使用glDrawArrays()
时的结果:
答案 0 :(得分:3)
承诺创建球体的工作代码:
public static Model3D createSphere(float radius, int stacks, int slices)
{
int vertexCount = (stacks + 1) * (slices + 1);
FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_VERTEX).order(ByteOrder.nativeOrder()).asFloatBuffer();
FloatBuffer normalBuffer = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_NORMAL).order(ByteOrder.nativeOrder()).asFloatBuffer();
FloatBuffer textureCoordBuffer = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_TEXTURE_COORD).order(ByteOrder.nativeOrder()).asFloatBuffer();
ShortBuffer indexBuffer = ByteBuffer.allocateDirect(vertexCount * GLHelpers.BYTES_PER_TRIANGLE_INDEX).order(ByteOrder.nativeOrder()).asShortBuffer();
for (int stackNumber = 0; stackNumber <= stacks; ++stackNumber)
{
for (int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber)
{
float theta = (float) (stackNumber * Math.PI / stacks);
float phi = (float) (sliceNumber * 2 * Math.PI / slices);
float sinTheta = FloatMath.sin(theta);
float sinPhi = FloatMath.sin(phi);
float cosTheta = FloatMath.cos(theta);
float cosPhi = FloatMath.cos(phi);
float nx = cosPhi * sinTheta;
float ny = cosTheta;
float nz = sinPhi * sinTheta;
float x = radius * nx;
float y = radius * ny;
float z = radius * nz;
float u = 1.f - ((float)sliceNumber / (float)slices);
float v = (float)stackNumber / (float)stacks;
normalBuffer.put(nx);
normalBuffer.put(ny);
normalBuffer.put(nz);
vertexBuffer.put(x);
vertexBuffer.put(y);
vertexBuffer.put(z);
textureCoordBuffer.put(u);
textureCoordBuffer.put(v);
}
}
for (int stackNumber = 0; stackNumber < stacks; ++stackNumber)
{
for (int sliceNumber = 0; sliceNumber < slices; ++sliceNumber)
{
int second = (sliceNumber * (stacks + 1)) + stackNumber;
int first = second + stacks + 1;
//int first = (stackNumber * slices) + (sliceNumber % slices);
//int second = ((stackNumber + 1) * slices) + (sliceNumber % slices);
indexBuffer.put((short) first);
indexBuffer.put((short) second);
indexBuffer.put((short) (first + 1));
indexBuffer.put((short) second);
indexBuffer.put((short) (second + 1));
indexBuffer.put((short) (first + 1));
}
}
vertexBuffer.rewind();
normalBuffer.rewind();
indexBuffer.rewind();
textureCoordBuffer.rewind();
Model3D sphere = new Model3D().setVertexBuffer(vertexBuffer)
.setNormalBuffer(normalBuffer)
.setIndexBuffer(indexBuffer)
.setTexture(R.drawable.earth)
.setTextureCoordBuffer(textureCoordBuffer)
.setDiffuseLighting(-3f, 2.3f, 2f);
return sphere;
}
答案 1 :(得分:1)
您将vertexCount
设为lat * lon * bytes per float
,这对我来说非常奇怪。
我认为你错误地命名了这个变量,因为顶点的数量与每个浮点数的字节无关。
你在glDrawArrays中使用相同的变量,在我看来,它不会有准确的顶点数。