Egloo 高级用法
自定义图形和着色器
1. 自定义形状
通过继承Gl2dDrawable
或Gl3dDrawable
类,你可以创建自定义的图形:
kotlin
class CustomShape : Gl2dDrawable() {
override fun getVertexArray(): FloatArray {
return floatArrayOf(
// 自定义顶点数据
-0.5f, -0.5f, // 左下
0.5f, -0.5f, // 右下
0.0f, 0.5f // 顶部
)
}
override fun draw() {
// 自定义绘制逻辑
super.draw()
}
}
2. 自定义着色器程序
创建自定义着色器程序,实现特殊的视觉效果:
kotlin
class CustomProgram : GlProgram() {
override fun getVertexShader(): String {
return """
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
}
""".trimIndent()
}
override fun getFragmentShader(): String {
return """
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
""".trimIndent()
}
}
3. 添加自定义Uniform变量
kotlin
class ShaderWithUniforms : GlProgram() {
private var timeLocation = -1
override fun onCreate() {
super.onCreate()
timeLocation = getUniformLocation("uTime")
}
fun setTime(time: Float) {
GLES20.glUniform1f(timeLocation, time)
}
override fun getFragmentShader(): String {
return """
precision mediump float;
uniform float uTime;
void main() {
float r = sin(uTime) * 0.5 + 0.5;
float g = cos(uTime) * 0.5 + 0.5;
gl_FragColor = vec4(r, g, 0.3, 1.0);
}
""".trimIndent()
}
}
变换和动画
1. 矩阵变换
kotlin
// 创建变换矩阵
val modelMatrix = FloatArray(16)
val viewMatrix = FloatArray(16)
val projectionMatrix = FloatArray(16)
val mvpMatrix = FloatArray(16)
// 设置模型矩阵(旋转)
Matrix.setIdentityM(modelMatrix, 0)
Matrix.rotateM(modelMatrix, 0, angle, 0f, 0f, 1f)
// 设置视图矩阵
Matrix.setLookAtM(viewMatrix, 0,
0f, 0f, 3f, // 相机位置
0f, 0f, 0f, // 观察点
0f, 1f, 0f // 上方向
)
// 设置投影矩阵
Matrix.frustumM(projectionMatrix, 0,
-ratio, ratio, -1f, 1f, 1f, 10f
)
// 计算最终的MVP矩阵
Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modelMatrix, 0)
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0)
// 应用到着色器程序
program.setMvpMatrix(mvpMatrix)
2. 动画实现
kotlin
class AnimatedRenderer : Renderer {
private var lastFrameTime = System.nanoTime()
private var angle = 0f
override fun onDrawFrame(gl: GL10) {
// 计算帧间隔时间
val currentTime = System.nanoTime()
val deltaTime = (currentTime - lastFrameTime) / 1_000_000_000f
lastFrameTime = currentTime
// 更新旋转角度
angle += 90f * deltaTime // 每秒旋转90度
// 应用旋转
val matrix = FloatArray(16)
Matrix.setRotateM(matrix, 0, angle, 0f, 0f, 1f)
drawable.setTransformMatrix(matrix)
// 绘制
drawable.draw()
}
}
高级纹理技术
1. 多重纹理
kotlin
class MultiTextureProgram : GlProgram() {
private var texture1Location = -1
private var texture2Location = -1
private var mixValueLocation = -1
override fun onCreate() {
super.onCreate()
texture1Location = getUniformLocation("uTexture1")
texture2Location = getUniformLocation("uTexture2")
mixValueLocation = getUniformLocation("uMixValue")
}
fun setTextures(texture1: Int, texture2: Int, mixValue: Float) {
// 激活并绑定第一个纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture1)
GLES20.glUniform1i(texture1Location, 0)
// 激活并绑定第二个纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture2)
GLES20.glUniform1i(texture2Location, 1)
// 设置混合值
GLES20.glUniform1f(mixValueLocation, mixValue)
}
override fun getFragmentShader(): String {
return """
precision mediump float;
uniform sampler2D uTexture1;
uniform sampler2D uTexture2;
uniform float uMixValue;
varying vec2 vTextureCoord;
void main() {
vec4 color1 = texture2D(uTexture1, vTextureCoord);
vec4 color2 = texture2D(uTexture2, vTextureCoord);
gl_FragColor = mix(color1, color2, uMixValue);
}
""".trimIndent()
}
}
2. 帧缓冲区后处理效果
kotlin
// 创建帧缓冲区和纹理
val framebuffer = GlFramebuffer()
val texture = GlTexture()
// 设置帧缓冲区
framebuffer.bind()
texture.bind()
texture.configure(width, height, null)
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, texture.id, 0)
// 渲染到帧缓冲区
scene.draw()
// 解绑帧缓冲区
framebuffer.unbind()
// 使用后处理着色器渲染到屏幕
postProcessingProgram.use()
postProcessingProgram.setTexture(texture.id)
screenQuad.draw()
性能优化技术
1. 顶点缓冲对象(VBO)和索引缓冲对象(IBO)
kotlin
// 创建VBO
val vbo = IntArray(1)
GLES20.glGenBuffers(1, vbo, 0)
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0])
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
vertices.size * 4,
vertexBuffer,
GLES20.GL_STATIC_DRAW)
// 创建IBO
val ibo = IntArray(1)
GLES20.glGenBuffers(1, ibo, 0)
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0])
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
indices.size * 2,
indexBuffer,
GLES20.GL_STATIC_DRAW)
// 绘制
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.size,
GLES20.GL_UNSIGNED_SHORT, 0)
2. 实例化渲染
kotlin
class InstancedProgram : GlProgram() {
private var instancePositionLocation = -1
override fun onCreate() {
super.onCreate()
instancePositionLocation = getAttribLocation("aInstancePosition")
}
override fun getVertexShader(): String {
return """
attribute vec4 aPosition;
attribute vec2 aInstancePosition;
void main() {
vec4 pos = aPosition;
pos.xy += aInstancePosition;
gl_Position = pos;
}
""".trimIndent()
}
// 设置实例数据
fun setInstanceData(buffer: FloatBuffer, count: Int) {
GLES20.glEnableVertexAttribArray(instancePositionLocation)
GLES20.glVertexAttribPointer(instancePositionLocation, 2,
GLES20.GL_FLOAT, false, 0, buffer)
GLES20.glVertexAttribDivisor(instancePositionLocation, 1)
// 绘制多个实例
GLES20.glDrawArraysInstanced(GLES20.GL_TRIANGLES, 0,
vertexCount, count)
}
}
3. 着色器计算优化
kotlin
// 优化前
float result = pow(base, exponent); // 计算开销大
// 优化后
float result = exp(log(base) * exponent); // 更高效
调试和分析
1. 性能分析
kotlin
class PerformanceMonitor {
private var frameCount = 0
private var lastTime = System.nanoTime()
private var totalTime = 0L
fun beginFrame() {
lastTime = System.nanoTime()
}
fun endFrame() {
val currentTime = System.nanoTime()
val frameTime = currentTime - lastTime
totalTime += frameTime
frameCount++
// 每秒输出一次统计信息
if (totalTime >= 1_000_000_000L) {
val fps = frameCount * 1_000_000_000L / totalTime
val avgFrameTime = totalTime / frameCount / 1_000_000f
Log.d("Egloo", "FPS: $fps, Avg frame time: $avgFrameTime ms")
frameCount = 0
totalTime = 0
}
}
}
2. 着色器调试
kotlin
// 检查着色器编译状态
val compiled = IntArray(1)
GLES20.glGetShaderiv(shaderId, GLES20.GL_COMPILE_STATUS, compiled, 0)
if (compiled[0] == 0) {
val log = GLES20.glGetShaderInfoLog(shaderId)
Log.e("Egloo", "Shader compilation failed: $log")
}
与其他框架集成
1. 与Camera2 API集成
kotlin
// 创建SurfaceTexture
val texture = GlTexture()
texture.bind()
val surfaceTexture = SurfaceTexture(texture.id)
// 设置缓冲区大小
surfaceTexture.setDefaultBufferSize(width, height)
// 创建Surface
val surface = Surface(surfaceTexture)
// 配置Camera2
val captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder.addTarget(surface)
// 设置SurfaceTexture回调
surfaceTexture.setOnFrameAvailableListener {
// 当新帧可用时更新纹理
surfaceTexture.updateTexImage()
// 获取变换矩阵
val matrix = FloatArray(16)
surfaceTexture.getTransformMatrix(matrix)
// 绘制
render()
}
2. 与MediaCodec集成
kotlin
// 创建编码器
val encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate)
format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate)
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
// 配置编码器
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
// 创建输入Surface
val inputSurface = encoder.createInputSurface()
// 创建EGL窗口表面
val encoderSurface = EglWindowSurface(eglCore, inputSurface)
// 渲染到编码器Surface
encoderSurface.makeCurrent()
// 绘制...
encoderSurface.swapBuffers()
高级场景管理
kotlin
class Scene {
private val drawables = mutableListOf<GlDrawable>()
private val lights = mutableListOf<Light>()
private val camera = Camera()
fun addDrawable(drawable: GlDrawable) {
drawables.add(drawable)
}
fun addLight(light: Light) {
lights.add(light)
}
fun setCamera(position: FloatArray, target: FloatArray, up: FloatArray) {
camera.position = position
camera.target = target
camera.up = up
}
fun render() {
// 计算视图和投影矩阵
val viewMatrix = camera.getViewMatrix()
val projectionMatrix = camera.getProjectionMatrix(aspect)
// 设置光照
for (light in lights) {
light.apply()
}
// 绘制所有对象
for (drawable in drawables) {
val program = drawable.program
program.use()
// 设置矩阵
program.setViewMatrix(viewMatrix)
program.setProjectionMatrix(projectionMatrix)
// 绘制对象
drawable.draw()
}
}
}
多线程渲染
1. 创建专用渲染线程
kotlin
class RenderThread : Thread() {
private val handler: Handler by lazy {
Looper.prepare()
val handler = Handler()
Looper.loop()
handler
}
fun queueEvent(runnable: Runnable) {
handler.post(runnable)
}
fun quit() {
handler.looper.quit()
}
}
// 使用
val renderThread = RenderThread()
renderThread.start()
// 在渲染线程上执行OpenGL操作
renderThread.queueEvent {
// OpenGL操作
eglCore.makeCurrent(surface)
program.use()
drawable.draw()
surface.swapBuffers()
}
2. 线程间共享EGL上下文
kotlin
// 主线程:创建共享上下文
val sharedEglCore = EglCore(null, EglCore.FLAG_TRY_GLES3)
// 渲染线程:使用共享上下文
val renderEglCore = EglCore(sharedEglCore.eglContext, EglCore.FLAG_TRY_GLES3)
// 资源加载线程:使用共享上下文
val resourceEglCore = EglCore(sharedEglCore.eglContext, EglCore.FLAG_TRY_GLES3)
高级特效
1. 粒子系统
kotlin
class ParticleSystem(private val maxParticles: Int) {
private val positions = FloatArray(maxParticles * 3)
private val velocities = FloatArray(maxParticles * 3)
private val colors = FloatArray(maxParticles * 4)
private val lifetimes = FloatArray(maxParticles)
fun update(deltaTime: Float) {
for (i in 0 until maxParticles) {
// 更新生命周期
lifetimes[i] -= deltaTime
// 跳过已死亡的粒子
if (lifetimes[i] <= 0f) {
resetParticle(i)
continue
}
// 更新位置
val idx = i * 3
positions[idx] += velocities[idx] * deltaTime
positions[idx + 1] += velocities[idx + 1] * deltaTime
positions[idx + 2] += velocities[idx + 2] * deltaTime
// 应用重力
velocities[idx + 1] -= 9.8f * deltaTime
}
}
private fun resetParticle(index: Int) {
// 重置粒子位置、速度、颜色和生命周期
val idx = index * 3
positions[idx] = 0f
positions[idx + 1] = 0f
positions[idx + 2] = 0f
// 随机速度
val angle = Math.random().toFloat() * 2f * Math.PI.toFloat()
val speed = 1f + Math.random().toFloat() * 2f
velocities[idx] = Math.cos(angle.toDouble()).toFloat() * speed
velocities[idx + 1] = Math.sin(angle.toDouble()).toFloat() * speed
velocities[idx + 2] = (Math.random().toFloat() - 0.5f) * speed
// 随机颜色
val colorIdx = index * 4
colors[colorIdx] = Math.random().toFloat()
colors[colorIdx + 1] = Math.random().toFloat()
colors[colorIdx + 2] = Math.random().toFloat()
colors[colorIdx + 3] = 1f
// 随机生命周期
lifetimes[index] = 1f + Math.random().toFloat() * 3f
}
fun draw(program: ParticleProgram) {
program.use()
program.setParticleData(positions, colors, lifetimes, maxParticles)
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, maxParticles)
}
}
2. 阴影映射
kotlin
// 创建阴影贴图
val shadowMapSize = 1024
val shadowMap = GlTexture()
val shadowFramebuffer = GlFramebuffer()
// 配置阴影贴图
shadowMap.bind()
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_DEPTH_COMPONENT,
shadowMapSize, shadowMapSize, 0, GLES20.GL_DEPTH_COMPONENT,
GLES20.GL_UNSIGNED_INT, null)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST)
// 配置阴影帧缓冲区
shadowFramebuffer.bind()
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
GLES20.GL_TEXTURE_2D, shadowMap.id, 0)
GLES20.glDrawBuffers(0, IntArray(0), 0) // 不需要颜色缓冲区
// 从光源视角渲染阴影贴图
shadowFramebuffer.bind()
GLES20.glViewport(0, 0, shadowMapSize, shadowMapSize)
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT)
val lightViewMatrix = calculateLightViewMatrix()
val lightProjectionMatrix = calculateLightProjectionMatrix()
shadowProgram.use()
shadowProgram.setViewMatrix(lightViewMatrix)
shadowProgram.setProjectionMatrix(lightProjectionMatrix)
// 渲染场景到阴影贴图
for (drawable in drawables) {
drawable.drawShadow(shadowProgram)
}
// 正常渲染场景,使用阴影贴图
defaultFramebuffer.bind()
GLES20.glViewport(0, 0, width, height)
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
mainProgram.use()
mainProgram.setViewMatrix(camera.viewMatrix)
mainProgram.setProjectionMatrix(camera.projectionMatrix)
mainProgram.setLightViewMatrix(lightViewMatrix)
mainProgram.setLightProjectionMatrix(lightProjectionMatrix)
mainProgram.setShadowMap(shadowMap.id)
// 渲染场景
for (drawable in drawables) {
drawable.draw(mainProgram)
}
结语
本文档介绍了Egloo框架的高级用法,包括自定义图形和着色器、变换和动画、高级纹理技术、性能优化、调试和分析、与其他框架集成、高级场景管理、多线程渲染以及高级特效等内容。通过这些高级技术,你可以充分发挥Egloo框架的潜力,创建复杂、高效的OpenGL ES应用程序。
如果你有任何问题或需要进一步的帮助,请参考API文档或在GitHub上提交issue。