bool Cylinder::intersectCap(const Ray &localRay, double &t) { if (localRay.direction().y() < 0.0) t = (0.5 * m_length - localRay.origin().y()) / localRay.direction().y(); else if (localRay.direction().y() > 0.0) t = (-0.5 * m_length - localRay.origin().y()) / localRay.direction().y(); else return false; QVector4D p = localRay.along(t); if (p.x() * p.x() + p.z() * p.z() < m_rSq) return true; return false; }
QVector3D WhittedRenderer::trace(const Ray& primaryRay, int depth, const QList<Shape*>& shapes, const QList<Light*>& lights) { double minDist = std::numeric_limits<double>::max(); Shape* closestShape = nullptr; QVector3D shaded; if (m_grid->intersect(primaryRay, closestShape, minDist)) { auto material = closestShape->material(); shaded = material->ambientReflectivity() * m_ambientLightColor * material->colorVector(); QColor color = material ? material->color() : QColor(40, 40, 40); QVector3D diffuseColor(color.redF(), color.greenF(), color.blueF()); QVector4D hitPoint = primaryRay.along(minDist); QVector4D normalVector = closestShape->surfaceNormal(hitPoint, primaryRay); QVector4D viewVector = -primaryRay.direction(); foreach(Light* light, lights) { QVector3D emittance; QVector4D lightVector; light->sample(lightVector, emittance); lightVector = lightVector - hitPoint; float lightVectorLengthSquared = lightVector.lengthSquared(); float lightVectorLength = sqrt(lightVectorLengthSquared); lightVector.normalize(); Ray shadowRay(hitPoint, lightVector); double t; Shape* blockingShape; bool shadowRayHit = m_grid->intersect(shadowRay, blockingShape, t); if (!shadowRayHit || (shadowRayHit && (lightVectorLengthSquared < t * t))) { // Diffuse float dot = fmax(0.0f, QVector4D::dotProduct(lightVector, normalVector)) * material->diffuseReflectivity(); emittance *= 1 / (1 + 0.2 * lightVectorLength + 0.08 * lightVectorLengthSquared); shaded += dot * QVector3D(emittance.x() * diffuseColor.x(), emittance.y() * diffuseColor.y(), emittance.z() * diffuseColor.z()); // Specular if (material->specularReflectivity() > 0.0) { QVector4D reflectedLightVector = MathUtils::reflect(-lightVector, normalVector); // lightVector and normalVector are already normalized float dot = QVector4D::dotProduct(reflectedLightVector, viewVector); if (dot > 0.0) shaded += material->specularReflectivity() * pow(dot, material->shininess()) * emittance; } } }