/// <summary> /// /// </summary> /// <param name="job"></param> private unsafe void RenderJob(RenderingJob job) { var threadColor = GetThreadColor(); var pixelColor = (ColorRGB *)job.OutputOffset; var widthIterator = job.Camera.PixelWidthIterator; var heightIterator = job.Camera.PixelHeightIterator; var imageOrigin = job.Camera.ImageOrigin; var cameraPosition = job.Camera.Position; var jobOffsetPosition = job.OffsetPosition; var jobSize = job.Size; var ray = new Ray(); var threadDebugging = ThreadDebugging; if (!threadDebugging) { threadColor = ColorRGB.White; } var jobColorBuffer = job.ColorBuffer; var jobColorBufferIndex = 0; var cornerSize = 8; var jobDebugging = JobDebugging; if (jobDebugging) { #region paint margin as white rectangle //jobColorBuffer = new ColorRGB[jobSize.X * 2 + (jobSize.Y - 2) * 2]; //// bottom line //for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++) // (*pixelColor) = marginColor; //pixelColor += job.NextOutputLineOffset; //// left and right margin //for (var joby = 1; joby < jobSize.Y - 1; joby++, pixelColor += job.NextOutputLineOffset + 1) //{ // (*pixelColor) = marginColor; // pixelColor += (jobSize.X - 1); // (*pixelColor) = marginColor; //} //// top line //for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++) // (*pixelColor) = marginColor; #endregion #region paint corners of job // bottom parts of corners for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++) { (*pixelColor) = threadColor; } pixelColor += jobSize.X - cornerSize * 2; for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++) { (*pixelColor) = threadColor; } pixelColor += job.NextOutputLineOffset; // bottom left and right parts of corners for (var joby = 1; joby < cornerSize; joby++, pixelColor += job.NextOutputLineOffset + 1) { (*pixelColor) = threadColor; pixelColor += (jobSize.X - 1); (*pixelColor) = threadColor; } // top left and right parts of corners pixelColor += ((job.NextOutputLineOffset + 1) + (jobSize.X - 1)) * (jobSize.Y - cornerSize * 2); for (var joby = 1; joby < cornerSize; joby++, pixelColor += job.NextOutputLineOffset + 1) { (*pixelColor) = threadColor; pixelColor += (jobSize.X - 1); (*pixelColor) = threadColor; } // top parts of corners for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++) { (*pixelColor) = threadColor; } pixelColor += jobSize.X - cornerSize * 2; for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++) { (*pixelColor) = threadColor; } pixelColor += job.NextOutputLineOffset; #endregion pixelColor = (ColorRGB *)job.OutputOffset; } // . // /|\ // | for (var joby = 0; joby < jobSize.Y; joby++, pixelColor += job.NextOutputLineOffset) { // \ // ----- // / for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++) { // create ray for pixel at [x,y] ray.Prepare(cameraPosition, ((widthIterator * (jobx + jobOffsetPosition.X) + heightIterator * (joby + jobOffsetPosition.Y) + imageOrigin) - cameraPosition).Normalize()); //ray.Pixel.X = jobx + job.OffsetPosition.X; //ray.Pixel.Y = joby + job.OffsetPosition.Y; // trace scene RayTracer.Trace(ray); if (threadDebugging) { ray.Color *= threadColor; } if (jobDebugging) { #region paint margin with real colors //if (jobx == 0 || jobx == jobSize.X - 1 || joby == 0 || joby == jobSize.Y - 1) //{ // jobColorBuffer[colorBufferIndex] = ray.Color; // colorBufferIndex++; // continue; //} #endregion #region corner colors if (((joby == 0 || joby == jobSize.Y - 1) && (jobx < cornerSize || jobx >= jobSize.X - cornerSize)) || ((jobx == 0 || jobx == jobSize.X - 1) && (joby < cornerSize || joby >= jobSize.Y - cornerSize))) { jobColorBuffer[jobColorBufferIndex] = ray.Color; jobColorBufferIndex++; continue; } #endregion } (*pixelColor) = ray.Color; } } if (jobDebugging) { pixelColor = (ColorRGB *)job.OutputOffset; jobColorBufferIndex = 0; #region paint margin with real colors //// bottom line //for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++, colorBufferIndex++) // (*pixelColor) = jobColorBuffer[colorBufferIndex]; //pixelColor += job.NextOutputLineOffset; //// left and right margin //for (var joby = 1; joby < jobSize.Y - 1; joby++, pixelColor += job.NextOutputLineOffset + 1) //{ // (*pixelColor) = jobColorBuffer[colorBufferIndex]; // colorBufferIndex++; // pixelColor += (jobSize.X - 1); // (*pixelColor) = jobColorBuffer[colorBufferIndex]; // colorBufferIndex++; //} //// top line //for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++, colorBufferIndex++) // (*pixelColor) = jobColorBuffer[colorBufferIndex]; #endregion #region paint corners of job // bottom parts of corners for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++, jobColorBufferIndex++) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; } pixelColor += jobSize.X - cornerSize * 2; for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++, jobColorBufferIndex++) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; } pixelColor += job.NextOutputLineOffset; // bottom left and right parts of corners for (var joby = 1; joby < cornerSize; joby++, pixelColor += job.NextOutputLineOffset + 1) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; jobColorBufferIndex++; pixelColor += (jobSize.X - 1); (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; jobColorBufferIndex++; } // top left and right parts of corners pixelColor += ((job.NextOutputLineOffset + 1) + (jobSize.X - 1)) * (jobSize.Y - cornerSize * 2); for (var joby = 1; joby < cornerSize; joby++, pixelColor += job.NextOutputLineOffset + 1) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; jobColorBufferIndex++; pixelColor += (jobSize.X - 1); (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; jobColorBufferIndex++; } // top parts of corners for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++, jobColorBufferIndex++) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; } pixelColor += jobSize.X - cornerSize * 2; for (var jobx = 0; jobx < cornerSize; jobx++, pixelColor++, jobColorBufferIndex++) { (*pixelColor) = jobColorBuffer[jobColorBufferIndex]; } pixelColor += job.NextOutputLineOffset; #endregion } if (threadDebugging) { var invThreaColor = threadColor.Inv(); pixelColor = (ColorRGB *)job.OutputOffset; for (var joby = 0; joby < jobSize.Y; joby++, pixelColor += job.NextOutputLineOffset) { for (var jobx = 0; jobx < jobSize.X; jobx++, pixelColor++) { (*pixelColor) = (*pixelColor) * invThreaColor; } } } }
public void Calculate() { // главный цикл по лучам for (var iteration = 0; iteration < NRays; iteration++) { // определяем источник var light = this.RouletteLight(); // розыгрыш луча от источника var ray = light.RandomRay(); //ray = new LightRay( light.Position, new Vector( -0f, -0f, -1.0f, true ), new Spectrum( 1f ) ); var wMinFact = ray.Illuminance.ValueMax * WMin; // основной блуждания луча int rayIteration = 0; while (ray.Illuminance.ValueMax > wMinFact && rayIteration < 8) { rayIteration++; // ищем пересечение с элементом сцены var intersection = RayTracer.Trace(ray.From, ray.Direction, Constants.Epsilon); while (intersection != null && intersection.Face.Material.Reflectance == null) { if (intersection.Face.Material.Mirror != null) { var mirrorRay = Vector.Reflect(ray.Direction, intersection.Face.Normal); mirrorRay.Normalize(); ray.From = intersection.Point; ray.Direction = mirrorRay; intersection = this.RayTracer.Trace(ray.From, ray.Direction, Constants.Epsilon); } else { throw new NotImplementedException(); } } if (intersection == null) { break; } //RayDebugStaticCollection.Add( new Ray( ray.From, intersection.Point ), Color.Blue ); //this.Log.Message( string.Format( "Ray.From = {0}, Ray.To = {1}", ray.From, intersection.Point ) ); var intersectionNormal = intersection.Face.Normal; var intesectionPointOcclude = intersection.Point + intersectionNormal * Constants.Epsilon; // для всех расчетных точек производимы вычисления foreach (var obj in Scene.Objects) { foreach (var vertex in obj.Vertices) { var renderPointNormal = vertex.Face.Normal; if (vertex.Face == intersection.Face) { continue; } var dnormals = intersection.Face.Normal - renderPointNormal; if (Math.Abs(dnormals.X) < Constants.Epsilon && Math.Abs(dnormals.Y) < Constants.Epsilon && Math.Abs(dnormals.Z) < Constants.Epsilon) { continue; } var mr = (new Vector(intersection.Point, vertex.Point).Reflect(vertex.Face.Normal)); //RayDebugStaticCollection.Add( new Ray( intersection.Point, vertex.Point ), Color.Green ); //RayDebugStaticCollection.Add( new Ray( vertex.Point,mr ), Color.Red ); //if (point.Obj.Name == "Box2") //{ // point.Illuminance = new Spectrum(1f, 0, 0); // continue; //} //if ( Vector.Dot( intersectionNormal, renderPointNormal ) > Constants.Epsilon ) //{ // vertex.CounterVisibleNormals++; // continue; //} var pointOcclude = vertex.Point; // направление от точки до точки рендеринга var r2 = Point3D.LenghtSquared(intesectionPointOcclude, pointOcclude); var coreDirection = new Vector(intesectionPointOcclude, pointOcclude, true); //var occludeRayLength = (float)Math.Sqrt( r2 ) - Constants.Epsilon; //r2 = Point3D.LenghtSquared(intesectionPointOcclude, point.Position ); var occludeRayLength = (float)Math.Sqrt(r2) - Constants.Epsilon; if (this.RayTracer.Occluded(intesectionPointOcclude, coreDirection, 0, occludeRayLength)) { //vertex.CounterOccluded++; continue; } //if ( this.RayTracer.Occluded( intersection.Point, coreDirection, Constants.Epsilon, occludeRayLength ) ) // continue; var cos1 = (Vector.Dot(coreDirection, intersectionNormal)); var cos2 = Math.Abs(Vector.Dot(coreDirection, renderPointNormal)); /* * if ( cos1 < Constants.Epsilon2 ) * vertex.CounterRaysCos1Zero++; * if ( cos2 < Constants.Epsilon ) * vertex.CounterRaysCos2Zero++; */ cos1 = Math.Abs(cos1); cos2 = Math.Abs(cos2); var sigma1 = intersection.Face.Material.Reflectance.BRDF(ray.Direction, intersectionNormal, coreDirection); if (sigma1.ValueMax > 0) { cos1 = Math.Abs(cos1); } var kernel1 = sigma1 * cos1 * cos2 / r2; //var kernel1 = intersection.Face.Material.BRDF( ray.Direction, intersection.Face.Normal, // core1Direction ); //var kernel1 = new Spectrum( sigma1 ); //kernel1.Multiplication( cos1 * cos2 / r2 ); // Ядро 2. Переход из суб. точки в искомое направление for (int i = 0; i < vertex.IlluminanceAngles.Directions.Count; i++) { var sigma2 = vertex.Face.Material.Reflectance.BRDF(coreDirection, renderPointNormal, vertex.IlluminanceAngles.Directions[i]); var kernel2 = sigma2; var q = ray.Illuminance * kernel1 * kernel2; if (float.IsNaN(q.R) || float.IsNaN(q.G) || float.IsNaN(q.B)) { q = new Spectrum( ); } vertex.IlluminanceIndirect[i] += q; } } } var newDirection = intersection.Face.Material.Reflectance.RandomReflectedDirection(ray.Direction, intersectionNormal); var brdf = intersection.Face.Material.Reflectance.BRDF(ray.Direction, intersectionNormal, newDirection); ray = new LightRay(intersection.Point, newDirection, ray.Illuminance * brdf); /* * if (rayIteration == 1) * ray = new LightRay(ray.From, new Vector(1f, 0, 1f), ray.Illuminance); * else if ( rayIteration == 2 ) * ray = new LightRay( ray.From, new Vector( -0.85f, 1.5f, 1.5f, true ), ray.Illuminance ); * * */ } if (iteration % 10 == 0) { Log.Message(string.Format("Render {0} rays", iteration), 1); } } const float XXXX = 0.25f; const float norm = 4 * Constants.PI * XXXX; foreach (var obj in Scene.Objects) { foreach (var vertex in obj.Vertices) { for (int i = 0; i < vertex.IlluminanceAngles.Directions.Count; i++) { vertex.IlluminanceIndirect[i] *= (norm / (NRays * Constants.PI * Constants.PI)); } } } }