anchor.diff:      #endif
       TexCoords texCoords = createTexCoords(result.index);
       vec2 texCoord = barycentricTexCoord(weights, texCoords);
  -    vec4 texRaw = texture(texArray, vec3(texCoord, mat.mapIndices.diffuse));
  -    vec3 texEmmissive = texture(texArray, vec3(texCoord, mat.mapIndices.specular)).rgb;
  +	  vec4 texRaw = texture(texArray, vec3(texCoord, mat.mapIndices.diffuse));
  +	  vec3 texEmmissive = texture(texArray, vec3(texCoord, mat.mapIndices.specular)).rgb;
       vec3 texDiffuse = texRaw.rgb;
  -    vec4 texMetallicRoughness = texture(texArray, vec3(texCoord, mat.mapIndices.roughness));
  -    float texRoughness = texMetallicRoughness.g;
  -    float texEmmissiveScale = texMetallicRoughness.b;
  +	  vec4 texMetallicRoughness = texture(texArray, vec3(texCoord, mat.mapIndices.roughness));
  +	  float texEmmissiveScale = texMetallicRoughness.b;
       vec3 texNormal = (texture(texArray, vec3(texCoord, mat.mapIndices.normal)).rgb - vec3(0.5, 0.5, 0.0)) * vec3(2.0, 2.0, 1.0);
  -    float roughness = texRoughness * texRoughness;
  +    texMetallicRoughness.g *= texMetallicRoughness.g;
       seed = origin.x * randBase + origin.y * 1.396529836 + origin.z * 4761.52835;
       vec3 baryNormal;
       vec3 macroNormal = barycentricNormal(weights, createNormals(result.index), texNormal, baryNormal);
  -    vec3 microNormal = ggxRandomImportantNormal(macroNormal, roughness);
       vec3 lightDir;
       ray.origin = origin + baryNormal * EPSILON * 2.0;
  -    float inside = sign(dot(-ray.dir, macroNormal));
  -    vec2 ns = inside > 0.0 ? vec2(1, mat.ior) : vec2(mat.ior, 1);
  -    bool metallic = rnd() > (1.0 - texMetallicRoughness.r);
  -    bool specular = false;
  -    if (!metallic){
  -      specular = schlick(ray.dir, inside * microNormal, ns.x, ns.y) > rnd();
  -    }
  -    texDiffuse = specular ? vec3(1.0) : texDiffuse;
  +
  +    //texDiffuse = specular ? vec3(1.0) : texDiffuse;
  +    // TODO: make this configurable in the materials
       color += accumulatedReflectance * texEmmissive * 10.0;
  -    float colorAlbedo = albedo(texDiffuse) + EPSILON;
  -    if( rnd() > colorAlbedo ){ break; }
  +
       #ifdef USE_EXPLICIT
       vec3 direct = getDirectEmission(ray.origin, macroNormal, lightDir);
       #else
  
