#include "marbleshader.h" Color MarbleShader::shade(const Scene &scene, const Ray &ray) const { // Get the intersection point of the ray and the object Vector3d intersection = ray.origin + ray.direction * ray.length; // Create a noise value based on the intersection point float noise = getMarbleNoise(intersection, scale); // return noise * Color(1, 1, 1); // Use the noise value to determine the color of the marble Color color = baseColor; if (noise > 0.5) { float fade = 1 - (noise - 0.5f) * 2 * edgeFade; fade = clamp(fade, 0, 1); color = color + (veinColor - baseColor) * fade; } // Get the lighting for the point // for (const auto &light: scene.lights()) // { // Light::Illumination illum = light->illuminate(scene, ray); // color = color * illum.color; // } return color; } MarbleShader::MarbleShader(Color baseColor, Color veinColor, float scale, float edgeFade) : baseColor(baseColor), veinColor(veinColor), scale(scale), edgeFade(edgeFade) { } float MarbleShader::getMarbleNoise(Vector3d position, float scale) const { float x = position.x * scale; float y = position.y * scale; float z = position.z * scale; // Calculate the integer coordinates of the point int xi = (int)floor(x); int yi = (int)floor(y); int zi = (int)floor(z); int xo = xi + 1; int yo = yi + 1; int zo = zi + 1; // Calculate colors of the corners in a three-dimensional vector float cube[2][2][2]; srand(xi + yi * 57 + zi * 997); cube[0][0][0] = rand() / (float)RAND_MAX; srand(xo + yi * 57 + zi * 997); cube[1][0][0] = rand() / (float)RAND_MAX; srand(xi + yo * 57 + zi * 997); cube[0][1][0] = rand() / (float)RAND_MAX; srand(xo + yo * 57 + zi * 997); cube[1][1][0] = rand() / (float)RAND_MAX; srand(xi + yi * 57 + zo * 997); cube[0][0][1] = rand() / (float)RAND_MAX; srand(xo + yi * 57 + zo * 997); cube[1][0][1] = rand() / (float)RAND_MAX; srand(xi + yo * 57 + zo * 997); cube[0][1][1] = rand() / (float)RAND_MAX; srand(xo + yo * 57 + zo * 997); cube[1][1][1] = rand() / (float)RAND_MAX; // Calculate the fractional part of the point float xf = x - xi; float yf = y - yi; float zf = z - zi; // Interpolate along x float dot1 = smoothstep(cube[0][0][0], cube[1][0][0], xf); float dot2 = smoothstep(cube[0][1][0], cube[1][1][0], xf); float dot3 = smoothstep(cube[0][0][1], cube[1][0][1], xf); float dot4 = smoothstep(cube[0][1][1], cube[1][1][1], xf); // Interpolate along y float dot5 = smoothstep(dot1, dot2, yf); float dot6 = smoothstep(dot3, dot4, yf); // Interpolate along z float dot7 = smoothstep(dot5, dot6, zf); return dot7; } float MarbleShader::smoothstep(float edge0, float edge1, float x) const { float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); return t * t * (3 - 2 * t); } float MarbleShader::lerp(float a, float b, float t) const { return a + t * (b - a); } float MarbleShader::clamp(float x, float lower, float upper) const { return std::max(lower, std::min(x, upper)); }