Esempio n. 1
0
vec3 Heightmap::getInterpolatedNormalAt(float x, float z) {
    if(0.0f <= x && x <= 1.0f && 0.0f <= z && z <= 1.0f) {
        int col1 = floor<int>(x * (float)(columns + 1));
        int col2 = col1 + 1;
        int row1 = floor<int>(z * (float)(rows + 1));
        int row2 = row1 + 1;
        vec3 n1 = getNormalAt(col1, row1);
        vec3 n2 = getNormalAt(col2, row1);
        vec3 n3 = getNormalAt(col1, row2);
        vec3 n4 = getNormalAt(col2, row2);
        return normalize(n1 + n2 + n3 + n4);
    }
    return vec3();
}
Esempio n. 2
0
/**
 * Computes the point intersected and the normal at this point when a ray is cast. 
 * Point Hit and Normal Hit attributes are only modified if intersection is detected, otherwise
 * returns only false result 
 * 
 * To test intersection with a sphere, we locate the point along the ray closest
 * to the center of the sphere and compare it with the radius.
 * 
 * @param ray Ray to test intersection
 * @param pointHit Point hit by the ray, if intersection is detected
 * @param normalHit Normal of the surface at the point that is hit, if intersection is detected
 * @return Boolean indicating whether intersection was detected or not
 */