positive.code: 
  float rnd() { return fract(sin(seed += 0.211324865405187)*43758.5453123); }
  
  vec3 ggxRandomImportantNormal(vec3 oNormal, float a){
    vec2 xi = vec2(rnd(), rnd());
    float phi = 2.0f * M_PI * xi.x;
    float theta = atan(a * sqrt(xi.y / (1.0 - xi.y)));
    float cosTheta = cos(theta);
    float sinTheta = sin(theta);
    vec3 u = normalize(cross(oNormal,vec3(0.0,0.0,1.0)));
    vec3 v = normalize(cross(u, oNormal));
    vec3 facet = cos(phi) * sinTheta * u + sinTheta * sin(phi) * v + cosTheta * oNormal;
    return facet;
  }
  
  // GGX PDF
  float ggxPdf(vec3 normal, vec3 microNormal, float a){
    float a2 = a*a;
    float ndh = dot(normal, microNormal);
    float denom = ndh*ndh * (a2 - 1.0) + 1.0;
    return max(dot(normal, microNormal), 0.0) * (a2) / (M_PI * denom * denom);
  }
  
  float smith(vec3 normal, vec3 outgoing, float a) {
    float nv = max(dot(normal, outgoing), 0.0);
    return max((2.0 * nv) / (nv + sqrt(a*a + (1.0 - a*a) * nv * nv)), EPSILON);
  }
  
  vec2 misWeights(float a, float b ) {
      float a2 = a*a;
      float b2 = b*b;
  
negative.code:     return max(vec2(a2, b2) / a2b2, vec2(EPSILON));
  }
  
  //-----------------------------------------------------------------------
  vec3 CosineSampleHemisphere(float u1, float u2)
  //-----------------------------------------------------------------------
  {
  	vec3 dir;
  	float r = sqrt(u1);
  	float phi = M_TAU * u2;
  	dir.x = r * cos(phi);
  	dir.y = r * sin(phi);
  	dir.z = sqrt(max(0.0, 1.0 - dir.x*dir.x - dir.y*dir.y));
  
  	return dir;
  }
  
  //-----------------------------------------------------------------------
  float SchlickFresnel(float u)
  //-----------------------------------------------------------------------
  {
  	float m = clamp(1.0 - u, 0.0, 1.0);
  	float m2 = m * m;
  	return m2 * m2*m; // pow(m,5)
  }
  
  //-----------------------------------------------------------------------
  float GTR2(float NDotH, float a)
  //-----------------------------------------------------------------------
  {
  	float a2 = a * a;
  	float t = 1.0 + (a2 - 1.0)*NDotH*NDotH;
  	return a2 / (M_PI * t*t);
  }
  
  //-----------------------------------------------------------------------
  float SmithG_GGX(float NDotv, float alphaG)
  //-----------------------------------------------------------------------
  {
  	float a = alphaG * alphaG;
  	float b = NDotv * NDotv;
  	return 1.0 / (NDotv + sqrt(a + b - a * b));
  }
  
  //-----------------------------------------------------------------------
  float UE4Pdf(vec3 incident, vec3 normal, vec2 matParams, in vec3 bsdfDir)
  //-----------------------------------------------------------------------
  {
  	vec3 n = normal;
  	vec3 V = -incident;
  	vec3 L = bsdfDir;
  
  	float specularAlpha = max(0.001, matParams.y);
  
  	float diffuseRatio = 0.5 * (1.0 - matParams.x);
  	float specularRatio = 1.0 - diffuseRatio;
  
  	vec3 halfVec = normalize(L + V);
  
  	float cosTheta = abs(dot(halfVec, n));
  	float pdfGTR2 = GTR2(cosTheta, specularAlpha) * cosTheta;
  
  	// calculate diffuse and specular pdfs and mix ratio
  	float pdfSpec = pdfGTR2 / (4.0 * abs(dot(L, halfVec)));
  	float pdfDiff = abs(dot(L, n)) * INV_PI;
  
  	// weight pdfs according to ratios
  	return diffuseRatio * pdfDiff + specularRatio * pdfSpec;
  }
  
  //-----------------------------------------------------------------------
  vec3 UE4Sample(vec3 incident, vec3 normal, vec2 matParams)
  //-----------------------------------------------------------------------
  {
  	vec3 N = normal;
  	vec3 V = -incident;
  
  	vec3 dir;
  
  	float probability = rnd();
  	float diffuseRatio = 0.5 * (1.0 - matParams.x);
  
  	float r1 = rnd();
  	float r2 = rnd();
  
  	vec3 UpVector = abs(N.z) < 0.999 ? vec3(0, 0, 1) : vec3(1, 0, 0);
  	vec3 TangentX = normalize(cross(UpVector, N));
  	vec3 TangentY = cross(N, TangentX);
  
  	if (probability < diffuseRatio) // sample diffuse
  	{
  		dir = CosineSampleHemisphere(r1, r2);
  		dir = TangentX * dir.x + TangentY * dir.y + N * dir.z;
  	}
  	else
  	{
  		float a = max(0.001, matParams.y);
  
  		float phi = r1 * M_TAU;
  
  		float cosTheta = sqrt((1.0 - r2) / (1.0 + (a*a - 1.0) *r2));
  		float sinTheta = clamp(sqrt(1.0 - (cosTheta * cosTheta)), 0.0, 1.0);
  		float sinPhi = sin(phi);
  		float cosPhi = cos(phi);
  
  		vec3 halfVec = vec3(sinTheta*cosPhi, sinTheta*sinPhi, cosTheta);
  		halfVec = TangentX * halfVec.x + TangentY * halfVec.y + N * halfVec.z;
  
  		dir = 2.0*dot(V, halfVec)*halfVec - V;
  	}
  	return dir;
  }
  
  //-----------------------------------------------------------------------
  vec3 UE4Eval(vec3 incident, vec3 normal, vec3 diffuseColor, vec2 matParams, in vec3 bsdfDir)
  //-----------------------------------------------------------------------
  {
  	vec3 N = normal;
  	vec3 V = -incident;
  	vec3 L = bsdfDir;
  
  	float NDotL = dot(N, L);
  	float NDotV = dot(N, V);
  	if (NDotL <= 0.0 || NDotV <= 0.0)
  		return vec3(0.0);
  
  	vec3 H = normalize(L + V);
  	float NDotH = dot(N, H);
  	float LDotH = dot(L, H);
  
  	// specular	
  	float specular = 0.5;
  	vec3 specularCol = mix(vec3(0.2), diffuseColor, matParams.x);
  	float a = max(0.001, matParams.y);
  	float Ds = GTR2(NDotH, a);
  	float FH = SchlickFresnel(LDotH);
  	vec3 Fs = mix(specularCol, vec3(1.0), FH);
  	float roughg = (matParams.y*0.5 + 0.5);
  	roughg = roughg * roughg;
  	float Gs = SmithG_GGX(NDotL, roughg) * SmithG_GGX(NDotV, roughg);
  
  	return diffuseColor * INV_PI * (1.0 - matParams.x) + Gs * Fs*Ds;
  }
  
  // Moller-Trumbore
  