From 48a5c36c3146c534d52b91158fc301bf96035c30 Mon Sep 17 00:00:00 2001 From: Gustl22 Date: Sun, 3 Feb 2019 20:49:39 +0100 Subject: [PATCH] Extrusions: light source calculation with normals (#651) --- .../assets/shaders/extrusion_layer_ext.glsl | 71 +++++++++++-------- .../assets/shaders/extrusion_layer_mesh.glsl | 41 ++++++----- .../org/oscim/renderer/ExtrusionRenderer.java | 20 ++++-- vtm/src/org/oscim/renderer/GLUtils.java | 7 ++ .../renderer/bucket/ExtrusionBucket.java | 34 ++++----- 5 files changed, 103 insertions(+), 70 deletions(-) diff --git a/vtm/resources/assets/shaders/extrusion_layer_ext.glsl b/vtm/resources/assets/shaders/extrusion_layer_ext.glsl index 66df7f1a..3c9f0473 100644 --- a/vtm/resources/assets/shaders/extrusion_layer_ext.glsl +++ b/vtm/resources/assets/shaders/extrusion_layer_ext.glsl @@ -5,51 +5,66 @@ uniform mat4 u_mvp; uniform vec4 u_color[4]; uniform int u_mode; uniform float u_alpha; +uniform vec3 u_light; uniform float u_zlimit; attribute vec4 a_pos; -attribute vec2 a_light; +attribute vec2 a_normal; varying vec4 color; //varying float depth; const float ff = 255.0; +/** + * The diffuse of surface dependent on the light position + * + * @param r_norm - the normal vector of vertex's face + */ +float diffuse(in vec3 r_norm) { + float l = dot(normalize(r_norm), normalize(u_light)); + l = clamp((1.0 + l) / 2.0, 0.0, 1.0); + return(0.8 + l * 0.2); +} + void main() { - // change height by u_alpha + // change height by u_alpha float height = a_pos.z * u_alpha; if (height > u_zlimit) { height = u_zlimit; } gl_Position = u_mvp * vec4(a_pos.xy, height, 1.0); - // depth = gl_Position.z; + //depth = gl_Position.z; if (u_mode == -1) { ; - // roof / depth pass - // color = u_color[0] * u_alpha; - } - else if (u_mode == 0) { - // roof / depth pass - color = u_color[0] * u_alpha; - } - else if (u_mode == 1) { - // sides 1 - use 0xff00 - // scale direction to -0.5<>0.5 - float dir = a_light.y / ff; - float z = (0.98 + gl_Position.z * 0.02); - float h = 0.9 + clamp(a_pos.z / 2000.0, 0.0, 0.1); - color = u_color[1]; - color.rgb *= (0.8 + dir * 0.2) * z * h; - color *= u_alpha; - } - else if (u_mode == 2) { - // sides 2 - use 0x00ff - float dir = a_light.x / ff; - float z = (0.98 + gl_Position.z * 0.02); - float h = 0.9 + clamp(a_pos.z / 2000.0, 0.0, 0.1); - color = u_color[2]; - color.rgb *= (0.8 + dir * 0.2) * z * h; + } else if(u_mode >= 0 && u_mode <= 2) { + vec3 r_norm; + if (u_mode == 0) { + // roof / depth pass + r_norm = vec3(0.0, 0.0, 1.0); + color = u_color[0] * u_alpha; + color.rgb *= diffuse(r_norm); + } else { + float lightX = u_mode == 1 ? a_normal.y : a_normal.x; + r_norm.x = (lightX / ff) * 2.0 - 1.0; + // normal points y left or right (1 or -1) + float dir = - 1.0 + (2.0 * abs(mod(lightX, 2.0))); + // recreate y vector + r_norm.y = dir * sqrt(clamp(1.0 - (r_norm.x * r_norm.x), 0.0, 1.0)); + r_norm.z = 0.0; + + float z = (0.98 + gl_Position.z * 0.02); + float h = 0.9 + clamp(a_pos.z / 2000.0, 0.0, 0.1); + if (u_mode == 1) { + // sides 1 - use 0xff00 + color = u_color[1]; + } else { + // sides 2 - use 0x00ff + color = u_color[2]; + } + color.rgb *= diffuse(r_norm) * z * h; + } color *= u_alpha; } else if (u_mode == 3) { - // outline + // outline float z = (0.98 - gl_Position.z * 0.02); color = u_color[3] * z; } diff --git a/vtm/resources/assets/shaders/extrusion_layer_mesh.glsl b/vtm/resources/assets/shaders/extrusion_layer_mesh.glsl index ee8ea3a9..e54d5d2b 100644 --- a/vtm/resources/assets/shaders/extrusion_layer_mesh.glsl +++ b/vtm/resources/assets/shaders/extrusion_layer_mesh.glsl @@ -4,35 +4,38 @@ precision highp float; uniform mat4 u_mvp; uniform vec4 u_color; uniform float u_alpha; +uniform vec3 u_light; attribute vec4 a_pos; -attribute vec2 a_light; +attribute vec2 a_normal; varying vec4 color; void main() { - // change height by u_alpha + // change height by u_alpha vec4 pos = a_pos; pos.z *= u_alpha; gl_Position = u_mvp * pos; - // normalize face x/y direction - vec2 enc = (a_light / 255.0); - vec2 fenc = enc * 4.0 - 2.0; - float f = dot(fenc, fenc); - float g = sqrt(1.0 - f / 4.0); + // normalize face x/y direction + vec2 enc = (a_normal / 255.0); + vec3 r_norm; - r_norm.xy = fenc * g; - r_norm.z = 1.0 - f / 2.0; - // normal points up or down (1,-1) - //// float dir = 1.0 - (2.0 * abs(mod(a_light.x,2.0))); - // recreate face normal vector - /// vec3 r_norm = vec3(n.xy, dir * (1.0 - length(n.xy))); - vec3 light_dir = normalize(vec3(0.2, 0.2, 1.0)); - float l = dot(r_norm, light_dir) * 0.8; + // 1² - |xy|² = |z|² + r_norm.xy = enc * 2.0 - 1.0; + // normal points up or down (1,-1) + float dir = - 1.0 + (2.0 * abs(mod(a_normal.x, 2.0))); + // recreate z vector + r_norm.z = dir * sqrt(clamp(1.0 - (r_norm.x * r_norm.x + r_norm.y * r_norm.y), 0.0, 1.0)); + r_norm = normalize(r_norm); - light_dir = normalize(vec3(-0.2, -0.2, 1.0)); - l += dot(r_norm, light_dir) * 0.2; + float l = dot(r_norm, normalize(u_light)); - // l = (l + (1.0 - r_norm.z))*0.5; - l = 0.4 + l * 0.6; + //l *= 0.8 + //vec3 opp_light_dir = normalize(vec3(-u_light.xy, u_light.z)); + //l += dot(r_norm, opp_light_dir) * 0.2; + + // [-1,1] to range [0,1] + l = (1.0 + l) / 2.0; + + l = 0.75 + l * 0.25; // extreme fake-ssao by height l += (clamp(a_pos.z / 2048.0, 0.0, 0.1) - 0.05); diff --git a/vtm/src/org/oscim/renderer/ExtrusionRenderer.java b/vtm/src/org/oscim/renderer/ExtrusionRenderer.java index 5f4a3fec..4315e275 100644 --- a/vtm/src/org/oscim/renderer/ExtrusionRenderer.java +++ b/vtm/src/org/oscim/renderer/ExtrusionRenderer.java @@ -2,7 +2,7 @@ * Copyright 2013 Hannes Janetzek * Copyright 2017 Izumi Kawashima * Copyright 2017 devemux86 - * Copyright 2018 Gustl22 + * Copyright 2018-2019 Gustl22 * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -45,6 +45,7 @@ public abstract class ExtrusionRenderer extends LayerRenderer { protected float mAlpha = 1; private float mZLimit = Float.MAX_VALUE; + private float[] mLightPos = new float[]{0.3f, 0.3f, 1f}; public ExtrusionRenderer(boolean mesh, boolean translucent) { mMesh = mesh; @@ -58,9 +59,9 @@ public abstract class ExtrusionRenderer extends LayerRenderer { int aPos; /** - * The light indicator of vertex's face as attribute. + * The normal of vertex's face as attribute. */ - int aLight; + int aNormal; /** * The alpha value (e.g. for fading animation) as uniform. @@ -72,6 +73,11 @@ public abstract class ExtrusionRenderer extends LayerRenderer { */ int uColor; + /** + * The lights position vector as uniform. + */ + int uLight; + /** * The shader render mode as uniform. *

@@ -104,7 +110,8 @@ public abstract class ExtrusionRenderer extends LayerRenderer { uMode = getUniform("u_mode"); uZLimit = getUniform("u_zlimit"); aPos = getAttrib("a_pos"); - aLight = getAttrib("a_light"); + aNormal = getAttrib("a_normal"); + uLight = getUniform("u_light"); } } @@ -164,6 +171,7 @@ public abstract class ExtrusionRenderer extends LayerRenderer { gl.depthFunc(GL.LESS); gl.uniform1f(s.uAlpha, mAlpha); gl.uniform1f(s.uZLimit, mZLimit); + GLUtils.glUniform3fv(s.uLight, 1, mLightPos); ExtrusionBuckets[] ebs = mExtrusionBucketSet; @@ -199,7 +207,7 @@ public abstract class ExtrusionRenderer extends LayerRenderer { GLState.blend(true); - GLState.enableVertexArrays(s.aPos, s.aLight); + GLState.enableVertexArrays(s.aPos, s.aNormal); for (int i = 0; i < mBucketsCnt; i++) { if (ebs[i].ibo == null) @@ -231,7 +239,7 @@ public abstract class ExtrusionRenderer extends LayerRenderer { gl.vertexAttribPointer(s.aPos, 3, GL.SHORT, false, RenderBuckets.SHORT_BYTES * 4, eb.getVertexOffset()); - gl.vertexAttribPointer(s.aLight, 2, GL.UNSIGNED_BYTE, + gl.vertexAttribPointer(s.aNormal, 2, GL.UNSIGNED_BYTE, false, RenderBuckets.SHORT_BYTES * 4, eb.getVertexOffset() + RenderBuckets.SHORT_BYTES * 3); /* draw extruded outlines (mMesh == false) */ diff --git a/vtm/src/org/oscim/renderer/GLUtils.java b/vtm/src/org/oscim/renderer/GLUtils.java index 654f35c4..ef3d732c 100644 --- a/vtm/src/org/oscim/renderer/GLUtils.java +++ b/vtm/src/org/oscim/renderer/GLUtils.java @@ -283,6 +283,13 @@ public class GLUtils { color[2] = FastMath.clampN((float) (p + (b - p) * change)); } + public static void glUniform3fv(int location, int count, float[] val) { + FloatBuffer buf = MapRenderer.getFloatBuffer(count * 3); + buf.put(val); + buf.flip(); + gl.uniform3fv(location, count, buf); + } + public static void glUniform4fv(int location, int count, float[] val) { FloatBuffer buf = MapRenderer.getFloatBuffer(count * 4); buf.put(val); diff --git a/vtm/src/org/oscim/renderer/bucket/ExtrusionBucket.java b/vtm/src/org/oscim/renderer/bucket/ExtrusionBucket.java index 0ab76276..54458434 100644 --- a/vtm/src/org/oscim/renderer/bucket/ExtrusionBucket.java +++ b/vtm/src/org/oscim/renderer/bucket/ExtrusionBucket.java @@ -1,6 +1,6 @@ /* * Copyright 2012, 2013 Hannes Janetzek - * Copyright 2017 Gustl22 + * Copyright 2017-2019 Gustl22 * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -68,7 +68,7 @@ public class ExtrusionBucket extends RenderBucket { private KeyMap mVertexMap; - //private static final int NORMAL_DIR_MASK = 0xFFFFFFFE; + private static final int NORMAL_DIR_MASK = 0xFFFFFFFE; //private int numIndexHits = 0; /** @@ -214,14 +214,9 @@ public class ExtrusionBucket extends RenderBucket { double len = Math.sqrt(cx * cx + cy * cy + cz * cz); // packing the normal in two bytes - // int mx = FastMath.clamp(127 + (int) ((cx / len) * 128), 0, 0xff); - // int my = FastMath.clamp(127 + (int) ((cy / len) * 128), 0, 0xff); - // short normal = (short) ((my << 8) | (mx & NORMAL_DIR_MASK) | (cz > 0 ? 1 : 0)); - - double p = Math.sqrt((cz / len) * 8.0 + 8.0); - int mx = FastMath.clamp(127 + (int) ((cx / len / p) * 128), 0, 255); - int my = FastMath.clamp(127 + (int) ((cy / len / p) * 128), 0, 255); - short normal = (short) ((my << 8) | mx); + int mx = FastMath.clamp(127 + (int) ((cx / len) * 128), 0, 0xff); + int my = FastMath.clamp(127 + (int) ((cy / len) * 128), 0, 0xff); + short normal = (short) ((my << 8) | (mx & NORMAL_DIR_MASK) | (cz > 0 ? 1 : 0)); if (key == null) key = vertexPool.get(); @@ -472,10 +467,13 @@ public class ExtrusionBucket extends RenderBucket { /* vector from previous point */ float ux, uy; + // Normalized normal of first point (with vy direction included) + // Normal of vector (x|y) is (y|-x) float a = (float) Math.sqrt(vx * vx + vy * vy); - short color1 = (short) ((1 + vx / a) * 127); + short mx1 = (short) ((1 + (vy / a)) * 127); + mx1 = (short) ((mx1 & NORMAL_DIR_MASK) | (-vx > 0 ? 1 : 0)); - short fcolor = color1, color2 = 0; + short mxStore = mx1, mx2 = 0; short h = (short) height, mh = (short) minHeight; @@ -502,7 +500,7 @@ public class ExtrusionBucket extends RenderBucket { nx = points[pos + 0]; ny = points[pos + 1]; } else { // if (addFace) - short c = (short) (color1 | fcolor << 8); + short c = (short) (mx1 | mxStore << 8); /* add bottom and top vertex for each point */ vertexItems.add((short) (cx * COORD_SCALE), (short) (cy * COORD_SCALE), mh, c); vertexItems.add((short) (cx * COORD_SCALE), (short) (cy * COORD_SCALE), h, c); @@ -515,20 +513,22 @@ public class ExtrusionBucket extends RenderBucket { vy = ny - cy; /* set lighting (by direction) */ + // Normal of vector (x|y) is (y|-x) a = (float) Math.sqrt(vx * vx + vy * vy); - color2 = (short) ((1 + vx / a) * 127); + mx2 = (short) ((1 + (vy / a)) * 127); + mx2 = (short) ((mx2 & NORMAL_DIR_MASK) | (-vx > 0 ? 1 : 0)); short c; if (even == 0) - c = (short) (color1 | color2 << 8); + c = (short) (mx1 | mx2 << 8); else - c = (short) (color2 | color1 << 8); + c = (short) (mx2 | mx1 << 8); /* add bottom and top vertex for each point */ vertexItems.add((short) (cx * COORD_SCALE), (short) (cy * COORD_SCALE), mh, c); vertexItems.add((short) (cx * COORD_SCALE), (short) (cy * COORD_SCALE), h, c); - color1 = color2; + mx1 = mx2; /* check if polygon is convex */ if (convex) {