Browse Source

Added raymarch example and thumbnail for write depth (#2919)

BugraAlptekinSari 2 years ago
parent
commit
4ae0a416f4

+ 5 - 4
examples/Makefile

@@ -523,7 +523,8 @@ SHADERS = \
     shaders/shaders_hot_reloading \
     shaders/shaders_mesh_instancing \
     shaders/shaders_multi_sample2d \
-    shaders/shaders_write_depth
+    shaders/shaders_write_depth \
+    shaders/shaders_hybrid_render
 
 AUDIO = \
     audio/audio_module_playing \
@@ -581,10 +582,10 @@ ifeq ($(PLATFORM),PLATFORM_DRM)
 	rm -fv *.o
 endif
 ifeq ($(PLATFORM),PLATFORM_WEB)
-	ifeq ($(PLATFORM_OS),WINDOWS)
+    ifeq ($(PLATFORM_OS),WINDOWS)
 		del *.wasm *.html *.js *.data
-	else
+    else
 		rm -f */*.wasm */*.html */*.js */*.data
-	endif
+    endif
 endif
 	@echo Cleaning done

+ 16 - 0
examples/shaders/resources/shaders/glsl100/hybrid_raster.fs

@@ -0,0 +1,16 @@
+#version 100             
+#extension GL_EXT_frag_depth : enable   // Extension required for writing depth         
+precision mediump float;                // Precision required for OpenGL ES2 (WebGL)
+
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+void main()
+{
+    vec4 texelColor = texture2D(texture0, fragTexCoord);
+    gl_FragColor = texelColor*colDiffuse*fragColor;
+	gl_FragDepthEXT = gl_FragCoord.z;
+}

+ 288 - 0
examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs

@@ -0,0 +1,288 @@
+#version 100             
+#extension GL_EXT_frag_depth : enable           //Extension required for writing depth
+#extension GL_OES_standard_derivatives : enable //Extension used for fwidth()
+precision mediump float;                // Precision required for OpenGL ES2 (WebGL)
+
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// Custom Input Uniform
+uniform vec3 camPos;
+uniform vec3 camDir;
+uniform vec2 screenCenter;
+
+#define ZERO 0
+
+// https://learnopengl.com/Advanced-OpenGL/Depth-testing
+float CalcDepth(in vec3 rd, in float Idist){
+    float local_z = dot(normalize(camDir),rd)*Idist;
+    return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01);
+}
+
+// https://iquilezles.org/articles/distfunctions/
+float sdHorseshoe( in vec3 p, in vec2 c, in float r, in float le, vec2 w )
+{
+    p.x = abs(p.x);
+    float l = length(p.xy);
+    p.xy = mat2(-c.x, c.y, 
+              c.y, c.x)*p.xy;
+    p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x),
+                (p.x>0.0)?p.y:l );
+    p.xy = vec2(p.x,abs(p.y-r))-vec2(le,0.0);
+    
+    vec2 q = vec2(length(max(p.xy,0.0)) + min(0.0,max(p.x,p.y)),p.z);
+    vec2 d = abs(q) - w;
+    return min(max(d.x,d.y),0.0) + length(max(d,0.0));
+}
+
+// r = sphere's radius
+// h = cutting's plane's position
+// t = thickness
+float sdSixWayCutHollowSphere( vec3 p, float r, float h, float t )
+{
+    // Six way symetry Transformation
+    vec3 ap = abs(p);
+    if(ap.x < max(ap.y, ap.z)){
+        if(ap.y < ap.z) ap.xz = ap.zx;
+        else ap.xy = ap.yx;
+    }
+
+    vec2 q = vec2( length(ap.yz), ap.x );
+    
+    float w = sqrt(r*r-h*h);
+    
+    return ((h*q.x<w*q.y) ? length(q-vec2(w,h)) : 
+                            abs(length(q)-r) ) - t;
+}
+
+// https://iquilezles.org/articles/boxfunctions
+vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad ) 
+{
+    vec3 m = 1.0/rd;
+    vec3 n = m*ro;
+    vec3 k = abs(m)*rad;
+    vec3 t1 = -n - k;
+    vec3 t2 = -n + k;
+	return vec2( max( max( t1.x, t1.y ), t1.z ),
+	             min( min( t2.x, t2.y ), t2.z ) );
+}
+
+vec2 opU( vec2 d1, vec2 d2 )
+{
+	return (d1.x<d2.x) ? d1 : d2;
+}
+
+vec2 map( in vec3 pos ){
+    vec2 res = vec2( sdHorseshoe(  pos-vec3(-1.0,0.08, 1.0), vec2(cos(1.3),sin(1.3)), 0.2, 0.3, vec2(0.03,0.5) ), 11.5 ) ;
+    res = opU(res, vec2( sdSixWayCutHollowSphere(  pos-vec3(0.0, 1.0, 0.0), 4.0, 3.5, 0.5 ), 4.5 )) ;
+    return res;
+}
+
+// https://www.shadertoy.com/view/Xds3zN
+vec2 raycast( in vec3 ro, in vec3 rd ){
+    vec2 res = vec2(-1.0,-1.0);
+
+    float tmin = 1.0;
+    float tmax = 20.0;
+
+    // raytrace floor plane
+    float tp1 = (-ro.y)/rd.y;
+    if( tp1>0.0 )
+    {
+        tmax = min( tmax, tp1 );
+        res = vec2( tp1, 1.0 );
+    }
+
+    float t = tmin;
+    for( int i=0; i<70 ; i++ )
+    {
+        if(t>tmax) break;
+        vec2 h = map( ro+rd*t );
+        if( abs(h.x)<(0.0001*t) )
+        { 
+            res = vec2(t,h.y); 
+            break;
+        }
+        t += h.x;
+    }
+
+    return res;
+}
+
+
+// https://iquilezles.org/articles/rmshadows
+float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
+{
+    // bounding volume
+    float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
+
+    float res = 1.0;
+    float t = mint;
+    for( int i=ZERO; i<24; i++ )
+    {
+		float h = map( ro + rd*t ).x;
+        float s = clamp(8.0*h/t,0.0,1.0);
+        res = min( res, s );
+        t += clamp( h, 0.01, 0.2 );
+        if( res<0.004 || t>tmax ) break;
+    }
+    res = clamp( res, 0.0, 1.0 );
+    return res*res*(3.0-2.0*res);
+}
+
+
+// https://iquilezles.org/articles/normalsSDF
+vec3 calcNormal( in vec3 pos )
+{
+    vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
+    return normalize( e.xyy*map( pos + e.xyy ).x + 
+					  e.yyx*map( pos + e.yyx ).x + 
+					  e.yxy*map( pos + e.yxy ).x + 
+					  e.xxx*map( pos + e.xxx ).x );
+}
+
+// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf
+float calcAO( in vec3 pos, in vec3 nor )
+{
+	float occ = 0.0;
+    float sca = 1.0;
+    for( int i=ZERO; i<5; i++ )
+    {
+        float h = 0.01 + 0.12*float(i)/4.0;
+        float d = map( pos + h*nor ).x;
+        occ += (h-d)*sca;
+        sca *= 0.95;
+        if( occ>0.35 ) break;
+    }
+    return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y);
+}
+
+// https://iquilezles.org/articles/checkerfiltering
+float checkersGradBox( in vec2 p )
+{
+    // filter kernel
+    vec2 w = fwidth(p) + 0.001;
+    // analytical integral (box filter)
+    vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
+    // xor pattern
+    return 0.5 - 0.5*i.x*i.y;                  
+}
+
+// https://www.shadertoy.com/view/tdS3DG
+vec4 render( in vec3 ro, in vec3 rd)
+{ 
+    // background
+    vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
+    
+    // raycast scene
+    vec2 res = raycast(ro,rd);
+    float t = res.x;
+	float m = res.y;
+    if( m>-0.5 )
+    {
+        vec3 pos = ro + t*rd;
+        vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
+        vec3 ref = reflect( rd, nor );
+        
+        // material        
+        col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
+        float ks = 1.0;
+        
+        if( m<1.5 )
+        {
+            float f = checkersGradBox( 3.0*pos.xz);
+            col = 0.15 + f*vec3(0.05);
+            ks = 0.4;
+        }
+
+        // lighting
+        float occ = calcAO( pos, nor );
+        
+		vec3 lin = vec3(0.0);
+
+        // sun
+        {
+            vec3  lig = normalize( vec3(-0.5, 0.4, -0.6) );
+            vec3  hal = normalize( lig-rd );
+            float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
+          //if( dif>0.0001 )
+        	      dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
+			float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
+                  spe *= dif;
+                  spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
+                //spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0);
+            lin += col*2.20*dif*vec3(1.30,1.00,0.70);
+            lin +=     5.00*spe*vec3(1.30,1.00,0.70)*ks;
+        }
+        // sky
+        {
+            float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
+                  dif *= occ;
+            float spe = smoothstep( -0.2, 0.2, ref.y );
+                  spe *= dif;
+                  spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
+          //if( spe>0.001 )
+                  spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
+            lin += col*0.60*dif*vec3(0.40,0.60,1.15);
+            lin +=     2.00*spe*vec3(0.40,0.60,1.30)*ks;
+        }
+        // back
+        {
+        	float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
+                  dif *= occ;
+        	lin += col*0.55*dif*vec3(0.25,0.25,0.25);
+        }
+        // sss
+        {
+            float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
+                  dif *= occ;
+        	lin += col*0.25*dif*vec3(1.00,1.00,1.00);
+        }
+        
+		col = lin;
+
+        col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
+    }
+
+	return vec4(vec3( clamp(col,0.0,1.0) ),t);
+}
+
+vec3 CalcRayDir(vec2 nCoord){
+    vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
+    vec3 vertical   = normalize(cross(horizontal,camDir));
+    return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
+}
+
+mat3 setCamera()
+{
+	vec3 cw = normalize(camDir);
+	vec3 cp = vec3(0.0, 1.0 ,0.0);
+	vec3 cu = normalize( cross(cw,cp) );
+	vec3 cv =          ( cross(cu,cw) );
+    return mat3( cu, cv, cw );
+}
+
+void main()
+{
+    vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y;
+    mat3 ca = setCamera();
+
+    // focal length
+    float fl = length(camDir);
+    vec3 rd = ca * normalize( vec3(nCoord,fl) );
+    vec3 color = vec3(nCoord/2.0 + 0.5, 0.0);
+    float depth = gl_FragCoord.z;
+    {
+        vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd );
+        color = res.xyz;
+        depth = CalcDepth(rd,res.w);
+    }
+    gl_FragColor = vec4(color , 1.0);
+	gl_FragDepthEXT = depth;
+}

