Trying to make gradient by VertexColor

Hello,

I’m working on gradient for my project, but I’m in trouble because the only solutions I found is about THREE.Geometry which is deprecated to use VertexColor (which seems the more simpliest to use Material and gradient in same time), or Shader which seems too complicate for me.
I tried to use ShaderGraph for it but the result wasn’t what I expected :confused:

For it I found this on overflow :
Making gradient (watch vertexColor)

Accessing faces because face property is not available on BufferGeometry

But to access to the index array I need to use geometry.setIndex(geometry.attributes.position)

I get this error : THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The “position” attribute is likely to have NaN values.

But without index I can’t access to my faces. I’m completly blocked.

Did somebody has an idea ?

Here my code to set my gradient :

Original Post on Discord

by user 224464722878005248

setGradient = (mesh, axis, reverse, geometryType) => {
    //works for meshBasicMaterial
    // let reverse = true;
    mesh.material.vertexColors = true
    let geometry = mesh.geometry

    let colors = this.colorMap[geometryType] // The gradient
    geometry.computeBoundingBox();
    geometry.setIndex(geometry.attributes.position) // Here the error

    let bbox = geometry.boundingBox;
    let size = new THREE.Vector3().subVectors(bbox.max, bbox.min); // To manage graident on the axis

    const colorsAttr = geometry.attributes.position.clone();
    geometry.setAttribute('color', colorsAttr); // Creation of color attributes to use VertexColor
    const colorAttributes = geometry.attributes.color
  
    // let vertexIndices = ['a', 'b', 'c'];
    let face = new THREE.Vector3()
    let normalized = new THREE.Vector3()
    let normalizedAxis = 0;
  
    let vertex = new THREE.Vector3()

    for (let c = 0; c < colors.length - 1; c++) {
  
      let colorDiff = colors[c + 1].stop - colors[c].stop;
  
      for (let i = 0; i < geometry.attributes.position.count; i++) {
        // face = geometry.attributes.color[i];

        for (let v = 0; v < 3; v++) {
          let index = geometry.index.array[ 3 * i + v ];

          vertex = vertex.fromBufferAttribute( geometry.attributes.position, index );

          normalizedAxis = normalized.subVectors(vertex, bbox.min).divide(size)[axis];

          if (reverse) {
            normalizedAxis = 1 - normalizedAxis;
          }
          if (normalizedAxis >= colors[c].stop && normalizedAxis <= colors[c + 1].stop) {

            let localNormalizedAxis = (normalizedAxis - colors[c].stop) / colorDiff;
            
            geometry.attributes.color.array[i*3 + v] = colors[c].color.clone().lerp(colors[c + 1].color, localNormalizedAxis);

            // colors.setXYZ( i, color.r, color.g, color.b )
          }
        }
          
      }
    }
  }

by user 224464722878005248

The gradient list :

colorMap = {'tooth' : [{
      stop: 0,
      color: new THREE.Color("#ffffff")
      }, {
        stop: 0.7,
        color: new THREE.Color("#ceb89c")
      }, {
        stop: 1,
        color: new THREE.Color("#c5af7e")
      },
      ],
      'gum' : [{
          stop: 0,
          color: new THREE.Color("#f0a9a7")
        }, {
          stop: 0.3,
          color: new THREE.Color("#ff8685")
        }, {
          stop: 0.7,
          color: new THREE.Color("#da4d52")
        }, {
          stop: 1,
          color: new THREE.Color("#da4d52")
        },
      ],
    };

by user 224464722878005248

by user 224464722878005248

Without setIndex, here the result :c

by user 224464722878005248

Hey, can you explain what the goal is? Do you need to assign colors at runtime or do you want to do that at editor time?

Hey !
I found a solution without index, I was confuse between the function call which use index and the vertex selection.

I fact I load obj from a server so I need to assign my material dynamically, so I load the model, I add the material to the model geometry, after it I set a gradient and I add it to my context.scene

by user 224464722878005248

But here the correct function :

by user 224464722878005248

setGradient = (mesh, axis, reverse, geometryType) => {
      //works for meshBasicMaterial
      mesh.material.vertexColors = true
      let geometry = mesh.geometry

      let colors = this.colorMap[geometryType] // The gradient
      geometry.computeBoundingBox();

      const count    =   geometry.attributes.position.count; 
      const buffer =  new THREE.BufferAttribute( new Float32Array( count * 3 ), 3 )
      geometry.setAttribute( 'color', buffer ); 
      let bbox = geometry.boundingBox;
      let size = new THREE.Vector3().subVectors(bbox.max, bbox.min); // To manage gradient on the axis

      const colorsAttr = geometry.attributes.color;
      const colorAttributes = geometry.attributes.color
    
      let normalized = new THREE.Vector3()
      let normalizedAxis = 0;
    
      let vertex = new THREE.Vector3()

      for (let c = 0; c < colors.length - 1; c++) {
    
        let colorDiff = colors[c + 1].stop - colors[c].stop;
    
        for (let i = 0; i < geometry.attributes.color.count; i++) {

          let index = i

          vertex = vertex.fromBufferAttribute( geometry.attributes.position, index );

          normalizedAxis = normalized.subVectors(vertex, bbox.min).divide(size)[axis];

          if (reverse) {
            normalizedAxis = 1 - normalizedAxis;
          }
          if (normalizedAxis >= colors[c].stop && normalizedAxis <= colors[c + 1].stop) {

            let localNormalizedAxis = (normalizedAxis - colors[c].stop) / colorDiff;
            
            let colorGenerate = colors[c].color.clone().lerp(colors[c + 1].color, localNormalizedAxis)
      
            colorAttributes.setXYZ( i, colorGenerate.r, colorGenerate.g, colorGenerate.b )
          }
        }
      }
    }

by user 224464722878005248

example to use :
setGradient(yourMesh, ‘y’, true, ‘gum’)
=> the colorMap upper to know why I use ‘gum’

by user 224464722878005248

the result :

by user 224464722878005248

by user 224464722878005248

It’s really helpful to add gradient easily ! Pnly with 0->1 Object type {number, color} Array, like
[{
stop: 0,
color: new THREE.Color(“#f0a9a7”)
}, {
stop: 0.3,
color: new THREE.Color(“#ff8685”)
}, {
stop: 0.7,
color: new THREE.Color(“#da4d52”)
}, {
stop: 1,
color: new THREE.Color(“#da4d52”)
},
]

by user 224464722878005248

Great that you got it to work! :slightly_smiling_face: