public Color CalcPixelColor(ref long seed, ref int maxDepth, int x, int y, PixelDebugData debug) { if (debug != null) { debug.Points.Add(Origin); } Color accumulateColor = Color.black; int c = debug == null ? AntiAliasRayCount : 1; for (int i = 0; i < c; ++i) { var offsetx = (debug == null ? SimpleRandom.RandNorm(ref seed) : 0.5f) * StepX; var offsety = (debug == null ? SimpleRandom.RandNorm(ref seed) : 0.5f) * StepY; var dir = new Vector4(StartX + x * StepX + offsetx, StartY + y * StepY + offsety, 1, 0); var dir2 = CameraLocal2World * dir; Ray ray = new Ray(Origin, dir2.normalized); accumulateColor += TraceScene(ref seed, ref maxDepth, ray, 0, debug); } Color col = accumulateColor / c; if (GammarCorrection) { col.r = Mathf.Sqrt(col.r); col.g = Mathf.Sqrt(col.g); col.b = Mathf.Sqrt(col.b); } col.a = 1; return(col); }
private Color TraceScene(ref long seed, ref int maxDepth, Ray ray, int depth, PixelDebugData debug) { HitRecord hit = RaycastScene(ray); //HitRecord hit = Scene.RayCast(ray); if (debug != null) { if (hit.t > 0) { debug.Points.Add(hit.Point); debug.DebugText += ("Hit " + hit.Point.ToString() + " " + hit.Normal.ToString() + "\n"); } else { debug.Points.Add(ray.origin + ray.direction * 100); debug.DebugText += "Miss\n"; } } Color col = new Color(0, 0, 0, 0); if (hit.t > 0 && depth < 20) { maxDepth = depth > maxDepth ? depth : maxDepth; //if (depth > 18) //{ // depthOverflow = true; //} var N = hit.Normal; var C = (debug == null && depth < 3) ? ScatterRayCount : 1; int c = 0; for (int i = 0; i < C; ++i) { Color atten; Ray rayNext; if (hit.Material.Scatter(debug, ref seed, ray, ref hit, out atten, out rayNext)) { col += atten * TraceScene(ref seed, ref maxDepth, rayNext, depth + 1, debug); c += 1; } } if (c == 0) { col = Color.Lerp(Color0, Color1, 0.5f + ray.direction.y); } else { col = col / c; } } else { col = Color.Lerp(Color0, Color1, 0.5f + ray.direction.y); } if (debug != null) { debug.DebugText += (" Color:" + col.ToString() + "\n"); } return(col); }
public bool Scatter(PixelDebugData debug, ref long seed, Ray rayIn, ref HitRecord hit, out Color atten, out Ray scattered) { switch (MatType) { case RayTracingMaterialType.Lambert: { Vector3 dir = hit.Normal * 1.0001f; if (debug == null) { dir += SimpleRandom.RandomInsideUnitSphere(ref seed); } Ray rayOut = new Ray(); rayOut.origin = hit.Point; rayOut.direction = Vector3.Normalize(dir); scattered = rayOut; atten = Albedo; return(true); } case RayTracingMaterialType.Metal: { Vector3 dir = Reflect(rayIn.direction, hit.Normal); Ray rayOut = new Ray(); rayOut.origin = hit.Point; rayOut.direction = Vector3.Normalize(dir); scattered = rayOut; atten = Albedo; return(Vector3.Dot(rayOut.direction, hit.Normal) > 0); } case RayTracingMaterialType.Dielectric: { Vector3 N = hit.Normal; Vector3 R = Reflect(rayIn.direction, N); atten = Color.white; float ni_over_nt = Mathf.Max(0.1f, RefractionIndex); if (Vector3.Dot(rayIn.direction, N) > 0) { // Ray travel through inside N = -N; } else { // Ray comming from outside ni_over_nt = 1.0f / ni_over_nt; } Vector3 refracted; float reflect_prob = 1.0f; if (Refract(rayIn.direction, N, ni_over_nt, out refracted)) { reflect_prob = Schlick(Vector3.Dot(N, -rayIn.direction), RefractionIndex); } if (SimpleRandom.RandNorm(ref seed) < reflect_prob) { scattered = new Ray(hit.Point, R); } else { scattered = new Ray(hit.Point, refracted); } return(true); } } atten = Color.black; scattered = new Ray(); return(false); }
private void OnGUI() { if (GUI.Button(new Rect(10, 10, 400, 26), "UpdateTexture")) { _CurrentJob = CreateJob(); int size = Width * Height; var handle = _CurrentJob.Schedule(Width * Height, Width); JobHandle.ScheduleBatchedJobs(); handle.Complete(); //_CurrentJob.Run(size); Color32[] pixels = _CurrentJob.OutputColors.ToArray(); if (DebugX > 0 && DebugY > 0 && DebugX < _CurrentJob.Width && DebugY < _CurrentJob.Height) { int x = DebugX; int y = DebugY; //for (int y = 0; y < Height; ++y) //{ // for (int x = 0; x < Width; ++x) // { _Debug = new PixelDebugData(); long seed = _CurrentJob.RandomSeeds[y * Width + x]; int maxDepth2 = 0; _CurrentJob.CalcPixelColor(ref seed, ref maxDepth2, x, y, _Debug); pixels[y * _CurrentJob.Width + x] = Color.red; //if (_CurrentJob.depthOverflow) //{ // x = Width; // y = Height; //} // } //} } if (OutputTexture) { if (OutputTexture.width != _CurrentJob.Width || OutputTexture.height != _CurrentJob.Height) { Object.Destroy(OutputTexture); } } if (!OutputTexture) { OutputTexture = new Texture2D(_CurrentJob.Width, _CurrentJob.Height); if (Preview != null) { Preview.material.mainTexture = OutputTexture; } } OutputTexture.SetPixels32(pixels); OutputTexture.Apply(); if (DepthTexture) { if (DepthTexture.width != _CurrentJob.Width || DepthTexture.height != _CurrentJob.Height) { Object.Destroy(DepthTexture); } } if (!DepthTexture) { DepthTexture = new Texture2D(_CurrentJob.Width, _CurrentJob.Height); } Color32[] depthPixels = new Color32[size]; int maxDepth = 0; for (int i = 0; i < size; ++i) { int depth = _CurrentJob.MaxDepth[i] * 13; maxDepth = maxDepth > depth ? maxDepth : depth; depthPixels[i] = new Color32((byte)((depth >> 0) & 0xFF), (byte)((depth >> 8) & 0xFF), (byte)((depth >> 16) & 0xFF), 255); } DepthTexture.SetPixels32(depthPixels); DepthTexture.Apply(); _CurrentJob.Dispose(); Debug.Log("Max Depth: " + maxDepth); } //GUI.Label(new Rect(10, 10, 400, 26), "Current Iteration: " + _Iteration); if (_Debug != null) { GUI.TextArea(new Rect(10, 40, 400, 360), _Debug.DebugText); } }