+ 14 - 0
examples/shaders/resources/shaders/glsl330/hybrid_raster.fs

@@ -0,0 +1,14 @@
+#version 330             
+
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+void main()
+{
+    vec4 texelColor = texture2D(texture0, fragTexCoord);
+    gl_FragColor = texelColor*colDiffuse*fragColor;
+	gl_FragDepth = gl_FragCoord.z;
+}

+ 284 - 0
examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs

@@ -0,0 +1,284 @@
+# version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// Custom Input Uniform
+uniform vec3 camPos;
+uniform vec3 camDir;
+uniform vec2 screenCenter;
+
+#define ZERO 0
+
+// https://learnopengl.com/Advanced-OpenGL/Depth-testing
+float CalcDepth(in vec3 rd, in float Idist){
+    float local_z = dot(normalize(camDir),rd)*Idist;
+    return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01);
+}
+
+// https://iquilezles.org/articles/distfunctions/
+float sdHorseshoe( in vec3 p, in vec2 c, in float r, in float le, vec2 w )
+{
+    p.x = abs(p.x);
+    float l = length(p.xy);
+    p.xy = mat2(-c.x, c.y, 
+              c.y, c.x)*p.xy;
+    p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x),
+                (p.x>0.0)?p.y:l );
+    p.xy = vec2(p.x,abs(p.y-r))-vec2(le,0.0);
+    
+    vec2 q = vec2(length(max(p.xy,0.0)) + min(0.0,max(p.x,p.y)),p.z);
+    vec2 d = abs(q) - w;
+    return min(max(d.x,d.y),0.0) + length(max(d,0.0));
+}
+
+// r = sphere's radius
+// h = cutting's plane's position
+// t = thickness
+float sdSixWayCutHollowSphere( vec3 p, float r, float h, float t )
+{
+    // Six way symetry Transformation
+    vec3 ap = abs(p);
+    if(ap.x < max(ap.y, ap.z)){
+        if(ap.y < ap.z) ap.xz = ap.zx;
+        else ap.xy = ap.yx;
+    }
+
+    vec2 q = vec2( length(ap.yz), ap.x );
+    
+    float w = sqrt(r*r-h*h);
+    
+    return ((h*q.x<w*q.y) ? length(q-vec2(w,h)) : 
+                            abs(length(q)-r) ) - t;
+}
+
+// https://iquilezles.org/articles/boxfunctions
+vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad ) 
+{
+    vec3 m = 1.0/rd;
+    vec3 n = m*ro;
+    vec3 k = abs(m)*rad;
+    vec3 t1 = -n - k;
+    vec3 t2 = -n + k;
+	return vec2( max( max( t1.x, t1.y ), t1.z ),
+	             min( min( t2.x, t2.y ), t2.z ) );
+}
+
+vec2 opU( vec2 d1, vec2 d2 )
+{
+	return (d1.x<d2.x) ? d1 : d2;
+}
+
+vec2 map( in vec3 pos ){
+    vec2 res = vec2( sdHorseshoe(  pos-vec3(-1.0,0.08, 1.0), vec2(cos(1.3),sin(1.3)), 0.2, 0.3, vec2(0.03,0.5) ), 11.5 ) ;
+    res = opU(res, vec2( sdSixWayCutHollowSphere(  pos-vec3(0.0, 1.0, 0.0), 4.0, 3.5, 0.5 ), 4.5 )) ;
+    return res;
+}
+
+// https://www.shadertoy.com/view/Xds3zN
+vec2 raycast( in vec3 ro, in vec3 rd ){
+    vec2 res = vec2(-1.0,-1.0);
+
+    float tmin = 1.0;
+    float tmax = 20.0;
+
+    // raytrace floor plane
+    float tp1 = (-ro.y)/rd.y;
+    if( tp1>0.0 )
+    {
+        tmax = min( tmax, tp1 );
+        res = vec2( tp1, 1.0 );
+    }
+
+    float t = tmin;
+    for( int i=0; i<70 ; i++ )
+    {
+        if(t>tmax) break;
+        vec2 h = map( ro+rd*t );
+        if( abs(h.x)<(0.0001*t) )
+        { 
+            res = vec2(t,h.y); 
+            break;
+        }
+        t += h.x;
+    }
+
+    return res;
+}
+
+
+// https://iquilezles.org/articles/rmshadows
+float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
+{
+    // bounding volume
+    float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
+
+    float res = 1.0;
+    float t = mint;
+    for( int i=ZERO; i<24; i++ )
+    {
+		float h = map( ro + rd*t ).x;
+        float s = clamp(8.0*h/t,0.0,1.0);
+        res = min( res, s );
+        t += clamp( h, 0.01, 0.2 );
+        if( res<0.004 || t>tmax ) break;
+    }
+    res = clamp( res, 0.0, 1.0 );
+    return res*res*(3.0-2.0*res);
+}
+
+
+// https://iquilezles.org/articles/normalsSDF
+vec3 calcNormal( in vec3 pos )
+{
+    vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
+    return normalize( e.xyy*map( pos + e.xyy ).x + 
+					  e.yyx*map( pos + e.yyx ).x + 
+					  e.yxy*map( pos + e.yxy ).x + 
+					  e.xxx*map( pos + e.xxx ).x );
+}
+
+// https://iquilezles.org/articles/nvscene2008/rwwtt.pdf
+float calcAO( in vec3 pos, in vec3 nor )
+{
+	float occ = 0.0;
+    float sca = 1.0;
+    for( int i=ZERO; i<5; i++ )
+    {
+        float h = 0.01 + 0.12*float(i)/4.0;
+        float d = map( pos + h*nor ).x;
+        occ += (h-d)*sca;
+        sca *= 0.95;
+        if( occ>0.35 ) break;
+    }
+    return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y);
+}
+
+// https://iquilezles.org/articles/checkerfiltering
+float checkersGradBox( in vec2 p )
+{
+    // filter kernel
+    vec2 w = fwidth(p) + 0.001;
+    // analytical integral (box filter)
+    vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
+    // xor pattern
+    return 0.5 - 0.5*i.x*i.y;                  
+}
+
+// https://www.shadertoy.com/view/tdS3DG
+vec4 render( in vec3 ro, in vec3 rd)
+{ 
+    // background
+    vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
+    
+    // raycast scene
+    vec2 res = raycast(ro,rd);
+    float t = res.x;
+	float m = res.y;
+    if( m>-0.5 )
+    {
+        vec3 pos = ro + t*rd;
+        vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
+        vec3 ref = reflect( rd, nor );
+        
+        // material        
+        col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
+        float ks = 1.0;
+        
+        if( m<1.5 )
+        {
+            float f = checkersGradBox( 3.0*pos.xz);
+            col = 0.15 + f*vec3(0.05);
+            ks = 0.4;
+        }
+
+        // lighting
+        float occ = calcAO( pos, nor );
+        
+		vec3 lin = vec3(0.0);
+
+        // sun
+        {
+            vec3  lig = normalize( vec3(-0.5, 0.4, -0.6) );
+            vec3  hal = normalize( lig-rd );
+            float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
+          //if( dif>0.0001 )
+        	      dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
+			float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
+                  spe *= dif;
+                  spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
+                //spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0);
+            lin += col*2.20*dif*vec3(1.30,1.00,0.70);
+            lin +=     5.00*spe*vec3(1.30,1.00,0.70)*ks;
+        }
+        // sky
+        {
+            float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
+                  dif *= occ;
+            float spe = smoothstep( -0.2, 0.2, ref.y );
+                  spe *= dif;
+                  spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
+          //if( spe>0.001 )
+                  spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
+            lin += col*0.60*dif*vec3(0.40,0.60,1.15);
+            lin +=     2.00*spe*vec3(0.40,0.60,1.30)*ks;
+        }
+        // back
+        {
+        	float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
+                  dif *= occ;
+        	lin += col*0.55*dif*vec3(0.25,0.25,0.25);
+        }
+        // sss
+        {
+            float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
+                  dif *= occ;
+        	lin += col*0.25*dif*vec3(1.00,1.00,1.00);
+        }
+        
+		col = lin;
+
+        col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
+    }
+
+	return vec4(vec3( clamp(col,0.0,1.0) ),t);
+}
+
+vec3 CalcRayDir(vec2 nCoord){
+    vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
+    vec3 vertical   = normalize(cross(horizontal,camDir));
+    return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
+}
+
+mat3 setCamera()
+{
+	vec3 cw = normalize(camDir);
+	vec3 cp = vec3(0.0, 1.0 ,0.0);
+	vec3 cu = normalize( cross(cw,cp) );
+	vec3 cv =          ( cross(cu,cw) );
+    return mat3( cu, cv, cw );
+}
+
+void main()
+{
+    vec2 nCoord = (gl_FragCoord.xy - screenCenter.xy)/screenCenter.y;
+    mat3 ca = setCamera();
+
+    // focal length
+    float fl = length(camDir);
+    vec3 rd = ca * normalize( vec3(nCoord,fl) );
+    vec3 color = vec3(nCoord/2.0 + 0.5, 0.0);
+    float depth = gl_FragCoord.z;
+    {
+        vec4 res = render( camPos - vec3(0.0, 0.0, 0.0) , rd );
+        color = res.xyz;
+        depth = CalcDepth(rd,res.w);
+    }
+    gl_FragColor = vec4(color , 1.0);
+	gl_FragDepth = depth;
+}