bool Sphere::hasIntersection(Ray* ray, Point3D* point_hit, Vector3D* normal_hit){
    //Geometric Solution
    
    //1. Generate a Vector going from the origin of the Ray to the center of the Sphere
    double vector_to_sphere_center_x = this->center_->getX() - ray->getOrigin()->getX();
    double vector_to_sphere_center_y = this->center_->getY() - ray->getOrigin()->getY();
    double vector_to_sphere_center_z = this->center_->getZ() - ray->getOrigin()->getZ();
    double distance_to_sphere_center = sqrt(vector_to_sphere_center_x * vector_to_sphere_center_x + 
                                            vector_to_sphere_center_y * vector_to_sphere_center_y + 
                                            vector_to_sphere_center_z * vector_to_sphere_center_z);
    
    //2. Compute the Dot Product of this vector and the original Ray
    //Note: This also the distance from the ray origin to a point that forms a right angle with the sphere center pt
    double distance_to_test_point = vector_to_sphere_center_x * ray->getDirection()->getX() + 
                                    vector_to_sphere_center_y * ray->getDirection()->getY() + 
                                    vector_to_sphere_center_z * ray->getDirection()->getZ();
    
    //3. Reject if the Sphere is not in the direction of the Ray (Dot Product is Negative)
    if(distance_to_test_point < 0){
        return false;
    }
    
    //4. Compute the distance to the closest point from the sphere center that exists along the ray by using the Pythagorean theorem
    //     along with the right triangle formed by the ray, the vector from the ray origin to the center, and the vector from the center to the closest pt on the ray
    double distance_from_sphere_center = sqrt(std::abs(distance_to_sphere_center * distance_to_sphere_center - distance_to_test_point * distance_to_test_point));
    
    //5. If this distance is greater than the radius, reject
    if(distance_from_sphere_center > this->radius_){
        return false;
    }
    
    //Compute the intersection pt and the normal
    
    //1. Find the amount of the ray penetrating the sphere up to the test point using the triangle formed by
    //     the radius and the distance to the closest pt on the sphere
    double penetration_amount = sqrt(this->radius_ * this->radius_ - distance_from_sphere_center * distance_from_sphere_center);
    
    //2. Subtract this distance from the distance from the origin to the closest pt on the ray to determine
    //      the distance from the origin to the intersection pt
    double distance_to_intersection = distance_to_test_point - penetration_amount;
    
    //3. Using parametric coordinates, find the point in 3D space where the sphere was intersected by the ray
    Point3D intersection_point = ray->findPoint(distance_to_intersection);
    
    //4. Return the intersection point and the normal at that point
    point_hit->setX(intersection_point.getX());
    point_hit->setY(intersection_point.getY());
    point_hit->setZ(intersection_point.getZ());
    
    Vector3D normal = getNormalAt(&intersection_point);
    normal_hit->setX(normal.getX());
    normal_hit->setY(normal.getY());
    normal_hit->setZ(normal.getZ());
    
    return true;
}
Esempio n. 3
0
void MatingGearConstructor::constructListsOfPossibleMatingPoints() {

	hpvec2 nextPoint = getValueAt(m_startKnots);
	hpvec2 nextNormal = getNormalAt(m_startKnots);

	hpreal radToDegree = 180.0f / M_PI;

	for(hpuint sampleStep = 1; sampleStep < m_samplingRate; ++sampleStep) {

		hpvec2 point = nextPoint;
		hpvec2 normal = nextNormal;
		nextPoint = getValueAt(m_startKnots + sampleStep * m_stepSize);
		nextNormal = getNormalAt(m_startKnots + sampleStep * m_stepSize);

		MatingPoint matingPoint = getMatingPointOf(point, normal);
		m_allMatingPoints.push_back(matingPoint);

		hpreal normalAngleDiff = std::abs(asin(normal.x * nextNormal.y - normal.y * nextNormal.x));
		hpreal direction = (normal.x * nextNormal.y > normal.y * nextNormal.x) ? 1.0f : -1.0f;
		if(normalAngleDiff > m_maxDiffAngle) {
			hpuint nPartitions = static_cast<hpuint>(normalAngleDiff / m_maxDiffAngle);
			hpvec2 pointDiff = nextPoint - point;
			for(hpuint partition = 1; partition <= nPartitions; ++partition) {
				hpvec2 partitionPoint = point + pointDiff * static_cast<hpreal> (partition / nPartitions);
				hpvec2 partitionNormal = glm::rotate(normal, m_maxDiffAngle * direction * partition * radToDegree);
				MatingPoint matingPoint = getMatingPointOf(partitionPoint, partitionNormal);
				m_allMatingPoints.push_back(matingPoint);
			}
		}
	}
	//Go again through all collected points and look at the the intersection point on the reference radius.
	//If two following points differ too much, insert again mating points to get around this inaccuracy.
	//Remark: As the relation of the angle in the reference circle and the angle of the normal difference isn't
	//used here, no guarantee exists, that consecutive mating points have at least an angle of m_maxDiffAngle
	//viewed in the reference circle.
	// for(std::list<MatingPoint>::iterator it = m_allMatingPoints.begin(), nextIt = ++(m_allMatingPoints.begin()); nextIt != m_allMatingPoints.end(); ++it, ++nextIt) {
	// 	if(it->error == ErrorCode::NO_ERROR) {
	// 		hpvec2 point = it->point;
	// 		hpvec2 normal = it->normal;
	// 		hpvec2 nextPoint = nextIt->point;
	// 		hpvec2 nextNormal = nextIt->normal;

	// 		hpreal angleDiff = nextIt->intersectionRefRadiusAngle - it->intersectionRefRadiusAngle;
	// 		if(angleDiff > m_maxDiffAngle) {
	// 			cerr << "              refA.>maxAngle" << endl;
	// 			hpuint nPartitions = static_cast<hpuint>(std::abs(angleDiff) / m_maxDiffAngle);
	// 			hpvec2 pointDiff = nextPoint - point;

	// 			hpreal areaBetween = normal.x * nextNormal.y - normal.y * nextNormal.x;
	// 			hpreal angleBetweenNormals = asin(areaBetween); //angleA is negative or positive, depending on the normals
	// 			hpreal turnAnglePerStep = angleBetweenNormals / nPartitions;

	// 			for(hpuint partition = 1; partition <= nPartitions; ++partition) {
	// 				hpvec2 partitionPoint = point + pointDiff * static_cast<hpreal>(partition / nPartitions);
	// 				hpvec2 partitionNormal = glm::rotate(normal, turnAnglePerStep * partition * radToDegree);
	// 				MatingPoint matingPoint = getMatingPointOf(partitionPoint, partitionNormal);
	// 				m_allMatingPoints.insert(nextIt, matingPoint);
	// 				cerr << "refA.> mating point created" << endl;
	// 				++it;
	// 			}
	// 		}
	// 	}
	// }
}