Opengl - GLSL - хранение 4 байтов внутри одного float и отправка его в шейдер - PullRequest
0 голосов
/ 11 декабря 2018

Использование: 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, не работает.Я понятия не имею, почему нет, это как волшебство!Я сейчас сдамся, но оставлю это здесь.

...