天天看点

Opengl ES系列学习--太阳

     继续积累Shadertoy,大家也可去Shader女神的CSDN逛逛:Shader女神。使用别人写好的shader实现的一个太阳的效果,太漂亮了!!!

Opengl ES系列学习--太阳

     该效果实现是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;
}
           

     在这个神奇的地方,还有很多我们所不懂的东西,需要继续深入学习。

继续阅读