
float linearize_depth(in float d)
{

    // from gl_FragCoord.z to world measurements
    return 2.0 * near  * far / (far + near - (2.0 * d - 1.0) * (far - near));

}


float get_depth_at(vec2 uv)
{
#if defined IS_IRIS && defined DISTANT_HORIZONS 
	//replace this with handling both depth textures
	return linearize_depth(texture2D(depthtex0,uv).r);
#else
	return linearize_depth(texture2D(depthtex0,uv).r);
#endif

}


	float far_adjusted = far;//this would be different for distant horizons

	if(		
		//check flags for reflections, like is this water or shiny
		material < far_adjusted  
		&& normals.w > .5
	)
	{
		//get position of pixel relative to the camera, from the position on screen
		vec3 pos = vec3(texcoord,texture2D(depthtex0,texcoord).r)*2.-1.;
		vec3 last_ray_pos = pos*.5+.5; // we keep this for refining position later
		pos=  projectAndDivide(gbufferProjectionInverse,pos) ;
		
		//get reflected ray angle, from camera off of surface, to see what is reflected
		vec3 ray_spd = normalize( reflect( normalize(pos),normals.xyz));
		
		//calculate fresnel, for how strong reflection will be
		float f = 1.-max(0., dot(normals.xyz,ray_spd) );
		
		//keep ray position seperate from starting position
		vec3 raypos = pos;
		
		//flags for raytracing
		bool hit = false;
		bool oob = false; //'out of bounds'
		
		//we are tracing based on a distance, you could alternately trace to the bounds of the screen if you calculate that based on the ray angle on screen
		 float RAY_DIST2 =
			ray_spd.z > 0.? 
				max(-pos.z,10.) : 	//go towards camera all the way
				min(far_adjusted,far_adjusted)+pos.z // go away from camera all the way
				; 

		//ray tracing steps, stop if hit something or go oob
		for(float i = 0.;i< 10. && !hit && !oob; i++)
		{
			//ray trace with exponentially accelerating ray 
			raypos = (pos+ ray_spd.xyz*RAY_DIST2*pow(i/10.,2.));
			
			//get where this is on screen, you can probably do this more efficiently by skipping this if using screen bounds for tracing and not tracing relative to the camera
			vec4 raypos2=gbufferProjection*vec4(raypos.xyz,1.);
					raypos2.xy/=raypos2.w;
    				raypos2.xy=raypos2.xy*.5+.5;
					raypos=raypos2.xyz;
			
			//check if ray is off screen
			oob = raypos.x<0. || raypos.x>1. || raypos.y<0. || raypos.y> 1. || raypos.z<0.;
			
			//see if the ray is behind or in something, causing a hit, this means it will be reflected, you can also guess if it is too far behind something to hit it to make overhangs like trees look better, but there will be screen space problems with that too
			float d = get_depth_at( raypos.xy) ;
			hit = d < raypos.z && !oob ;
			
			//keep last position on screen for refining the position for better looking reflections
		    last_ray_pos = !hit ? raypos : last_ray_pos;
			
		}//>main raytracing loop
		

		if(hit || !oob)
		{
			//refine pos
			float d;
			pos = raypos;
			float reverse = -1.0;
			float refined = 1.0;
			float rrayspeed = 1.0;
			for(int rr = 0;rr<0.;rr++)
			{ 
				rrayspeed*=.5;
				refined+=rrayspeed*reverse;
				raypos = mix(last_ray_pos, pos,refined);

				d = get_depth_at( raypos.xy) ;
				hit = d < raypos.z;
				
				reverse = hit? -1.0 : 1.0;
			}
			
	
			//fade reflections on screen edges
			f*= f*( clamp( min( (1.-abs(raypos.x-.5 )*2.)*20. , (1.-abs(raypos.y-.5 )*2.)*5.) ,0.,1.) );
			
			//sample reflection from screen
			vec3 reflection = texture2D(colortex0, raypos.xy).rgb;	
			
			//blend onto scene, albedo is not seen where reflections are, so it is mixed instead of added
			color.rgb = mix(color.rgb,reflection,f);
		
		} // > hit or not oob, checking screen

	} //> doing reflections forthis pixel
