Example #1
0
int main()
{
  Imath::Rand48 rng;

  float min = std::numeric_limits<float>::max(); 
  float max = -std::numeric_limits<float>::max();

  PerlinNoise::Ptr perlin(new PerlinNoise);

  for (int i = 0; i < 1000000; i++) {
    Vector p;
    p.x = rng.nextf() * 100;
    p.y = rng.nextf() * 100;
    p.z = rng.nextf() * 100;
    float noise = perlin->eval(p.x, p.y, p.z);
    min = std::min(min, noise);
    max = std::max(max, noise);
  }
  
  cout << "min: " << min << endl
       << "max: " << max << endl;
}
void
testTranslationRotationMatrix (const Imath::M44d& mat)
{
    std::cout << "Testing known translate/rotate matrix:\n " << mat;
    typedef Imath::Vec3<T> Vec;

    static Imath::Rand48 rand (2047);

    size_t numPoints = 7;
    std::vector<Vec> from;  from.reserve (numPoints);
    std::vector<Vec> to;    to.reserve (numPoints);
    for (size_t i = 0; i < numPoints; ++i)
    {
        Imath::V3d a (rand.nextf(), rand.nextf(), rand.nextf());
        Imath::V3d b = a * mat;

        from.push_back (Vec(a));
        to.push_back (Vec(b));
    }

    std::vector<T> weights (numPoints, T(1));
    const Imath::M44d m1 = procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], numPoints);
    const Imath::M44d m2 = procrustesRotationAndTranslation (&from[0], &to[0], numPoints);

    const T eps = sizeof(T) == 8 ? 1e-8 : 1e-4;
    for (size_t i = 0; i < numPoints; ++i)
    {
        const Imath::V3d a = from[i];
        const Imath::V3d b = to[i];
        const Imath::V3d b1 = a * m1;
        const Imath::V3d b2 = a * m2;

        assert ((b - b1).length() < eps);
        assert ((b - b2).length() < eps);
    }
    std::cout << "  OK\n";
}
void
testProcrustesWithMatrix (const Imath::M44d& m)
{
    std::cout << "Testing Procrustes algorithm with arbitrary matrix: \n" << m;
    std::vector<Imath::Vec3<T> > fromPoints;
    std::vector<Imath::Vec3<T> > toPoints;

    Imath::Rand48 random (1209);
    std::cout << "   numPoints: ";
    for (size_t numPoints = 1; numPoints < 10; ++numPoints)
    {
        std::cout << numPoints << " " << std::flush;
        fromPoints.clear(); toPoints.clear();
        for (size_t i = 0; i < numPoints; ++i)
        {
            const Imath::V3d fromPt (random.nextf(), random.nextf(), random.nextf());
            const Imath::V3d toPt = fromPt * m;
            fromPoints.push_back (Imath::Vec3<T>(fromPt));
            toPoints.push_back (Imath::Vec3<T>(toPt));
        }
        verifyProcrustes (fromPoints, toPoints);
    }
    std::cout << "OK\n";
}
Example #4
0
Imath::C3f radiance(Scene& scene, Ray& ray, Imath::Rand48& rnd, const int depth)
{
	Imath::V3d intersection_point, intersection_normal;
	int obj_id;
	if (!scene.intersect(ray, intersection_point, intersection_normal, obj_id))
	{
		return scene.bgColor;
	}

	Geometry geom = scene.geometries[obj_id];

	Imath::V3d orienting_normal = intersection_normal;
	if ((intersection_normal ^ ray.dir) > 0.0)
	{
		orienting_normal *= -1.0;
	}

	if (depth > LIMIT_DEPTH)
	{
		return geom.emission;
	}

	float reflect_ratio = (5.0f - static_cast<float>(depth)) / 5.0f;

	Imath::C3f inc_rad(0,0,0), weight(1,1,1);

	switch (geom.reflection)
	{
	case Reflection::Diffuse:
	{
		Imath::V3d w, u, v;
		w = orienting_normal;
		if (fabs(w.x) > 0.0000009)
		{
			u = (Imath::V3d(0.0, 1.0, 0.0) % w).normalized();
		}
		else
		{
			u = (Imath::V3d(1.0, 0.0, 0.0) % w).normalized();
		}
		v = w % u;
		double r1 = 2.0 * M_PI * rnd.nextf();
		double r2 = rnd.nextf();
		double rr2 = sqrt(r2);
		ray.pos = intersection_point;
		ray.dir = (u * cos(r1) * rr2 + v * sin(r1) * rr2 + w * sqrt(1.0 - r2)).normalized();
		inc_rad = radiance(scene, ray, rnd, depth + 1);
		weight = geom.color * reflect_ratio;
	}
		break;

	case Reflection::Specular:
		ray.pos = intersection_point;
		ray.dir -= intersection_normal * 2.0 * (intersection_normal ^ ray.dir);
		inc_rad = radiance(scene, ray, rnd, depth + 1);
		weight = geom.color * reflect_ratio;
		break;

	case Reflection::Refraction:
		bool into = (orienting_normal ^ intersection_normal) > 0.0;

		double default_refraction = 1.0;
		double object_refraction = 1.5;
		double ray_refraction;
		if (into)
		{
			ray_refraction = default_refraction / object_refraction;
		}
		else
		{
			ray_refraction = object_refraction / default_refraction;
		}
		double incident_dot = ray.dir ^ orienting_normal;
		double critical_factor = 1.0 - pow(ray_refraction, 2) * (1.0 - pow(incident_dot,2));

		Ray reflection_ray(intersection_point, ray.dir - intersection_normal * 2.0 * (intersection_normal ^ ray.dir));
		Ray refraction_ray(intersection_point, (ray.dir * ray_refraction - intersection_normal * (into ? 1.0 : -1.0) * (incident_dot * ray_refraction + sqrt(critical_factor))).normalized());

		// total reflection
		if (critical_factor < 0.0)
		{
			inc_rad = radiance(scene, reflection_ray, rnd, depth + 1);
			weight = geom.color * reflect_ratio;
			break;
		}

		double a = object_refraction - default_refraction;
		double b = object_refraction + default_refraction;
		double vertical_incidence_factor = pow(a, 2) / pow(b, 2);
		double c = 1.0 - (into ? -1.0 * incident_dot : (refraction_ray.dir ^ -1.0 * orienting_normal));
		double fresnel_incidence_factor = vertical_incidence_factor + (1.0 - vertical_incidence_factor) * pow(c,5);
		double radiance_scale = pow(ray_refraction, 2.0);
		double refraction_factor = (1.0 - fresnel_incidence_factor) * radiance_scale;

		double probability = 0.75 + fresnel_incidence_factor;
		if (depth > 2)
		{
			if (rnd.nextf() < probability)
			{
				inc_rad = radiance(scene, reflection_ray, rnd, depth + 1) * fresnel_incidence_factor;
				weight = geom.color * reflect_ratio;
			}
			else
			{
				inc_rad = radiance(scene, refraction_ray, rnd, depth + 1) * refraction_factor;
				weight = geom.color * reflect_ratio;
			}
		}
		else
		{
			inc_rad = 
				radiance(scene, reflection_ray, rnd, depth + 1) * fresnel_incidence_factor +
				radiance(scene, refraction_ray, rnd, depth + 1) * refraction_factor;
			weight = geom.color * reflect_ratio;
		}		

		break;
	}

	return geom.emission + weight * inc_rad;

}
void
testProcrustesImp ()
{
    // Test the empty case:
    Imath::M44d id = 
        procrustesRotationAndTranslation ((Imath::Vec3<T>*) 0, 
                                          (Imath::Vec3<T>*) 0,
                                          (T*) 0,
                                          0);
    assert (id == Imath::M44d());

    id = procrustesRotationAndTranslation ((Imath::Vec3<T>*) 0, 
                                           (Imath::Vec3<T>*) 0,
                                           0);
    assert (id == Imath::M44d());

    // First we'll test with a bunch of known translation/rotation matrices
    // to make sure we get back exactly the same points:
    Imath::M44d m;
    m.makeIdentity();
    testTranslationRotationMatrix<T> (m);

    m.translate (Imath::V3d(3.0, 5.0, -0.2));
    testTranslationRotationMatrix<T> (m);

    m.rotate (Imath::V3d(M_PI, 0, 0));
    testTranslationRotationMatrix<T> (m);
    
    m.rotate (Imath::V3d(0, M_PI/4.0, 0));
    testTranslationRotationMatrix<T> (m);

    m.rotate (Imath::V3d(0, 0, -3.0/4.0 * M_PI));
    testTranslationRotationMatrix<T> (m);

    m.makeIdentity();
    testWithTranslateRotateAndScale<T> (m);

    m.translate (Imath::V3d(0.4, 6.0, 10.0));
    testWithTranslateRotateAndScale<T> (m);

    m.rotate (Imath::V3d(M_PI, 0, 0));
    testWithTranslateRotateAndScale<T> (m);

    m.rotate (Imath::V3d(0, M_PI/4.0, 0));
    testWithTranslateRotateAndScale<T> (m);

    m.rotate (Imath::V3d(0, 0, -3.0/4.0 * M_PI));
    testWithTranslateRotateAndScale<T> (m);

    m.scale (Imath::V3d(2.0, 2.0, 2.0));
    testWithTranslateRotateAndScale<T> (m);

    m.scale (Imath::V3d(0.01, 0.01, 0.01));
    testWithTranslateRotateAndScale<T> (m);

    // Now we'll test with some random point sets and verify
    // the various Procrustes properties:
    std::vector<Imath::Vec3<T> > fromPoints;
    std::vector<Imath::Vec3<T> > toPoints;
    fromPoints.clear(); toPoints.clear();

    for (size_t i = 0; i < 4; ++i)
    {
        const T theta = T(2*i) / T(M_PI);
        fromPoints.push_back (Imath::Vec3<T>(cos(theta), sin(theta), 0));
        toPoints.push_back (Imath::Vec3<T>(cos(theta + M_PI/3.0), sin(theta + M_PI/3.0), 0));
    }
    verifyProcrustes (fromPoints, toPoints);

    Imath::Rand48 random (1209);
    for (size_t numPoints = 1; numPoints < 10; ++numPoints)
    {
        fromPoints.clear(); toPoints.clear();
        for (size_t i = 0; i < numPoints; ++i)
        {
            fromPoints.push_back (Imath::Vec3<T>(random.nextf(), random.nextf(), random.nextf()));
            toPoints.push_back (Imath::Vec3<T>(random.nextf(), random.nextf(), random.nextf()));
        }
    }
    verifyProcrustes (fromPoints, toPoints);

    // Test with some known matrices of varying degrees of quality:
    testProcrustesWithMatrix<T> (m);

    m.translate (Imath::Vec3<T>(3, 4, 1));
    testProcrustesWithMatrix<T> (m);

    m.translate (Imath::Vec3<T>(-10, 2, 1));
    testProcrustesWithMatrix<T> (m);

    Imath::Eulerd rot (M_PI/3.0, 3.0*M_PI/4.0, 0);
    m = m * rot.toMatrix44();
    testProcrustesWithMatrix<T> (m);

    m.scale (Imath::Vec3<T>(1.5, 6.4, 2.0));
    testProcrustesWithMatrix<T> (m);

    Imath::Eulerd rot2 (1.0, M_PI, M_PI/3.0);
    m = m * rot.toMatrix44();

    m.scale (Imath::Vec3<T>(-1, 1, 1));
    testProcrustesWithMatrix<T> (m);

    m.scale (Imath::Vec3<T>(1, 0.001, 1));
    testProcrustesWithMatrix<T> (m);

    m.scale (Imath::Vec3<T>(1, 1, 0));
    testProcrustesWithMatrix<T> (m);
}
void
verifyProcrustes (const std::vector<Imath::Vec3<T> >& from, 
                  const std::vector<Imath::Vec3<T> >& to)
{
    typedef Imath::Vec3<T> V3;

    const T eps = std::sqrt(std::numeric_limits<T>::epsilon());

    const size_t n = from.size();

    // Validate that passing in uniform weights gives the same answer as
    // passing in no weights:
    std::vector<T> weights (from.size());
    for (size_t i = 0; i < weights.size(); ++i)
        weights[i] = 1;
    Imath::M44d m1 = procrustesRotationAndTranslation (&from[0], &to[0], n);
    Imath::M44d m2 = procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n);
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            assert (std::abs(m1[i][j] - m2[i][j]) < eps);

    // Now try the weighted version:
    for (size_t i = 0; i < weights.size(); ++i)
        weights[i] = i+1;

    Imath::M44d m = procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n);

    // with scale:
    Imath::M44d ms = procrustesRotationAndTranslation (&from[0], &to[0], &weights[0], n, true);

    // Verify that it's orthonormal w/ positive determinant.
    const T det = m.determinant();
    assert (std::abs(det - T(1)) < eps);

    // Verify orthonormal:
    Imath::M33d upperLeft;
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            upperLeft[i][j] = m[i][j];
    Imath::M33d product = upperLeft * upperLeft.transposed();
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            const double expected = (i == j ? 1.0 : 0.0);
            assert (std::abs(product[i][j] - expected) < eps);
        }
    }

    // Verify that nearby transforms are worse:
    const size_t numTries = 10;
    Imath::Rand48 rand (1056);
    const double delta = 1e-3;
    for (size_t i = 0; i < numTries; ++i)
    {
        // Construct an orthogonal rotation matrix using Euler angles:
        Imath::Eulerd diffRot (delta * rand.nextf(), delta * rand.nextf(), delta * rand.nextf());
 
        assert (procrustesError (&from[0], &to[0], &weights[0], n, m * diffRot.toMatrix44()) >
                procrustesError (&from[0], &to[0], &weights[0], n, m));

        // Try a small translation:
        Imath::V3d diffTrans (delta * rand.nextf(), delta * rand.nextf(), delta * rand.nextf());
        Imath::M44d translateMatrix;
        translateMatrix.translate (diffTrans);
        assert (procrustesError (&from[0], &to[0], &weights[0], n, m * translateMatrix) >
                procrustesError (&from[0], &to[0], &weights[0], n, m));
    }

    // Try a small scale:
    Imath::M44d newMat = ms;
    const double scaleDiff = delta;
    for (size_t i = 0; i < 3; ++i)
        for (size_t j = 0; j < 3; ++j)
            newMat[i][j] = ms[i][j] * (1.0 + scaleDiff);
    assert (procrustesError (&from[0], &to[0], &weights[0], n, newMat) >
            procrustesError (&from[0], &to[0], &weights[0], n, ms));

    for (size_t i = 0; i < 3; ++i)
        for (size_t j = 0; j < 3; ++j)
            newMat[i][j] = ms[i][j] * (1.0 - scaleDiff);
    assert (procrustesError (&from[0], &to[0], &weights[0], n, newMat) >
            procrustesError (&from[0], &to[0], &weights[0], n, ms));

    //
    // Verify the magical property that makes shape springs work:
    // when the displacements Q*A-B, times the weights,
    // are applied as forces at B,
    // there is zero net force and zero net torque.
    //
    {
        Imath::V3d center (0, 0, 0);

        Imath::V3d netForce(0);
        Imath::V3d netTorque(0);
        for (int iPoint = 0; iPoint < n; ++iPoint)
        {
            const Imath::V3d force = weights[iPoint] * (from[iPoint]*m - to[iPoint]);
            netForce += force;
            netTorque += to[iPoint].cross (force);
        }

        assert (netForce.length2() < eps);
        assert (netTorque.length2() < eps);
    }
}