继续积累Shadertoy,大家也可去Shader女神的CSDN逛逛:Shader女神。使用别人写好的shader实现的一个太阳的效果,太漂亮了!!!
该效果实现是GlSunRender类,完整源码如下:
package com.opengl.learn.aric;
import android.content.Context;
import android.opengl.GLES32;
import android.opengl.GLSurfaceView;
import android.util.Log;
import com.opengl.learn.OpenGLUtils;
import com.opengl.learn.R;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_TEST;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_STATIC_DRAW;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE1;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TRIANGLES;
import static android.opengl.GLES20.glGenBuffers;
import static android.opengl.GLES20.glGetUniformLocation;
public class GlSunRender implements GLSurfaceView.Renderer {
private static final String TAG = GlSunRender.class.getSimpleName();
private final float[] mVerticesData =
{
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
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 static final int BYTES_PER_FLOAT = 4;
private static final int POSITION_COMPONENT_COUNT = 3;
private Context mContext;
private FloatBuffer mVerticesBuffer;
private int mProgramObject, mVAO, mVBO, iTime, iResolution;
private int sunChannel0, iChannel0, sunChannel1, iChannel1;
private int mWidth, mHeight;
private long startTime;
public GlSunRender(Context context) {
mContext = context;
mVerticesBuffer = ByteBuffer.allocateDirect(mVerticesData.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVerticesBuffer.put(mVerticesData).position(0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mProgramObject = OpenGLUtils.loadProgram(mContext, R.raw.glsea_vertex, R.raw.glsun_fragment);
iTime = glGetUniformLocation(mProgramObject, "iTime");
iResolution = glGetUniformLocation(mProgramObject, "iResolution");
iChannel0 = glGetUniformLocation(mProgramObject, "iChannel0");
iChannel1 = glGetUniformLocation(mProgramObject, "iChannel1");
int[] array = new int[1];
GLES32.glGenVertexArrays(array.length, array, 0);
mVAO = array[0];
array = new int[1];
glGenBuffers(array.length, array, 0);
mVBO = array[0];
Log.e(TAG, "onSurfaceCreated, " + mProgramObject + ", uTime: " + iTime + ", uResolution: " + iResolution);
GLES32.glBindVertexArray(mVAO);
mVerticesBuffer.position(0);
GLES32.glBindBuffer(GL_ARRAY_BUFFER, mVBO);
GLES32.glBufferData(GL_ARRAY_BUFFER, BYTES_PER_FLOAT * mVerticesData.length, mVerticesBuffer, GL_STATIC_DRAW);
GLES32.glVertexAttribPointer(0, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, 0);
GLES32.glEnableVertexAttribArray(0);
sunChannel0 = OpenGLUtils.loadTexture(mContext, R.mipmap.sun_channel0);
sunChannel1 = OpenGLUtils.loadTexture(mContext, R.mipmap.sun_channel1);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mWidth = width;
mHeight = height;
}
@Override
public void onDrawFrame(GL10 gl) {
long now = System.currentTimeMillis();
if (startTime == 0) {
startTime = now;
}
float time = (now - startTime) / (1000f * 5f);
GLES32.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLES32.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
GLES32.glEnable(GL_DEPTH_TEST);
GLES32.glUseProgram(mProgramObject);
GLES32.glUniform1f(iTime, time);
GLES32.glUniform2f(iResolution, mWidth, mHeight);
GLES32.glActiveTexture(GL_TEXTURE0);
GLES32.glBindTexture(GL_TEXTURE_2D, sunChannel0);
GLES32.glUniform1i(iChannel0, 0);
GLES32.glActiveTexture(GL_TEXTURE1);
GLES32.glBindTexture(GL_TEXTURE_2D, sunChannel1);
GLES32.glUniform1i(iChannel1, 1);
GLES32.glEnableVertexAttribArray(0);
GLES32.glBindVertexArray(mVAO);
GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);
GLES32.glBindVertexArray(0);
GLES32.glDisableVertexAttribArray(0);
}
}
都是我们之前用过的知识,就不细讲了,顶点着色器和上一节的大海完全一样,就是四个点,片段着色器源码如下:
// based on https://www.shadertoy.com/view/lsf3RH by
// trisomie21 (THANKS!)
// My apologies for the ugly code.
#version 320 es
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
out vec4 FragColor;
uniform float iTime;
uniform vec2 iResolution;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
float freqs[4];
float snoise(vec3 uv, float res)// by trisomie21
{
const vec3 s = vec3(1e0, 1e2, 1e4);
uv *= res;
vec3 uv0 = floor(mod(uv, res))*s;
vec3 uv1 = floor(mod(uv+vec3(1.), res))*s;
vec3 f = fract(uv); f = f*f*(3.0-2.0*f);
vec4 v = vec4(uv0.x+uv0.y+uv0.z, uv1.x+uv0.y+uv0.z,
uv0.x+uv1.y+uv0.z, uv1.x+uv1.y+uv0.z);
vec4 r = fract(sin(v*1e-3)*1e5);
float r0 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y);
r = fract(sin((v + uv1.z - uv0.z)*1e-3)*1e5);
float r1 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y);
return mix(r0, r1, f.z)*2.-1.;
}
void main(void) {
freqs[0] = texture(iChannel1, vec2(0.01, 0.25)).x;
freqs[1] = texture(iChannel1, vec2(0.07, 0.25)).x;
freqs[2] = texture(iChannel1, vec2(0.15, 0.25)).x;
freqs[3] = texture(iChannel1, vec2(0.30, 0.25)).x;
float brightness = freqs[1] * 0.25 + freqs[2] * 0.25;
float radius = 0.24 + brightness * 0.2;
float invRadius = 1.0/radius;
vec3 orange = vec3(0.8, 0.65, 0.3);
vec3 orangeRed = vec3(0.8, 0.35, 0.1);
float time = iTime * 0.1;
float aspect = iResolution.x/iResolution.y;
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec2 p = -0.5 + uv;
p.x *= aspect;
float fade = pow(length(2.0 * p), 0.5);
float fVal1 = 1.0 - fade;
float fVal2 = 1.0 - fade;
float angle = atan(p.x, p.y)/6.2832;
float dist = length(p);
vec3 coord = vec3(angle, dist, time * 0.1);
float newTime1 = abs(snoise(coord + vec3(0.0, -time * (0.35 + brightness * 0.001), time * 0.015), 15.0));
float newTime2 = abs(snoise(coord + vec3(0.0, -time * (0.15 + brightness * 0.001), time * 0.015), 45.0));
for (int i=1; i<=7; i++){
float power = pow(2.0, float(i + 1));
fVal1 += (0.5 / power) * snoise(coord + vec3(0.0, -time, time * 0.2), (power * (10.0) * (newTime1 + 1.0)));
fVal2 += (0.5 / power) * snoise(coord + vec3(0.0, -time, time * 0.2), (power * (25.0) * (newTime2 + 1.0)));
}
float corona = pow(fVal1 * max(1.1 - fade, 0.0), 2.0) * 50.0;
corona += pow(fVal2 * max(1.1 - fade, 0.0), 2.0) * 50.0;
corona *= 1.2 - newTime1;
vec3 sphereNormal = vec3(0.0, 0.0, 1.0);
vec3 dir = vec3(0.0);
vec3 center = vec3(0.5, 0.5, 1.0);
vec3 starSphere = vec3(0.0);
vec2 sp = -1.0 + 2.0 * uv;
sp.x *= aspect;
sp *= (2.0 - brightness);
float r = dot(sp, sp);
float f = (1.0-sqrt(abs(1.0-r)))/(r) + brightness * 0.5;
if (dist < radius){
corona *= pow(dist * invRadius, 24.0);
vec2 newUv;
newUv.x = sp.x*f;
newUv.y = sp.y*f;
newUv += vec2(time, 0.0);
vec3 texSample = texture(iChannel0, newUv).rgb;
float uOff = (texSample.g * brightness * 4.5 + time);
vec2 starUV = newUv + vec2(uOff, 0.0);
starSphere = texture(iChannel0, starUV).rgb;
}
float starGlow = min(max(1.0 - dist * (1.0 - brightness), 0.0), 1.0);
FragColor.rgb = vec3(f * (0.75 + brightness * 0.3) * orange) + starSphere + corona * orange + starGlow * orangeRed;
FragColor.a = 1.0;
}
在这个神奇的地方,还有很多我们所不懂的东西,需要继续深入学习。