public override double GetValue(double x, double y) { // Get random samples: Vector3[] samples = RandomSamples[MaterialID_]; // read random normal from noise texture: // From 0-1 range to 0-RandomVectorImageSize, clamp, then (y*xSize)+x int pixelIndex = ( ((int)(y * RandomVectorImageSize) % RandomVectorImageSize) * RandomVectorImageSize + ((int)(x * RandomVectorImageSize) % RandomVectorImageSize) ); // Get the colour: Color randNC = RandomVectorsColours[pixelIndex]; Vector3 randN = new Vector3(randNC.r, randNC.g, randNC.b); // read scene depth/normal Color viewNormC = Normals.GetColour(x, y); Vector3 viewNorm = new Vector3(viewNormC.r, viewNormC.g, viewNormC.b); float depth = (float)Depth.GetValue(x, y); float scale = SSAOPower / depth; // accumulated occlusion factor float occ = 0f; int sampleCount = samples.Length; for (int s = 0; s < sampleCount; s++) { // Reflect sample direction around a random vector Vector3 randomDir = Vector3.Reflect(samples[s], randN); // Make it point to the upper hemisphere float flip = (Vector3.Dot(viewNorm, randomDir) >= 0f) ? 1f : -1f; randomDir *= flip; // Add a bit of normal to reduce self shadowing randomDir.x += viewNorm.x * 0.3f; randomDir.y += viewNorm.y * 0.3f; randomDir.z += viewNorm.z * 0.3f; float sD = depth - (randomDir.z * Radius); // Sample depth at offset location: float sampleD = (float)Depth.GetValue(x + (randomDir.x * scale), y + (randomDir.y * scale)); float zd = (sD - sampleD); if (zd > MinZ) { // Clamp zd such that it's no higher than 1. if (zd > 1f) { zd = 1f; } // This sample occludes, contribute to occlusion occ += (float)System.Math.Pow(1f - zd, AttenuationPower); // + 1.0-saturate(pow(1.0 - zd, 11.0) + zd) + 1.0/(1.0+zd*zd*10); // iq } } return(1f - (occ / (float)sampleCount)); }