Fabric shader on threejs

Hello there, i try to make some thing like this photo or a random fabric on ground,
crumpled-red-cloth-fabric-on-260nw-1390099040
is the best way is using shaders , cus any fabric on blender take a lot of vertices up to 30k,
so i really try to start, write a shader with some some fabric look,but i wonder how i can get the same result, maybe some generator or somthing ! (i mean about that waves not the render)
thanks
demo:Edit fiddle - JSFiddle - Code Playground

For fabric and velvet materials you definitely want to have a look at the sheen implementation of MeshPhysicalMaterial: three.js webgl - GLTFloader + sheen

1 Like

Thank you for replay, but i mean not the material the fabric it self, like create it from plane?

Sorry if i misexplain

You can fold a PlaneGeometry in the shader.
A dynamically deformable circle (+shader) - #6 by hofk

But to get such a natural drape, such a curved shape is certainly not easy.

yah i see, so is there another solution for that ?

I took a look at https://www.shadertoy.com/. But it’s all way too geometric and doesn’t bring that natural fall of soft fabric.

I don’t know if this is a thing better done with Blender, since I don’t use modeling software myself.

A very elaborate artistic way would be to specify for a number of points (vertices) their xyz coordinates and then determine the intermediate points with CatmullRomCurve3.

I have done something similar.
However, with somewhat different specifications.

View there Curved2Geometry

1 Like

If need for phisiq
https://threejs.org/examples/?q=ammo#physics_ammo_cloth
https://threejs.org/examples/physics_ammo_volume.html

1 Like

I will take a look thank you, i have to study it :joy:

Mmm, do you think is this a right way, if i need just an static fabric ?

For static u can use 3ds max, unity, unreal engine etc.

I have made an example of a corrugated fabric.

CorrugatedFabric

The position of the vertices is determined by three functions. If you now experiment with room curves or even better construct them beforehand, you might get a useful result.


// use t for movement
const positionX = ( w, h, t ) => w / 20 - 4 + 0.1 * Math.cos( 2 * Math.PI * w / 100  + t );
const positionY = ( w, h, t ) => h / 10 + 0.1 * Math.cos( 4 * Math.PI * w / 100  + t );
const positionZ = ( w, h, t ) => 0.5 * Math.sin( 1.4 * Math.PI * ( w + h )/ 50  + t ) - 0.4;

I am using a custom geometry.

function CustomGeometry( ws, hs, positionX, positionY, positionZ ) {

    const wss = ws + 1;
    const hss = hs + 1;
    
    const faceCount = ws * hs * 2;
    const vertexCount = wss * hss;
    
    const g = new THREE.BufferGeometry( );
    
    g.faceIndices = new Uint32Array( faceCount * 3 );
    g.vertices = new Float32Array( vertexCount * 3 );  
    g.uvs = new Float32Array( vertexCount * 2 );
    
    g.setIndex( new THREE.BufferAttribute( g.faceIndices, 1 ) );	
    g.setAttribute( 'position', new THREE.BufferAttribute( g.vertices, 3 ).setUsage( THREE.DynamicDrawUsage) );
    g.setAttribute( 'uv', new THREE.BufferAttribute( g.uvs, 2 ) );
    
    let idxCount = 0;
    
    let a, b1, b2, c1, c2;
    
    for ( let j = 0; j < ws; j ++ ) {
            
        for ( let i = 0; i < hs; i ++ ) {
            
            // 2 faces / segment,  3 vertex indices
            a =  hss * j + i;
            b1 = hss * ( j + 1 ) + i;		// right-bottom
            c1 = hss * ( j + 1 ) + 1 + i;
            //b2 = hss * ( j + 1 ) + 1 + i;	// left-top
            c2 = hss * j + 1 + i;
            
            g.faceIndices[ idxCount     ] = a; // right-bottom
            g.faceIndices[ idxCount + 1 ] = b1;
            g.faceIndices[ idxCount + 2 ] = c1; 
            
            g.faceIndices[ idxCount + 3 ] = a; // left-top
            g.faceIndices[ idxCount + 4 ] = c1 // = b2
            g.faceIndices[ idxCount + 5 ] = c2; 
            
            idxCount += 6;
            
        }
            
    }
    
    let x, y, z;
    let vIdx = 0;   // vertex index
    let posIdx;     // position  index
    
    idxCount = 0;
    let u, v;
    
    for ( let j = 0; j < wss; j ++ ) {
        
        u = j / ws;
        
        for ( let i = 0; i < hss; i ++ ) {
            
            v = i / hs;
           
           g.uvs[ idxCount     ] = u;
           g.uvs[ idxCount + 1 ] = v;
           
           idxCount += 2; 
           
        }
        
    }
    
    g.calculateCoordinates = function ( t ) { 
        
        vIdx = 0;
    
        for ( let j = 0; j < wss; j ++ ) {  // width 
                
            for ( let i = 0; i < hss; i ++ ) { // height 
                
                x = positionX( j, i, t );
                y = positionY( j, i, t );
                z = positionZ( j, i, t );
                
                xyzSet();
                
                vIdx ++;
                
            }
            
        }
        
        g.attributes.position.needsUpdate = true; // to change the positions of the vertices
        
    }
    
    // set vertex position
    function xyzSet() {
        
        posIdx = vIdx * 3;
        
        g.vertices[ posIdx ]  = x;
        g.vertices[ posIdx + 1 ]  = y;
        g.vertices[ posIdx + 2 ]  = z;
        
    }
    
    return g;
    
}
1 Like

Another idea would be to use raycaster to reshape a plane piece by piece.

One can take the two examples as a basis and create a specific solution from them.

From the Collection of examples from discourse.threejs.org

see Interaction with Points

and

Modify indexed BufferGeometry (mouse or input)
see modify Geo

The drawing of points must be processed in such a way that it is only possible within certain limits. Points in a neighbourhood up to a specified distance must follow a compensation curve. The distances can vary in a small percentage. This corresponds to a slight stretching of the fabric during folding.

That doesn’t sound too difficult at first, but I know from experience that the problems are hidden in the details. In a way it has similarities to Addon for triangulation of implicit surfaces/ forms with holes