// path trace from depth point
void pathTrace(vec3 start, ivec3 originIndex, vec3 incident, vec3 direction, vec3 normal, vec3 albedo, out vec3 indirect, out vec3 direct, out vec3 rayHitPos, float sunlightLeakFix) {//, float[K] r_seq, inout int r_index
    indirect = vec3(0.0);
    direct = vec3(0.0);

	vec3 dirToSun = normalize(viewToWorld(lightDirView));
	vec3 mask = vec3(1.0);

	vec3 rayDir = direction;
	vec3 rayPos = start;
	ivec3 hitIndex;
	vec3 hitPos;
	vec3 hitNormal;
	vec3 hitAlbedo = vec3(0.0);
	// for(int i = 0; i < BOUNCES-1; i++) {

		vec4[2] voxel;
		vec3 rayTint;
		bool rayHit = RaytraceVoxel(rayPos, originIndex, rayDir, voxel, hitPos, hitIndex, hitNormal, rayTint, MAX_RAY_DIST, DIFFUSE_SPHERE_RADIUS);
		rayHitPos = hitPos;
		int hitId = ExtractVoxelId(voxel);

		// Sky contrib
		if(!rayHit) {
            vec3 accumulator = vec3(0.0);
			float groundHitAlbedo = rayDir.y > 0.0 ? 1.0 : 0.1;
			accumulator += samplePrecomputedSky(rayDir).rgb * groundHitAlbedo * mask * sunlightLeakFix;// * (smoothstep(-0.15, -0.05, rayDir.y) * 0.8 + 0.2);

			//Fake sun approx
			// if(rayDir.y < 0.0) {
			// 	vec3 NEE_BounceWeight = computeNEEWeight(vec3(0,1,0), rayDir, dirToSun, vec3(groundHitAlbedo), vec2(1.0, 0.0), false) * sunlightGIBoost;
			// 	accumulator += directLight(hitIndex, vec3(0,1,0))*shadowLightTransmitted * NEE_BounceWeight * mask;
			// } 
			indirect += accumulator*rayTint;
			return;
		}


		//update normal and raypos
		normal = hitNormal;
		rayPos = hitPos - hitNormal*0.001;

		//Get hit material
		Material hitMat = getMaterialAt(hitPos, hitNormal, voxel);
		vec2 specularMap = vec2(hitMat.roughness, hitMat.f0);

		#ifdef CAUSTICS_ENABLED
		bool isMetal = isMetal(specularMap.y);// && i == 0;
		float sunBounceIntensity = 1.0;//mix(1.0, CAUSTICS_INTENSITY*0.35, float(isMetal));
		// specularMap.x = mix(specularMap.x, clamp(specularMap.x*2.2, 0.3, 1.0), float(isMetal));
		#else
		bool isMetal = false;
		float sunBounceIntensity = 1.0;
		#endif

		#ifndef WHITE_WORLD
		hitAlbedo = hitMat.albedo;
		vec3 tint = hitMat.tint;
		#else
		hitAlbedo = vec3(1.0);
		vec3 tint = vec3(1.0);
		#endif

		//Get emission of hit point
		#ifdef GUIDED_PASS
		float emitterMult = 1.0;
		#else
		float emitterMult = 1.0;
		#endif
		direct += getEmissionCol(hitMat.emission, tint, EMISSIVE_CURVE, hitId) * emitterMult * mask;


		//Sun indirect light
		vec3 NEE_BounceWeight = computeNEEWeight(normal, rayDir, dirToSun, hitAlbedo, specularMap, isMetal) * sunBounceIntensity * sunlightGIBoost;
		#ifdef GUIDED_PASS
			// NEE_BounceWeight *= PI;
		#endif
		indirect += directLight(rayPos, normal) * shadowLightTransmitted * NEE_BounceWeight * mask * sunlightLeakFix; // Sunlight indirect is considered direct because its noise is more like direct


		// Prepare next bounce dir
		// vec3 weight;
		// if(i < BOUNCES-2) {
		// 	rayDir = reflectDiffuseRay(normal, rayDir, hitAlbedo, specularMap, true, weight, seed);
		// 	mask *= weight;
		// }
		

	// }

	//Apply irradiance cache GI
	int face = getFace(hitNormal);
	indirect += cacheRead(GetCacheStoragePos(ivec3(floor(hitPos - hitNormal*0.1)), face)) * hitAlbedo * mask * PATH_BOUNCE_MULTIPLIER;

	direct *= rayTint;
	indirect *= rayTint;
}