今天的这个蜗牛真是太猛了,计算量超大,GPU直接拉到最高频,而且负载99%!!这是什么样的计算量,我们相机使用Opengl ES平时绘制的预览,GPU是最低频,而且负载也只有3%--10%左右,看来我们的技术还不够深,要能真正实现一个功能,正常使用GPU达到这样的频率的话,那才能突显出一定的水平。来看下蜗牛的效果。
GlSnailRender类的完整源码如下:
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_TEXTURE2;
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 GlSnailRender implements GLSurfaceView.Renderer {
private static final String TAG = GlSnailRender.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 iChannel1, channel1, iChannel2, channel2, iChannel3, channel3;
private int mWidth, mHeight;
private long startTime;
public GlSnailRender(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.glsnail_fragment);
iResolution = glGetUniformLocation(mProgramObject, "iResolution");
iTime = glGetUniformLocation(mProgramObject, "iTime");
iChannel1 = glGetUniformLocation(mProgramObject, "iChannel1");
iChannel2 = glGetUniformLocation(mProgramObject, "iChannel2");
iChannel3 = glGetUniformLocation(mProgramObject, "iChannel3");
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);
channel1 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel1);
channel2 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel2);
channel3 = OpenGLUtils.loadTexture(mContext, R.mipmap.snail_channel3);
}
@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, channel1);
GLES32.glUniform1i(iChannel1, 0);
GLES32.glActiveTexture(GL_TEXTURE1);
GLES32.glBindTexture(GL_TEXTURE_2D, channel2);
GLES32.glUniform1i(iChannel2, 1);
GLES32.glActiveTexture(GL_TEXTURE2);
GLES32.glBindTexture(GL_TEXTURE_2D, channel3);
GLES32.glUniform1i(iChannel3, 2);
GLES32.glEnableVertexAttribArray(0);
GLES32.glBindVertexArray(mVAO);
GLES32.glDrawArrays(GL_TRIANGLES, 0, mVerticesData.length);
GLES32.glBindVertexArray(0);
GLES32.glDisableVertexAttribArray(0);
}
}
重点还是在片段着色器,网上有些说法也叫像素着色器,不过两个的重点不一样,片段着色器的重点是FragColor;像素着色器的重点是gl_FragCoord,一个变量就可以展开无数种炫丽的效果,像素着色器的魔法也就在gl_FragCoord内建变量中了。片段着色器的源码如下:
// Created by inigo quilez - 2015
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0
// You can buy a metal print of this shader here:
// https://www.redbubble.com/i/metal-print/Snail-by-InigoQuilez/39845499.0JXQP
#version 320 es
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
// antialiasing - make AA 2, meaning 4x AA, if you have a fast machine
#define AA 1
#define ZERO (min(2, 0))
out vec4 FragColor;
uniform float iTime;
uniform vec2 iResolution;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
const float pi = 3.1415927;
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdSphere(in vec3 p, in vec4 s) {
return length(p-s.xyz) - s.w;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdEllipsoid(in vec3 p, in vec3 c, in vec3 r) {
return (length((p-c)/r) - 1.0) * min(min(r.x, r.y), r.z);
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdCircle(in vec2 p, in vec2 c, in float r) {
return length(p-c) - r;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdTorus(vec3 p, vec2 t) {
return length(vec2(length(p.xz)-t.x, p.y))-t.y;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
vec3 pa = p-a, ba = b-a;
float h = clamp(dot(pa, ba)/dot(ba, ba), 0.0, 1.0);
return length(pa - ba*h) - r;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
vec2 udSegment(vec3 p, vec3 a, vec3 b)
{
vec3 pa = p-a, ba = b-a;
float h = clamp(dot(pa, ba)/dot(ba, ba), 0.0, 1.0);
return vec2(length(pa - ba*h), h);
}
// http://research.microsoft.com/en-us/um/people/hoppe/ravg.pdf
float det(vec2 a, vec2 b) { return a.x*b.y-b.x*a.y; }
vec3 getClosest(vec2 b0, vec2 b1, vec2 b2)
{
float a = det(b0, b2);
float b = 2.0*det(b1, b0);
float d = 2.0*det(b2, b1);
float f = b*d - a*a;
vec2 d21 = b2-b1;
vec2 d10 = b1-b0;
vec2 d20 = b2-b0;
vec2 gf = 2.0*(b*d21+d*d10+a*d20); gf = vec2(gf.y, -gf.x);
vec2 pp = -f*gf/dot(gf, gf);
vec2 d0p = b0-pp;
float ap = det(d0p, d20);
float bp = 2.0*det(d10, d0p);
float t = clamp((ap+bp)/(2.0*a+b+d), 0.0, 1.0);
return vec3(mix(mix(b0, b1, t), mix(b1, b2, t), t), t);
}
vec4 sdBezier(vec3 a, vec3 b, vec3 c, vec3 p)
{
vec3 w = normalize(cross(c-b, a-b));
vec3 u = normalize(c-b);
vec3 v = (cross(w, u));
vec2 a2 = vec2(dot(a-b, u), dot(a-b, v));
vec2 b2 = vec2(0.0);
vec2 c2 = vec2(dot(c-b, u), dot(c-b, v));
vec3 p3 = vec3(dot(p-b, u), dot(p-b, v), dot(p-b, w));
vec3 cp = getClosest(a2-p3.xy, b2-p3.xy, c2-p3.xy);
return vec4(sqrt(dot(cp.xy, cp.xy)+p3.z*p3.z), cp.z, length(cp.xy), p3.z);
}
// http://iquilezles.org/www/articles/smin/smin.htm
float smin(float a, float b, float k)
{
float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0);
return mix(b, a, h) - k*h*(1.0-h);
}
// http://iquilezles.org/www/articles/smin/smin.htm
float smax(float a, float b, float k)
{
float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0);
return mix(a, b, h) + k*h*(1.0-h);
}
// http://iquilezles.org/www/articles/smin/smin.htm
vec3 smax(vec3 a, vec3 b, float k)
{
vec3 h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0);
return mix(a, b, h) + k*h*(1.0-h);
}
//---------------------------------------------------------------------------
float hash1(float n)
{
return fract(sin(n)*43758.5453123);
}
vec3 hash3(float n)
{
return fract(sin(n+vec3(0.0, 13.1, 31.3))*158.5453123);
}
vec3 forwardSF(float i, float n)
{
const float PI = 3.141592653589793238;
const float PHI = 1.618033988749894848;
float phi = 2.0*PI*fract(i/PHI);
float zi = 1.0 - (2.0*i+1.0)/n;
float sinTheta = sqrt(1.0 - zi*zi);
return vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, zi);
}
//---------------------------------------------------------------------------
float mapShell(in vec3 p, out vec4 matInfo)
{
const float sc = 1.0/1.0;
p -= vec3(0.05, 0.12, -0.09);
p *= sc;
vec3 q = mat3(-0.6333234236, -0.7332753384, 0.2474039592,
0.7738444477, -0.6034162289, 0.1924931824,
0.0081370606, 0.3133626215, 0.9495986813) * p;
const float b = 0.1759;
float r = length(q.xy);
float t = atan(q.y, q.x);
// https://swiftcoder.wordpress.com/2010/06/21/logarithmic-spiral-distance-field/
float n = (log(r)/b - t)/(2.0*pi);
float nm = (log(0.11)/b-t)/(2.0*pi);
n = min(n, nm);
float ni = floor(n);
float r1 = exp(b * (t + 2.0*pi*ni));
float r2 = r1 * 3.019863;
//-------
float h1 = q.z + 1.5*r1 - 0.5; float d1 = sqrt((r1-r)*(r1-r)+h1*h1) - r1;
float h2 = q.z + 1.5*r2 - 0.5; float d2 = sqrt((r2-r)*(r2-r)+h2*h2) - r2;
float d, dx, dy;
if (d1>1)&1), ((i>>1)&1), (i&1))-1.0);
n += e*mapOpaque(pos+eps*e, kk).x;
}
return normalize(n);
#endif
}
//=========================================================================
float mapLeafWaterDrops(in vec3 p)
{
p -= vec3(-1.8, 0.6, -0.75);
vec3 s = p;
p = mat3(0.671212, 0.366685, -0.644218,
-0.479426, 0.877583, 0.000000,
0.565354, 0.308854, 0.764842)*p;
vec3 q = p;
p.y += 0.2*exp(-abs(2.0*p.z));
//---------------
float r = clamp((p.x+2.0)/4.0, 0.0, 1.0);
r = r*(1.0-r)*(1.0-r)*6.0;
float d0 = sdEllipsoid(p, vec3(0.0), vec3(2.0, 0.25*r, r));
float d1 = sdEllipsoid(q, vec3(0.5, 0.0, 0.2), 1.0*vec3(0.15, 0.13, 0.15));
float d2 = sdEllipsoid(q, vec3(0.8, -0.07, -0.15), 0.5*vec3(0.15, 0.13, 0.15));
float d3 = sdEllipsoid(s, vec3(0.76, -0.8, 0.6), 0.5*vec3(0.15, 0.2, 0.15));
float d4 = sdEllipsoid(q, vec3(-0.5, 0.09, -0.2), vec3(0.04, 0.03, 0.04));
d3 = max(d3, p.y-0.01);
return min(min(d1, d4), min(d2, d3));
}
vec2 mapTransparent(vec3 p, out vec4 matInfo)
{
matInfo = vec4(0.0);
float d5 = mapDrop(p);
vec2 res = vec2(d5, 4.0);
float d6 = mapLeafWaterDrops(p);
res.x = min(res.x, d6);
return res;
}
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
vec3 calcNormalTransparent(in vec3 pos, in float eps)
{
vec4 kk;
vec2 e = vec2(1.0, -1.0)*0.5773*eps;
return normalize(e.xyy*mapTransparent(pos + e.xyy, kk).x +
e.yyx*mapTransparent(pos + e.yyx, kk).x +
e.yxy*mapTransparent(pos + e.yxy, kk).x +
e.xxx*mapTransparent(pos + e.xxx, kk).x);
}
//=========================================================================
float calcAO(in vec3 pos, in vec3 nor)
{
vec4 kk;
float ao = 0.0;
for (int i=ZERO; i<32; i++)
{
vec3 ap = forwardSF(float(i), 32.0);
float h = hash1(float(i));
ap *= sign(dot(ap, nor)) * h*0.1;
ao += clamp(mapOpaque(pos + nor*0.01 + ap, kk).x*3.0, 0.0, 1.0);
}
ao /= 32.0;
return clamp(ao*6.0, 0.0, 1.0);
}
float calcSSS(in vec3 pos, in vec3 nor)
{
vec4 kk;
float occ = 0.0;
for (int i=ZERO; i<8; i++)
{
float h = 0.002 + 0.11*float(i)/7.0;
vec3 dir = normalize(sin(float(i)*13.0 + vec3(0.0, 2.1, 4.2)));
dir *= sign(dot(dir, nor));
occ += (h-mapOpaque(pos-h*dir, kk).x);
}
occ = clamp(1.0 - 11.0*occ/8.0, 0.0, 1.0);
return occ*occ;
}
// http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
float calcSoftShadow(in vec3 ro, in vec3 rd, float k)
{
vec4 kk;
float res = 1.0;
float t = 0.01;
for (int i=ZERO; i<32; i++)
{
float h = mapOpaque(ro + rd*t, kk).x;
res = min(res, smoothstep(0.0, 1.0, k*h/t));
t += clamp(h, 0.04, 0.1);
if (res<0.01) break;
}
return clamp(res, 0.0, 1.0);
}
const vec3 sunDir = normalize(vec3(0.2, 0.1, 0.02));
vec3 shadeOpaque(in vec3 ro, in vec3 rd, in float t, in float m, in vec4 matInfo)
{
float eps = 0.002;
vec3 pos = ro + t*rd;
vec3 nor = calcNormalOpaque(pos, eps);
vec3 mateD = vec3(0.0);
vec3 mateS = vec3(0.0);
vec2 mateK = vec2(0.0);
vec3 mateE = vec3(0.0);
float focc = 1.0;
float fsha = 1.0;
if (m<1.5)// snail body
{
float dis = texture(iChannel1, 5.0*pos.xy).x;
float be = sdEllipsoid(pos, vec3(-0.3, -0.5, -0.1), vec3(0.2, 1.0, 0.5));
be = 1.0-smoothstep(-0.01, 0.01, be);
float ff = abs(matInfo.x-0.20);
mateS = 6.0*mix(0.7*vec3(2.0, 1.2, 0.2), vec3(2.5, 1.8, 0.9), ff);
mateS += 2.0*dis;
mateS *= 1.5;
mateS *= 1.0 + 0.5*ff*ff;
mateS *= 1.0-0.5*be;
mateD = vec3(1.0, 0.8, 0.4);
mateD *= dis;
mateD *= 0.015;
mateD += vec3(0.8, 0.4, 0.3)*0.15*be;
mateK = vec2(60.0, 0.7 + 2.0*dis);
float f = clamp(dot(-rd, nor), 0.0, 1.0);
f = 1.0-pow(f, 8.0);
f = 1.0 - (1.0-f)*(1.0-texture(iChannel2, 0.3*pos.xy).x);
mateS *= vec3(0.5, 0.1, 0.0) + f*vec3(0.5, 0.9, 1.0);
float b = 1.0-smoothstep(0.25, 0.55, abs(pos.y));
focc = 0.2 + 0.8*smoothstep(0.0, 0.15, sdSphere(pos, vec4(0.05, 0.52, 0.0, 0.13)));
}
else if (m<2.5)// shell
{
mateK = vec2(0.0);
float tip = 1.0-smoothstep(0.05, 0.4, length(pos-vec3(0.17, 0.2, 0.35)));
mateD = mix(0.7*vec3(0.2, 0.21, 0.22), 0.2*vec3(0.15, 0.1, 0.0), tip);
vec2 uv = vec2(.5*atan(matInfo.x, matInfo.y)/3.1416, 1.5*matInfo.w);
vec3 ral = texture(iChannel1, vec2(2.0*matInfo.w+matInfo.z*0.5, 0.5)).xxx;
mateD *= 0.25 + 0.75*ral;
float pa = smoothstep(-0.2, 0.2, 0.3+sin(2.0+40.0*uv.x + 3.0*sin(11.0*uv.x)));
float bar = mix(pa, 1.0, smoothstep(0.7, 1.0, tip));
bar *= (matInfo.z<0.6) ? 1.0 : smoothstep(0.17, 0.21, abs(matInfo.w));
mateD *= vec3(0.06, 0.03, 0.0)+vec3(0.94, 0.97, 1.0)*bar;
mateK = vec2(64.0, 0.2);
mateS = 1.5*vec3(1.0, 0.65, 0.6) * (1.0-tip);//*0.5;
}
else if (m<3.5)// plant
{
mateD = vec3(0.05, 0.1, 0.0)*0.2;
mateS = vec3(0.1, 0.2, 0.02)*25.0;
mateK = vec2(5.0, 1.0);
float fre = clamp(1.0+dot(nor, rd), 0.0, 1.0);
mateD += 0.2*fre*vec3(1.0, 0.5, 0.1);
vec3 te = texture(iChannel2, pos.xy*0.2).xyz;
mateS *= 0.5 + 1.5*te;
mateE = 0.5*vec3(0.1, 0.1, 0.03)*(0.2+0.8*te.x);
}
else //if( m<4.5 ) // leave
{
vec3 p = pos - vec3(-1.8, 0.6, -0.75);
vec3 s = p;
p = mat3(0.671212, 0.366685, -0.644218,
-0.479426, 0.877583, 0.000000,
0.565354, 0.308854, 0.764842)*p;
vec3 q = p;
p.y += 0.2*exp(-abs(2.0*p.z));
float v = smoothstep(0.01, 0.02, abs(p.z));
float rr = sin(4.0*0.25*50.0*p.x - 4.0*0.25*75.0*abs(p.z));
vec3 te = texture(iChannel2, p.xz*0.35).xyz;
float r = clamp((p.x+2.0)/4.0, 0.0, 1.0);
r = r*(1.0-r)*(1.0-r)*6.0;
float ff = length(p.xz/vec2(2.0, r));
mateD = mix(vec3(0.07, 0.1, 0.0), vec3(0.05, 0.2, 0.01)*0.25, v);
mateD = mix(mateD, vec3(0.16, 0.2, 0.01)*0.25, ff);
mateD *= 1.0 + 0.25*te;
mateD *= 0.8;
mateS = vec3(0.15, 0.2, 0.02)*0.8;
mateS *= 1.0 + 0.2*rr;
mateS *= 0.8;
mateK = vec2(64.0, 0.25);
//---------------------
nor.xz += v*0.15*(-1.0+2.0*texture(iChannel3, 1.0*p.xz).xy);
nor = normalize(nor);
float d1 = sdEllipsoid(q, vec3(0.5-0.07, 0.0, 0.20), 1.0*vec3(1.4*0.15, 0.13, 0.15));
float d2 = sdEllipsoid(q, vec3(0.8-0.05, -0.07, -0.15), 0.5*vec3(1.3*0.15, 0.13, 0.15));
float d4 = sdEllipsoid(q, vec3(-0.5-0.07, 0.09, -0.20), 1.0*vec3(1.4*0.04, 0.03, 0.04));
float dd = min(d1, min(d2, d4));
fsha = 0.05 + 0.95*smoothstep(0.0, 0.05, dd);
d1 = abs(sdCircle(q.xz, vec2(0.5, 0.20), 1.0*0.15));
d2 = abs(sdCircle(q.xz, vec2(0.8, -0.15), 0.5*0.15));
d4 = abs(sdCircle(q.xz, vec2(-0.5, -0.20), 1.0*0.04));
dd = min(d1, min(d2, d4));
focc *= 0.55 + 0.45*smoothstep(0.0, 0.08, dd);
d1 = distance(q.xz, vec2(0.5-0.07, 0.20));
d2 = distance(q.xz, vec2(0.8-0.03, -0.15));
fsha += (1.0-smoothstep(0.0, 0.10, d1))*1.5;
fsha += (1.0-smoothstep(0.0, 0.05, d2))*1.5;
}
vec3 hal = normalize(sunDir-rd);
float fre = clamp(1.0+dot(nor, rd), 0.0, 1.0);
float occ = calcAO(pos, nor)*focc;
float sss = calcSSS(pos, nor);
sss = sss*occ + fre*occ + (0.5+0.5*fre)*pow(abs(matInfo.x-0.2), 1.0)*occ;
float dif1 = clamp(dot(nor, sunDir), 0.0, 1.0);
float sha = calcSoftShadow(pos, sunDir, 20.0);
dif1 *= sha*fsha;
float spe1 = clamp(dot(nor, hal), 0.0, 1.0);
float bou = clamp(0.3-0.7*nor.y, 0.0, 1.0);
// illumination
vec3 col = vec3(0.0);
col += 7.0*vec3(1.7, 1.2, 0.6)*dif1*2.0;// sun
col += 4.0*vec3(0.2, 1.2, 1.6)*occ*(0.5+0.5*nor.y);// sky
col += 1.8*vec3(0.1, 2.0, 0.1)*bou*occ;// bounce
col *= mateD;
col += 0.4*sss*(vec3(0.15, 0.1, 0.05)+vec3(0.85, 0.9, 0.95)*dif1)*(0.05+0.95*occ)*mateS;// sss
col = pow(col, vec3(0.6, 0.8, 1.0));
col += vec3(1.0, 1.0, 1.0)*0.2*pow(spe1, 1.0+mateK.x)*dif1*(0.04+0.96*pow(fre, 4.0))*mateK.x*mateK.y;// sun lobe1
col += vec3(1.0, 1.0, 1.0)*0.1*pow(spe1, 1.0+mateK.x/3.0)*dif1*(0.1+0.9*pow(fre, 4.0))*mateK.x*mateK.y;// sun lobe2
col += 0.1*vec3(1.0, max(1.5-0.7*col.y, 0.0), 2.0)*occ*occ*smoothstep(0.0, 0.3, reflect(rd, nor).y)*mateK.x*mateK.y*(0.04+0.96*pow(fre, 5.0));// sky
col += mateE;
return col;
}
vec3 shadeTransparent(in vec3 ro, in vec3 rd, in float t, in float m, in vec4 matInfo, in vec3 col, in float depth)
{
vec3 oriCol = col;
float dz = depth - t;
float ao = clamp(dz*50.0, 0.0, 1.0);
vec3 pos = ro + t*rd;
vec3 nor = calcNormalTransparent(pos, 0.002);
float fre = clamp(1.0 + dot(rd, nor), 0.0, 1.0);
vec3 hal = normalize(sunDir-rd);
vec3 ref = reflect(-rd, nor);
float spe1 = clamp(dot(nor, hal), 0.0, 1.0);
float spe2 = clamp(dot(ref, sunDir), 0.0, 1.0);
float ds = 1.6 - col.y;
col *= mix(vec3(0.0, 0.0, 0.0), vec3(0.4, 0.6, 0.4), ao);
col += ds*1.5*vec3(1.0, 0.9, 0.8)*pow(spe1, 80.0);
col += ds*0.2*vec3(0.9, 1.0, 1.0)*smoothstep(0.4, 0.8, fre);
col += ds*0.9*vec3(0.6, 0.7, 1.0)*smoothstep(-0.5, 0.5, -reflect(rd, nor).y)*smoothstep(0.2, 0.4, fre);
col += ds*0.5*vec3(1.0, 0.9, 0.8)*pow(spe2, 80.0);
col += ds*0.5*vec3(1.0, 0.9, 0.8)*pow(spe2, 16.0);
col += vec3(0.8, 1.0, 0.8)*0.5*smoothstep(0.3, 0.6, texture(iChannel1, 0.8*nor.xy).x)*(0.1+0.9*fre*fre);
// hide aliasing a bit
return mix(col, oriCol, smoothstep(0.6, 1.0, fre));
}
//--------------------------------------------
vec2 intersectOpaque(in vec3 ro, in vec3 rd, const float mindist, const float maxdist, out vec4 matInfo)
{
vec2 res = vec2(-1.0);
float t = mindist;
for (int i=ZERO; i<64; i++)
{
vec3 p = ro + t*rd;
vec2 h = mapOpaque(p, matInfo);
res = vec2(t, h.y);
if (h.x<(0.001*t) || t>maxdist) break;
t += h.x*0.9;
}
return res;
}
vec2 intersectTransparent(in vec3 ro, in vec3 rd, const float mindist, const float maxdist, out vec4 matInfo)
{
vec2 res = vec2(-1.0);
float t = mindist;
for (int i=ZERO; i<64; i++)
{
vec3 p = ro + t*rd;
vec2 h = mapTransparent(p, matInfo);
res = vec2(t, h.y);
if (h.x<(0.001*t) || t>maxdist) break;
t += h.x;
}
return res;
}
vec3 background(in vec3 d)
{
// cheap cubemap
vec3 n = abs(d);
vec2 uv = (n.x>n.y && n.x>n.z) ? d.yz/d.x:
(n.y>n.x && n.y>n.z) ? d.zx/d.y:
d.xy/d.z;
// fancy blur
vec3 col = vec3(0.0);
for (int i=ZERO; i<200; i++)
{
float h = float(i)/200.0;
float an = 31.0*6.2831*h;
vec2 of = vec2(cos(an), sin(an)) * h;
vec3 tmp = texture(iChannel2, uv*0.25 + 0.0075*of, 4.0).yxz;
col = smax(col, tmp, 0.5);
}
return pow(col, vec3(3.5, 3.0, 6.0))*0.2;
}
vec3 render(in vec3 ro, in vec3 rd, in vec2 q) {
vec3 col = background(rd);
//-----------------------------
float mindist = 1.0;
float maxdist = 4.0;
vec4 matInfo;
vec2 tm = intersectOpaque(ro, rd, mindist, maxdist, matInfo);
if (tm.y>-0.5 && tm.x < maxdist)
{
col = shadeOpaque(ro, rd, tm.x, tm.y, matInfo);
maxdist = tm.x;
}
//-----------------------------
tm = intersectTransparent(ro, rd, mindist, maxdist, matInfo);
if (tm.y>-0.5 && tm.x < maxdist)
{
col = shadeTransparent(ro, rd, tm.x, tm.y, matInfo, col, maxdist);
}
//-----------------------------
float sun = clamp(dot(rd, sunDir), 0.0, 1.0);
col += 1.0*vec3(1.5, 0.8, 0.7)*pow(sun, 4.0);
//-----------------------------
col = pow(col, vec3(0.45));
col = vec3(1.05, 1.0, 1.0)*col*(0.7+0.3*col*max(3.0-2.0*col, 0.0)) + vec3(0.0, 0.0, 0.04);
col *= 0.3 + 0.7*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1);
return clamp(col, 0.0, 1.0);
}
mat3 setCamera(in vec3 ro, in vec3 rt)
{
vec3 w = normalize(ro-rt);
float m = sqrt(1.0-w.y*w.y);
return mat3(w.z, 0.0, -w.x,
0.0, m*m, -w.z*w.y,
w.x*m, w.y*m, w.z*m);
}
void main(void) {
#if AA < 2
vec2 p = (2.0 * gl_FragCoord.xy - iResolution.xy) / iResolution.y;
vec2 q = gl_FragCoord.xy/iResolution.xy;
float an = 1.87 - 0.04*(1.0-cos(0.5*iTime));
vec3 ro = vec3(-0.4, 0.2, 0.0) + 2.2*vec3(cos(an), 0.0, sin(an));
vec3 ta = vec3(-0.6, 0.2, 0.0);
mat3 ca = setCamera(ro, ta);
vec3 rd = normalize(ca * vec3(p, -2.8));
vec3 col = render(ro, rd, q);
#else
vec3 col = vec3(0.0);
for (int m=ZERO; m
回到正题,下节我们继续光照贴图的内容。