Linearly interpolate colors in a triangle using SVG (Gouraud shading)

Alec Jacobson

August 12, 2013

weblog/

After a long battle with the SVG documentation here is a triangle colored by linearly interpolated colors specified at each vertex.


<svg xmlns="http://www.w3.org/2000/svg" version="1.200000" width="100%" height="100%" viewBox="0 0 100.000000 86.600000" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g transform="matrix(1 0 0 -1 0 86.600000)">
    <defs>

      <linearGradient id="fadeA-1" gradientUnits="userSpaceOnUse" x1="50.000000" y1="0.000000" x2="50.000000" y2="86.600000">
        <stop offset="0%" stop-color="#FF0000"/>
        <stop offset="100%" stop-color="#000000" />
      </linearGradient>
      <linearGradient id="fadeB-1" gradientUnits="userSpaceOnUse" x1="0.000000" y1="86.60000" x2="75.000000" y2="43.300000">
        <stop offset="0%" stop-color="#00FF00"/>
        <stop offset="100%" stop-color="#000000" />
      </linearGradient>
      <linearGradient id="fadeC-1" gradientUnits="userSpaceOnUse" x1="100.000000" y1="86.60000" x2="25.000000" y2="43.300000">
        <stop offset="0%" stop-color="#0000FF"/>
        <stop offset="100%" stop-color="#000000" />
      </linearGradient>

      <path id="pathA-1" d="M 50.000000,0.000000 L 0.000000,86.600000 100.000000,86.600000 Z" fill="url(#fadeA-1)"/>
      <path id="pathB-1" d="M 50.000000,0.000000 L 0.000000,86.600000 100.000000,86.600000 Z" fill="url(#fadeB-1)"/>
      <filter id="Default">
        <feImage xlink:href="#pathA-1" result="layerA" x="0" y="0" />
        <feImage xlink:href="#pathB-1" result="layerB" x="0" y="0" />
        <feComposite in="layerA" in2="layerB" operator="arithmetic" k1="0" k2="1.0" k3="1.0" k4="0" result="temp"/>
        <feComposite in="temp" in2="SourceGraphic"   operator="arithmetic" k1="0" k2="1.0" k3="1.0" k4="0"/>
      </filter>
    </defs>
    <g stroke="none" stroke-width="0" shape-rendering="crispEdges" >
      <path d="M 50.000000,0.000000 L 0.000000,86.600000 100.000000,86.600000 Z" fill="url(#fadeC-1)" filter="url(#Default)" />
    </g>
  </g>
</svg>

SVG render

JPG rasterization

What you should see above if your browser supports SVG resterized linear interpolation of colors in triangle svg

Update: This still isn't quite linear interpolation. For some reason I get a tendency toward black in the middle. I tried using fancier arithmetic (multiplication) with masks but this made things worse (quantization artifacts). There is also a nasty relative coordinates issue with the filters I used above.

Update: For reference, here's what I'd like to see:

linear interpolation