/
am98pln
/
AndroidOpenGLESExample
Обзор
Документация
Войти
/
am98pln
/
AndroidOpenGLESExample
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
TexturedTriangle/app/src/main/java/com/example/openglesdemo/Triangle.kt
295 строк
12 KB
Leonid Pakholkov
Fixed package's name and application's name for examples
12 янв 2026, 12:23
12 янв 2026, 12:23
d98e9af
Код
Авторство
О чём код?
package com.example.openglestexturestrianle import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.opengl.GLES20 import android.opengl.GLUtils import android.util.Log import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.FloatBuffer import java.nio.ShortBuffer class TexturedTriangle(private val context: Context) { // Вершинный шейдер с текстурой private val vertexShaderCode = """ uniform mat4 uMVPMatrix; attribute vec4 vPosition; attribute vec2 aTexCoord; varying vec2 vTexCoord; void main() { gl_Position = uMVPMatrix * vPosition; vTexCoord = aTexCoord; } """.trimIndent() // Фрагментный шейдер с текстурой private val fragmentShaderCode = """ precision mediump float; varying vec2 vTexCoord; uniform sampler2D uTexture; void main() { gl_FragColor = texture2D(uTexture, vTexCoord); } """.trimIndent() // Координаты вершин треугольника private val triangleCoords = floatArrayOf( // в порядке против часовой стрелки: 0.0f, 0.622008459f, 0.0f, // верх -0.5f, -0.311004243f, 0.0f, // левый нижний 0.5f, -0.311004243f, 0.0f // правый нижний ) // Координаты текстуры (UV координаты) private val textureCoords = floatArrayOf( // S, T (или U, V) 0.5f, 1.0f, // верх 0.0f, 0.0f, // левый низ 1.0f, 0.0f // правый низ ) // Порядок отрисовки вершин (не нужен для простого треугольника) private val drawOrder = shortArrayOf(0, 1, 2) // Буферы private var vertexBuffer: FloatBuffer private var textureBuffer: FloatBuffer private var drawListBuffer: ShortBuffer // Программа и хэндлы private var mProgram: Int = 0 private var positionHandle: Int = 0 private var texCoordHandle: Int = 0 private var mvpMatrixHandle: Int = 0 private var textureHandle: Int = 0 // Текстура private var textureId = IntArray(1) init { Log.d("OpenGLESDemo", "TexturedTriangle init") // Инициализация буфера вершин val bb = ByteBuffer.allocateDirect(triangleCoords.size * 4) bb.order(ByteOrder.nativeOrder()) vertexBuffer = bb.asFloatBuffer() vertexBuffer.put(triangleCoords) vertexBuffer.position(0) // Инициализация буфера текстурных координат val tb = ByteBuffer.allocateDirect(textureCoords.size * 4) tb.order(ByteOrder.nativeOrder()) textureBuffer = tb.asFloatBuffer() textureBuffer.put(textureCoords) textureBuffer.position(0) // Инициализация буфера порядка отрисовки val dlb = ByteBuffer.allocateDirect(drawOrder.size * 2) dlb.order(ByteOrder.nativeOrder()) drawListBuffer = dlb.asShortBuffer() drawListBuffer.put(drawOrder) drawListBuffer.position(0) // Компиляция шейдеров val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode) val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode) // Создание программы mProgram = GLES20.glCreateProgram() GLES20.glAttachShader(mProgram, vertexShader) GLES20.glAttachShader(mProgram, fragmentShader) GLES20.glLinkProgram(mProgram) // Загрузка текстуры //loadTexture() // Программная loadTextureFromResource(R.drawable.tree) // Из ресурсов } private fun loadShader(type: Int, shaderCode: String): Int { val shader = GLES20.glCreateShader(type) GLES20.glShaderSource(shader, shaderCode) GLES20.glCompileShader(shader) // Проверка компиляции val compileStatus = IntArray(1) GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0) if (compileStatus[0] == 0) { val error = GLES20.glGetShaderInfoLog(shader) Log.e("OpenGLESDemo", "Shader compile error: $error") GLES20.glDeleteShader(shader) return 0 } return shader } private fun loadTexture() { // Генерируем ID текстуры GLES20.glGenTextures(1, textureId, 0) // Привязываем текстуру GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]) // Устанавливаем параметры фильтрации GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR) // Устанавливаем параметры натяжения (wrap) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT) // Создаем простую текстуру программно (красно-синий градиент) val width = 64 val height = 64 val pixels = IntArray(width * height) for (y in 0 until height) { for (x in 0 until width) { val r = (x * 255 / width).toInt() val g = 0 val b = (y * 255 / height).toInt() val a = 255 pixels[y * width + x] = (a shl 24) or (r shl 16) or (g shl 8) or b } } // Загружаем текстуру GLUtils.texImage2D( GLES20.GL_TEXTURE_2D, 0, Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888), 0 ) // Отвязываем текстуру GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0) Log.d("OpenGLESDemo", "Texture loaded with ID: ${textureId[0]}") } // Альтернативный метод: загрузка текстуры из ресурсов private fun loadTextureFromResource(resourceId: Int) { // 1. Генерируем ID текстуры GLES20.glGenTextures(1, textureId, 0) // 2. Привязываем текстуру GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]) // 3. Настройки текстуры (ВАЖНО!) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR) GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE) // Измените на CLAMP_TO_EDGE GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE) // 4. Загружаем Bitmap val options = BitmapFactory.Options().apply { inScaled = false // КРИТИЧЕСКИ ВАЖНО! inPreferredConfig = Bitmap.Config.ARGB_8888 } Log.d("OpenGLESDemo", "Loading texture from resource ID: $resourceId") // 5. Загрузка ресурса val bitmap = try { // Открываем поток ресурсов val inputStream = context.resources.openRawResource(resourceId) BitmapFactory.decodeStream(inputStream, null, options)?.also { inputStream.close() Log.d("OpenGLESDemo", "Bitmap loaded: ${it.width}x${it.height}") } } catch (e: Exception) { Log.e("OpenGLESDemo", "Error loading bitmap: ${e.message}") null } if (bitmap == null) { Log.e("OpenGLESDemo", "Failed to load bitmap, creating fallback") //createFallbackTexture() return } // 6. Загружаем в OpenGL GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0) // 7. Генерируем мипмапы (опционально, но улучшает качество) GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D) // 8. Освобождаем память bitmap.recycle() // 9. Отвязываем текстуру GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0) Log.d("OpenGLESDemo", "Texture loaded successfully. ID: ${textureId[0]}") } fun draw(mvpMatrix: FloatArray) { if (mProgram == 0) { Log.e("OpenGLESDemo", "Program not initialized") return } // Используем программу GLES20.glUseProgram(mProgram) // Получаем хэндл атрибута позиции positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition") GLES20.glEnableVertexAttribArray(positionHandle) // Подготавливаем данные вершин GLES20.glVertexAttribPointer( positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer ) // Получаем хэндл текстурных координат texCoordHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord") GLES20.glEnableVertexAttribArray(texCoordHandle) // Подготавливаем текстурные координаты GLES20.glVertexAttribPointer( texCoordHandle, 2, GLES20.GL_FLOAT, false, textureStride, textureBuffer ) // Получаем хэндл матрицы mvpMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix") GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0) // Активируем текстуру GLES20.glActiveTexture(GLES20.GL_TEXTURE0) GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]) // Получаем хэндл сэмплера текстуры textureHandle = GLES20.glGetUniformLocation(mProgram, "uTexture") GLES20.glUniform1i(textureHandle, 0) // 0 соответствует GL_TEXTURE0 // Рисуем треугольник GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount) // Отключаем массивы атрибутов GLES20.glDisableVertexAttribArray(positionHandle) GLES20.glDisableVertexAttribArray(texCoordHandle) // Отвязываем текстуру GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0) } companion object { const val COORDS_PER_VERTEX = 3 const val TEXTURE_COORDS_PER_VERTEX = 2 const val vertexCount = 3 const val vertexStride = COORDS_PER_VERTEX * 4 // 4 байта на float const val textureStride = TEXTURE_COORDS_PER_VERTEX * 4 } }