GLES20.glUniform4fv и fragshader

#android #kotlin #opengl-es

#Android #kotlin #opengl-es

Вопрос:

Хорошо, итак, я пытаюсь просто перебирать и использовать несколько цветов в объекте, но, похоже, не могу в этом разобраться и, честно говоря, готов рвать на себе волосы, но этот код взят из руководств по андроидам, и я уже минуту играюсь с ним и перепробовал множество разных вещей, но всегда в конечном итоге возвращаюсь к вопросу: «Это фрагментный шейдер, или я просто использую функцию GLES20.glUniform4fv(colorHandle, 2, color, 0) неправильно? Зачем ему иметь значение «count» и аргумент массива, если он не может принимать аргумент массива цветов?»

 class Triangle {
    private var mProgram: Int
    private var vPMatrixHandle: Int = 0
    private var positionHandle: Int = 0
    private var mColorHandle: Int = 0
    private val fragmentShaderCode: String =
        "precision mediump float;n"  
        "uniform vec4 vColor[];n"  
        "void main() {n"  
            "tgl_FragColor = vColor;n"  
        "}"
    private val vertexShaderCode: String =
        "uniform mat4 uMVPMatrix;n"  
        "attribute vec4 vPosition;n"  
        "void main() {n"  
            "tgl_Position = uMVPMatrix * vPosition;n"  
        "}"

    private val COORDS_PER_VERTEX: Int = 3
    private var triangleCoords: FloatArray = floatArrayOf(
        -0.5f, -0.5f, -0.5f,
        0.5f, -0.5f, -0.5f,
        0.5f, 0.5f, -0.5f,
        -0.5f, 0.5f, -0.5f,
        -0.5f, -0.5f, 0.5f,
        0.5f, -0.5f, 0.5f,
        0.5f, 0.5f, 0.5f,
        -0.5f, 0.5f, 0.5f
    )
    private val color: FloatArray = floatArrayOf(
        0.63671875f, 0.76953125f, 0.22265625f, 1.0f,
        0.63671875f, 0.22953125f, 0.78265625f, 1.0f
    )
    private val indiceCoords: ByteArray = byteArrayOf(
        0, 4, 5, 0, 5, 1,
        1, 5, 6, 1, 6, 2,
        2, 6, 7, 2, 7, 3,
        3, 7, 4, 3, 4, 0,
        4, 7, 6, 4, 6, 5,
        3, 0, 1, 3, 1, 2
    )

    private val vertexCount: Int = triangleCoords.size / COORDS_PER_VERTEX
    private val vertexStride: Int = COORDS_PER_VERTEX * 4

    private var vertexBuffer: FloatBuffer =
        ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
            order(ByteOrder.nativeOrder())
            asFloatBuffer().apply {
                put(triangleCoords)
                position(0)
            }
        }

    private var indiceBuffer: ByteBuffer =
        ByteBuffer.allocateDirect(indiceCoords.size * 4).run {
            order(ByteOrder.nativeOrder()).apply {
                put(indiceCoords)
                position(0)
            }
        }

    init {
        val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        mProgram = GLES20.glCreateProgram().also {
            GLES20.glAttachShader(it, vertexShader)
            GLES20.glAttachShader(it, fragmentShader)
            GLES20.glLinkProgram(it)
        }
    }

    fun loadShader(type: Int, shaderCode: String): Int {
        return GLES20.glCreateShader(type).also { shader ->
            GLES20.glShaderSource(shader, shaderCode)
            GLES20.glCompileShader(shader)
        }
    }

    fun draw(mvpMatrix: FloatArray) {
        GLES20.glUseProgram(mProgram)
        positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition").also {
            GLES20.glEnableVertexAttribArray(it)
            GLES20.glVertexAttribPointer(
                it,
                COORDS_PER_VERTEX,
                GLES20.GL_FLOAT,
                false,
                vertexStride,
                vertexBuffer
            )
            mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor").also { colorHandle ->
                GLES20.glUniform4fv(colorHandle, 2, color, 0)
            }
            vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")
            GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0)
            GLES20.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, indiceBuffer)
            GLES20.glDisableVertexAttribArray(it)
        }
    }
}
  

