LYGIA Shader Library

normal (lygia/lighting/raymarch/normal)

Calculate normals http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm

Dependencies:

Use:

<float> raymarchNormal( in <vec3> pos )

Check it on Github



#ifndef RAYMARCH_NORMAL_OFFSET
#define RAYMARCH_NORMAL_OFFSET 0.0001
#endif

#ifndef FNC_RAYMARCH_NORMAL
#define FNC_RAYMARCH_NORMAL

vec3 raymarchNormal(vec3 pos, vec2 pixel) {
   vec2 offset = vec2(1.0, -1.0) * pixel;
   return normalize( offset.xyy * RAYMARCH_MAP_FNC( pos + offset.xyy ).sdf +
                     offset.yyx * RAYMARCH_MAP_FNC( pos + offset.yyx ).sdf +
                     offset.yxy * RAYMARCH_MAP_FNC( pos + offset.yxy ).sdf +
                     offset.xxx * RAYMARCH_MAP_FNC( pos + offset.xxx ).sdf );
}

vec3 raymarchNormal(vec3 pos, float e) {
   vec2 offset = vec2(1.0, -1.0) * e;
   return normalize( offset.xyy * RAYMARCH_MAP_FNC( pos + offset.xyy ).sdf +
                     offset.yyx * RAYMARCH_MAP_FNC( pos + offset.yyx ).sdf +
                     offset.yxy * RAYMARCH_MAP_FNC( pos + offset.yxy ).sdf +
                     offset.xxx * RAYMARCH_MAP_FNC( pos + offset.xxx ).sdf );
}

vec3 raymarchNormal( in vec3 pos ) {
   return raymarchNormal(pos, RAYMARCH_NORMAL_OFFSET);
}

#endif

Dependencies:

Use:

<float> raymarchNormal( in <float3> pos )

Check it on Github



#ifndef RAYMARCH_NORMAL_OFFSET
#define RAYMARCH_NORMAL_OFFSET 0.0001
#endif

#ifndef FNC_RAYMARCH_NORMAL
#define FNC_RAYMARCH_NORMAL

float3 raymarchNormal(float3 pos, float2 pixel) {
   float2 offset = float2(1.0, -1.0) * pixel;
   return normalize( offset.xyy * RAYMARCH_MAP_FNC(pos + offset.xyy).sdf +
                     offset.yyx * RAYMARCH_MAP_FNC(pos + offset.yyx).sdf +
                     offset.yxy * RAYMARCH_MAP_FNC(pos + offset.yxy).sdf +
                     offset.xxx * RAYMARCH_MAP_FNC(pos + offset.xxx).sdf);
}

float3 raymarchNormal(float3 pos, float e) {
   const float2 offset = float2(1.0, -1.0) * e;
    return normalize(offset.xyy * RAYMARCH_MAP_FNC(pos + offset.xyy).sdf +
                     offset.yyx * RAYMARCH_MAP_FNC(pos + offset.yyx).sdf +
                     offset.yxy * RAYMARCH_MAP_FNC(pos + offset.yxy).sdf +
                     offset.xxx * RAYMARCH_MAP_FNC(pos + offset.xxx).sdf);
}

float3 raymarchNormal( in float3 pos ) {
   return raymarchNormal(pos, RAYMARCH_NORMAL_OFFSET);
}

#endif

Check it on Github


// #include "map.wgls"

fn raymarchNormal( pos: vec3f ) -> vec3f {
    let eps = 0.002;
    let v1 = vec3f( 1.0,-1.0,-1.0);
    let v2 = vec3f(-1.0,-1.0, 1.0);
    let v3 = vec3f(-1.0, 1.0,-1.0);
    let v4 = vec3f( 1.0, 1.0, 1.0);
    return normalize( v1 * map( pos + v1 * eps ) + 
                      v2 * map( pos + v2 * eps ) + 
                      v3 * map( pos + v3 * eps ) + 
                      v4 * map( pos + v4 * eps ) );
}

Dependencies:

Use:

<float> raymarchNormal( in <float3> pos )

Check it on Github



#ifndef RAYMARCH_MAP_FNC
#define RAYMARCH_MAP_FNC(POS) raymarchMap(POS)
#endif

#ifndef RAYMARCH_MAP_DISTANCE
#define RAYMARCH_MAP_DISTANCE w
#endif

#ifndef FNC_RAYMARCH_NORMAL
#define FNC_RAYMARCH_NORMAL

inline __host__ __device__ float3 raymarchNormal(const float3& pos, float2 pixel) {
   float2 offset = make_float2(1.0f, -1.0f) * pixel;
   float3 offset_xyy = make_float3(offset.x, offset.y, offset.y);
   float3 offset_yyx = make_float3(offset.y, offset.y, offset.x);
   float3 offset_yxy = make_float3(offset.y, offset.x, offset.y);
   float3 offset_xxx = make_float3(offset.x, offset.x, offset.x);
   return normalize( offset_xyy * RAYMARCH_MAP_FNC( pos + offset_xyy ).RAYMARCH_MAP_DISTANCE +
                     offset_yyx * RAYMARCH_MAP_FNC( pos + offset_yyx ).RAYMARCH_MAP_DISTANCE +
                     offset_yxy * RAYMARCH_MAP_FNC( pos + offset_yxy ).RAYMARCH_MAP_DISTANCE +
                     offset_xxx * RAYMARCH_MAP_FNC( pos + offset_xxx ).RAYMARCH_MAP_DISTANCE );
}

