Skip to content

Instantly share code, notes, and snippets.

@crykn
Last active February 17, 2021 20:01
Show Gist options
  • Save crykn/bd2219698b62f76854d800d0b7d42416 to your computer and use it in GitHub Desktop.
Save crykn/bd2219698b62f76854d800d0b7d42416 to your computer and use it in GitHub Desktop.
This is a simple example of how to render this sea shader (http://glslsandbox.com/e#69872.0) in libGDX.
package issue.test;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.utils.Logger;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import de.damios.guacamole.gdx.graphics.QuadMeshGenerator;
import de.damios.guacamole.gdx.graphics.ShaderProgramFactory;
import test.MyGdxGame2;
public class SeaShaderExample {
// See http://glslsandbox.com/e#69872.0
public static final String frag = "#ifdef GL_ES\n" + "precision mediump float;\n" + "#endif\n" + "\n" //
+ "uniform float time;\n" //
+ "const vec2 mouse = vec2(0.0, 0.0);\n" //
+ "const vec2 resolution = vec2(1024.0, 720.0);\n" //
+ "\n"
+ "// \"Seascape\" by Alexander Alekseev aka TDM - 2014\n"
+ "// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n" + "\n"
+ "const int NUM_STEPS = 16;\n" + "const float PI = 3.1415;\n" + "const float EPSILON = 1e-3;\n"
+ "float EPSILON_NRM = 0.;\n" + "\n" + "// sea\n" + "const int ITER_GEOMETRY = 3;\n"
+ "const int ITER_FRAGMENT = 5;\n" + "const float SEA_HEIGHT = 0.6;\n" + "const float SEA_CHOPPY = 01.0;\n"
+ "const float SEA_SPEED = 0.8;\n" + "const float SEA_FREQ = 0.16;\n"
+ "const vec3 SEA_BASE = vec3(0.1,0.19,0.22);\n" + "const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6);\n"
+ "float SEA_TIME = 0.;\n" + "mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);\n" + "\n" + "// math\n"
+ "mat3 fromEuler(vec3 ang) {\n" + " vec2 a1 = vec2(sin(ang.x),cos(ang.x));\n"
+ " vec2 a2 = vec2(sin(ang.y),cos(ang.y));\n" + " vec2 a3 = vec2(sin(ang.z),cos(ang.z));\n"
+ " mat3 m;\n" + " m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);\n"
+ " m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);\n"
+ " m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);\n" + " return m;\n" + "}\n"
+ "float hash( vec2 p ) {\n" + " float h = dot(p,vec2(127.1,311.7)); \n"
+ " return fract(sin(h)*2121.5453123);\n" + "}\n" + "float noise( in vec2 p ) {\n"
+ " vec2 i = floor( p );\n" + " vec2 f = fract( p ); \n" + " vec2 u = f*f*(3.0-2.0*f);\n"
+ " return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), \n"
+ " hash( i + vec2(1.0,0.0) ), u.x),\n"
+ " mix( hash( i + vec2(0.0,1.0) ), \n"
+ " hash( i + vec2(1.0,1.0) ), u.x), u.y);\n" + "}\n" + "\n" + "// lighting\n"
+ "float diffuse(vec3 n,vec3 l,float p) {\n" + " return pow(dot(n,l) * 0.4 + 0.6,p);\n" + "}\n"
+ "float specular(vec3 n,vec3 l,vec3 e,float s) { \n" + " float nrm = (s + 8.0) / (3.1415 * 8.0);\n"
+ " return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;\n" + "}\n" + "\n" + "// sky\n"
+ "vec3 getSkyColor(vec3 e) {\n" + " e.y = max(e.y,0.0);\n" + " vec3 ret;\n"
+ " ret.x = pow(1.0-e.y,2.0);\n" + " ret.y = 1.0-e.y;\n" + " ret.z = 0.6+(1.0-e.y)*0.4;\n"
+ " return ret;\n" + "}\n" + "\n" + "// sea\n" + "float sea_octave(vec2 uv, float choppy) {\n"
+ " uv += noise(uv); \n" + " vec2 wv = 1.0-abs(sin(uv));\n"
+ " vec2 swv = abs(cos(uv)); \n" + " wv = mix(wv,swv,wv);\n"
+ " return pow(1.0-pow(wv.x * wv.y,0.65),choppy);\n" + "}\n" + "\n" + "float map(vec3 p) {\n"
+ " float freq = SEA_FREQ;\n" + " float amp = SEA_HEIGHT;\n" + " float choppy = SEA_CHOPPY;\n"
+ " vec2 uv = p.xz; uv.x *= 0.75;\n" + " \n" + " float d, h = 0.0; \n"
+ " for(int i = 0; i < ITER_GEOMETRY; i++) { \n"
+ " d = sea_octave((uv+SEA_TIME)*freq,choppy);\n"
+ " d += sea_octave((uv-SEA_TIME)*freq,choppy);\n" + " h += d * amp; \n"
+ " uv *= octave_m; freq *= 1.9; amp *= 0.22;\n" + " choppy = mix(choppy,1.0,0.2);\n" + " }\n"
+ " return p.y - h;\n" + "}\n" + "\n" + "float map_detailed(vec3 p) {\n" + " float freq = SEA_FREQ;\n"
+ " float amp = SEA_HEIGHT;\n" + " float choppy = SEA_CHOPPY;\n"
+ " vec2 uv = p.xz; uv.x *= 0.75;\n" + " \n" + " float d, h = 0.0; \n"
+ " for(int i = 0; i < ITER_FRAGMENT; i++) { \n"
+ " d = sea_octave((uv+SEA_TIME)*freq,choppy);\n"
+ " d += sea_octave((uv-SEA_TIME)*freq,choppy);\n" + " h += d * amp; \n"
+ " uv *= octave_m; freq *= 1.9; amp *= 0.22;\n" + " choppy = mix(choppy,1.0,0.2);\n" + " }\n"
+ " return p.y - h;\n" + "}\n" + "\n"
+ "vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) { \n"
+ " float fresnel = 1.0 - max(dot(n,-eye),0.0);\n" + " fresnel = pow(fresnel,3.0) * 0.65;\n"
+ " \n" + " vec3 reflected = getSkyColor(reflect(eye,n)); \n"
+ " vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12; \n" + " \n"
+ " vec3 color = mix(refracted,reflected,fresnel);\n" + " \n"
+ " float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);\n"
+ " color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;\n" + " \n"
+ " color += vec3(specular(n,l,eye,60.0));\n" + " \n" + " return color;\n" + "}\n" + "\n"
+ "// tracing\n" + "vec3 getNormal(vec3 p, float eps) {\n" + " vec3 n;\n"
+ " n.y = map_detailed(p); \n" + " n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;\n"
+ " n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;\n" + " n.y = eps;\n"
+ " return normalize(n);\n" + "}\n" + "\n"
+ "float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) { \n" + " float tm = 0.0;\n"
+ " float tx = 1000.0; \n" + " float hx = map(ori + dir * tx);\n"
+ " if(hx > 0.0) return tx; \n" + " float hm = map(ori + dir * tm); \n"
+ " float tmid = 0.0;\n" + " for(int i = 0; i < NUM_STEPS; i++) {\n"
+ " tmid = mix(tm,tx, hm/(hm-hx)); \n"
+ " p = ori + dir * tmid; \n" + " float hmid = map(p);\n"
+ " if(hmid < 0.0) {\n" + " tx = tmid;\n" + " hx = hmid;\n" + " } else {\n"
+ " tm = tmid;\n" + " hm = hmid;\n" + " }\n" + " }\n" + " return tmid;\n"
+ "}\n" + "\n" + "// main\n" + "void main( void ) {\n" + " EPSILON_NRM = 0.1 / resolution.x;\n"
+ " SEA_TIME = time * SEA_SPEED;\n" + " \n" + " vec2 uv = gl_FragCoord.xy / resolution.xy;\n"
+ " uv = uv * 2.0 - 1.0;\n" + " uv.x *= resolution.x / resolution.y; \n"
+ " float time = time * 0.3 + mouse.x*0.01;\n" + " \n" + " // ray\n"
+ " vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time); \n"
+ " vec3 ori = vec3(0.0,3.5,time*5.0);\n"
+ " vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.15;\n"
+ " dir = normalize(dir) * fromEuler(ang);\n" + " \n" + " // tracing\n" + " vec3 p;\n"
+ " heightMapTracing(ori,dir,p);\n" + " vec3 dist = p - ori;\n"
+ " vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);\n"
+ " vec3 light = normalize(vec3(0.0,1.0,55)); \n" + " \n" + " // color\n"
+ " vec3 color = mix(\n" + " getSkyColor(dir),\n" + " getSeaColor(p,n,light,dir,dist),\n"
+ " pow(smoothstep(0.0,-0.05,dir.y),0.3));\n" + " \n" + " // post\n"
+ " gl_FragColor = vec4(pow(color,vec3(0.75)), 1.0);\n" + "}";
public static final String vert =
"attribute vec4 a_position;\n" + "attribute vec4 a_color;\n" + "attribute vec2 a_texCoord0;\n" + "\n"
+ "uniform mat4 u_projTrans;\n" + "\n" + "varying vec4 v_color;\n" + "varying vec2 v_texCoords;\n"
+ "\n" + "void main() {\n" + " v_color = a_color;\n" + " v_texCoords = a_texCoord0;\n"
+ " gl_Position = u_projTrans * a_position;\n" + "}";
public static void main(String[] args) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setWindowedMode(1024, 720);
config.setResizable(true);
config.setTitle("Sea Shader Example");
new Lwjgl3Application(new ApplicationAdapter() {
ShaderProgram shader;
Mesh mesh;
Viewport viewport = new ScreenViewport();
float time;
@Override
public void create() {
// both provided by https://github.com/crykn/guacamole
shader = ShaderProgramFactory.fromString(vert, frag);
mesh = QuadMeshGenerator.createFullScreenQuad(1024, 720, true);
}
@Override
public void render() {
ScreenUtils.clear(Color.BLACK);
time += Gdx.graphics.getDeltaTime();
shader.bind();
shader.setUniformMatrix("u_projTrans", viewport.getCamera().combined);
shader.setUniformf("time", time);
mesh.render(shader, GL20.GL_TRIANGLE_STRIP);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height, true);
}
}, config);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment