#java #android #opengl-es #opengl-es-2.0 #gpu
#java #Android #opengl-es #opengl-es-2.0 #графический процессор
Вопрос:
Я пытался нарисовать квадрат в OpenGL ES для Android, но по какой-то причине мой код выходит из строя или показывает только чистый цвет. Я уверен, что настройка проекта с помощью средства визуализации и класса GLSurfaceView верна, и что функция для импорта вершины и шейдера фрагмента из файла работает. Это код для рисования квадрата (конструктор вызывается в onSurfaceCreated в методе рисования в методе onDrawFrame моего класса визуализации):
import android.content.Context;
import android.opengl.GLES20;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class Square {
int ShaderProgramID;
private FloatBuffer vertexBuffer;
private int vertexBufferID;
private int vertexCount;
private int vertexStride;
static final int COORDS_PER_VERTEX = 3;
static final int COLORS_PER_VERTEX = 4;
static final int SIZE_OF_FLOAT = 4;
static final float coords[] = {
//x: y: z: r: g: b: a:
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
};
public Square(Context context) {
String vertexShaderSrc = ReadFromfile("defaultVertexShader.glsl", context);
String fragmentShaderSrc = ReadFromfile("defaultFragmentShader.glsl", context);
int vertexID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexID, vertexShaderSrc);
GLES20.glCompileShader(vertexID);
int fragmetID = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmetID, fragmentShaderSrc);
GLES20.glCompileShader(fragmetID);
ShaderProgramID = GLES20.glCreateProgram();
GLES20.glAttachShader(ShaderProgramID, vertexID);
GLES20.glAttachShader(ShaderProgramID, fragmetID);
GLES20.glBindAttribLocation(ShaderProgramID, 0, "aPos");
GLES20.glBindAttribLocation(ShaderProgramID, 1, "aColor");
GLES20.glLinkProgram(ShaderProgramID);
positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Position");
colorHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Color");
vertexBuffer = FloatBuffer.allocate(coords.length);
vertexBuffer.put(coords);
vertexBuffer.position(0);
IntBuffer buffer = IntBuffer.allocate(1);
GLES20.glGenBuffers(1, buffer);
vertexBufferID = buffer.get(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, coords.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
vertexCount = coords.length / (COORDS_PER_VERTEX COLORS_PER_VERTEX);
vertexStride = (COORDS_PER_VERTEX COLORS_PER_VERTEX) * 4;
}
private int positionHandle;
private int colorHandle;
public void draw() {
GLES20.glUseProgram(ShaderProgramID);
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
vertexBuffer.position(3);
GLES20.glVertexAttribPointer(colorHandle, COLORS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(colorHandle);
}
public String ReadFromfile(String fileName, Context context) {
StringBuilder ReturnString = new StringBuilder();
InputStream fIn = null;
InputStreamReader isr = null;
BufferedReader input = null;
try {
fIn = context.getResources().getAssets()
.open(fileName);
isr = new InputStreamReader(fIn);
input = new BufferedReader(isr);
String line = "";
while ((line = input.readLine()) != null) {
ReturnString.append(line "n");
}
} catch (Exception e) {
e.getMessage();
} finally {
try {
if (isr != null)
isr.close();
if (fIn != null)
fIn.close();
if (input != null)
input.close();
} catch (Exception e2) {
e2.getMessage();
}
}
return ReturnString.toString();
}
}
это код VertexShaderCode:
attribute vec4 aPos;
attribute vec4 aColor;
varying vec4 v_Color;
void main()
{
v_Color = a_Color;
gl_Position = a_Position;
}
и это FragmentShaderCode
precision mediump float;
varying vec4 v_Color;
void main()
{
gl_FragColor = v_Color;
}
Ответ №1:
В вершинном шейдере:
attribute vec4 aPos;
позиция — это 4-компонентный вектор, но в «VertexBuffer» позиция записывается как 3-компонентный вектор. Так что попробуйте улучшить шейдер:
attribute vec3 aPos;
Также используется «a_Position», но нигде не объявлено, сделайте это:
gl_Position = vec4(a_Pos,1.0);
и улучшайте здесь:
positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "a_Pos");
Этот код может показать, скомпилирован шейдер или нет, и ошибку.
int[] compiled = new int[1];
GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
GLES31.glDeleteShader(shader);
throw new RuntimeException("Could not compile program: "
GLES31.glGetShaderInfoLog(shader) " | ");
}
Это правильный способ подготовки буфера с плавающей запятой:
ByteBuffer bb = ByteBuffer.allocateDirect(coords.length*4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = bb.asFloatBuffer();
Комментарии:
1. вершина теперь выглядит так: атрибут vec3 aPos; атрибут vec4 aColor; изменение vec4 vColor; void main() { v_Color = aColor; gl_Position = aPos; } но он все еще падает. также я убедился, что нужно использовать только aPos и aColor, а не a_Pos или a_Color где-либо в коде
2. gl_Position = vec4(a_Pos,1.0);
3. я исправил все ошибки, теперь шейдеры успешно скомпилированы, но приложение по-прежнему работает с ошибками
4. Какая строка вылетает?
5. строка 76: GLES20.glVertexAttribPointer(positionHandle, COORD_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, VertexBuffer);
Ответ №2:
Это текущий код:
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLES31;
import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class Square {
int ShaderProgramID;
private FloatBuffer vertexBuffer;
private int vertexBufferID;
private int vertexCount;
private int vertexStride;
static final int COORDS_PER_VERTEX = 3;
static final int COLORS_PER_VERTEX = 4;
static final int SIZE_OF_FLOAT = 4;
static final float coords[] = {
//x: y: z: r: g: b: a:
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
};
public Square(Context context) {
String vertexShaderSrc = ReadFromfile("defaultVertexShader.glsl", context);
String fragmentShaderSrc = ReadFromfile("defaultFragmentShader.glsl", context);
int vertexID = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexID, vertexShaderSrc);
GLES20.glCompileShader(vertexID);
int fragmetID = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmetID, fragmentShaderSrc);
GLES20.glCompileShader(fragmetID);
ShaderProgramID = GLES20.glCreateProgram();
GLES20.glAttachShader(ShaderProgramID, vertexID);
GLES20.glAttachShader(ShaderProgramID, fragmetID);
GLES20.glBindAttribLocation(ShaderProgramID, 0, "aPos");
GLES20.glBindAttribLocation(ShaderProgramID, 1, "aColor");
GLES20.glLinkProgram(ShaderProgramID);
positionHandle = GLES20.glGetAttribLocation(ShaderProgramID, "aPos");
colorHandle = GLES20.glGetAttribLocation(ShaderProgramID, "aColor");
vertexBuffer = FloatBuffer.allocate(coords.length);
vertexBuffer.put(coords);
vertexBuffer.position(0);
IntBuffer buffer = IntBuffer.allocate(1);
GLES20.glGenBuffers(1, buffer);
vertexBufferID = buffer.get(0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, coords.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
vertexCount = coords.length / (COORDS_PER_VERTEX COLORS_PER_VERTEX);
vertexStride = (COORDS_PER_VERTEX COLORS_PER_VERTEX) * 4;
}
private int positionHandle;
private int colorHandle;
public void draw() {
GLES20.glUseProgram(ShaderProgramID);
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 0);
GLES20.glEnableVertexAttribArray(positionHandle);
vertexBuffer.position(3);
GLES20.glVertexAttribPointer(colorHandle, COLORS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 3);
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(colorHandle);
}
public String ReadFromfile(String fileName, Context context) {
StringBuilder ReturnString = new StringBuilder();
InputStream fIn = null;
InputStreamReader isr = null;
BufferedReader input = null;
try {
fIn = context.getResources().getAssets()
.open(fileName);
isr = new InputStreamReader(fIn);
input = new BufferedReader(isr);
String line = "";
while ((line = input.readLine()) != null) {
ReturnString.append(line "n");
}
} catch (Exception e) {
e.getMessage();
} finally {
try {
if (isr != null)
isr.close();
if (fIn != null)
fIn.close();
if (input != null)
input.close();
} catch (Exception e2) {
e2.getMessage();
}
}
return ReturnString.toString();
}
}
Фрагмент:
#version 310 es
precision mediump float;
in vec4 vColor;
void main()
{
gl_FragColor = vColor;
}
Вершина:
#version 310 es
attribute vec3 aPos;
attribute vec4 aColor;
out vec4 vColor;
void main()
{
vColor = aColor;
gl_Position = vec4(aPos,1.0);
}