inline __host__ __device__ float3 raymarchNormal(const float3& pos, float e) {
   const float2 offset = make_float2(1.0f, -1.0f) * e;
   float3 offset_xyy = make_float3(offset.x, offset.y, offset.y);
   float3 offset_yyx = make_float3(offset.y, offset.y, offset.x);
   float3 offset_yxy = make_float3(offset.y, offset.x, offset.y);
   float3 offset_xxx = make_float3(offset.x, offset.x, offset.x);
   return normalize( offset_xyy * RAYMARCH_MAP_FNC( pos + offset_xyy ).RAYMARCH_MAP_DISTANCE +
                     offset_yyx * RAYMARCH_MAP_FNC( pos + offset_yyx ).RAYMARCH_MAP_DISTANCE +
                     offset_yxy * RAYMARCH_MAP_FNC( pos + offset_yxy ).RAYMARCH_MAP_DISTANCE +
                     offset_xxx * RAYMARCH_MAP_FNC( pos + offset_xxx ).RAYMARCH_MAP_DISTANCE );
}

inline __host__ __device__ float3 raymarchNormal(const float3& pos) {
    return raymarchNormal(pos, 0.5773f * 0.0005f);
}


#endif

Examples

58
 
1
#ifdef GL_ES
2
precision mediump float;
3
#endif
4
5
uniform vec2        u_resolution;
6
uniform vec2        u_mouse;
7
uniform float       u_time;
8
9
#define RESOLUTION          u_resolution
10
#define RAYMARCH_MULTISAMPLE 4
11
#define RAYMARCH_BACKGROUND (RAYMARCH_AMBIENT + rayDirection.y * 0.8)
12
#define RAYMARCH_AMBIENT    vec3(0.7, 0.9, 1.0)
13
14
// #include "lygia/lighting/atmosphere.glsl"
15
// #define RAYMARCH_BACKGROUND atmosphere(normal, normalize(u_light))
16
// #define RAYMARCH_AMBIENT atmosphere(normal, normalize(u_light))
17
#include "lygia/space/ratio.glsl"
18
#include "lygia/sdf.glsl"
19
#include "lygia/lighting/raymarch.glsl"
20
#include "lygia/color/space/linear2gamma.glsl"
21
22
float checkBoard(vec2 uv, vec2 _scale) {
23
    uv = floor(fract(uv * _scale) * 2.0);
24
    return min(1.0, uv.x + uv.y) - (uv.x * uv.y);
25
}
26
27
Material raymarchMap( in vec3 pos ) {
28
    float check = 0.5 + checkBoard(pos.xz, vec2(1.0, 1.0)) * 0.5;
29
    Material res = materialNew(vec3(check), 0.0, 0.5, planeSDF(pos));
30
31
    res = opUnion( res, materialNew( vec3(1.0, 1.0, 1.0), 1.0, 0.0, sphereSDF(   pos-vec3( 0.0, 0.60, 0.0), 0.5 ) ) );
32
    res = opUnion( res, materialNew( vec3(0.0, 1.0, 1.0), boxSDF(      pos-vec3( 2.0, 0.5, 0.0), vec3(0.4, 0.4, 0.4) ) ) );
33
    res = opUnion( res, materialNew( vec3(0.3, 0.3, 1.0), torusSDF(    pos-vec3( 0.0, 0.5, 2.0), vec2(0.4,0.1) ) ) );
34
    res = opUnion( res, materialNew( vec3(0.3, 0.1, 0.3), capsuleSDF(  pos,vec3(-2.3, 0.4,-0.2), vec3(-1.6,0.75,0.2), 0.2 ) ) );
35
    res = opUnion( res, materialNew( vec3(0.5, 0.3, 0.4), triPrismSDF( pos-vec3(-2.0, 0.50,-2.0), vec2(0.5,0.1) ) ) );
36
    res = opUnion( res, materialNew( vec3(0.2, 0.2, 0.8), cylinderSDF( pos-vec3( 2.0, 0.50,-2.0), vec2(0.2,0.4) ) ) );
37
    res = opUnion( res, materialNew( vec3(0.7, 0.5, 0.2), coneSDF(     pos-vec3( 0.0, 0.75,-2.0), vec3(0.8,0.6,0.6) ) ) );
38
    res = opUnion( res, materialNew( vec3(0.4, 0.2, 0.9), hexPrismSDF( pos-vec3(-2.0, 0.60, 2.0), vec2(0.5,0.1) ) ) );
39
    res = opUnion( res, materialNew( vec3(0.1, 0.3, 0.6), pyramidSDF(  pos-vec3( 2.0, 0.10, 2.0), 1.0 ) ) );;
40
41
    return res;
42
}
43
44
void main() {
45
    vec3 color = vec3(0.0);
46
    vec2 pixel = 1.0/u_resolution;
47
    vec2 st = gl_FragCoord.xy * pixel;
48
    vec2 uv = ratio(st, u_resolution);
49
50
    vec2 mo = u_mouse * pixel;
51
    float time = 32.0 + u_time * 1.5;
52
    vec3 cam = vec3( 4.5*cos(0.1*time - 7.0*mo.x), 2.2, 4.5*sin(0.1*time - 7.0*mo.x) );
53
    
54
    color = raymarch(cam, vec3(0.0), uv).rgb;
55
    color = linear2gamma(color);
56
57
    gl_FragColor = vec4( color, 1.0 );
58
}

LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.

Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).

It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.

Get the latest news and releases

Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository