private Primitive RenderRay(Vector3D screenPos, ref Color3D acc) { Vector3D dir = (screenPos - _origin).Normalize(); Ray r = new Ray(_origin, dir); RaysCast++; double dist = 0; //trace ray return Raytrace(r, ref acc, 1, 1.0, ref dist, Constants.Samples, 1.0 / Constants.Samples); }
public bool RenderTiles() { //render scene long ticks = DateTime.Now.Ticks; // render remaining tiles int tx = _currCol, ty = _currRow; Vector3D tdir = _p1 + (tx * Constants.TileSize) * _dX + (ty * Constants.TileSize) * _dY; while (true) { Vector3D ldir = tdir; for (int y = 0; y < Constants.TileSize; y++) { Vector3D pdir = ldir; for (int x = 0; x < Constants.TileSize; x++) { Color3D acc = new Color3D(0, 0, 0); RenderRay(pdir, ref acc); int red = (int) (acc.R*256); int green = (int) (acc.G*256); int blue = (int) (acc.B*256); if (red > 255) red = 255; if (green > 255) green = 255; if (blue > 255) blue = 255; int pX = tx*Constants.TileSize + x; int pY = ty*Constants.TileSize + y; _frameBuffer.SetPixel(pX, pY, Color.FromArgb(red, green, blue)); pdir += _dX; } ldir += _dY; } tdir += _dX*Constants.TileSize; if (++tx == _xTiles) { tx = 0; ty++; tdir = _p1 + (ty*Constants.TileSize)*_dY; } if (ty < _yTiles) { //See if we've been drawing for a while now if (DateTime.Now.Ticks - ticks > 200) { //Return temporary to windows to let it redraw itself _currCol = tx; _currRow = ty; return false; //possibly still work to do } } else break; } //done return true; }
private Primitive Raytrace(Ray ray, ref Color3D acc, int depth, double rIndex, ref double distance, double samples, double sScale) { //trace primary ray distance = Constants.Maxdouble; Primitive prim = null; //find the nearest intersection RayHitDetection result = FindNearest(ray, ref distance, ref prim); //No hit? Return null then if (result == RayHitDetection.Miss || prim == null) return null; //Determine color at point of intersection Vector3D pi = ray.Origin + ray.Direction * distance; Color3D color = prim.GetColor(pi); Vector3D n = prim.GetNormal(pi); //trace lights foreach (Light light in _scene.Lights) { Vector3D l = null; double shade = CalcShade(light, pi, ref l, samples, sScale); if (shade > 0) { //calculate diffuse shading if (prim.Material.Diffuse > 0) { double dot = l.DotProduct(n); if (dot > 0) { double diff = dot * prim.Material.Diffuse * shade; //add diffuse component to ray color acc += diff*color*light.Color; } } // determine specular component using Schlick's BRDF approximation if (prim.Material.Specular > 0) { //point light source: sample once for specular highlight Vector3D r = l - 2 * l.DotProduct(n) * n; double dot = ray.Direction.DotProduct(r); if (dot > 0) { double spec = dot*prim.Material.Specular*shade/(50 - 50*dot + dot); //add specular component to ray color acc += spec*light.Color; } } } } //Calculate reflections if (Constants.ReflectionsEnabled) { double refl = prim.Material.Reflection; if (refl > 0 && depth < Constants.TraceDepth) { double drefl = prim.Material.DiffuseReflection; if (drefl > 0 && depth < 3) { //calculate diffuse reflection Vector3D rp = ray.Direction - 2*ray.Direction.DotProduct(n)*n; Vector3D rn1 = new Vector3D(rp.Z, rp.Y, -rp.X); Vector3D rn2 = rp.CrossProduct(rn1); refl *= sScale; for (int i = 0; i < Constants.Samples; i++) { double xoffs, yoffs; do { xoffs = (_twister.Rand - .5)*drefl; yoffs = (_twister.Rand - .5)*drefl; } while (xoffs*xoffs + yoffs*yoffs > drefl*drefl); Vector3D r = (rp + rn1*xoffs + rn2*yoffs*drefl).Normalize(); Color3D rCol = new Color3D(0, 0, 0); double dist = 0; Raytrace(new Ray(pi + r*Constants.Epsilon, r), ref rCol, depth + 1, rIndex, ref dist, samples*.25, sScale*4); RaysCast++; acc += refl*rCol*color; } } else { //calculate perfect reflection Vector3D r = ray.Direction - 2*ray.Direction.DotProduct(n)*n; Color3D rCol = new Color3D(0, 0, 0); double dist = 0; Raytrace(new Ray(pi + r*Constants.Epsilon, r), ref rCol, depth + 1, rIndex, ref dist, samples*.5, sScale*2); RaysCast++; acc += refl*rCol*color; } } } //Calculate refraction if (Constants.RefractionsEnabled) { double refr = prim.Material.Refraction; if (refr > 0 && depth < Constants.TraceDepth) { double localRIndex = prim.Material.RefractionIndex; double indexDiff = rIndex/localRIndex; Vector3D vN = prim.GetNormal(pi)*(double) result; double cosI = -(vN.DotProduct(ray.Direction)); double cosT2 = 1f - indexDiff*indexDiff*(1f - cosI*cosI); if (cosT2 > 0) { Vector3D t = indexDiff*ray.Direction + (indexDiff*cosI - Math.Sqrt(cosT2))*vN; Color3D rCol = new Color3D(); double dist = 0; Raytrace(new Ray(pi + t*Constants.Epsilon, t), ref rCol, depth + 1, localRIndex, ref dist, samples*.5, sScale*2); RaysCast++; //Apply Beer's law Color3D absorbance = prim.Material.Color*.15*-dist; Color3D transparency = new Color3D(Math.Exp(absorbance.R), Math.Exp(absorbance.G), Math.Exp(absorbance.B)); acc += rCol*transparency; } } } return prim; }
public void SetColor(Color3D c) { R = c.R; G = c.G; B = c.B; }