android shadertoy效果 转换成 Android动态壁纸的写法

kotlin 复制代码
package com.example.wallpaper3d.shader

import android.content.Context
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.service.wallpaper.WallpaperService
import android.util.Log
import android.view.SurfaceHolder
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class ShaderWallpaperService : WallpaperService() {
    override fun onCreateEngine(): Engine {
        return ShaderEngine()
    }
    
    inner class ShaderEngine : Engine() {
        private lateinit var glSurfaceView: GLSurfaceView
        private lateinit var renderer: ShaderRenderer

        override fun onCreate(surfaceHolder: SurfaceHolder) {
            super.onCreate(surfaceHolder)
            glSurfaceView = MyGLSurfaceView(this@ShaderWallpaperService)
            renderer = ShaderRenderer(this@ShaderWallpaperService)
            glSurfaceView.setRenderer(renderer)
            glSurfaceView.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
        }

        override fun onVisibilityChanged(visible: Boolean) {
            super.onVisibilityChanged(visible)
            if (visible) {
                glSurfaceView.onResume()
            } else {
                glSurfaceView.onPause()
            }
        }

        inner class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {
            init {
                setEGLContextClientVersion(2)
                holder.setFormat(android.graphics.PixelFormat.TRANSLUCENT)
                setZOrderOnTop(false)
            }

            override fun getHolder(): SurfaceHolder {
                return surfaceHolder // 使用壁纸引擎的 SurfaceHolder
            }
        }
    }
}

class ShaderRenderer(val context: Context) : GLSurfaceView.Renderer {
    // 顶点坐标(全屏四边形)
    private val vertexCoords = floatArrayOf(
        -1.0f, -1.0f, 0.0f,  // 左下
        1.0f, -1.0f, 0.0f,   // 右下
        -1.0f, 1.0f, 0.0f,   // 左上
        1.0f, 1.0f, 0.0f     // 右上
    )
    private val vertexBuffer: FloatBuffer

    // Shader 程序 ID
    private var programId: Int = 0
    // 时间和分辨率的 uniform 位置
    private var timeLoc: Int = 0
    private var resolutionLoc: Int = 0
    private var startTime: Long = 0

    init {
        // 初始化顶点缓冲
        vertexBuffer = ByteBuffer.allocateDirect(vertexCoords.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(vertexCoords)
        vertexBuffer.position(0)
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        // 编译并链接 shaders
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)

        val  fragmentShaderCode = ShaderLoader.loadFromAssets(context,"shaders/shader_3.glsl")
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        programId = GLES20.glCreateProgram().apply {
            GLES20.glAttachShader(this, vertexShader)
            GLES20.glAttachShader(this, fragmentShader)
            GLES20.glLinkProgram(this)
        }
        GLES20.glUseProgram(programId)

        // 获取 uniform 变量位置
        timeLoc = GLES20.glGetUniformLocation(programId, "iTime")
        resolutionLoc = GLES20.glGetUniformLocation(programId, "iResolution")

        // 记录开始时间
        startTime = System.currentTimeMillis()
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
        // 传递分辨率给 shader
        GLES20.glUniform2f(resolutionLoc, width.toFloat(), height.toFloat())
    }

    override fun onDrawFrame(gl: GL10?) {
        GLES20.glClearColor(0f, 0f, 0f, 1f)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

        // 计算运行时间(秒)
        val currentTime = (System.currentTimeMillis() - startTime) / 1000f
        GLES20.glUniform1f(timeLoc, currentTime)

        // 绑定顶点数据
        val positionLoc = GLES20.glGetAttribLocation(programId, "aPosition")
        GLES20.glEnableVertexAttribArray(positionLoc)
        GLES20.glVertexAttribPointer(
            positionLoc, 3, GLES20.GL_FLOAT, false,
            3 * 4, vertexBuffer
        )

        // 绘制全屏四边形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
        GLES20.glDisableVertexAttribArray(positionLoc)
    }

    // 加载并编译 shader
    private fun loadShader(type: Int, shaderCode: String): Int {
        Log.i("ccccccc", "shader_code===$shaderCode")
        return GLES20.glCreateShader(type).apply {
            GLES20.glShaderSource(this, shaderCode)
            GLES20.glCompileShader(this)
        }
    }

    // 顶点着色器(全屏四边形)
    private val vertexShaderCode = """
        attribute vec3 aPosition;
        void main() {
            gl_Position = vec4(aPosition, 1.0);
        }
    """.trimIndent()
    
}

shader_3.glsl内容

ini 复制代码
#version 100
precision mediump float;

uniform float iTime;
uniform vec2 iResolution;

// 旋转90度开关(注释掉可关闭旋转)
#define ROTATE_90

void main() {
    vec2 fragCoord = gl_FragCoord.xy;

    // 处理90度旋转:交换x/y坐标并修正方向
    #ifdef ROTATE_90
    // 交换x和y,实现旋转;反转x轴修正方向
    fragCoord = vec2(fragCoord.y, iResolution.x - fragCoord.x);
    // 旋转后重新计算分辨率比例(宽高互换)
    vec2 r = vec2(iResolution.y, iResolution.x);
    #else
    vec2 r = iResolution.xy;
    #endif

    vec3 c;
    float l, z = iTime;

    // 减少迭代次数(原3次→2次,提升性能)
    for(int i = 0; i < 2; i++) {
        vec2 uv, p = fragCoord.xy / r;
        uv = p;

        // 坐标中心化并适配宽高比
        p -= 0.5;
        p.x *= r.x / r.y;

        // 时间动画控制(略微降低速度,避免过度闪烁)
        z += 0.05;
        l = length(p);

        // 核心扭曲计算(保留原效果)
        uv += p / l * (sin(z) + 1.0) * abs(sin(l * 9.0 - z * 2.0));

        // 颜色计算(增强对比度)
        c[i] = 0.02 / length(mod(uv, 1.0) - 0.5);
    }

    // 补充第三通道颜色(保持三通道平衡)
    c[2] = 0.02 / length(mod((fragCoord.xy / r) + sin(z)*0.1, 1.0) - 0.5);

    // 输出颜色(调整透明度避免过亮)
    gl_FragColor = vec4(c / l, 1.0);
}

拷贝对应的效果代码 扔给ai 然后替换glsl文件内容。这里仅限于 变量只有 iTime iResolution 的效果。如果有其他变量 需要ai帮你把其他变量的设置 补充上

相关推荐
花卷HJ25 分钟前
Android 项目中 BaseActivity 封装实践(支持 ViewBinding、PermissionUtils动态权限、加载弹窗和跳转动画)
android
消失的旧时光-19432 小时前
Android 接入 Flutter(Add-to-App)最小闭环:10 分钟跑起第一个混合页面
android·flutter
城东米粉儿2 小时前
android StrictMode 笔记
android
Zender Han2 小时前
Flutter Android 启动页 & App 图标替换(不使用任何插件的完整实践)
android·flutter·ios
童无极3 小时前
Android 弹幕君APP开发实战01
android
赛恩斯3 小时前
kotlin 为什么可以在没有kotlin 环境的安卓系统上运行的
android·开发语言·kotlin
于山巅相见3 小时前
【3588】Android动态隐藏导航栏
android·导航栏·状态栏·android11
乡野码圣3 小时前
【RK3588 Android12】开发效率提升技巧
android·嵌入式硬件
eybk3 小时前
Beeware生成安卓apk取得系统tts语音朗读例子
android