Texture disappears on block fragments

Hello. to blocks in the demo version of the ammo engine three.js examples , I decided to attach a texture

textureLoader.load( 'examples/textures/wall_brick.png', function ( texture ) {
				texture.wrapS = THREE.RepeatWrapping;
				texture.wrapT = THREE.RepeatWrapping;
				texture.repeat.set( 4, 4 );
				object.material.map = texture;
				object.material.needsUpdate = true;
			} );


but when the block is destroyed the texture disappears, although in the properties of the material map, the texture remains

How can this problem be solved? Do you need a demo with texture?

There’s a high chance that the UV mapping is not preserved / properly split after the fragmentation of the mesh - but that’s internal workings of ammo.

1 Like

The breaking code isn’t handled by ammo.

Its in the ConvexObjectBreaker.js

and you’re correct… it’s not handling/observing UVs but it might not be too hard to fix for your case @Dek_ker, by following how it handles .normal and doing the same for .uv :

1 Like

so where exactly do I need to put the fragment texturing code. The ConvexObjectBreaker.js file does not transfer material properties. I configure them in the index file

					const debris = convexBreaker.subdivideByImpact( threeObject0, impactPoint, impactNormal, 1, 2, 1.5 );

					const numObjects = debris.length;
					for ( let j = 0; j < numObjects; j ++ ) {

						const vel = rb0.getLinearVelocity();
						const angVel = rb0.getAngularVelocity();
						const fragment = debris[ j ];
						fragment.userData.velocity.set( vel.x(), vel.y(), vel.z() );
						fragment.userData.angularVelocity.set( angVel.x(), angVel.y(), angVel.z() );
				textureLoader.load( 'examples/textures/wall_brick.png', function ( texture ) {
				texture.wrapS = THREE.RepeatWrapping;
				texture.wrapT = THREE.RepeatWrapping;
				texture.repeat.set( 4, 4 );
				fragment.material.map = texture;
				fragment.material.needsUpdate = true;
				} );
						createDebrisFromBreakableObject( fragment );

					}

					objectsToRemove[ numObjectsToRemove ++ ] = threeObject0;
					userData0.collided = true;

If I texture only here, then in the game you can see how the color of the broken fragments changes, but the texture, alas, does not appear. Tell me what exactly needs to be added to ConvexObjectBreaker.js for it to work

Ok I was wrong. It a lot harder than I thought initially, and you’d have to modify quite a few source files.

Instead, I wrote you something that gets you part/most of the way there, (at least for the first breakage)…

It’s a box UV unwrap… you run it on your first box by itself, and then when the object is broken, you call it on the debris pieces along with the original box the debris was broken from to unwrap/generate their UVs. It’s not a perfect solution, but it shows how to manipulate Uvs and do a box unwrap.
It checks the normal of the vertex and based on the largest normal axis, takes the uv from the other 2 position axis components as the uv coordinate.

For the first shatter, you would call it for each debris piece, and the original mesh
For subsequent shatters, I guess you would call it with the debris piece, and the debris piece it was shattered from…

The code of interest is in “test.js”

The code:

2 Likes

Thank you very much for the source code of the project. It will be easier for me to figure it out. I’ll test this in my project.

1 Like

Yes, everything worked out.
bandicam2024-01-1312-48-54-311-ezgif.com-video-to-gif-converter
I moved your function

let vec3 = THREE.Vector3;
  let {abs,sin} = Math;
let boxUVUnwrap=(mesh,sourceMesh=mesh)=>{
    //Box UV unwrap by thrax... takes optional sourceMesh to use as unwrap reference bounds
    let pa = mesh.geometry.attributes.position.array;
    let na = mesh.geometry.attributes.normal.array;
    let ta = new Float32Array(pa.length*2/3);
    let n=new vec3()
    let p=new vec3()
    let sz=new vec3()
    if(!sourceMesh.geometry.boundingBox)
      sourceMesh.geometry.computeBoundingBox()
    sourceMesh.geometry.boundingBox.getSize(sz)
    for(let i=0,ui=0;i<pa.length;i+=3,ui+=2){
      p.set(pa[i],pa[i+1],pa[i+2]);
      if(sourceMesh!==mesh)
        sourceMesh.worldToLocal(mesh.localToWorld(p))
      
      p.sub(sourceMesh.geometry.boundingBox.min);
      p.divide(sz)
      n.set(abs(na[i]),abs(na[i+1]),abs(na[i+2]));
      if(n.x>=n.y){
        if(n.x>n.z){//YZ
          ta[ui]=p.y;
          ta[ui+1]=p.z
        }else{//XY
          ta[ui]=p.y
          ta[ui+1]=p.x
        }
      }else{
        if(n.y>n.z){//XZ
          ta[ui]=p.x
          ta[ui+1]=p.z
        }else{//XY
          ta[ui]=p.x
          ta[ui+1]=p.y
        }
      }
    }
    mesh.geometry.setAttribute('uv',new THREE.Float32BufferAttribute(ta,2))
  }

to my project, and added its boxUVUnwrap(fragment) request to all split events, like here

					const debris = convexBreaker.subdivideByImpact( threeObject0, impactPoint, impactNormal, 1, 2, 1.5 );

					const numObjects = debris.length;
					for ( let j = 0; j < numObjects; j ++ ) {

						const vel = rb0.getLinearVelocity();
						const angVel = rb0.getAngularVelocity();

						const fragment = debris[ j ];
						fragment.userData.velocity.set( vel.x(), vel.y(), vel.z() );
						fragment.userData.angularVelocity.set( angVel.x(), angVel.y(), angVel.z() );
							textureLoader.load( 'examples/textures/wall_brick.png', function ( texture ) {
				texture.wrapS = THREE.RepeatWrapping;
				texture.wrapT = THREE.RepeatWrapping;
				texture.repeat.set( 4, 4 );
				fragment.material.map = texture;
				fragment.material.needsUpdate = true;

			} );
			boxUVUnwrap(fragment)
						createDebrisFromBreakableObject( fragment );

					}

					objectsToRemove[ numObjectsToRemove ++ ] = threeObject0;
					userData0.collided = true;
3 Likes

Ya nice! … I do notice the orientation of the texture changed on the cracked pieces. You might be able to fix that by swapping some of the ta[ui] and ta[ui+1] with ta[ui+1] and ta[ui]
:slight_smile: