: meshgradient get rendered in Krita just like you'd expect them to render in other apps
because I couldn't get Bicubic interpolation fully working by the time
of writing and publishing this blog. This part is still in pending state
Firstly, here are is a screenshot of a complex meshgradient which I found from Inkscape
(I modified it to be Bilinear to get this):
As, there isn't much else to say besides giving out the details, I'll jump straight to the technicalities :-)
started with reading the algorithm mentioned in the specs sheet i.e
Divide And Conquer. I had some confusions about it, but thanks to my
mentors. I got the idea. Then, to implement this algorithm, the idea was
to subdivide the patches, until the difference between the corners is
Now the question was, how am I going to divide the
surface. Luckily, there was a paper, one search away, which I picked up.
I read it quickly and started writing the algorithm on paper.
Somethings didn't quite make sense, but as I later found out that they
were probably misprints.
So, as I implemented the algorithm, the
first thing that I tried to open was this, to check if the subdivision
algorithm was right. Comparing this to Inkscape, it was pretty accurate
(not the color, but the surface itself).
get colors for the new corners was simple too. You could get it by
dividing it in half (we get this from the fact that the surface is
Bilinear). Then just mix them when difference is less than the tolerance
and you get this:
Because rendering meshgradients is expensive and anything e.g a simple translation would call for a complete redraw. I had to write a way for poor man's caching. Instead of painting directly on a the canvas. I would first paint on QImage and then paint it on QPainter.
Simple enough! However, there was a problem, rendering on QImage and then on scaled up QPainter made things look very pixelated because of scaling. So, to counteract this, my solution was to paint on scaled up QImage i.e scale it up by the same factor as the QPainter. This made everything a whole lot better.
Rendering (Bicubic Interpolation)
has been the hardest part about this GSoC (till now). The way I usually write code is, I write everything in a bit messy way till I get something
running. Then I come back and check if something could be written in a
better way (read efficiency and readability). This approach went horribly
wrong as I probably had made mistakes and my render was pure chaos and
nowhere close to what you call interpolation. Then I git stashed everything
and started over in a more manageable way, now the interpolation was
working. But turns out, it was an exact replica of the Bilinear
interpolation, but slower (because it did actually calculate derivatives
and what not).
So, I asked for help. But then I
immediately realized that my assumptions were wrong. In short, I was
calculating derivatives incorrectly. I quickly modified the code in the
dirty way and finally I could see a smooth render with no Mach Banding.
Unfortunately, this too is based on an assumption, which is not correct
for the all cases. So, Bicubic interpolation works neatly for Mesh Patches which are relatively linear. But falls out of place
for a more messy (generic case) ones.
But why? The problem here is with the way I
do subdivision, it is only valid for linear Coons patches. I haven't written the code to subdivide a Bicubic surface. That isn't the only problem, subdividing Bicubic surface is an expensive operation as well. So, I'll have to find a middle ground.
SavingSince I spent a lot of time on getting Bicubic Interpolation to work, for a context switch I moved to the next milestone.
So, I tried to implement the saving operation. Thanks to all the abstractions! This was pretty straightforward to implement.
I will now write tests for it and the final rendering :)
That's all I have for now, hopefully I'll post an update when I get the Bicubic shading working :)