public ViewForm(string fileName) { InitializeComponent(); Manager = new SceneManager(); context = Manager.LoadScene(fileName, ctlCanvas.ClientRectangle.Width, ctlCanvas.ClientRectangle.Height); this.imagePlane = context.Image; iteration = 0; rnd = new DotNetSampler(); ctlCanvas.Image = new Bitmap(ctlCanvas.ClientRectangle.Width, ctlCanvas.ClientRectangle.Height); }
} // Camera public void GetFrame(Scene scene, Sampler randomIn, Image image) { RayTracer rayTracer = new RayTracer(scene); int width = image.Width; int height = image.Height; float halfAngle = (float)Math.Tan(viewAngle * 0.5f); #if PARALLEL Parallel.For(0, height, delegate(int y) { var random = randomIn.Clone(); #else for (int y = 0; y < height; ++y) { Random random = randomIn; #endif for (int x = 0; x < width; ++x) { // make image plane displacement vector coefficients float xF = (float)((x + random.GetNextSample()) * 2.0f / width) - 1.0f; float yF = (float)((y + random.GetNextSample()) * 2.0f / height) - 1.0f; // make image plane offset vector Vector offset = (right * xF) + (up * yF * (height / width)); // make sample ray direction, stratified by pixels Vector sampleDirection = (viewDirection + offset * halfAngle).Unitize(); // get radiance from RayTracer Vector radiance = rayTracer.GetRadiance(ViewPosition, sampleDirection, random, null); // add radiance to image image.AddToPixel(x, y, radiance); } } #if PARALLEL ); #endif } }
Vector SampleEmitters(Vector rayDirection, SurfacePoint surfacePoint, Sampler random) { Vector radiance; // single emitter sample, ideal diffuse BRDF: // reflected = (emitivity * solidangle) * (emitterscount) * // (cos(emitdirection) / pi * reflectivity) // -- SurfacePoint does the first and last parts (in separate methods) // get position on an emitter Vector emitterPosition; Triangle emitter; scene.GetEmitter(random, out emitterPosition, out emitter); // check an emitter was found if (null != emitter) { // make direction to emit point Vector emitDirection = (emitterPosition - surfacePoint.Position).Unitize(); // send shadow ray Triangle hitObject; Vector hitPosition; scene.GetIntersection(surfacePoint.Position, emitDirection, surfacePoint.Item, out hitObject, out hitPosition); StatsCounter.RayTraced(); // if unshadowed, get inward emission value Vector emissionIn = null; if ((null == hitObject) || (emitter == hitObject)) emissionIn = new SurfacePoint(emitter, emitterPosition).GetEmission(surfacePoint.Position, -emitDirection, true); else emissionIn = new Vector(); // get amount reflected by surface radiance = surfacePoint.GetReflection(emitDirection, emissionIn * scene.GetEmittersCount(), -rayDirection); } else radiance = new Vector(); return radiance; }
public Vector GetRadiance(Vector rayOrigin, Vector rayDirection, Sampler random, Triangle lastHit) { // intersect ray with scene Triangle pHitObject; Vector hitPosition; scene.GetIntersection(rayOrigin, rayDirection, lastHit, out pHitObject, out hitPosition); Vector radiance; if (null != pHitObject) { // make surface point of intersection SurfacePoint surfacePoint = new SurfacePoint(pHitObject, hitPosition); // local emission only for first-hit if (lastHit != null) radiance = Vector.ZERO; else radiance = surfacePoint.GetEmission(rayOrigin, -rayDirection, false); // add emitter sample radiance = radiance + SampleEmitters(rayDirection, surfacePoint, random); // add recursive reflection // // single hemisphere sample, ideal diffuse BRDF: // reflected = (inradiance * pi) * (cos(in) / pi * color) * reflectance // -- reflectance magnitude is 'scaled' by the russian roulette, cos is // importance sampled (both done by SurfacePoint), and the pi and 1/pi // cancel out Vector nextDirection; Vector color; // check surface bounces ray, recurse if (surfacePoint.GetNextDirection(random, -rayDirection, out nextDirection, out color)) radiance = radiance + (color * GetRadiance(surfacePoint.Position, nextDirection, random, surfacePoint.Item)); } else // no hit: default/background scene emission radiance = scene.GetDefaultEmission(-rayDirection); return radiance; }
public Vector GetSamplePoint(Sampler random) { // get two randoms float sqr1 = (float)Math.Sqrt(random.GetNextSample()); float r2 = (float)random.GetNextSample(); // make barycentric coords float a = 1.0f - sqr1; float b = (1.0f - r2) * sqr1; // make position from barycentrics // calculate interpolation by using two edges as axes scaled by the // barycentrics return edge1 * a + edge2 * b + verts[0]; }
public void GetEmitter(Sampler random, out Vector position, out Triangle triangle) { if (emitters.Count != 0) { // select emitter // not using lower bits, by treating the random as fixed-point i.f bits int index = ((((int)(int.MaxValue*random.GetNextSample()) & ((1 << MAX_EMITTERS_P) - 1)) * emitters.Count) >> MAX_EMITTERS_P); // get position on triangle position = emitters[index].GetSamplePoint(random); triangle = emitters[index]; } else { position = Vector.ZERO; triangle = null; } }