diff --git a/RayTracer/shape/Sphere.cpp b/RayTracer/shape/Sphere.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ad940f4100828cc7670bea0c67ca11e543900df
--- /dev/null
+++ b/RayTracer/shape/Sphere.cpp
@@ -0,0 +1,44 @@
+#define _USE_MATH_DEFINES
+
+#include "Sphere.h"
+#include "math.h"
+
+namespace shapes {
+Sphere::Sphere(float radius, const std::shared_ptr<material::Material>& material)
+    : radius(radius)
+    , material(material)
+{
+}
+std::shared_ptr<cam::Hit> Sphere::intersect(const cam::Ray& r)
+{
+    util::Vec3 d = r.d;
+    util::Vec3 x0 = r.x0;
+    float a = util::dot(d, d);
+    float b = 2 * util::dot(x0, d);
+    float c = util::dot(x0, x0) - (radius * radius);
+    float discrim = b * b - 4 * a * c;
+
+    if (discrim >= 0) {
+        double t1 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
+
+        if (r.in_range(t1)) {
+            util::Vec3 t1HitPoint = r(t1);
+            double theta = acos(t1HitPoint.y() / radius);
+            double phi = M_PI + atan2(t1HitPoint.x(), t1HitPoint.z());
+            return std::make_shared<cam::Hit>(cam::Hit(t1HitPoint, t1HitPoint, t1, material));
+        } else {
+            double t2 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
+            if (r.in_range(t2)) {
+                util::Vec3 t2HitPoint = r(t2);
+                double theta = acos(t2HitPoint.y() / radius);
+                double phi = M_PI + atan2(t2HitPoint.x(), t2HitPoint.z());
+                return std::make_shared<cam::Hit>(cam::Hit(t2HitPoint, t2HitPoint, t2, material));
+            } else {
+                return nullptr;
+            }
+        }
+    } else {
+        return nullptr;
+    }
+}
+}
diff --git a/RayTracer/shape/Sphere.h b/RayTracer/shape/Sphere.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd980d0b9d45894d736dd64a915f5499c6e90163
--- /dev/null
+++ b/RayTracer/shape/Sphere.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Shape.h"
+
+namespace shapes {
+class Sphere : public Shape {
+public:
+    Sphere(float radius, const std::shared_ptr<material::Material>& material);
+    std::shared_ptr<cam::Hit> intersect(const cam::Ray& r);
+
+private:
+    std::shared_ptr<material::Material> material;
+    const float radius;
+};
+}