如何从 OpenGL ES 2.0 中的数组中读取超过 4 个顶点数据?
How can I read more than 4 vertex data from an array in OpenGL ES 2.0?
我正在尝试从用于顶点位置和颜色的浮点数组缓冲区中 OpenGL ES 2.0
中一个接一个地绘制点,但每次绘制只能接受 4 个顶点。当我添加更多然后告诉它绘制更多时它只会在数组中绘制 2 个不相邻的顶点。为什么会这样?为什么我不能在一个实例中绘制超过 4 个顶点?如果可以,怎么做?
这是一个例子。
当我有 3*4
数组数据时,它会像这样绘制它们:
. . . .
,做的很到位。
如果我设置 3*6
数组数据,它不会画 6 个点,它会画这样的东西:
. .
我的大部分代码来自 OpenGL ES
课程项目,我仍在学习,不太了解 onSurfaceCreated
中的代码是如何完成的。
这是我的 OpenGLRenderer class:
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
...
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ " v_Color = a_Color; \n" // Pass the color through to the fragment shader.
// It will be interpolated across the triangle.
+ " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position.
+ " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in
+ "} \n"; // normalized screen coordinates.
final String fragmentShader =
"precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// triangle per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ \n"
+ " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
// Load in the vertex shader.
int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (vertexShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(vertexShaderHandle, vertexShader);
// Compile the shader.
GLES20.glCompileShader(vertexShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
}
}
if (vertexShaderHandle == 0)
{
throw new RuntimeException("Error creating vertex shader.");
}
// Load in the fragment shader shader.
int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if (fragmentShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
// Compile the shader.
GLES20.glCompileShader(fragmentShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(fragmentShaderHandle);
fragmentShaderHandle = 0;
}
}
if (fragmentShaderHandle == 0)
{
throw new RuntimeException("Error creating fragment shader.");
}
// Create a program object and store the handle to it.
int programHandle = GLES20.glCreateProgram();
if (programHandle != 0)
{
// Bind the vertex shader to the program.
GLES20.glAttachShader(programHandle, vertexShaderHandle);
// Bind the fragment shader to the program.
GLES20.glAttachShader(programHandle, fragmentShaderHandle);
// Bind attributes
GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
// Link the two shaders together into a program.
GLES20.glLinkProgram(programHandle);
// Get the link status.
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
// If the link failed, delete the program.
if (linkStatus[0] == 0)
{
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0)
{
throw new RuntimeException("Error creating program.");
}
// Set program handles. These will later be used to pass in values to the program.
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
// Tell OpenGL to use this program when rendering.
GLES20.glUseProgram(programHandle);
}
画点数:
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setIdentityM(mModelMatrix, 0);
drawPoints();
}
// Like I said, 4 and below works without any issue
private final int vertexesToDraw = 6;
// x, y, z (z being upwards)
private final float[] vertexPosData = {
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
2.0f, 0.0f, 0.0f,
3.0f, 0.0f, 0.0f,
4.0f, 0.0f, 0.0f,
5.0f, 0.0f, 0.0f
};
// red, green, blue, alpha
private final float[] vertexColorData = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
FloatBuffer mVertexPos, mVertexColor;
// this gets initialized first
private void setupPoints() {
mVertexPos = ByteBuffer.allocateDirect(vertexPosData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertexPos.put(vertexPosData).position(0);
mVertexPos.position(0);
mVertexColor = ByteBuffer.allocateDirect(vertexColorData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertexColor.put(vertexColorData).position(0);
mVertexColor.position(0);
}
private void drawPoints() {
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * vertexesToDraw, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * vertexesToDraw, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexesToDraw);
}
glVertexAttribPointer
的第5个参数是连续通用顶点属性(stride
)之间的字节偏移量,而不是缓冲区中元素的数量。
这意味着,对于 float 类型的属性(float 的大小为 4 个字节)且元组大小为 3(例如 x、y、z 坐标),stride 参数必须为 4 * 3 = 12 .
对于元组大小为 4(RGBA 颜色)的属性,步幅参数必须为 4 * 4 = 16。
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
由于顶点紧密排列,stride可以设置为0。这是glVertexAttribPointer
提供的特例。当stride为0时,则由size和type参数自动计算
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
请注意,当您有 4 个属性时,缓冲区中的元素数量(浮点值数量)恰好与连续通用顶点属性之间的字节偏移量匹配。所以 4 个顶点巧合,但 6 个顶点失败。
缓冲区的大小永远不会明确设置。当调用 glDrawArrays
时,启用的顶点属性必须引用一个缓冲区,该缓冲区足够大以提供所需的属性。
我正在尝试从用于顶点位置和颜色的浮点数组缓冲区中 OpenGL ES 2.0
中一个接一个地绘制点,但每次绘制只能接受 4 个顶点。当我添加更多然后告诉它绘制更多时它只会在数组中绘制 2 个不相邻的顶点。为什么会这样?为什么我不能在一个实例中绘制超过 4 个顶点?如果可以,怎么做?
这是一个例子。
当我有 3*4
数组数据时,它会像这样绘制它们:
. . . .
,做的很到位。
如果我设置 3*6
数组数据,它不会画 6 个点,它会画这样的东西:
. .
我的大部分代码来自 OpenGL ES
课程项目,我仍在学习,不太了解 onSurfaceCreated
中的代码是如何完成的。
这是我的 OpenGLRenderer class:
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
...
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ " v_Color = a_Color; \n" // Pass the color through to the fragment shader.
// It will be interpolated across the triangle.
+ " gl_Position = u_MVPMatrix \n" // gl_Position is a special variable used to store the final position.
+ " * a_Position; \n" // Multiply the vertex by the matrix to get the final point in
+ "} \n"; // normalized screen coordinates.
final String fragmentShader =
"precision mediump float; \n" // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// triangle per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ \n"
+ " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
// Load in the vertex shader.
int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (vertexShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(vertexShaderHandle, vertexShader);
// Compile the shader.
GLES20.glCompileShader(vertexShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
}
}
if (vertexShaderHandle == 0)
{
throw new RuntimeException("Error creating vertex shader.");
}
// Load in the fragment shader shader.
int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if (fragmentShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
// Compile the shader.
GLES20.glCompileShader(fragmentShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(fragmentShaderHandle);
fragmentShaderHandle = 0;
}
}
if (fragmentShaderHandle == 0)
{
throw new RuntimeException("Error creating fragment shader.");
}
// Create a program object and store the handle to it.
int programHandle = GLES20.glCreateProgram();
if (programHandle != 0)
{
// Bind the vertex shader to the program.
GLES20.glAttachShader(programHandle, vertexShaderHandle);
// Bind the fragment shader to the program.
GLES20.glAttachShader(programHandle, fragmentShaderHandle);
// Bind attributes
GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
// Link the two shaders together into a program.
GLES20.glLinkProgram(programHandle);
// Get the link status.
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
// If the link failed, delete the program.
if (linkStatus[0] == 0)
{
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0)
{
throw new RuntimeException("Error creating program.");
}
// Set program handles. These will later be used to pass in values to the program.
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
// Tell OpenGL to use this program when rendering.
GLES20.glUseProgram(programHandle);
}
画点数:
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setIdentityM(mModelMatrix, 0);
drawPoints();
}
// Like I said, 4 and below works without any issue
private final int vertexesToDraw = 6;
// x, y, z (z being upwards)
private final float[] vertexPosData = {
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
2.0f, 0.0f, 0.0f,
3.0f, 0.0f, 0.0f,
4.0f, 0.0f, 0.0f,
5.0f, 0.0f, 0.0f
};
// red, green, blue, alpha
private final float[] vertexColorData = {
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
FloatBuffer mVertexPos, mVertexColor;
// this gets initialized first
private void setupPoints() {
mVertexPos = ByteBuffer.allocateDirect(vertexPosData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertexPos.put(vertexPosData).position(0);
mVertexPos.position(0);
mVertexColor = ByteBuffer.allocateDirect(vertexColorData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertexColor.put(vertexColorData).position(0);
mVertexColor.position(0);
}
private void drawPoints() {
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * vertexesToDraw, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * vertexesToDraw, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexesToDraw);
}
glVertexAttribPointer
的第5个参数是连续通用顶点属性(stride
)之间的字节偏移量,而不是缓冲区中元素的数量。
这意味着,对于 float 类型的属性(float 的大小为 4 个字节)且元组大小为 3(例如 x、y、z 坐标),stride 参数必须为 4 * 3 = 12 .
对于元组大小为 4(RGBA 颜色)的属性,步幅参数必须为 4 * 4 = 16。
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
由于顶点紧密排列,stride可以设置为0。这是glVertexAttribPointer
提供的特例。当stride为0时,则由size和type参数自动计算
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);
请注意,当您有 4 个属性时,缓冲区中的元素数量(浮点值数量)恰好与连续通用顶点属性之间的字节偏移量匹配。所以 4 个顶点巧合,但 6 个顶点失败。
缓冲区的大小永远不会明确设置。当调用 glDrawArrays
时,启用的顶点属性必须引用一个缓冲区,该缓冲区足够大以提供所需的属性。