解决。解决问题的方法: attribStride
未正确设置。
我正在编写一个小型Google Cardboard应用程序,可以加载和呈现任何Wavefront .obj文件及其链接.mtl文件中表面的材质属性。为了渲染我正在使用VBO和IBO。对于表面和闪电的材料特性,我正在使用phong着色。
我的问题是,glDrawElements()
只会渲染一个立方体的前两个三角形,它由12个三角形组成。
glBufferData()
设置的VBO和IBO的长度有效。glGetAttribLocation()
和glGetUniformLocation()
设置的所有属性和统一位置均有效。我在Debugger和logcat中检查过这些点。 我意识到它的代码很多。但我无法在任何地方找到问题或解决我的问题。所以请帮助:D并首先感谢:)
此方法设置VBO,IBO,着色器程序,着色器程序位置,纹理和着色器程序统一值:
private void initializeGL() {
Log.i(TAG, "initializeGL()");
// Set camera matrix.
Matrix.setLookAtM(camera, OFFSET, EYE_POINT_X, EYE_POINT_Y, EYE_POINT_Z, CENTER_OF_VIEW_X, CENTER_OF_VIEW_Y, CENTER_OF_VIEW_Z, UP_VECTOR_X, UP_VECTOR_Y, UP_VECTOR_Z);
// Initialize shader program.
shaderProgram.init();
shaderProgramHandle = shaderProgram.getProgramHandle();
// Initialize object information.
objectInformation.init();
vboHandle = objectInformation.getVbo().getVboHandle();
vboLength = objectInformation.getVbo().getVboLength();
iboHandle = objectInformation.getIbo().getIboHandle();
iboLength = objectInformation.getIbo().getIboLength();
uniforms = objectInformation.getUniformArray();
numOfUniforms = objectInformation.getNumOfUniforms();
Log.i(TAG, "initializeGL(): Number of uniforms = " + numOfUniforms);
textures = objectInformation.getTextureArray();
numOfTextures = objectInformation.getNumOfTextures();
Log.i(TAG, "initializeGL(): Number of textures = " + numOfTextures);
// Get vertex shader uniform locations.
modelViewProjectionParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_ModelViewProjection");
Log.i(TAG, "initializeGL(): modelViewProjectionParam = " + modelViewProjectionParam);
modelViewParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_ModelView");
Log.i(TAG, "initializeGL(): modelViewParam = " + modelViewParam);
normalMatrixParam = GLES20.glGetUniformLocation(shaderProgramHandle, "u_NormalMatrix");
Log.i(TAG, "initializeGL(): normalMatrixParam = " + normalMatrixParam);
// Get vertex shader attribute locations.
positionParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_Position");
Log.i(TAG, "initializeGL(): positionParam = " + positionParam);
if(boolTexCoords) {
attribStride += 4 * BYTES_PER_FLOAT;
texCoordParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_TexCoord");
Log.i(TAG, "initializeGL(): texCoordParam = " + texCoordParam);
}
normalParam = GLES20.glGetAttribLocation(shaderProgramHandle, "a_Normal");
Log.i(TAG, "initializeGL(): normalParam = " + normalParam);
// Get fragment shader phong uniform locations.
if(boolPhongLightning) {
lightPosParam = GLES20.glGetUniformLocation(shaderProgramHandle, "lightPosition");
Log.i(TAG, "initializeGL(): lightPosParam = " + lightPosParam);
IaParam = GLES20.glGetUniformLocation(shaderProgramHandle, "Ia");
Log.i(TAG, "initializeGL(): IaParam = " + IaParam);
IpParam = GLES20.glGetUniformLocation(shaderProgramHandle, "Ip");
Log.i(TAG, "initializeGL(): IpParam = " + IpParam);
}
// Set fragment shader material uniforms.
GLES20.glUseProgram(shaderProgramHandle);
for(int i = 0; i < numOfUniforms; i++) {
String unifName = uniforms[i].getUnifName();
location = GLES20.glGetUniformLocation(shaderProgramHandle, unifName);
checkGLError(TAG, "initializeGL(): " + unifName + " shader location");
vec = uniforms[i].getArray();
if(vec != null) {
GLES20.glUniform3fv(location, 1, vec, 0);
Log.i(TAG, "initializeGL(): " + unifName + "_Param = " + location);
} else {
float value = uniforms[i].getValue();
GLES20.glUniform1f(location, value);
Log.i(TAG, "initializeGL(): " + unifName + "_Param = " + location);
}
}
// Set fragment shader phong uniforms.
if(boolPhongLightning) {
GLES20.glUniform3fv(IaParam, 1, Ia, 0);
GLES20.glUniform3fv(IpParam, 1, Ip, 0);
}
// Set fragment shader textures.
for(int i = 0; i < numOfTextures; i++) {
// Set active texture unit.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
// Bind texture to active texture unit.
int texHandle = textures[i].getTextureHandle();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texHandle);
// Assign texture unit to uniform in fragment shader.
String unifName = textures[i].getUnifName();
location = GLES20.glGetUniformLocation(shaderProgramHandle, unifName);
GLES20.glUniform1i(location, i);
checkGLError(TAG, "initializeGL(): glUniform1i()");
Log.i(TAG, "initializeGL(): " + unifName + "Param = " + location);
}
GLES20.glUseProgram(0);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthFunc(GLES20.GL_LESS);
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glFrontFace(GLES20.GL_CCW);
GLES20.glCullFace(GLES20.GL_BACK);
GLES20.glClearColor(0.3f, 0.3f, 0.3f, 0.1f);
}
public void onDrawEye():
@Override
public void onDrawEye(Eye eye) {
Log.i(TAG, "onDrawEye()");
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
projection = eye.getPerspective(Z_NEAR, Z_FAR);
Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0);
Matrix.multiplyMM(modelView, 0, view, 0, modelMatrix, 0);
Matrix.multiplyMM(modelViewProjection, 0, projection, 0, modelView, 0);
Matrix.multiplyMV(lightPosInEyeSpace, 0, view, 0, lightPosInWorldSpace, 0);
normalMatrix = RPMath.getNormalMatrix3x3(modelView);
draw();
}
private void draw():
private void draw() {
Log.i(TAG, "draw()");
// Bind shader program, VBO and IBO.
GLES20.glUseProgram(shaderProgramHandle);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboHandle);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, iboHandle);
// Set vertex shader uniforms.
GLES20.glUniformMatrix4fv(modelViewProjectionParam, 1, false, modelViewProjection, 0);
GLES20.glUniformMatrix4fv(modelViewParam, 1, false, modelView, 0);
GLES20.glUniformMatrix3fv(normalMatrixParam, 1, false, normalMatrix, 0);
if(boolPhongLightning) { // fragment shader uniforms.
vec = new float[3];
vec[0] = lightPosInEyeSpace[0];
vec[1] = lightPosInEyeSpace[1];
vec[2] = lightPosInEyeSpace[2];
GLES20.glUniform3fv(lightPosParam, 1, vec, 0);
}
// Set vertex attribute pointers.
attribOffset = 0;
GLES20.glVertexAttribPointer(positionParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);
if(boolTexCoords) {
attribOffset += 4 * BYTES_PER_FLOAT;
GLES20.glVertexAttribPointer(texCoordParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);
}
attribOffset += 4 * BYTES_PER_FLOAT;
GLES20.glVertexAttribPointer(normalParam, 4, GLES20.GL_FLOAT, false, attribStride, attribOffset);
// Enable vertex attribute arrays.
GLES20.glEnableVertexAttribArray(positionParam);
if(boolTexCoords) {
GLES20.glEnableVertexAttribArray(texCoordParam);
}
GLES20.glEnableVertexAttribArray(normalParam);
// Draw.
GLES20.glDrawElements(GLES20.GL_TRIANGLES, iboLength, GLES20.GL_UNSIGNED_SHORT, 0);
// Disable vertex attribute arrays.
GLES20.glDisableVertexAttribArray(positionParam);
if(boolTexCoords) {
GLES20.glDisableVertexAttribArray(texCoordParam);
}
GLES20.glDisableVertexAttribArray(normalParam);
// Unbind shader program, VBO and IBO.
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glUseProgram(0);
}
修改 RPVBO和RPIBO类。有趣的部分是init()方法:
public final class RPVBO {
private static final String TAG = "RPVBO";
private static final int BYTES_PER_FLOAT = 4;
private int[] vboHandles;
private Vector<Float> vertices;
private int vboLength;
public RPVBO() {
Log.i(TAG, "Constructor()");
vboHandles = null;
vertices = new Vector();
vboLength = 0;
}
public void init() {
Log.i(TAG, "init()");
if((vboHandles != null) && (vboHandles[0] != 0)) {
return;
}
vboHandles = new int[1];
GLES20.glGenBuffers(1, vboHandles, 0);
if(vboHandles[0] != 0) {
float[] vertexArray = getVertexArray();
FloatBuffer clientSideBuffer = ByteBuffer.allocateDirect(vertexArray.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
clientSideBuffer.position(0);
clientSideBuffer.put(vertexArray);
clientSideBuffer.position(0);
if(clientSideBuffer.capacity() != vertexArray.length) {
Log.e(TAG, "init(): Error creating client side Floatbuffer.");
throw new RuntimeException("Error: " + TAG + "init(): Error creating client side Floatbuffer.");
}
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboHandles[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, clientSideBuffer.capacity() * BYTES_PER_FLOAT, clientSideBuffer, GLES20.GL_STATIC_DRAW);
MainActivity.checkGLError(TAG, "init(): glBufferData()");
int[] params = new int[2];
GLES20.glGetBufferParameteriv(GLES20.GL_ARRAY_BUFFER, GLES20.GL_BUFFER_SIZE, params, 0);
MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
GLES20.glGetBufferParameteriv(GLES20.GL_ARRAY_BUFFER, GLES20.GL_BUFFER_USAGE, params, 1);
MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
if(params[0] != (clientSideBuffer.capacity() * BYTES_PER_FLOAT)) {
Log.e(TAG, "init(): Error setting OpenGL VBO data.");
throw new RuntimeException("Error: " + TAG + ": init(): Error setting OpenGL VBO data.");
}
Log.i(TAG, "init(): OpenGL VBO handle: " + vboHandles[0]);
Log.i(TAG, "init(): OpenGL VBO size in Bytes: " + params[0]);
switch(params[1]) {
case GLES20.GL_STREAM_DRAW:
Log.i(TAG, "init(): OpenGL VBO usage: GL_STREAM_DRAW.");
break;
case GLES20.GL_STATIC_DRAW:
Log.i(TAG, "init(): OpenGL VBO usage: GL_STATIC_DRAW.");
break;
case GLES20.GL_DYNAMIC_DRAW:
Log.i(TAG, "init(): OpenGL VBO usage: GL_DYNAMIC_DRAW.");
}
vertices.clear();
}
if(vboHandles[0] == 0) {
Log.e(TAG, "init(): Error creating VBO in OpenGL.");
throw new RuntimeException("Error: " + TAG + "init(): Error creating VBO in OpenGL.");
}
}
public void addValue(final float value) {
vertices.add(value);
++vboLength;
}
public void addValue(final Float value) {
vertices.add(value);
++vboLength;
}
public void addArray(final float[] array) {
final int arrayLength = array.length;
for(int i = 0; i < arrayLength; i++) {
vertices.add(array[i]);
++vboLength;
}
}
public void addArray(final Float[] array) {
final int arrayLength = array.length;
for(int i = 0; i < arrayLength; i++) {
vertices.add(array[i]);
++vboLength;
}
}
public int getVboHandle() {
if(vboHandles == null) {
return 0;
}
return vboHandles[0];
}
@Nullable
public float[] getVertexArray() {
float[] array = new float[vertices.size()];
for(int i = 0; i < vertices.size(); i++) {
array[i] = vertices.get(i);
}
return array;
}
public int getVboLength() {
return vboLength;
}
}
public final class RPIBO {
private static final String TAG = "RPIBO";
private static final int BYTES_PER_SHORT = 2;
private int[] iboHandles;
private Vector<Short> indices;
private int iboLength;
public RPIBO() {
Log.i(TAG, "Constructor()");
iboHandles = null;
indices = new Vector();
iboLength = 0;
}
public void init() {
Log.i(TAG, "init()");
if((iboHandles != null) && (iboHandles[0] != 0)) {
return;
}
iboHandles = new int[1];
GLES20.glGenBuffers(1, iboHandles, 0);
if(iboHandles[0] != 0) {
short[] indexArray = getIndexArray();
ShortBuffer clientSideBuffer = ByteBuffer.allocateDirect(indexArray.length * BYTES_PER_SHORT).order(ByteOrder.nativeOrder()).asShortBuffer();
clientSideBuffer.position(0);
clientSideBuffer.put(indexArray);
clientSideBuffer.position(0);
if(clientSideBuffer.capacity() != indexArray.length) {
Log.e(TAG, "init(): Error creating client side Shortbuffer.");
throw new RuntimeException("Error: " + TAG + "init(): Error creating client side Shortbuffer.");
}
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, iboHandles[0]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, clientSideBuffer.capacity() * BYTES_PER_SHORT, clientSideBuffer, GLES20.GL_STATIC_DRAW);
MainActivity.checkGLError(TAG, "init(): glBufferData()");
int[] params = new int[2];
GLES20.glGetBufferParameteriv(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLES20.GL_BUFFER_SIZE, params, 0);
MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
GLES20.glGetBufferParameteriv(GLES20.GL_ELEMENT_ARRAY_BUFFER, GLES20.GL_BUFFER_USAGE, params, 1);
MainActivity.checkGLError(TAG, "init(): glGetBufferParameteriv()");
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
if(params[0] != (clientSideBuffer.capacity() * BYTES_PER_SHORT)) {
Log.e(TAG, "init(): Error setting OpenGL IBO data.");
throw new RuntimeException("Error: " + TAG + ": init(): Error setting OpenGL IBO data.");
}
Log.i(TAG, "init(): OpenGL IBO handle: " + iboHandles[0]);
Log.i(TAG, "init(): OpenGL IBO size in Bytes: " + params[0]);
switch(params[1]) {
case GLES20.GL_STREAM_DRAW:
Log.i(TAG, "init(): OpenGL IBO usage: GL_STREAM_DRAW.");
break;
case GLES20.GL_STATIC_DRAW:
Log.i(TAG, "init(): OpenGL IBO usage: GL_STATIC_DRAW.");
break;
case GLES20.GL_DYNAMIC_DRAW:
Log.i(TAG, "init(): OpenGL IBO usage: GL_DYNAMIC_DRAW.");
}
indices.clear();
}
if(iboHandles[0] == 0) {
Log.e(TAG, "init(): Error creating IBO in OpenGL.");
throw new RuntimeException("Error: " + TAG + "init(): Error creating IBO in OpenGL.");
}
}
public void addValue(final short value) {
indices.add(value);
++iboLength;
}
public void addValue(final Short value) {
indices.add(value);
++iboLength;
}
public void addArray(final short[] array) {
final int arrayLength = array.length;
for(int i = 0; i < arrayLength; i++) {
indices.add(array[i]);
++iboLength;
}
}
public void addArray(final Short[] array) {
final int arrayLength = array.length;
for(int i = 0; i < arrayLength; i++) {
indices.add(array[i]);
++iboLength;
}
}
public int getIboHandle() {
if(iboHandles == null) {
return 0;
}
return iboHandles[0];
}
@Nullable
public short[] getIndexArray() {
short[] array = new short[indices.size()];
for(int i = 0; i < indices.size(); i++) {
array[i] = indices.get(i);
}
return array;
}
public int getIboLength() {
return iboLength;
}
}
答案 0 :(得分:0)
glVertexAttribPointer
(stride
)的第4个参数,指定连续通用顶点属性之间的字节偏移量。
请参阅Khronos OpenGL specification - Chapter 10.3. VERTEX ARRAYS,其中包含:
从缓冲区对象获取顶点数据时,
offset
指定顶点缓冲区中第一个元素的基本机器单位的偏移量。指向数组的 i 和(i + 1)
st元素的指针相差stride
个基本机器单元,指向(i + 1)
st元素的指针更大。
这意味着,如果您的顶点缓冲区包含顶点,纹理坐标和法线向量,格式为:
vx, vy, vz, 1.0, s, t, 0.0, 1.0, nx, ny, nz, 1.0
然后stride
必须是(4+4+4)*BYTES_PER_FLOAT = 48
,因为顶点的大小是4
,纹理坐标的大小是4
和法线向量的大小是4
纹理坐标的offset
为4*BYTES_PER_FLOAT = 16
,法线向量的偏移为(4+4)*BYTES_PER_FLOAT = 32
。