| @ -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; | |||
| } | |||
| @ -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; | |||
| } | |||
| @ -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; | |||
| } | |||
| @ -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; | |||
| } | |||
| @ -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); | |||
| } | |||
| } | |||