如何在Android的OpenGL ES中向着色器传递时间变量实现雨滴动画
在Android OpenGL ES中实现动态雨滴效果(含时间变量传递方案)
核心问题解决:传递时间变量到着色器
Three.js会自动管理时间变量,但OpenGL ES需要你在Android代码中手动计算并传递u_time uniform变量,具体步骤如下:
计算累计时间:初始化时记录起始时间,在渲染循环中用当前时间减去起始时间,转换成秒数:
// 初始化阶段记录起始时间 private long startTime = System.nanoTime(); // 渲染循环内计算已流逝时间(单位:秒) long currentTime = System.nanoTime(); float elapsedTime = (currentTime - startTime) / 1_000_000_000f;更新uniform变量:在着色器程序链接完成后,获取
u_time的位置,每次渲染时传入最新时间值:// 初始化时获取u_time的uniform位置 int uTimeLocation = GLES20.glGetUniformLocation(program, "u_time"); // 渲染循环内更新时间变量 GLES20.glUniform1f(uTimeLocation, elapsedTime);
现有着色器代码优化建议
你的着色器已经实现了雨滴的随机生成和动态强度逻辑,但可以调整以下细节让效果更自然:
添加雨滴下落动画
当前代码的雨滴位置固定,把时间变量融入Y轴偏移,实现下落效果:// 修改Drops函数中的shiftY计算 float shiftY = fract(Random11(0.5, seed) + u_time * 0.2); // 0.2控制下落速度 uv.y += shiftY;混合雨滴与原纹理
当前直接输出雨滴颜色,改为和传入的纹理混合,让雨滴叠加在原图上:void main(void){ vec2 uv = v_TexCoord; vec4 textureColor = texture2D(u_Texture, uv); vec2 drop = Drops(uv, 123.3); // 用半透明蓝色模拟雨滴,混合到原图 vec4 dropColor = vec4(0.2, 0.4, 0.8, drop.x * 0.6); gl_FragColor = mix(textureColor, dropColor, drop.x); }优化随机函数稳定性
调整随机函数的参数,避免sin函数的周期性问题:float Random11(float inputValue, float seed){ return fract(sin(inputValue * 12.9898 + seed) * 43758.5453); }
完整优化后的片段着色器代码
precision highp float; #define HIGHFLOAT highp uniform sampler2D u_Texture; varying vec2 v_TexCoord; uniform HIGHFLOAT float u_time; float Random11(float inputValue, float seed){ return fract(sin(inputValue * 12.9898 + seed) * 43758.5453); } float Random21(vec2 inputValue, float seed){ return fract(sin(dot(inputValue, vec2(12.9898, 78.233)) + seed) * 43758.5453); } vec2 Drops(vec2 uv, float seed){ // 加入时间变量实现雨滴下落 float shiftY = fract(Random11(0.5, seed) + u_time * 0.2); uv.y += shiftY; float cellRes = 10.0; uv *= cellRes; float rowInd = floor(uv.y); float shiftX = Random11(rowInd, seed); uv.x += shiftX; vec2 cellIndex = floor(uv); vec2 cellUv = fract(uv); // 定义雨滴圆形区域 vec2 cellCenter = vec2(0.5); float distFromCenter = distance(cellUv, cellCenter); float isInside = 1.0 - step(0.1, distFromCenter); // 随机控制雨滴显示 float isDropShown = step(0.8, Random21(cellIndex, seed + 1422.14)); // 雨滴淡入淡出动画 float dropIntensity = 1.0 - fract(u_time * 0.1 + Random21(cellIndex, seed + 3221.12) * 2.0) * 2.0; dropIntensity = sin(dropIntensity * 3.14159) * pow(abs(dropIntensity), 4.0); dropIntensity = clamp(dropIntensity, 0.0, 1.0); return vec2(isInside) * isDropShown * dropIntensity; } void main(void){ vec2 uv = v_TexCoord; vec4 baseColor = texture2D(u_Texture, uv); vec2 dropValue = Drops(uv, 123.3); // 叠加半透明雨滴效果 vec4 dropColor = vec4(0.1, 0.3, 0.6, dropValue.x * 0.7); gl_FragColor = baseColor + dropColor; }
Android端渲染循环关键代码示例
确保在每次渲染时更新时间变量:
@Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 计算已流逝的时间(秒) long currentTime = System.nanoTime(); float elapsedTime = (currentTime - startTime) / 1_000_000_000f; // 更新着色器中的时间变量 GLES20.glUniform1f(uTimeLocation, elapsedTime); // 绘制承载纹理的平面 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); }
内容的提问来源于stack exchange,提问作者Areeb Lone
相关产品推荐
相关产品推荐

