# \[SOLVED\] Gradient to TextGeometry

**URL:** <https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603>\
**Category:** Questions\
**Tags:** text-geometry, vertex-colors, materials\
**Created:** [January 12, 2018, 2:02pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603 "2018-01-12T14:02:27Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![lucagentile](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lucagentile/32/948_2.png) [@lucagentile](https://discourse.threejs.org/u/lucagentile)\
**Post date:** [January 12, 2018, 2:02pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/1 "2018-01-12T14:02:27Z")

</div>

Hello,

I’m having trouble in modifying a gradient applied to a TextGeometry.  
[https://codepen.io/lucgenti/pen/WdybLg](https://codepen.io/lucgenti/pen/WdybLg)

The gradient I’m trying to apply is this one:  
[https://jsfiddle.net/lucav/zLw1jw80/](https://jsfiddle.net/lucav/zLw1jw80/)

I took the algorithm for the gradient from there:  
[https://stemkoski.github.io/Three.js/Vertex-Colors.html](https://stemkoski.github.io/Three.js/Vertex-Colors.html) (last cube)

Basically is using the position in the space of the point in the vertex to calculate the colors on each Face3. But there’s a way to do this way to make a more complex gradient?

I also tried a simpler approach with the canvas, but I din’t make it work (can’t draw a Rect from bottom to top on the arc of the letter).

```
var texture = new THREE.Texture( generateTexture() );
texture.needsUpdate = true; 
var materials = [ 
  new THREE.MeshBasicMaterial( { color: '#ECECEE', overdraw: 0.5 } ),
  new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5, transparent: true } )
];    

function generateTexture() {
            var size = 25;

            canvas = document.createElement( 'canvas' );
            canvas.width = size;
            canvas.height = size;

            var context = canvas.getContext( '2d' );

            var gradient = context.createLinearGradient( 0, 0, size, 0 );
            gradient.addColorStop(0, '#f7b000');
            gradient.addColorStop(0.25, '#dd0080');
            gradient.addColorStop(0.5, '#622b85');
            gradient.addColorStop(0.75, '#007dae');
            gradient.addColorStop(1, '#77c8db');
            context.fillStyle = gradient;
            context.fillRect(size/1.6, 7, size, size);

            return canvas;
}
```

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [January 12, 2018, 3:40pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/2 "2018-01-12T15:40:17Z")

</div>

![ColorLerp](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/1X/6bc45bc1dd04de4f32fb60454cbf6851c7bbb0c2.png)

[https://jsfiddle.net/prisoner849/nr141fk7/](https://jsfiddle.net/prisoner849/nr141fk7/)

A start point for you to make transition from one colour to another, using `.lerp()` method of `THREE.Color()`.

```
var geom = new THREE.TorusKnotGeometry( 2.5, .5, 100, 16 );
geom.computeBoundingBox();

var bbox = geom.boundingBox;
var size = new THREE.Vector3().subVectors(bbox.max, bbox.min); // we'll use it to get normalized positions of vertices in faces of geometry

var vertexIndices = ['a', 'b', 'c'];
var face, vertex, normalized = new THREE.Vector3(), normalizedY = 0;

var red = new THREE.Color("red"), blue = new THREE.Color("blue");

for(var i = 0; i < geom.faces.length; i++){
  face = geom.faces[i];
  for (var v = 0; v < 3; v++){
    vertex = geom.vertices[face[vertexIndices[v]]];
    normalizedY = normalized.subVectors(vertex, bbox.min).divide(size).y; // we'll use the normalized Y-coordinate
    face.vertexColors[v] = red.clone().lerp(blue, normalizedY);
  }
}

```

Imagine that the red color is at 0, and the blue one is at 1. Having this, try to adapt it to a function which works with several colours.

---

<div class="post-metadata">

**Author:** ![lucagentile](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lucagentile/32/948_2.png) [@lucagentile](https://discourse.threejs.org/u/lucagentile)\
**Post date:** [January 15, 2018, 10:09am UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/3 "2018-01-15T10:09:48Z")

</div>

> [@prisoner849](#):
>
> normalizedY = normalized.subVectors(vertex, bbox.min).divide(size).y; // we’ll use the normalized Y-coordinate

Thanks for your reply.

I tried this

```
if (normalizedY < 0.35) {
    face.vertexColors[v] = yellow.clone().lerp(purple, normalizedY);
}
else if (normalizedY >= 0.35 && normalizedY < 0.5) {
    face.vertexColors[v] = purple.clone().lerp(violet, normalizedY);
}
else if (normalizedY >= 0.5 && normalizedY < 0.65) {
    face.vertexColors[v] = violet.clone().lerp(cyan, normalizedY);
}
else if (normalizedY >= 0.65) {
    face.vertexColors[v] = cyan.clone().lerp(lightblue, normalizedY);
}    

```

https://codepen.io/lucgenti/embed/preview/ppZZRg?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=ppZZRg

But it doesn’t smoothly interpolate between colors (spline interpolation?).

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [January 15, 2018, 10:12am UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/4 "2018-01-15T10:12:26Z")

</div>

> [@lucagentile](#):
>
> But it doesn’t smoothly interpolate between colors

Any thoughts why it behaves like that? 🙂

---

<div class="post-metadata">

**Author:** ![lucagentile](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lucagentile/32/948_2.png) [@lucagentile](https://discourse.threejs.org/u/lucagentile)\
**Post date:** [January 15, 2018, 10:47am UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/6 "2018-01-15T10:47:20Z")

</div>

Honestly I have no idea (first time ever I’m diving into rendering, vectors etc.). Maybe is also due to the fact that a smooth curve means that from point a to the next point b the difference between vectors is subtle, and the lerp function works better (I’m not good in this kind of mathematics so I’m just wondering).

But it can also be to the fact that I should not use this kind of breakpoints like in a canvas gradient, but adapt the normalizedY dynamically between less number of colors.

---

<div class="post-metadata">

**Author:** ![lucagentile](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lucagentile/32/948_2.png) [@lucagentile](https://discourse.threejs.org/u/lucagentile)\
**Post date:** [January 15, 2018, 12:01pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/7 "2018-01-15T12:01:09Z")

</div>

With some edits I reached this result:

[https://codepen.io/lucgenti/pen/jYpevR](https://codepen.io/lucgenti/pen/jYpevR)

```
var bluette = new THREE.Color(0x559BBF), lightblue = new THREE.Color(0x77c8db), cyan = new THREE.Color(0x007dae), violet = new THREE.Color(0x622b85), yellow = new THREE.Color("yellow"), purple = new THREE.Color(0xdd0080), magenta = new THREE.Color("magenta");
            var red = new THREE.Color("red"), blue = new THREE.Color("blue");

            for ( var i = 0; i < length; i++ ) 
            {
                face = geometry.faces[i];
                var j = i/length;
                for (var v = 0; v < 3; v++){
                    vertex = geometry.vertices[face[faceIndices[v]]];
                    normalizedX = normalized.subVectors(vertex, bbox.min).divide(size).x;
                    normalizedY = Math.abs(normalized.subVectors(vertex, bbox.max).divide(size).y);
                    if (normalizedY < 0.5) {
                        face.vertexColors[v] = yellow.clone().lerp(purple, normalizedY * (normalizedY/0.5)*2);
                    }
                    else if (normalizedY >= 0.5) {
                        face.vertexColors[v] = purple.clone().lerp(bluette, normalizedY * Math.abs((normalizedY/0.5-1))*2);
                    }                    
                }
            }

```

I’m basically exponentially increasing the lerp’s alpha in proximity of the breakpoint for the first part and viceversa on the other half, using only 3 colors.

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [January 15, 2018, 7:11pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/8 "2018-01-15T19:11:10Z")

</div>

![StopColorsGradient](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/1X/93a8ccfb010931665b2247c6e79565907036287a.png)

[https://jsfiddle.net/prisoner849/k3895nho/](https://jsfiddle.net/prisoner849/k3895nho/)

Okay, as you, at least, try to do something 👍, there’s the function which applies a gradient to a geometry 🙂

Maybe there is another, better, approach. I came up with that one 🙂

```
var geom = new THREE.TorusKnotGeometry(2.5, .5, 100, 16);

var rev = true;

var cols = [{
  stop: 0,
  color: new THREE.Color(0xf7b000)
}, {
  stop: .25,
  color: new THREE.Color(0xdd0080)
}, {
  stop: .5,
  color: new THREE.Color(0x622b85)
}, {
  stop: .75,
  color: new THREE.Color(0x007dae)
}, {
  stop: 1,
  color: new THREE.Color(0x77c8db)
}];

setGradient(geom, cols, 'y', rev);

function setGradient(geometry, colors, axis, reverse){

  geometry.computeBoundingBox();

  var bbox = geometry.boundingBox;
  var size = new THREE.Vector3().subVectors(bbox.max, bbox.min);

  var vertexIndices = ['a', 'b', 'c'];
  var face, vertex, normalized = new THREE.Vector3(),
    normalizedAxis = 0;

  for (var c = 0; c < colors.length - 1; c++) {

    var colorDiff = colors[c + 1].stop - colors[c].stop;

    for (var i = 0; i < geometry.faces.length; i++) {
      face = geometry.faces[i];
      for (var v = 0; v < 3; v++) {
        vertex = geometry.vertices[face[vertexIndices[v]]];
        normalizedAxis = normalized.subVectors(vertex, bbox.min).divide(size)[axis];
        if (reverse) {
          normalizedAxis = 1 - normalizedAxis;
        }
        if (normalizedAxis >= colors[c].stop && normalizedAxis <= colors[c + 1].stop) {
          var localNormalizedAxis = (normalizedAxis - colors[c].stop) / colorDiff;
          face.vertexColors[v] = colors[c].color.clone().lerp(colors[c + 1].color, localNormalizedAxis);
        }
      }
    }
  }
}
```

---

<div class="post-metadata">

**Author:** ![lucagentile](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lucagentile/32/948_2.png) [@lucagentile](https://discourse.threejs.org/u/lucagentile)\
**Post date:** [January 16, 2018, 7:47pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/10 "2018-01-16T19:47:00Z")

</div>

Wow, many thanks for your help. I wouldn’t have done it by myself.

I just changed your function by taking the y axis, and voila, 100% as desidered.

https://codepen.io/lucgenti/embed/preview/BJqBvx?height=300&slug-hash=BJqBvx&default-tabs=js,result&host=https://codepen.io

---

<div class="post-metadata">

**Author:** ![prisoner849](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/prisoner849/32/535_2.png) [@prisoner849](https://discourse.threejs.org/u/prisoner849)\
**Post date:** [January 16, 2018, 8:06pm UTC](https://discourse.threejs.org/t/solved-gradient-to-textgeometry/1603/11 "2018-01-16T20:06:51Z")

</div>

😉 You’re welcome! That gradiental “C” looks nice ))
