public Vector3 shading(Vector3 pos, Vector3 norm, Ray ray, Actor actor, bool isShade) { // 点光源 var l = light - pos; var l2 = l.LengthSquared(); l.Normalize(); // 視線 var dir = ray.Position - pos; dir.Normalize(); // ハーフベクトル var h = dir + l; h.Normalize(); var ln = Vector3.Dot(l, norm); var hn = Vector3.Dot(h, norm); if (ln < 0) ln = 0; if (hn < 0) hn = 0; var dst = actor.GetColor(isShade ? 0.0f : ln, hn, pos); // 光源の色の反映 dst.X *= lightColor.X; dst.Y *= lightColor.Y; dst.Z *= lightColor.Z; // 光の強さの適当な補正 //dst *= Math.Min(1.5f, 500000.0f / (10000.0f + l2)); //dst *= Math.Min(1.0f, l.Y + 0.1f); return dst; }
Vector3 trace(Ray ray, Actor sender, int depth) { if (depth > MAX_DEPTH) return Vector3.Zero; var nearestNorm = Vector3.Zero; var nearestPos = Vector3.Zero; Actor nearestActor = null; var color = Vector3.Zero; foreach (var actor in actors) { if (actor == sender) continue; var norm = Vector3.Zero; var pos = Vector3.Zero; if (actor.isIntersect(ray, out norm, out pos)) { var d1 = pos - ray.Position; var d2 = nearestPos - ray.Position; if (nearestActor == null) { nearestActor = actor; nearestNorm = norm; nearestPos = pos; } else if (d1.LengthSquared() < d2.LengthSquared()) { nearestActor = actor; nearestNorm = norm; nearestPos = pos; } } } if (nearestActor == null) { return Vector3.Zero; } var crl = nearestActor.material.reflection; var crr = nearestActor.material.refraction; var cr = nearestActor.material.refraction; // 反射ベクトル var v = ray.Direction - 2 * Vector3.Dot(nearestNorm, ray.Direction) * nearestNorm; v.Normalize(); var reflectionRay = new Ray(nearestPos, v); // 屈折ベクトル var vn = Vector3.Dot(ray.Direction, nearestNorm); float eta = 1.5f; // 屈折率 Vector3 t; if (vn < 0) { var d = 1 - (1 + vn) * (1 + vn) / (eta * eta); if (d < 0) { t = Vector3.Zero; } else { t = (-vn / eta - (float)Math.Sqrt(d)) * nearestNorm + (1 / eta) * ray.Direction; } } else { var d = (1 - vn) * (1 - vn) / (eta * eta); if (d < 0) { t = Vector3.Zero; } else { t = -(vn / eta - (float)Math.Sqrt(d)) * nearestNorm + eta * ray.Direction; } } t.Normalize(); var refractionRay = new Ray(nearestPos, t); var reflect = nearestActor.material.reflection <= 0.00001f ? Vector3.Zero : trace(reflectionRay, nearestActor, depth + 1); var refraction = nearestActor.material.refraction <= 0.00001f ? Vector3.Zero : trace(refractionRay, nearestActor, depth + 1); bool shade = false; foreach (var actor in actors) { if (actor == nearestActor) continue; var norm = Vector3.Zero; var pos = Vector3.Zero; var d = shader.light - nearestPos; d.Normalize(); if (actor.isIntersect(new Ray(nearestPos, d), out norm, out pos)) { shade = true; break; } } var diffuse = shader.shading(nearestPos, nearestNorm, ray, nearestActor, shade); return nearestActor.material.diffuse * diffuse + nearestActor.material.reflection * reflect + nearestActor.material.refraction * refraction; }