I've tried to implement an inefficient function to generate the points, normals, tex coords, and index list of a sphere.
Ignoring the lines, when I draw the sphere with OpenGL I get the following output which is clearly wrong:
Can anyone help me understand what's wrong with my code?
public SphereObject()
{
super();
// inefficient but quick sphere data
int num_points = 16;
double as = Math.PI / num_points;
double theta, phi;
double [] p;
ArrayList<double []> points = new ArrayList<double []>();
ArrayList<Integer> edges = new ArrayList<Integer>();
ArrayList<double []> normals = new ArrayList<double []>();
ArrayList<double []> tex = new ArrayList<double []>();
theta = Math.PI;
phi = Math.PI / 2;
for(int row = 0; row < num_points; row++)
{
for(int col = 0; col < num_points; col++)
{
p = new double[3];
p[0] = Math.sin(theta) * Math.cos(phi - as);
p[1] = Math.cos(theta) * Math.cos(phi - as);
p[2] = Math.sin(phi - as);
points.add(p);
normals.add(p);
tex.add(new double [] {0, 0});
p = new double[3];
p[0] = Math.sin(theta + 2 * as) * Math.cos(phi - as);
p[1] = Math.cos(theta + 2 * as) * Math.cos(phi - as);
p[2] = Math.sin(phi - as);
points.add(p);
normals.add(p);
tex.add(new double [] {1, 0});
p = new double[3];
p[0] = Math.sin(theta + 2 * as) * Math.cos(phi);
p[1] = Math.cos(theta + 2 * as) * Math.cos(phi);
p[2] = Math.sin(phi);
points.add(p);
normals.add(p);
tex.add(new double [] {1, 1});
p = new double[3];
p[0] = Math.sin(theta) * Math.cos(phi);
p[1] = Math.cos(theta) * Math.cos(phi);
p[2] = Math.sin(phi);
points.add(p);
normals.add(p);
tex.add(new double [] {0, 1});
// make triangles
edges.add(points.size()-1);
edges.add(points.size()-3);
edges.add(points.size()-4);
edges.add(points.size()-1);
edges.add(points.size()-2);
edges.add(points.size()-3);
theta -= 2 * as;
}
phi -= as;
}
sphereVertices = new double[points.size() * 3];
sphereTexcoords = new double[tex.size() * 2];
sphereNormals = new double[normals.size() * 3];
sphereIndices = new short[edges.size() * 1];
for(int c1 = 0; c1 < points.size(); c1 += 3)
{
sphereVertices[c1] = points.get(c1)[0];
sphereVertices[c1+1] = points.get(c1)[1];
sphereVertices[c1+2] = points.get(c1)[2];
}
for(int c1 = 0; c1 < tex.size(); c1 += 2)
{
sphereTexcoords[c1] = tex.get(c1)[0];
sphereTexcoords[c1+1] = tex.get(c1)[1];
}
for(int c1 = 0; c1 < normals.size(); c1 += 3)
{
sphereNormals[c1] = normals.get(c1)[0];
sphereNormals[c1+1] = normals.get(c1)[1];
sphereNormals[c1+2] = normals.get(c1)[2];
}
for(int c1 = 0; c1 < edges.size(); c1++)
{
sphereIndices[c1] = edges.get(c1).shortValue();
}
mVertBuff = fillBuffer(sphereVertices);
mTexCoordBuff = fillBuffer(sphereTexcoords);
mNormBuff = fillBuffer(sphereNormals);
mIndBuff = fillBuffer(sphereIndices);
}
My OpenGL code is below. The getVertices()
functions et al return the buffers created in the Sphere constructor above.
Matrix.translateM(modelViewMatrix, 0, 0, 0, kObjectScale);
Matrix.scaleM(modelViewMatrix, 0, kObjectScale, kObjectScale, kObjectScale);
GLES20.glUseProgram(shaderProgramID);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getVertices());
GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getNormals());
GLES20.glVertexAttribPointer(textureCoordHandle, 2, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getTexCoords());
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glEnableVertexAttribArray(normalHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures.get(2).mTextureID[0]);
Matrix.translateM(modelViewMatrix, 0, (float)result[0], (float)result[1], (float)result[2]);
Matrix.rotateM(modelViewMatrix, 0, 0, 1, 0, 0);
Matrix.rotateM(modelViewMatrix, 0, 0, 0, 1, 0);
Matrix.rotateM(modelViewMatrix, 0, 0, 0, 0, 1);
Matrix.scaleM(modelViewMatrix, 0, 5, 5, 5);
Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession.getProjectionMatrix().getData(), 0, modelViewMatrix, 0);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, modelViewProjection, 0);
GLES20.glUniform1i(texSampler2DHandle, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphere.getInstance().getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT, sphere.getInstance().getIndices());
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisableVertexAttribArray(vertexHandle);
GLES20.glDisableVertexAttribArray(normalHandle);
GLES20.glDisableVertexAttribArray(textureCoordHandle);
The fillBuffer
code is as follows:
protected Buffer fillBuffer(double[] array)
{
// Convert to floats because OpenGL doesn't work on doubles, and manually
// casting each input value would take too much time.
// Each float takes 4 bytes
ByteBuffer bb = ByteBuffer.allocateDirect(4 * array.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
for (double d : array)
bb.putFloat((float) d);
bb.rewind();
return bb;
}
The problem is when you add the points to the final arrays:
instead of using the same index for both the array and the list us separate ones:
same for the other arrays