Использование: OpenGLES 2.0 на Android-устройстве
Я хочу нарисовать много точек.Прямо сейчас мне нужно 3 поплавка для хранения каждой позиции пикселей, а затем еще 4 поплавка для хранения его цвета (rgba).Вместо этого я хочу сохранить цвет внутри 1 float (4 байта).Так что в целом мне нужно всего 4 поплавка на пиксель вместо 7.
В Java я выбрал цвет следующим образом:
public float getOneFloatColor(float fr, float fg, float fb, float fa) {
char r = (char)(fr*255);
char g = (char)(fg*255);
char b = (char)(fb*255);
char a = (char)(fa*255);
return (r << 24) | (g << 16) | (b << 8) | a;
}
Обновление: Эта функция может бытьнедостатки, это может только спасти rgb, но не a.Я думаю, что это как-то связано с приведением от int к float в конце в операторе return.
Затем я помещаю его в большой массив float: float vertices[]
Сначала я ставлю позицию (xyz), а затем цвет
После этого я рисую его так:
ByteBuffer vbb = ByteBuffer.allocateDirect(bufferSize);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.position(0);
vertexBuffer.put(vertices);
vertexBuffer.position(0);
GLES20.glEnableVertexAttribArray(PixelShader.sPosition);
GLES20.glEnableVertexAttribArray(PixelShader.sColor);
int stride = 16; // 4 floats each 4 byte
GLES20.glVertexAttribPointer(PixelShader.sPosition, 3, GLES20.GL_FLOAT, false, stride, vertexBuffer);
vertexBuffer.position(3); // move offset of buffer by 3 (after xyz)
GLES20.glVertexAttribPointer(PixelShader.sColor, 4, GLES20.GL_UNSIGNED_BYTE, false, stride, vertexBuffer);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexBufferSize);
Мой вершинный шейдер:
precision mediump float;
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_PointSize = 1.0;
v_Color = a_Color;
gl_Position = a_Position;
}
Мой фрагментный шейдер:
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = vec4(v_Color.r/255., v_Color.g/255., v_Color.b/255., v_Color.a/255.);
}
Это не работает, положение пикселей будет правильным, но цвет отсутствует.Если я не делю цвет на 255 во фрагментном шейдере, то иногда я получаю какой-то цвет, но никогда не правильный.
Я думаю, что моя проблема заключается в этой строке:
GLES20.glVertexAttribPointer(PixelShader.sColor, 4, GLES20.GL_UNSIGNED_BYTE, false, stride, vertexBuffer);
Я хочу, чтобы opengl преобразовывал мой 1 float в 4 байта без знака, но это не то, что происходит?Что я делаю неправильно?Есть ли другое решение этой проблемы?Это вообще возможно?
Я нашел похожий вопрос с другим подходом здесь Но у него нет решения.
Обновление:
Я попробовал другой подход -> Отправка 1-го числа с данными rgb в шейдеры и преобразование его внутри vertexShader.
В Java:
// takes in 3 floats in the range of 0 - 1 and transforms them to one
public float rgbToFloat2(float r, float g, float b, float factor) {
r = (int)(r*factor); g = (int)(g*factor); b = (int)(b*factor);
return r/factor + g/Math.pow(factor,2) + b/Math.pow(factor,3);
}
Затем я изменил строку glVertexAttribPointer для отправки 1-го числа с плавающей точкой:
GLES20.glVertexAttribPointer(PixelShader.sColor, 1, GLES20.GL_FLOAT, false, stride, vertexBuffer);
Изменен вершинный шейдер:
precision highp float;
attribute vec4 a_Position;
attribute float a_Color;
varying vec4 v_Color;
vec3 floatToRGB(float f, float factor) {
vec3 rgb;
rgb.r = f*factor;
rgb.g = fract(rgb.r)*factor;
rgb.b = fract(rgb.g)*factor;
rgb.r = floor(rgb.r)/factor;
rgb.g = floor(rgb.g)/factor;
rgb.b = floor(rgb.b)/factor;
return rgb;
}
void main() {
gl_PointSize = 1.0;
v_Color = vec4(floatToRGB(a_Color, 255.), 1.0);
gl_Position = a_Position;
}
и фрагментный шейдер:
precision highp float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
Я тестировалэтот метод преобразования в Java, и он работал очень хорошо, но как только я пытаюсь преобразовать его внутри шейдера, он больше не работает.Я также пробовал разные факторы, даже очень низкий коэффициент, например 10, не работает.Я понятия не имею, почему нет, это как волшебство!Я сейчас сдамся, но оставлю это здесь.