public Sphere(string name, Vector3 center, float radius, Color color, ITexture texture = null, bool isWall = false, float brightness = 1f, float reflectiveness = 0.2f) { _name = name; _centerVector = center; _radius = radius; _color = color; _brightness = brightness; _rgb = Conversions.FromColor(_color); _texture = texture; _isWall = isWall; _reflectiveness = reflectiveness; }
public WriteableBitmap GetBitmap(int width, int height, double dpiX, double dpiY) { var fromRGB = Conversions.FromColor(_fromColor); var toRGB = Conversions.FromColor(_toColor); // 4 channels (blue, green, red, alpha). Order of channels is important! int channels = 4; byte[] pixels = new byte[width * height * channels]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { var rgb = Vector3.Lerp(fromRGB, toRGB, i / (float)width); var color = Conversions.FromRGB(rgb, gammaCorrection: j < (height / 2)); color.Clamp(); var pos = (j * width * channels) + (i * channels); // blue channel pixels[pos + 0] = color.B; // green channel pixels[pos + 1] = color.G; // red channel pixels[pos + 2] = color.R; // alpha channel pixels[pos + 3] = byte.MaxValue; } } var bitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Bgra32, BitmapPalettes.Halftone256); bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * channels, 0); return(bitmap); }
public bool CalcColorDeferred(int x, int y, LightSource[] lightSources, float z, out Vector3 rgb) { rgb = Vector3.Zero; var p = new Vector2(x, y); var AP = p - _a.ScreenPosition; var vec = _barryCentricMatrixInverse * AP; var u = vec.X; var v = vec.Y; bool drawPoint = (u >= 0 && v >= 0 && (u + v) < 1); if (drawPoint) { var interpolatedPosition = _a.HomogenousPosition + u * (_b.HomogenousPosition - _a.HomogenousPosition) + v * (_c.HomogenousPosition - _a.HomogenousPosition); var position = interpolatedPosition.HomogenousNormalize(); if (position.Z == z) { var material = Vector3.Zero; if (_options.SingleColor) { material = new Vector3(1, 0, 0); // red } else { if (_options.Texture == null) { var interpolatedMaterial = _a.HomogenousColor + u * (_b.HomogenousColor - _a.HomogenousColor) + v * (_c.HomogenousColor - _a.HomogenousColor); material = interpolatedMaterial.HomogenousNormalize(); } else { var interpolatedTexture = _a.HomogenousTexturePosition + u * (_b.HomogenousTexturePosition - _a.HomogenousTexturePosition) + v * (_c.HomogenousTexturePosition - _a.HomogenousTexturePosition); var texturePosition = interpolatedTexture.HomogenousNormalize(); material = _options.Texture.CalcColor(texturePosition.X, texturePosition.Y, _options.BilinearFilter, _options.GammaCorrect); } } var interpolatedNormal = Vector3.Normalize(_a.Normal + u * (_b.Normal - _a.Normal) + v * (_c.Normal - _a.Normal)); for (int i = 0; i < lightSources.Length; i++) { var lightSource = lightSources[i]; var lVec = lightSource.Center - position; // Gibt dasselbe für lVec: // lVec = (new Vector4(lightSource.Center, w: 1) - interpolatedPosition).HomogenousNormalize(); var lVecNorm = Vector3.Normalize(lVec); //var nVecNorm = _currentSurfaceNormal; var nVecNorm = interpolatedNormal; var light = Conversions.FromColor(lightSource.Color); // Diffuse Lambert var dot_diffuse = Vector3.Dot(nVecNorm, lVecNorm); if (_options.DiffuseLambert && dot_diffuse > 0) { var diffuse = Vector3.Multiply(light, material) * dot_diffuse; rgb += diffuse; } // Specular Phong var eye = new Vector3(0, 0, 0); var rayVecNorm = Vector3.Normalize(position - eye); var sVec = (lVec - ((Vector3.Dot(lVec, nVecNorm)) * nVecNorm)); var rVec = lVec - (2 * sVec); var dot_phong = -Vector3.Dot(Vector3.Normalize(rVec), rayVecNorm); if (_options.SpecularPhong && dot_phong > 0) { var specular = light * (float)Math.Pow(dot_phong, _options.SpecularPhongFactor); rgb += specular; } } return(true); } } return(false); }
private Vector3 CalcColor(Ray ray, int pathTracingLimit, int reflectionLimit) { var rgb = Vector3.Zero; var hitPoint = FindClosestHitPoint(ray); if (hitPoint != null) { var sphere = hitPoint.Sphere; var rayVecNorm = Vector3.Normalize(hitPoint.Ray.DirectionVec); var rayVec = (hitPoint.Ray.Lambda * rayVecNorm) + (-rayVecNorm * 0.001f) /* nudging..? */; var hitPointVec = hitPoint.Ray.StartVec + rayVec; var nVecNorm = Vector3.Normalize(hitPointVec - hitPoint.Sphere.Center); var material = sphere.CalcColor(hitPointVec); if (!PathTracing) { if (sphere.Brightness > 0) { rgb += material * sphere.Brightness; } if (Reflection) { // Reflection if (!sphere.IsWall && /* ignore walls */ reflectionLimit > 0) { var reflectionMaterial = Conversions.FromColor(Colors.White); var refVecNorm = Vector3.Normalize(rayVecNorm - 2 * Vector3.Dot(nVecNorm, rayVecNorm) * nVecNorm); var refVec2 = refVecNorm + (Vector3.One - refVecNorm) * (float)Math.Pow((1 - Vector3.Dot(nVecNorm, refVecNorm)), 5); var reflectionRay = new Ray(hitPointVec, refVec2); var reflectionColor = CalcColor(reflectionRay, 0, --reflectionLimit); var reflection = Vector3.Multiply(reflectionColor, reflectionMaterial) * 0.25f; rgb += reflection; } } for (int i = 0; i < _lightSources.Length; i++) { var lightSource = _lightSources[i]; var lVec = lightSource.Center - hitPointVec; var lVecNorm = Vector3.Normalize(lVec); var light_cos = Vector3.Dot(nVecNorm, lVecNorm); if (light_cos >= 0) { var light = Conversions.FromColor(lightSource.Color); if (Shadows) { if (SoftShadows) { light_cos *= GetShadowedRatio(hitPointVec, lightSource); } else { // Shadows if (HasObjectInFrontOfLightSource(hitPointVec, lightSource.Center)) { light_cos *= 0.01f; } } } if (DiffuseLambert) { // Diffuse "Lambert" var diffuse = Vector3.Multiply(light, material) * light_cos; rgb += diffuse; } if (SpecularPhong) { // Ignore walls if (!sphere.IsWall) { // Specular "Phong" var sVec = (lVec - ((Vector3.Dot(lVec, nVecNorm)) * nVecNorm)); var rVec = lVec - (2 * sVec); var specular = light * (float)Math.Pow((Vector3.Dot(Vector3.Normalize(rVec), rayVecNorm)), SpecularPhongFactor); rgb += specular; } } } } } else { if (pathTracingLimit > 0) { var numberOfRandomRays = 0; bool isBounced = pathTracingLimit < PathTracingMaxBounces; if (!isBounced) { numberOfRandomRays = PathTracingRays; } else { var russianRoulette = (float)_random.NextDouble(); if (russianRoulette > 0.2f) { numberOfRandomRays = 1; } } if (numberOfRandomRays > 0) { // Source: https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation Vector3 indirectDiffuse = Vector3.Zero; Vector3 ntVec = Vector3.Zero; if (Math.Abs(nVecNorm.X) > Math.Abs(nVecNorm.Y)) { ntVec = (new Vector3(nVecNorm.Z, 0, -nVecNorm.X) / (float)Math.Sqrt(nVecNorm.X * nVecNorm.X + nVecNorm.Z * nVecNorm.Z)); } else { ntVec = (new Vector3(0, -nVecNorm.Z, nVecNorm.Y) / (float)Math.Sqrt(nVecNorm.Y * nVecNorm.Y + nVecNorm.Z * nVecNorm.Z)); } var nbVec = Vector3.Cross(nVecNorm, ntVec); for (int i = 0; i < numberOfRandomRays; i++) { var cosTheta = (float)_random.NextDouble(); var phi = (float)(_random.NextDouble() * 2 * Math.PI); var sinTheta = (float)Math.Sqrt(1 - cosTheta * cosTheta); float x = sinTheta * (float)Math.Cos(phi); float z = sinTheta * (float)Math.Sin(phi); var sampleLocalVec = new Vector3(x, cosTheta, z); var sampleWorldVec = new Vector3() { X = sampleLocalVec.X * nbVec.X + sampleLocalVec.Y * nVecNorm.X + sampleLocalVec.Z * ntVec.X, Y = sampleLocalVec.X * nbVec.Y + sampleLocalVec.Y * nVecNorm.Y + sampleLocalVec.Z * ntVec.Y, Z = sampleLocalVec.X * nbVec.Z + sampleLocalVec.Y * nVecNorm.Z + sampleLocalVec.Z * ntVec.Z }; var randomRay = new Ray(hitPointVec, sampleWorldVec); indirectDiffuse += CalcColor(randomRay, pathTracingLimit - 1, 0) * cosTheta; } indirectDiffuse /= numberOfRandomRays * _pdf; rgb += Vector3.Multiply(indirectDiffuse, material) * sphere.Reflectiveness; } else { rgb += material * sphere.Brightness; } } else { rgb += material * sphere.Brightness; } } } return(rgb); }