// steps convolution like a coroutine // returns true if more pixels are to be processed on IN, false if last pixel was processed private void stepConvo() { ps.blockMetric.begin(); ulong isize = ps.lightCount; ulong osize = ps.lightCount; float invLightCount = 1f / (float)ps.lightCount; ulong passSize = isize * osize; ulong endOfPass = passSize - 1; //re-initialize iterator state ulong expPass = ps.curr / passSize; ulong ixyoxy = ps.curr % passSize; ulong ixy = ixyoxy / osize; ulong oxy = ixyoxy % osize; expPass = ps.exponentCount - expPass - 1; /* * ulong passItr = ps.curr / passSize; //iterates over every exponent pass * ulong inoutItr = ps.curr % passSize; //iterates over every in-out pairing * ulong inItr = inoutItr / osize; //iterates over every input pixel * ulong outItr = inoutItr % osize; //iterates over every output pixel * passItr = (ulong)outExponentCount - passItr - 1; //flip pass iterators to do high exponents last */ // iterate over all 5 nested for loops of expPass { iy { ix { oy { ox } } } } linearly and extract pixel coordinates from i for ( ; ps.curr < ps.total;) { ixyoxy = ps.curr % passSize; // needed every frame to check for end of pass oxy = ps.curr % osize; if (oxy == 0) // next input pixel { ixy = ixyoxy / osize; if (ixyoxy == 0) //start an exponent pass { expPass = ps.curr / passSize; expPass = ps.exponentCount - expPass - 1; //if we're putting the reflection into the highest mip level, skip the first exponent pass and do this instead if (expPass == 0 && ps.reflectionInSIM) { uploadReflection(0, outMipSizes[0]); ps.skip(ps.lightCount * ps.lightCount); if (ps.needsRepaint()) { break; } else { continue; } } ps.exponent = outExponents[expPass]; ps.exponentFunc = QPow.closestPowFunc(ps.exponent); ps.exposure = specNormalizer(ps.exponent) * invLightCount; Util.clearTo(ref ps.CONVO.pixels, Color.black); } ps.inLookup = ps.lightDirs[ixy]; ps.LColor = ps.lights[ixy]; } //NOTE: this assumes input and output dimensions match! ps.outLookup = ps.lightDirs[oxy]; float dp = ps.inLookup.x * ps.outLookup.x + ps.inLookup.y * ps.outLookup.y + ps.inLookup.z * ps.outLookup.z; if (dp > 0f) { dp = ps.exponentFunc(dp); //compute two pixels with the same dot product //NOTE: this only works if input dimensions match output dimensions! ps.CONVO.pixels[oxy] += ps.exposure * dp * ps.LColor; if (oxy != ixy) { ps.CONVO.pixels[ixy] += ps.exposure * dp * ps.lights[oxy]; } } if (ixyoxy == endOfPass) //end of exponent pass { ps.passWriteMetric.begin(); if (uiShowPreview) { uiConvoPreview.SetPixels(ps.CONVO.pixels); uiConvoPreview.Apply(); } if (ps.exponent == 1) { // DIM finishDIM(); } else { // SIM if (ps.buildMipChain) { int mipSize = outMipSizes[expPass]; uploadMipLevel((int)expPass, mipSize); } else { finishSIM(); } } ps.passWriteMetric.end(); } // modified j=i for loop. Since we compute two pixels with the same dot product above, // we can skip any repeating permutations of input/output pixels. if (oxy >= ixy) { ps.skip(osize - oxy); } else { ps.next(); } if (ps.needsRepaint()) { break; } } ps.blockMetric.end(); }