# Is it possible to dynamically change only a portion of a material attached to a plane?

**URL:** <https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416>\
**Category:** Questions\
**Tags:** materials, react-three-fiber\
**Created:** [March 22, 2023, 12:02am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416 "2023-03-22T00:02:57Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ShoOsaka](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/shoosaka/32/33293_2.png) [@ShoOsaka](https://discourse.threejs.org/u/ShoOsaka)\
**Post date:** [March 22, 2023, 12:02am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/1 "2023-03-22T00:02:57Z")

</div>

Thank you to everyone in the community

I’m currently working on my own development editor and creating a terrain generation maker as part of its functionality.

I have succeeded in changing the terrain by changing the Z coordinates of the vertices according to the Radius range specified by PointerMove, but I would like to add the ability to paint in any color.

But I don’t know how to change the Material to a Face or Fragment within any range.

Does anyone know a specific method?  
The URL of the reference site is also acceptable.

TerrainMakerCapture(GIF):  
 ![terrain](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/5/a/5a4d822e841eb2e37bedba6830d7d36c26cd9eb8.gif)

VertexChangeCode:

```javascript
/**
 * Get vertices in range
 * @param intersects : THREE.Intersection[]
 * @param radius : Brush Range Raduis
 * @returns 
 */
const getVertexes = (intersects: Intersection[], radius: number): { vertexIndexes: number[], values: number[] } => {
  const nearVertexIntexes: number[] = []; // the index of the vertex in the range
  const values: number[] = []; // distance from center
  if (intersects.length > 0 && intersects[0].object) {
    const object: Mesh = intersects[0].object as Mesh;
    const geometry = object.geometry;
    const stride = geometry.attributes.position.itemSize;
    let position: Vector3;
    if (intersects.length > 0) {
      position = intersects[0].point;
      if (position) {
        const vertices = geometry.attributes.position.array;
        const maxDistance = radius * radius; // squared distance
        for (let i = 0; i < vertices.length; i += stride) {
          const v = new Vector3(vertices[i], vertices[i + 1], vertices[i + 2]);
          // Consider rotation
          v.applyMatrix4(object.matrixWorld);
          if (v.distanceToSquared(position) < maxDistance) {
            nearVertexIntexes.push(i / stride);
            values.push(1 - v.distanceToSquared(position) / maxDistance);
          }
        }
      }
    }
  }
  return {
    vertexIndexes: nearVertexIntexes,
    values: values
  };
}

/**
* Shape Change Processing
**/
const intersects = raycaster.intersectObject(planeRef.current);
const { vertexIndexes, values } = getVertexes(intersects, terrainManager.radius);
if (intersects.length > 0 && intersects[0]) {
  const intersectPosition = intersects[0].point;
  const object: Mesh = intersects[0].object as Mesh;
  if (!object) return;
  vertexIndexes.map((index, i) => {
    const value = values[i];
    if (brush == "sculpt"){
      let position = object.geometry.attributes.position;
      position.setZ(
        index,
        (position.getZ(index) + (value * (isReverse? -1 : 1)))
      );
      position.needsUpdate = true;
    }
    else if (brush == "paint") {
      // How to get a Face or Fragment and attach a material
    }
  });
}

```

---

<div class="post-metadata">

**Author:** ![Man](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/man/32/34985_2.png) [@Man](https://discourse.threejs.org/u/Man)\
**Post date:** [March 22, 2023, 12:20am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/2 "2023-03-22T00:20:28Z")

</div>

Hello.  
I think it is not difficult to modify the color of limited surface of model.  
Now, I write my example code. I wish it will help your good work.

const colorList = new Float32Array(mesh.geometry.attributes.color.array);  
const geometryPositionsArray = Array.from(mesh.geometry.getAttribute(“position”).array);  
const vertex = new Three.Vector3();  
const areaCenter = new Three.Vector3(area.center.x, area.center.y, area.center.z);  
const color = new Three.Color(AREA\_NEW\_COLOR);  
const rgbValues = [color.r, color.g, color.b];

```
for (let i = 0; i <= geometryPositionsArray.length - 3; i += 3) {
    vertex.set(geometryPositionsArray[i], geometryPositionsArray[i + 1], geometryPositionsArray[i + 2]);
    const distance = vertex.distanceTo(areaCenter);

    // if this vertex is within the radius, color it
    if (distance <= radius) {
        colorList.set(rgbValues, i);
    }
}
// Will only work for non indexed geometry
const colorsAttribute = new Three.BufferAttribute(colorList, 3);
mesh.geometry.setAttribute("color", colorsAttribute);
mesh.geometry.attributes.color.needsUpdate = true;

```

Thanks.

---

<div class="post-metadata">

**Author:** ![ShoOsaka](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/shoosaka/32/33293_2.png) [@ShoOsaka](https://discourse.threejs.org/u/ShoOsaka)\
**Post date:** [March 22, 2023, 2:10am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/3 "2023-03-22T02:10:25Z")

</div>

Hello.  
Thank you for being prompt.

Looking at the your code, you can understood the general flow, but there was no color in the geometry attribute.  
Therefore, I used uv and formatted it with the following code, but the color is not drawn well, What’s wrong?

Fixed code

```javascript
const radius = 10;
const area = intersects[0].point;
const colorList = new Float32Array(ref.current.geometry.attributes.uv.count * 3);
const geometryPositionsArray = ref.current.geometry.attributes.position.array;
const vertex = new Vector3();
const color = new Color(0xff0000);
const rgbValues = [color.r, color.g, color.b];
for (let i = 0; i <= geometryPositionsArray.length - 3; i += 3) {
  vertex.set(geometryPositionsArray[i], geometryPositionsArray[i + 1], geometryPositionsArray[i + 2]);
  const distance = vertex.distanceTo(area);
  if (distance <= radius) {
      colorList.set(rgbValues, i);
  }
}
const colorsAttribute = new BufferAttribute(colorList, 3);
ref.current.geometry.setAttribute("color", colorsAttribute);
ref.current.geometry.attributes.color.needsUpdate = true;

```

---

<div class="post-metadata">

**Author:** ![Man](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/man/32/34985_2.png) [@Man](https://discourse.threejs.org/u/Man)\
**Post date:** [March 22, 2023, 2:34am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/4 "2023-03-22T02:34:00Z")

</div>

Right.  
Normally, the gltf model doesn’t have color attribute first.  
You can code like this before above code. I mean you can create color attribute before call it.

let cloneGeometry = mesh?.geometry.clone();  
const count = cloneGeometry.attributes.position.count;  
const buffer = new Three.BufferAttribute( new Float32Array( count \* 3 ), 3 );  
cloneGeometry.setAttribute(“color”, buffer);

Like this, you can create color attribute. then you can call it.  
I wish it will be a help.  
Thanks.

---

<div class="post-metadata">

**Author:** ![ShoOsaka](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/shoosaka/32/33293_2.png) [@ShoOsaka](https://discourse.threejs.org/u/ShoOsaka)\
**Post date:** [March 22, 2023, 3:49am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/5 "2023-03-22T03:49:17Z")

</div>

I am so grateful to have knowledgeable people like you in this community.

This works perfectly and I can confirm that it works.

![terrain2](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/9/3988320fdcb3fb70682d322c6f1bde59f1636384.gif)

Here is the code after the change.

```javascript
const radius = terrainManager.radius;
const intersectPosition = intersects[0].point;
const cloneGeometry = ref.current.geometry.clone();
if (!cloneGeometry.attributes.color) {
  const count = cloneGeometry.attributes.position.count;
  const buffer = new BufferAttribute( new Float32Array( count * 3 ), 3 );
  cloneGeometry.setAttribute("color", buffer);
}
const numVertices = cloneGeometry.attributes.color.array;
let colors = new Float32Array(numVertices);
const color = new Color(terrainManager.color);
const vertex = new Vector3();
const positionArray = Array.from(cloneGeometry.attributes.position.array);
for (let i = 0; i <= positionArray.length - 3; i += 3) {
  vertex.set(positionArray[i], positionArray[i + 1], positionArray[i + 2]);
  vertex.applyMatrix4(ref.current.matrixWorld); // Consider rotation
  const distance = vertex.distanceTo(intersectPosition);
  if (distance <= radius) {
    colors.set(color.toArray(), i);
  }
}
cloneGeometry.setAttribute("color", new BufferAttribute(colors, 3));
ref.current.geometry.copy(cloneGeometry);

```

---

<div class="post-metadata">

**Author:** ![Man](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/man/32/34985_2.png) [@Man](https://discourse.threejs.org/u/Man)\
**Post date:** [March 22, 2023, 3:54am UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/6 "2023-03-22T03:54:04Z")

</div>

I’m very glad for hearing your work is going well.  
In the future, I wish we will help each other.  
Cheers.

---

<div class="post-metadata">

**Author:** ![richi-coder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/richi-coder/32/48048_2.png) [@richi-coder](https://discourse.threejs.org/u/richi-coder)\
**Post date:** [May 24, 2024, 6:33pm UTC](https://discourse.threejs.org/t/is-it-possible-to-dynamically-change-only-a-portion-of-a-material-attached-to-a-plane/49416/7 "2024-05-24T18:33:49Z")

</div>

> [@ShoOsaka](#):
>
> ```javascript
> for (let i = 0; i <= geometryPositionsArray.length - 3; i += 3) {
> vertex.set(geometryPositionsArray[i], geometryPositionsArray[i + 1], geometryPositionsArray[i + 2]);
> const distance = vertex.distanceTo(area);
> if (distance <= radius) {
> colorList.set(rgbValues, i);
> }
> }
> 
> ```

Hi Sho, I was checking your code and I saw you finally solved, but just a question…  
is this solution performing well?  
from your code I imagine this: checking thousands of vertices at each frame…  
right now I am working a project with a 7000+ vertices, so imagine looping through all those vertices every 16ms…  
I was trying to create this in a shader with a render target and SD function… what’s your opinion?
