#include "RenderMaterial.h" namespace raytry { RenderMaterial::RenderMaterial(QColor materialColor) : diffuseColor{materialColor}, ambientIntensity{0.1f}, diffuseIntensity{0.75f}, specularIntensity{0.15f}, specularFalloff{10.0f}, reflectivity{0}, transparency{0}, refractionIndex{0} { ambientColor = mixColor(materialColor, 0.25f); specularColor = addColors({204, 204, 204}, mixColor(materialColor, 0.2f)); } RenderMaterial::RenderMaterial(float ambientIntensity, const QColor &ambientColor, float diffuseIntensity, const QColor &diffuseColor, float specularIntensity, float specularFalloff, const QColor &specularColor) : ambientIntensity(ambientIntensity), ambientColor(ambientColor), diffuseIntensity(diffuseIntensity), diffuseColor(diffuseColor), specularIntensity(specularIntensity), specularFalloff(specularFalloff), specularColor(specularColor), reflectivity{0}, transparency{0}, refractionIndex{0} { assert(ambientIntensity >= 0 && ambientIntensity <= 1); assert(diffuseIntensity >= 0 && diffuseIntensity <= 1); assert(specularIntensity >= 0 && specularIntensity <= 1); assert(qFuzzyCompare(1.0f, ambientIntensity + diffuseIntensity + specularIntensity)); } RenderMaterial::RenderMaterial(float ambientIntensity, const QColor &ambientColor, float diffuseIntensity, const QColor &diffuseColor, float specularIntensity, float specularFalloff, const QColor &specularColor, float reflectivity, float transparency, float refractionIndex) : ambientIntensity(ambientIntensity), ambientColor(ambientColor), diffuseIntensity(diffuseIntensity), diffuseColor(diffuseColor), specularIntensity(specularIntensity), specularFalloff(specularFalloff), specularColor(specularColor), reflectivity(reflectivity), transparency(transparency), refractionIndex(refractionIndex) { assert(ambientIntensity >= 0 && ambientIntensity <= 1); assert(diffuseIntensity >= 0 && diffuseIntensity <= 1); assert(specularIntensity >= 0 && specularIntensity <= 1); assert(qFuzzyCompare(1.0f, ambientIntensity + diffuseIntensity + specularIntensity)); } std::optional RenderMaterial::refractionRay(const Ray &incoming, const QVector3D &hitpoint, const QVector3D &normal) const { // source: https://www.scratchapixel.com/code.php?id=32&origin=/lessons/3d-basic-rendering/phong-shader-BRDF float cosi = std::clamp(QVector3D::dotProduct(incoming.directionVec, normal), -1.0f, 1.0f); float etai = 1, etat = refractionIndex; QVector3D n = normal; if (cosi < 0) { cosi = -cosi; } else { std::swap(etai, etat); n= -normal; } float eta = etai / etat; float k = 1 - eta * eta * (1 - cosi * cosi); if (k < 0) { return std::nullopt; } else { return std::make_optional(hitpoint, eta * incoming.directionVec + (eta * cosi - sqrtf(k)) * n); } } Ray RenderMaterial::reflectionRay(const Ray &incoming, const QVector3D &hitpoint, const QVector3D &normal) const { // source: https://www.scratchapixel.com/code.php?id=32&origin=/lessons/3d-basic-rendering/phong-shader-BRDF return {hitpoint, incoming.directionVec - (2 * QVector3D::dotProduct(incoming.directionVec, normal) * normal)}; } QColor mixColor(QColor input, float intensity) { input.setRedF(input.redF() * intensity); input.setGreenF(input.greenF() * intensity); input.setBlueF(input.blueF() * intensity); return input; } QColor addColors(QColor color1, const QColor& color2) { color1.setRedF(color1.redF() + color2.redF()); color1.setGreenF(color1.greenF() + color2.greenF()); color1.setBlueF(color1.blueF() + color2.blueF()); return color1; } }