+ 212 - 0
examples/shaders/shaders_hybrid_render.c

@@ -0,0 +1,212 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - Hybrid Rendering
+*
+*   Example originally created with raylib 4.2, last time updated with raylib 4.2
+*
+*   Example contributed by Buğra Alptekin Sarı (@BugraAlptekinSari) and reviewed by Ramon Santamaria (@raysan5)
+*
+*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+*   BSD-like license that allows static linking with closed source software
+*
+*   Copyright (c) 2022-2023 Buğra Alptekin Sarı (@BugraAlptekinSari)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rlgl.h"
+#include "math.h" // Used for tan()
+#include "raymath.h" // Used to calculate camera Direction
+
+#if defined(PLATFORM_DESKTOP)
+#define GLSL_VERSION            330
+#else   // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
+#define GLSL_VERSION            100
+#endif
+
+//------------------------------------------------------------------------------------
+// Declare custom functions required for the example
+//------------------------------------------------------------------------------------
+// Load custom render texture, create a writable depth texture buffer
+static RenderTexture2D LoadRenderTextureDepthTex(int width, int height);
+// Unload render texture from GPU memory (VRAM)
+static void UnloadRenderTextureDepthTex(RenderTexture2D target);
+
+//------------------------------------------------------------------------------------
+// Declare custom Structs
+//------------------------------------------------------------------------------------
+
+typedef struct {
+    unsigned int camPos, camDir, screenCenter;
+}RayLocs ;
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    const int screenWidth = 800;
+    const int screenHeight = 450;
+
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - write depth buffer");
+
+    // This Shader calculates pixel depth and color using raymarch.
+    Shader raymarch_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raymarch.fs", GLSL_VERSION));
+    // This Shader is a standard rasterization fragment shader with the addition of depth writing. You are required to write depth for all shaders if one shader does it.
+    Shader raster_shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/hybrid_raster.fs", GLSL_VERSION));
+
+    // Declare Struct used to store camera locs.
+    RayLocs march_locs = {0};
+
+    // Fill the struct with shader locs.
+    march_locs.camPos = GetShaderLocation(raymarch_shader, "camPos");
+    march_locs.camDir = GetShaderLocation(raymarch_shader, "camDir");
+    march_locs.screenCenter = GetShaderLocation(raymarch_shader, "screenCenter");
+
+    {   // Transfer screenCenter position to shader. Which is used to calculate ray direction. 
+        Vector2 screenCenter = {.x = screenWidth/2.0, .y = screenHeight/2.0};
+        SetShaderValue(raymarch_shader, march_locs.screenCenter , &screenCenter , SHADER_UNIFORM_VEC2);
+    }
+
+
+    // Use Customized function to create writable depth texture buffer
+    RenderTexture2D target = LoadRenderTextureDepthTex(screenWidth, screenHeight);
+
+    // Define the camera to look into our 3d world
+    Camera camera = {
+        .position = (Vector3){ 0.5f, 1.0f, 1.5f },    // Camera position
+        .target = (Vector3){ 0.0f, 0.5f, 0.0f },      // Camera looking at point
+        .up = (Vector3){ 0.0f, 1.0f, 0.0f },          // Camera up vector (rotation towards target)
+        .fovy = 45.0f,                                // Camera field-of-view Y
+        .projection = CAMERA_PERSPECTIVE              // Camera mode type
+    };
+    
+    // Camera FOV is pre-calculated in the camera Distance.
+    double camDist = 1.0/(tan(camera.fovy*0.5*DEG2RAD));
+
+    SetCameraMode(camera, CAMERA_FIRST_PERSON);
+    
+    SetTargetFPS(60);
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera);
+
+        //Update Camera Postion in the ray march shader.
+        SetShaderValue(raymarch_shader, march_locs.camPos, &(camera.position), RL_SHADER_UNIFORM_VEC3);
+        
+        {   // Update Camera Looking Vector. Vector length determines FOV.
+            Vector3 camDir = Vector3Scale( Vector3Normalize( Vector3Subtract(camera.target, camera.position)) , camDist);
+            SetShaderValue(raymarch_shader, march_locs.camDir, &(camDir), RL_SHADER_UNIFORM_VEC3);
+        }
+        //----------------------------------------------------------------------------------
+        
+        // Draw
+        //----------------------------------------------------------------------------------
+        
+        // Draw into our custom render texture (framebuffer)
+        BeginTextureMode(target);
+            ClearBackground(WHITE);
+
+            // Raymarch Scene
+            rlEnableDepthTest(); //Manually enable Depth Test to handle multiple rendering methods.
+            BeginShaderMode(raymarch_shader);
+                DrawRectangleRec((Rectangle){0,0,screenWidth,screenHeight},WHITE);
+            EndShaderMode();
+            
+            // Raserize Scene
+            BeginMode3D(camera);
+                BeginShaderMode(raster_shader);
+                    DrawCubeWiresV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, RED);
+                    DrawCubeV((Vector3){ 0.0f, 0.5f, 1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, PURPLE);
+                    DrawCubeWiresV((Vector3){ 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, DARKGREEN);
+                    DrawCubeV((Vector3) { 0.0f, 0.5f, -1.0f }, (Vector3){ 1.0f, 1.0f, 1.0f }, YELLOW);
+                    DrawGrid(10, 1.0f);
+                EndShaderMode();
+            EndMode3D();
+        EndTextureMode();
+
+        // Draw into screen our custom render texture 
+        BeginDrawing();
+            ClearBackground(RAYWHITE);
+        
+            DrawTextureRec(target.texture, (Rectangle) { 0, 0, screenWidth, -screenHeight }, (Vector2) { 0, 0 }, WHITE);
+            DrawFPS(10, 10);
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadRenderTextureDepthTex(target);
+    UnloadShader(raymarch_shader);
+    UnloadShader(raster_shader);
+
+    CloseWindow();        // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Define custom functions required for the example
+//------------------------------------------------------------------------------------
+// Load custom render texture, create a writable depth texture buffer
+RenderTexture2D LoadRenderTextureDepthTex(int width, int height)
+{
+    RenderTexture2D target = { 0 };
+
+    target.id = rlLoadFramebuffer(width, height);   // Load an empty framebuffer
+
+    if (target.id > 0)
+    {
+        rlEnableFramebuffer(target.id);
+
+        // Create color texture (default to RGBA)
+        target.texture.id = rlLoadTexture(0, width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
+        target.texture.width = width;
+        target.texture.height = height;
+        target.texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
+        target.texture.mipmaps = 1;
+
+        // Create depth texture buffer (instead of raylib default renderbuffer)
+        target.depth.id = rlLoadTextureDepth(width, height, false);
+        target.depth.width = width;
+        target.depth.height = height;
+        target.depth.format = 19;       //DEPTH_COMPONENT_24BIT?
+        target.depth.mipmaps = 1;
+
+        // Attach color texture and depth texture to FBO
+        rlFramebufferAttach(target.id, target.texture.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
+        rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0);
+
+        // Check if fbo is complete with attachments (valid)
+        if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id);
+
+        rlDisableFramebuffer();
+    }
+    else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created");
+
+    return target;
+}
+
+// Unload render texture from GPU memory (VRAM)
+void UnloadRenderTextureDepthTex(RenderTexture2D target)
+{
+    if (target.id > 0)
+    {
+        // Color texture attached to FBO is deleted
+        rlUnloadTexture(target.texture.id);
+        rlUnloadTexture(target.depth.id);
+
+        // NOTE: Depth texture is automatically
+        // queried and deleted before deleting framebuffer
+        rlUnloadFramebuffer(target.id);
+    }
+}

BIN
examples/shaders/shaders_hybrid_render.png


BIN
examples/shaders/shaders_write_depth.png