Комментарии:

1. Вы не можете использовать массивы открытого размера в формах glsl и вы не можете назначить массив gl_FragColor . Тип gl_FragColor является vec4 . Если вы хотите связать цвета с вершинами, то вам придется добавить дополнительный атрибут.

Ответ №1:

Если вы хотите связать цвета с вершинами, то вам придется добавить дополнительный атрибут. Количество цветов должно совпадать с количеством вершин.

Добавьте атрибут цвета к вершинному шейдеру ( attribute vec4 vColor; ). Передайте атрибут из вершинного шейдера в фрагментный шейдер ( varying vec4 color; ):

 private val fragmentShaderCode: String =
    "precision mediump float;n"  
    "varying vec4 color;n"  
    "void main() {n"  
        "tgl_FragColor = color;n"  
    "}"
private val vertexShaderCode: String =
    "uniform mat4 uMVPMatrix;n"  
    "attribute vec4 vPosition;n"  
    "attribute vec4 vColor;n"  
    "varying vec4 color;n"  
    "void main() {n"  
        "tcolor = vColor;n"  
        "tgl_Position = uMVPMatrix * vPosition;n"  
    "}"
  

Определите массив из 8 цветов. Например:

 private val COORDS_PER_COLOR: Int = 4
private val color: FloatArray = floatArrayOf(
    0.63671875f, 0.76953125f, 0.22265625f, 1.0f,
    0.63671875f, 0.22953125f, 0.78265625f, 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,
    1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 1.0f, 1.0f
)

private val colorCount: Int = color.size / COORDS_PER_COLOR
private val colorStride: Int = COORDS_PER_COLOR * 4
  

Создайте буфер для атрибутов цвета:

 private var colorBuffer: FloatBuffer =
    ByteBuffer.allocateDirect(color.size * 4).run {
        order(ByteOrder.nativeOrder())
        asFloatBuffer().apply {
            put(color)
            position(0)
        }
    }
  

Укажите массив атрибутов цвета:

 mColorHandle = GLES20.glGetAttribLocation(mProgram, "vColor").also { colorHandle ->
    GLES20.glEnableVertexAttribArray(colorHandle)
    GLES20.glVertexAttribPointer(
        colorHandle,
        COORDS_PER_COLOR,
        GLES20.GL_FLOAT,
        false,
        colorStride,
        colorBuffer
    )
}
  

Комментарии:

1. И снова ты решил мою проблему! Я наткнулся на некоторые очень полезные спецификации на khronos.org/registry/OpenGL/index_gl.php который я только начал читать и который я определенно рекомендовал бы прочитать всем, кто впервые пытается поиграть с OpenGL, и, надеюсь, я действительно верю из этих спецификаций, что я скоро смогу перестать быть таким занудой, задавая здесь все эти такие нубовские вопросы. Знаете ли вы какие-либо другие руководства, спецификации или сайты, которые вы могли бы порекомендовать кому-либо, не разбирающемуся в графике? Я разбираюсь в веб-разработке с помощью PHP Javascript и ассемблера и немного Kotlin в качестве опыта.

2. Для веб-приложений и приложений на JavaScript я рекомендую WebGL соответственно WebGL 2.0 . Начните с основ WebGL и продолжайте с основами WebGL2 .

Ответ №2:

Если вы хотите использовать «однородный» массив (vColor[]), явно укажите размер массива в объявлении.

 private val fragmentShaderCode: String =
        "precision mediump float;n"  
                "uniform vec4 vColor[2];n"  
                "varying vec4 vParam;"  
                "void main() {n"  
                "tgl_FragColor = vColor[int(step(vParam.x * vParam.y * vParam.z, 0.0))];n"  
                "}"
private val vertexShaderCode: String =
        "uniform mat4 uMVPMatrix;n"  
                "attribute vec4 vPosition;n"  
                "varying vec4 vParam;"  
                "void main() {n"  
                "tgl_Position = uMVPMatrix * vPosition;n"  
                "tvParam = vPosition;"  
                "}"