Announcement

Collapse
No announcement yet.

Mimic Vraymaterial blend between diffuse and reflection in an FX-Shader

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mimic Vraymaterial blend between diffuse and reflection in an FX-Shader

    Dear all,

    I try to create an FX-Shader for interactive walkthroughs which has the same math as the VrayMaterial. Especially the blending between Diffuse and Reflect Color slot is interesting. I tried to figure out the math with some testscenes but the result is not exact to me.

    So I assume the following for simplification:

    -no fresnel
    -diffuse is just a color, no texture
    -reflection is also a color, no greyscale value, but also no texture
    -put together diffuse and incoming light as a baked VrayRawTotalLightMap, in my formula it is the diffuse value

    So which of the following terms is the correct one?

    1. resultColor = lerp(diffuseColor, env_reflection * reflectionColor, intensityFromRGBFloat(reflectionColor));

    2. resultColor = lerp(diffuseColor, env_reflection, intensityFromRGBFloat(reflectionColor));

    3. resultColor = lerp(diffuseColor, env_reflection * reflectionColor, reflectionColor);

    4. resultColor = lerp(diffuseColor, env_reflection, reflectionColor);


    Thank you much in advance.
    Robert

    Max, VRay, Fusion:

    https://www.youtube.com/watch?v=g5fSLrVzpxg
    https://www.youtube.com/watch?v=bpmJgTb_9Ro

  • #2
    Got it, it seems to be the last formula, the simplest one.
    Robert

    Max, VRay, Fusion:

    https://www.youtube.com/watch?v=g5fSLrVzpxg
    https://www.youtube.com/watch?v=bpmJgTb_9Ro

    Comment


    • #3
      Yes, the last one is the correct one if the "energy preservation mode" is left to the default "rgb".

      Best regards,
      Vlado
      I only act like I know everything, Rogers.

      Comment


      • #4
        Thanks, Vlado. Two more questions:

        1. Is for "Energy preservation mode" = "monchrome" the formula then
        resultColor = lerp(diffuseColor, env_reflection, intensityFromRGB(reflectionColor)); ?

        2. Adding the fresnel term to the first blend term for rgb preservation mode, this simply would be
        resultColor = lerp(diffuseColor, env_reflection, reflectionColor * fresnelAmount)); ?

        I have calculated the Fresnel amount with a fresnel function that I found, taking airIOR, materialIOR, normal and viewDir. Reason that I used this and not the simplified fresnel using exponent, min and max is, that I wanted to automatically convert the Vraymaterial properties into a shader, given the IOR of the material.

        float fresnel(float IOR, float3 normal, float3 viewDir)
        {
        float nAirIOR = 1.000293;
        float matIOR = IOR;
        float R0 = pow((nAirIOR - matIOR), 2) / pow ((nAirIOR + matIOR), 2);
        float blendAmount = R0 + (1 - R0) * pow (1.0 - dot(normal, viewDir ), 5.0 );
        return clamp(blendAmount, 0.0, 1.0);
        }

        Thank you and best regards

        Robert
        Last edited by Robert1977; 19-09-2014, 04:51 AM.
        Robert

        Max, VRay, Fusion:

        https://www.youtube.com/watch?v=g5fSLrVzpxg
        https://www.youtube.com/watch?v=bpmJgTb_9Ro

        Comment


        • #5
          Here is a simplified version of what V-Ray does:
          Code:
          BRDFVRayMtl::init() {
          	// ....
          	local_ior=par.refract_ior;
          	fresnel_ior=par.reflect_ior;
          
          	VR::Vector nrm=par.normal;
          
          	reflectDir=Vlado::getReflectDir(rc->rayparams.viewDir, nrm);
          	
          	// Check if the view direction and the reflection direction are on opposite sides
          	// of the geometric normal. If yes, reflect with respect to the geometric normal
          	// and not the smooth one - otherwise shading errors appear at grazing angles.
          	float r0=-dotf(rc->rayparams.viewDir, par.gnormal);
          	float r1=dotf(reflectDir, par.gnormal);
          	if (r0*r1<0.0f) {
          		nrm=par.gnormal;
          		reflectDir=VR::getReflectDir(rc->rayparams.viewDir, nrm);
          	}
          
          	int needFresnel=(!par._reflect_color.isBlack() && par.pc->reflect_fresnel);
          	par.internalReflection=false;
          
          	// Compute refraction direction. We need this for computing the Fresnel term,
          	// and also obviously when we have refraction.
          	if (!par._refract_color.isBlack() || needFresnel) {
          		refractDir=VR::getRefractDir(rc->rayparams.viewDir, nrm, local_ior, par.internalReflection);
          	} else {
          		refractDir=-nrm;
          	}
          
          	// Compute the Fresnel term
          	float Fresnel=1.0f;
          
          	if (par.internalReflection) {
          		// Total internal reflection
          		Fresnel=1.0f;
          		local_ior=1.0f;
          		fresnel_ior=1.0f;
          	} else {
          		if (par.backside && !par.pc->reflect_back) {
          			// We are hitting the back side and those reflections are disabled
          			Fresnel=0.0f;
          		} else if (needFresnel) {
          			if (fabsf(fresnel_ior-1.0f)<1e-6f) Fresnel=0.0f;
          			else {
          				// We use a modified Fresnel function that keeps total internal reflections exactly.
          				Fresnel=VR::getFresnelCoeff(rc->rayparams.viewDir, par.normal, refractDir, fresnel_ior);
          				Fresnel=VR::clamp(Fresnel, 0.0f, 1.0f);
          			}
          		} else Fresnel=1.0f;
          	}
          
          	// Dim the reflection color by the Fresnel coefficient
          	par._reflect_color*=Fresnel;
          
          	// Dim the refraction by the reflection color
          	if (par.pc->preserveMode==preserveMode_rgb) par._refract_color*=par._reflect_color.whiteComplement(); // RGB energy preservation
          	else par._refract_color*=1.0f-par._reflect_color.intensity(); // Monochrome energy preservation
          
          	// Dim the diffuse by the reflection+refraction color
          	VR::Color rsum=par._reflect_color+par._refract_color;
          	if (par.pc->preserveMode==preserveMode_rgb) par._diffuse_color*=rsum.whiteComplement(); // RGB energy preservation
          	else par._diffuse_color*=1.0f-rsum.intensity(); // Monochrome energy preservation
          
          	// The resulting par._diffuse_color, par._reflect_color and par._refract_color are used for actual lighting calculations.
          	// The results are simply summed together.
          }
          Additionally, we use the following code for the Fresnel coefficient:
          Code:
          inline float getFresnelCoeff(const Vector &viewDir, const Vector &normal, const Vector &refractDir, float ior) {
          	if (fabsf(ior-1.0f)<1e-6f) return 0.0f;
          
          	float cosIn=-dotf(viewDir, normal);
          	float cosR=-dotf(refractDir, normal);
          
          	if (cosIn>1.0f-1e-12f || cosR>1.0f-1e-12f) {
          		// View direction is perpendicular to the surface
          		return sqr((ior-1.0f)/(ior+1.0f));
          	}
          
          	float ks=(cosR/cosIn)*ior;
          	float Fs=sqr((ks-1.0f)/(ks+1.0f));
          
          	float kp=(cosIn/cosR)*ior;
          	float Fp=sqr((kp-1.0f)/(kp+1.0f));
          
          	return 0.5f*(Fs+Fp);
          }
          Best regards,
          Vlado
          I only act like I know everything, Rogers.

          Comment

          Working...
          X