問1
三次元ベクトルクラスVec3を作れ。加減(+, -)とスカラー倍(*, /)を定義せよ。
問2
2つのVec3を受けとり、内積を返す関数double dot(const Vec3& v1, const Vec3& v2)を作れ。
問3
Vec3クラスに長さを求めるメンバ関数double length() const を追加せよ。
解答例
#include <cstdio>
#include <cmath>
class Vec3 {
public:
double x;
double y;
double z;
Vec3() {
x = y = z = 0;
};
Vec3(double _x, double _y, double _z) {
x = _x;
y = _y;
z = _z;
};
double length() const {
return std::sqrt(x*x + y*y + z*z);
};
};
Vec3 operator+(const Vec3& v1, const Vec3& v2) {
return Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
Vec3 operator-(const Vec3& v1, const Vec3& v2) {
return Vec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
Vec3 operator*(double k, const Vec3& v) {
return Vec3(k * v.x, k * v.y, k * v.z);
}
Vec3 operator*(const Vec3& v, double k) {
return k*v;
}
Vec3 operator/(double k, const Vec3& v) {
return Vec3(k / v.x, k / v.y, k / v.z);
}
Vec3 operator/(const Vec3& v, double k) {
return Vec3(v.x / k, v.y / k, v.z / k);
}
double dot(const Vec3& v1, const Vec3& v2) {
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}
int main() {
Vec3 v1(1, 1, 1);
Vec3 v2(2, 2, 2);
Vec3 v3 = v1 + v2;
printf("%f\n", dot(v1, v2));
printf("%f\n", v3.length());
return 0;
}
問4
作成したVec3クラスを使って、球を表すクラスSphereを作れ。球は中心座標(Vec3)と半径(double)をメンバ変数として持つとする。
解答例
class Sphere {
public:
Vec3 center; //中心座標
double radius; //半径
Sphere(const Vec3& center, double radius) : center(center), radius(radius) {};
};
問5
作成したVec3クラスを使って、直線を表すクラスRayを作れ。直線は始点(Vec3)と方向(Vec3)をメンバ変数として持つとする。
解答例
class Ray {
public:
Vec3 origin; //始点
Vec3 direction; //方向
Ray(const Vec3& origin, const Vec3& direction) : origin(origin), direction(direction) {};
};
問6(レイトレ)
SphereにRayとの衝突計算を行うメンバ関数bool intersect(const Ray& ray) const
を作れ。衝突したらtrueを、衝突しない場合はfalseを返す。直線の方向を前側としたときに、直線の始点より後側で衝突した場合もfalseとする。
解答例
class Sphere {
public:
Vec3 center;
double radius;
Sphere(const Vec3& center, double radius) : center(center), radius(radius) {};
bool intersect(const Ray& ray) const {
double d_norm = ray.direction.length();
double oc_norm = (ray.origin - center).length();
double a = d_norm*d_norm;
double b = 2*dot(ray.direction, ray.origin - center);
double c = oc_norm*oc_norm - radius*radius;
double D = b*b - 4*a*c;
if(D < 0) return false;
//解の候補
double t1 = (-b - std::sqrt(D))/(2*a);
double t2 = (-b + std::sqrt(D))/(2*a);
//衝突距離
double t = t1;
if(t < 0) {
t = t2;
if(t < 0) return false;
}
return true;
}
};