public PointLight(Vector pos, Color color, double value) : base(pos, color, value) { this.Pos = pos; this.Color = color; this.Value = value; }
public Sphere(Vector position, double radius, MaterialFunc materialFunc) : base(materialFunc) { this.Position = position; this.Radius = radius; box = createBoundingBox(); }
public BoundingBox(Vector leftTopFront, Vector rightBottomBack) { if (!leftTopFront.SmallerAllCoordsThan(rightBottomBack)) throw new Exception("Box specified incorrectly"); this.LeftTopFront = leftTopFront; this.RightBottomBack = rightBottomBack; }
/// <summary> /// Returns material at given point. /// </summary> /// <param name="v">Point in space.</param> public Material GetMaterialAt(Vector v) { if (this.materialFunc == null) { return this.material; } else { return materialFunc(v); } }
private void initFromVertices(Vector[] vertices) { if (vertices.Length < 3) { throw new ArgumentException("Cannot construct plane from less than 3 vertices."); } Vector v1, v2; v1 = vertices[1] - vertices[0]; v2 = vertices[2] - vertices[0]; this.Normal = v1.Cross(v2); this.Normal.Normalize(); // from plane equation by inserting vertices[0] (or [1] or [2]) this.D = -vertices[0].Dot(this.Normal); }
public override Vector GetNormalAt(Vector v) { // determine to which side "center to v" points Vector outwards = v - center; // transform to [1x1x1] cube outwards.X /= (box.RightBottomBack.X - box.LeftTopFront.X); outwards.Y /= (box.RightBottomBack.Y - box.LeftTopFront.Y); outwards.Z /= (box.RightBottomBack.Z - box.LeftTopFront.Z); double absX = Math.Abs(outwards.X); double absY = Math.Abs(outwards.Y); double absZ = Math.Abs(outwards.Z); double maxCoord = Math.Max(absX, Math.Max(absY, absZ)); if (maxCoord == absX) return outwards.X < 0 ? vLeft : vRight; else if (maxCoord == absY) return outwards.Y < 0 ? vUp : vDown; else return outwards.Z < 0 ? vBack : vForward; }
public override Vector GetNormalAt(Vector v) { Vector n = v - this.Position; // normalize (divide by radius) n.Mul(1.0 / Radius); return n/* + new Vector(Math.Sin(v.X*v.Y * 15) * 0.05, Math.Cos(v.Z * 12) * 0.05, Math.Cos(v.Y * 8)*0.08)*/; }
public Plane(Vector[] vertices, MaterialFunc materialFunc) : base(materialFunc) { initFromVertices(vertices); }
public Light(Vector pos, Color color, double value) { this.Pos = pos; this.Color = color; this.Value = value; }
private BoundingBox createBoundingBox() { double x = Math.Min(Vertices[0].X, Math.Min(Vertices[1].X, Vertices[2].X)); double y = Math.Min(Vertices[0].Y, Math.Min(Vertices[1].Y, Vertices[2].Y)); double z = Math.Min(Vertices[0].Z, Math.Min(Vertices[1].Z, Vertices[2].Z)); Vector leftUpFront = new Vector(x, y, z); x = Math.Max(Vertices[0].X, Math.Max(Vertices[1].X, Vertices[2].X)); y = Math.Max(Vertices[0].Y, Math.Max(Vertices[1].Y, Vertices[2].Y)); z = Math.Max(Vertices[0].Z, Math.Max(Vertices[1].Z, Vertices[2].Z)); return new BoundingBox(leftUpFront - new Vector(Constants.Epsilon, Constants.Epsilon, Constants.Epsilon), new Vector(x + Constants.Epsilon, y + Constants.Epsilon, z + Constants.Epsilon)); }
/// <summary> /// Cross product. /// </summary> public Vector Cross(Vector v) { return new Vector(Y * v.Z - Z * v.Y, Z * v.X - X * v.Z, X * v.Y - Y * v.X); }
/// <summary> /// Linear combination. /// </summary> public static Vector Combine(Vector v1, double t1, Vector v2, double t2) { return new Vector(v1.X * t1 + v2.X * t2, v1.Y * t1 + v2.Y * t2, v1.Z * t1 + v2.Z * t2); }
/// <summary> /// Splits node's primitives into 8 new children nodes. /// </summary> private void split() { if (boundingBox == null) throw new Exception("Cannot split null bounding box"); try { this.childs = new OctreeNode[8]; for (int i = 0; i < 8; i++) { childs[i] = new OctreeNode(); childs[i].boundingBox = new BoundingBox(new Vector(), new Vector()); } double dx2 = (boundingBox.RightBottomBack.X - boundingBox.LeftTopFront.X) / 2; double dy2 = (boundingBox.RightBottomBack.Y - boundingBox.LeftTopFront.Y) / 2; double dz2 = (boundingBox.RightBottomBack.Z - boundingBox.LeftTopFront.Z) / 2; childs[0].boundingBox.LeftTopFront = boundingBox.LeftTopFront; childs[1].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(dx2, 0, 0); childs[2].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(0, dy2, 0); childs[3].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(dx2, dy2, 0); childs[4].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(0, 0, dz2); childs[5].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(dx2, 0, dz2); childs[6].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(0, dy2, dz2); childs[7].boundingBox.LeftTopFront = boundingBox.LeftTopFront + new Vector(dx2, dy2, dz2); Vector sizeVector = new Vector(dx2, dy2, dz2); // all childs same size for (int i = 0; i < 8; i++) { childs[i].boundingBox.RightBottomBack = childs[i].boundingBox.LeftTopFront + sizeVector; } // distribute primitives into children foreach (Primitive primitive in primitives) { // primitive may fall into multiple children at the same time // ideally it will fall in only 1 child for (int i = 0; i < 8; i++) { if (primitive.BoundingBox.Intersects(childs[i].boundingBox)) { childs[i].Add(primitive); } } } primitives = null; } catch { // in case of exception clean up any inconsistencies this.childs = null; this.boundingBox = BoundingBox.Zero; throw; } }
public BoxPrimitive(Vector leftTopFront, Vector rightBottomBack, MaterialFunc matFunc) : base(matFunc) { box = new BoundingBox(leftTopFront, rightBottomBack); center = Vector.Combine(leftTopFront, 1.0, (rightBottomBack - leftTopFront), 0.5); }
/// <summary> /// Multiplies vector by matrix including translation. /// </summary> public static Vector operator *(Matrix m, Vector v) { Vector result = new Vector(); // calc result vector coordinates for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { result[i] += m[i, j] * v[j]; } // add translation, we suppose that 4th coord of the vector is always 1 result[i] += m[i, 3]; } return result; }
/// <summary> /// Returns surface normal at given point. /// </summary> /// <param name="v">Point in space.</param> public abstract Vector GetNormalAt(Vector v);
public override Vector GetNormalAt(Vector v) { return plane.Normal/* + new Vector(Math.Sin(v.x * 8) * 0.05, Math.Cos(v.z * 8) * 0.05, 0)*/; }
/// <summary> /// Dot product. /// </summary> public double Dot(Vector v) { return X * v.X + Y * v.Y + Z * v.Z; }
/// <summary> /// Tells if given vector lies on negative side of this plane. /// </summary> internal bool liesOnNegativeSide(ref Vector v) { return (Normal.Dot(v) + d < -Constants.Epsilon); }
/// <summary> /// Returns true if all coords of this vector are smaller than corresponding v coords. /// </summary> public bool SmallerAllCoordsThan(Vector v) { return this.X <= v.X && this.Y <= v.Y && this.Z <= v.Z; }
public Plane(Vector normal, double d, MaterialFunc materialFunc) : base(materialFunc) { this.Normal = normal; this.D = d; }
/// <summary> /// Returns true if any coord of this vector is smaller than corresponding v coord. /// </summary> public bool SmallerAnyCoordThan(Vector v) { return this.X <= v.X || this.Y <= v.Y || this.Z <= v.Z; }
public override Vector GetNormalAt(Vector v) { return this.Normal; }
public bool Contains(Vector v) { return (v.X > LeftTopFront.X && v.X < RightBottomBack.X) && (v.Y > LeftTopFront.Y && v.Y < RightBottomBack.Y) && (v.Z > LeftTopFront.X && v.Z < RightBottomBack.Z); }
/// <summary> /// Gets lightness and specular ligthness at given point in the scene. /// </summary> /// <param name="specularLightness">Returned specular lightness.</param> /// <param name="pos">Point in space where to calc ligthness.</param> /// <param name="reflectionDir">Direction of reflection.</param> /// <param name="normalDir">Direction of normal.</param> /// <param name="surfaceSpecular">Specular of the material.</param> /// <returns></returns> private Color lightColorAt(Vector pos, out double specularLightness, Vector vReflection, Vector normal, double surfaceSpecular) { Ray shadowRay = new Ray(); shadowRay.Origin = pos; Color result = Color.Black; specularLightness = 0.0; foreach (Light light in this.lights) { int visibleRayCount = 0; // test all rays to this light for (int i = 0; i < light.GetRayCount(); i++) { shadowRay.Direction = light.GetNextRaySource() - shadowRay.Origin; // only front sides get lit if (shadowRay.Direction.Dot(normal) >= Constants.Epsilon) { double isectDistance = 0; objects.GetClosestIntersection(ref shadowRay, out isectDistance); //double isectDistance2 = isectDistance * isectDistance; //light visible from pos? //if (!(isectDistance2 > Constants.Epsilon && isectDistance2 < shadowRay.Direction.LenSquared - Constants.Epsilon)) double lightDist2 = shadowRay.Direction.LenSquared; shadowRay.Direction.Normalize(); if (!(isectDistance > Constants.Epsilon && isectDistance*isectDistance < lightDist2 - Constants.Epsilon)) { visibleRayCount++; Vector reflectionNorm = vReflection; reflectionNorm.Normalize(); // is reflected ray pointing towards light? double specularDot = reflectionNorm.Dot(shadowRay.Direction); if (specularDot > -Constants.Epsilon) { specularDot *= specularDot; specularDot *= specularDot; specularDot *= specularDot; specularDot *= specularDot; specularDot *= specularDot; // ^32 specularLightness += specularDot; } } } } result = Color.Combine(result, 1.0, light.Color, visibleRayCount / (double)light.GetRayCount() * light.Value * shadowRay.Direction.Dot(normal)); } specularLightness *= surfaceSpecular; return result; }
private static void addSphereGrid(ScnFile file, int xs, int ys, int zs) { Material mat = getRandMaterial(); file.Materials.Add(mat); // real dimensions double xw = 8; double yw = 8; double zw = 8; for (int x = 0; x < xs; x++) { for (int y = 0; y < ys; y++) { for (int z = 0; z < zs; z++) { Vector center = new Vector(-4 + x / (double)xs * xw, -4 + y / (double)ys * yw, 2 + z / (double)zs * zw); file.Primitives.Add(new Sphere(center, 0.05/*rand(0.06, 0.16)*/, mat)); } } } }