# Round-edged box flat

**URL:** <https://discourse.threejs.org/t/round-edged-box-flat/30012>\
**Category:** Resources\
**Tags:** uv-mapping, textures, geometry\
**Created:** [September 17, 2021, 6:11pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012 "2021-09-17T18:11:38Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [September 17, 2021, 6:11pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/1 "2021-09-17T18:11:38Z")

</div>

There is already a series of boxes with rounded corners. Links to some rounded boxes see:  
[Addon to create special / extended geometries - #3 by hofk](https://discourse.threejs.org/t/addon-to-create-special-extended-geometries/1855/3)

In response to a question ( [Problems applying texture to Extruded Geometry](https://discourse.threejs.org/t/problems-applying-texture-to-extruded-geometry/29935)), I created another special one - based on [RoundedRectangle + Squircle](https://discourse.threejs.org/t/roundedrectangle/28645) .

In the [Collection of examples from discourse.threejs.org](https://discourse.threejs.org/t/collection-of-examples-from-discourse-threejs-org/4315) see [RoundEdgedBoxFlat](https://hofk.de/main/discourse.threejs/2021/RoundEdgedBoxFlat/RoundEdgedBoxFlat.html)

 ![2021-09-17 19.41.01](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/8/e/8e1767d548384aaa8e0389dad43793ffdac38fba.jpeg)

 ![2021-09-16 20.18.44](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/3/43cc6315820f2f6da3db859bb940b384b09fdb76.jpeg)

![2021-09-17 19.59.09](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/5/b/5b4f82692eedf0e04c58b8609dee9bcf5e29f8c1.png)

```javascript

// non indexed BufferGeometry

function RoundEdgedBoxFlat( w, h, t, r, s ) { // width, height, thick, radius corner, smoothness
	
	// helper const's and let's
	const wi = w / 2 - r; // inner width, half
	const hi = h / 2 - r; // inner height, half 
	const w2 = w / 2; // half width
	const h2 = h / 2; // half height

	let ul = r / w; // u left front side
	let ur = ( w - r ) / w; // u right front side
	const vl = r / h; // v low
	const vh = ( h - r ) / h;	// v high
	
	let phia, phib, xc, yc, uc, vc, cosa, sina, cosb, sinb;
	
	let positions = [];
	let uvs = [];
	
	// for front side
	let t2 = t / 2; // + half thick
	let u0 = ul;
	let u1 = ur;
	let u2 = 0;
	let u3 = 1;
	let sign = 1;
		
	for( let k = 0; k < 2; k ++ ) { // front and back side
		
		positions.push(
		
			-wi, -h2, t2, wi, -h2, t2, wi, h2, t2,
			-wi, -h2, t2, wi, h2, t2, -wi, h2, t2,
			-w2, -hi, t2, -wi, -hi, t2, -wi, hi, t2,
			-w2, -hi, t2, -wi, hi, t2, -w2, hi, t2,
			 wi, -hi, t2, w2, -hi, t2, w2, hi, t2,
			 wi, -hi, t2, w2, hi, t2, wi, hi, t2
			
		);
		
		uvs.push(
		
			u0, 0, u1, 0, u1, 1,
			u0, 0, u1, 1, u0, 1,
			u2, vl, u0, vl, u0, vh,
			u2, vl, u0, vh, u2, vh,
			u1, vl, u3, vl, u3, vh,
			u1, vl, u3, vh,	u1, vh
		
		);
			
		phia = 0; 
		
		for ( let i = 0; i < s * 4; i ++ ) {
		
			phib = Math.PI * 2 * ( i + 1 ) / ( 4 * s );
			
			cosa = Math.cos( phia );
			sina = Math.sin( phia );
			cosb = Math.cos( phib );
			sinb = Math.sin( phib );
			
			xc = i < s || i >= 3 * s ? wi : -wi;
			yc = i < 2 * s ? hi : -hi;
		
			positions.push( xc, yc, t2, xc + r * cosa, yc + r * sina, t2, xc + r * cosb, yc + r * sinb, t2 );
			
			uc = i < s || i >= 3 * s ? u1 : u0;
			vc = i < 2 * s ? vh : vl;
			
			uvs.push( uc, vc, uc + sign * ul * cosa, vc + vl * sina, uc + sign * ul * cosb, vc + vl * sinb );
 
			phia = phib;
				
		}
		
		// for back side
		t2 = -t2;	// - half thick
		u0 = ur;	// right left exchange
		u1 = ul;
		u2 = 1;
		u3 = 0;
		sign = -1;
		
	}
	
	// framing
	
	t2 = t / 2;	// + half thick (again)
	 
	positions.push(
		
		-wi, -h2, t2, -wi, -h2, -t2, wi, -h2, -t2,
		-wi, -h2, t2, wi, -h2, -t2, wi, -h2, t2,
		 w2, -hi, t2, w2, -hi, -t2, w2, hi, -t2,
		 w2, -hi, t2, w2, hi, -t2, w2, hi, t2,
		 wi, h2, t2, wi, h2, -t2, -wi, h2, -t2,
		 wi, h2, t2, -wi, h2, -t2, -wi, h2, t2,
		-w2, hi, t2, -w2, hi, -t2, -w2, -hi, -t2,
		-w2, hi, t2, -w2, -hi, -t2, -w2, -hi, t2
		
	);

	const cf = 2 * ( ( w + h - 4 * r ) + Math.PI * r ); // circumference
	const cc4 = Math.PI * r / 2 / cf // circle-circumference / 4 / circumference
	u0 = 0;
	u1 = 2 * wi / cf;
	u2 = u1 + cc4;
	u3 = u2 + 2 * hi / cf;
	
	const u4 = u3 + cc4;
	const u5 = u4 + 2 * wi / cf;
	const u6 = u5 + cc4;
	const u7 = u6 + 2 * hi / cf;
	
	uvs.push(
		
		u0, 1, 0, 0, u1, 0,
		u0, 1, u1, 0, u1, 1,
		u2, 1, u2, 0, u3, 0,
		u2, 1, u3, 0, u3, 1,
		u4, 1, u4, 0, u5, 0,
		u4, 1, u5, 0, u5, 1,
		u6, 1, u6, 0, u7, 0, 
		u6, 1, u7, 0, u7, 1
		
	);
	
	phia = 0; 
	let u, j, j1;
	const ccs = cc4 / s; // partial value according to smoothness
	
	for ( let i = 0; i < s * 4; i ++ ) {
	
		phib = Math.PI * 2 * ( i + 1 ) / ( 4 * s );
		
		cosa = Math.cos( phia );
		sina = Math.sin( phia );
		cosb = Math.cos( phib );
		sinb = Math.sin( phib );
		
		xc = i < s || i >= 3 * s ? wi : -wi;
		yc = i < 2 * s ? hi : -hi;
		
		positions.push( xc + r * cosa, yc + r * sina, t2, xc + r * cosa, yc + r * sina, -t2, xc + r * cosb, yc + r * sinb, -t2 );
		positions.push( xc + r * cosa, yc + r * sina, t2, xc + r * cosb, yc + r * sinb, -t2, xc + r * cosb, yc + r * sinb, t2 );
		
		u = i < s ? u3 : ( i < 2 * s ? u5 : ( i < 3 * s ? u7 : u1 ) ); // Attention! different start to front/back
		
		j = i % s;
		j1 = j + 1;
		
		uvs.push( u + j * ccs, 1, u + j * ccs, 0, u + j1 * ccs, 0 );
		uvs.push( u + j * ccs, 1, u + j1 * ccs, 0, u + j1 * ccs, 1 );
		
		phia = phib;
			
	}
	
	const geometry = new THREE.BufferGeometry( );
	geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
	geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), 2 ) );
	
	// add multimaterial groups for front, back, framing
	
	const vtc = ( 6 + 4 * s ) * 3; // vertex count one side
	geometry.addGroup ( 0, vtc , 0 );
	geometry.addGroup ( vtc, vtc , 1 );
	geometry.addGroup ( 2 * vtc, 24 + 2 * 3 * 4 * s, 2 );
	
	return geometry;
	
}

```

* * *

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [December 5, 2022, 7:54pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/2 "2022-12-05T19:54:26Z")

</div>

* * *

**UPDATE 2022: 📋 ✏ 📐 📏 ✂**

**Another construction:**

[RoundedBoxFlat](https://hofk.de/main/discourse.threejs/2021/RoundEdgedBoxFlat/RoundedBoxFlat.html)

 ![2022-12-02 20.57.17](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/1/3/13888c04df9acad8ca3b2338b8bf502816cdf0f0.png)

```javascript
function RoundedBoxFlat( w, h, d, r, s ) {
    
    const pi2 = Math.PI * 2;
    const n = ( s + 1 ) * 4; // number of segments
    
    let indices = [];
    let positions = [];
    let uvs = [];
    
    makeFronts( n, 1, 0 ); // segments, front is 1, start index 0 is center front
    makeFronts( n, -1, n + 1 ); // segments, back is -1, start index n + 1 is center back
    
    makeFrame( n, 2 * n + 2, 1, n + 2 ); // segments, start index framing ,start index front, start index back
    
    const geometry = new THREE.BufferGeometry( );
    geometry.setIndex( new THREE.BufferAttribute( new Uint32Array( indices ), 1 ) );
    geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
    geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), 2 ) );
    
    // add multimaterial groups for front, back, framing
    
    const vtc = n * 3 ; // vertex count
    geometry.addGroup ( 0, vtc, 0 );
    geometry.addGroup ( vtc, vtc, 1 );
    geometry.addGroup ( 2 * vtc, 2 * vtc + 3, 2 ); 
    
    geometry.computeVertexNormals( );
    
    return geometry;
    
    function makeFronts( n, side, idx ) {
        
        const d0 = side === 1 ? 0 : 1;
        const d1 = side === 1 ? 1 : 0;
        
        for ( let j = 1; j < n; j ++ ) {
    
            indices.push( idx, idx + d0 + j, idx + d1 + j );
            
        }
        
        const d2 = side === 1 ? n : 1;
        const d3 = side === 1 ? 1 : n;
        
        indices.push( idx, idx + d2 , idx + d3 );
        
        positions.push( 0, 0, side * d / 2 ); // center
        uvs.push( 0.5, 0.5 );
        
        for ( let j = 0; j < n; j ++ ) { // contour
        
            const qu = Math.trunc( 4 * j / n ) + 1 ; // quadrant qu: 1..4         
            const sgn = ( qu === 1 || qu === 4 ? 1: -1) // signum left/right
            
            const c = { x: sgn * ( w / 2 - r ), y: ( qu < 3 ? 1 : -1 ) * ( h / 2 - r ), z: side * d / 2 } // quadrant center
            
            const x = c.x + r * Math.cos( pi2 * ( j - qu + 1 ) / ( n - 4 ) );
            const y = c.y + r * Math.sin( pi2 * ( j - qu + 1 ) / ( n - 4 ) );      
            const z = c.z;
            positions.push( x, y, z );
            
            const u0 = side === 1 ? 0 : 1; 
            uvs.push( u0 + side * ( 0.5 + x / w ), 0.5 + y / h ); 
        
        }
        
    }
          
    function makeFrame( n, sidx, sif, sib ) {
    
        let a, b, c, d, xf, yf, zf, xb, yb, zb;
        const pif = sif * 3; // position start index front
        const pib = sib * 3; // position start index back
        let st = [];
        
        let idx = sidx;
        
        for ( let j = 0; j < n; j ++ ) {
        
            a = idx;
            b = idx + 1;
            c = idx + 2;
            d = idx + 3; 
            
            indices.push( a, b, d, a, d, c );
            
            idx += 2;
            
        }
        
        for ( let j = 0; j < n ; j ++ ) {   
            
            const j3 = j * 3;
            
            xf = positions[pif + j3]; 
            yf = positions[pif + j3 + 1]; 
            zf = positions[pif + j3 + 2];
            
            xb = positions[pib + j3]; 
            yb = positions[pib + j3 + 1]; 
            zb = positions[pib + j3 + 2];
            
            positions.push( xf, yf, zf, xb, yb, zb );
            
            if ( j === 0 ) st = [xf, yf, zf, xb, yb, zb]; // memorize
            
            const v = j / n; // here only independent of section height
            uvs.push( 0, v, 1, v );
            
        }
        
        positions.push( st[0], st[1], st[2], st[3], st[4], st[5] ); // end = start
        uvs.push( 0, 1, 1, 1 );
        
    }
    
}

```

**Note:** In this version the uv values of the frame are different and only independent of the segment size.  
`v = j / n;`

_Addition:_  
_However, it is not a problem to calculate the v values according to the length of the partial circumference sections, if necessary._

_It is also easy to swap u and v to obtain the representation as in the first construction._

The `makeFrame` function with “neat” uv values for a texture.

```javascript
function makeFrame( n, sidx, sif, sib ) {

    let a, b, c, d, xf, yf, zf, xb, yb, zb;
    const pif = sif * 3; // position start index front
    const pib = sib * 3; // position start index back
    let st = [];
    
    let idx = sidx;
    
    for ( let j = 0; j < n; j ++ ) {
    
        a = idx;
        b = idx + 1;
        c = idx + 2;
        d = idx + 3; 
        
        indices.push( a, b, d, a, d, c );
        
        idx += 2;
        
    }
    
    const dx = positions[3] - positions[6]; // first of contour, 0 is center
    const dy = positions[4] - positions[7];
    const ls = Math.sqrt( dx * dx + dy * dy ); // length of contour of one corner segment
    const peri = 2 * ( w - 2 * r ) + 2 * ( h - 2 * r ) + 4 * s * ls; // perimeter  
    const uds = ls / peri; // u difference of one corner segment
    
    const j0 = s;
    const j1 = j0 + s + 1;
    const j2 = j1 + s + 1;
    
    let u = 1;
    
    for ( let j = 0; j < n ; j ++ ) {   
        
        xf = positions[pif + j * 3]; 
        yf = positions[pif + j * 3 + 1]; 
        zf = positions[pif + j * 3 + 2];
        
        xb = positions[pib + j * 3]; 
        yb = positions[pib + j * 3 + 1]; 
        zb = positions[pib + j * 3 + 2];

        positions.push( xf, yf, zf, xb, yb, zb );
        
        if ( j === 0 ) st = [xf, yf, zf, xb, yb, zb]; // memorize

        uvs.push( u, 0, u, 1 );
        
        u -= ( j === j0 || j === j2 ) ? ( w - 2 * r ) / peri : ( j === j1 ? ( h - 2 * r ) / peri : uds );
        
    }
    
    positions.push( st[0], st[1], st[2], st[3], st[4], st[5] ); // end = start
    uvs.push( 0, 0, 0, 1 );
    
}

```

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [December 9, 2022, 11:43am UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/3 "2022-12-09T11:43:47Z")

</div>

**Yet another variant.**

[RoundedBoxFlatUV](https://hofk.de/main/discourse.threejs/2021/RoundEdgedBoxFlat/RoundedBoxFlatUV.html)

The disadvantage of the previous variants is the rigid assignment of the u values of the frame to the respective construction. Therefore, both variants are different regarding the position of the texture to the quadrants. Also, the texture is not applied symmetrically.

With 4 more triangles compared to the previous variant and the duplication of the positions in the middle of the four sides I solved the problem. Thereby I like even the quadrant-wise construction very much. It is clearer than the previous ones.

![2022-12-09 12.21.06](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/e/aed624da557a7a4689bce7dd77e6a5f78b0a8cbf.png)

The texture can be wrapped neatly around the object.  
 ![2022-12-09 12.18.58](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/4/c4ee2615bf47593d343daecb4d4ce955ea763131.png)

Other variant  
 ![2022-12-09 12.19.30](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/c/ec26c6161cc7624801210eee523c7e0f75559f74.png)

An additional optional parameter allows to select the starting quadrant for the texture.

`RoundedBoxFlat( width, height, depth, radiusCorner, smoothness, uStartQuadr ); // uStartQuadr optional`

* * *

```javascript

function RoundedBoxFlat( w, h, d, r, s, q ) {

    let qu = q || 1; // qu: start quadrant regarding u, optional
    const pi = Math.PI;
    let indices = [];
    let positions = [];
    let uvs = [];
    
    makeFronts( s, 1, 0 ); // smoothness, front is 1, start index center front
    makeFronts( s, -1, 4 * ( s + 3 ) + 1 ); // smoothness, back is -1, start index center back
    makeFrame( s, 2 * ( 4 * ( s + 3 ) + 1 ), 1, 4 * ( s + 3 ) + 2 ); // smoothness, start index framing ,start index front, start index back

    const geometry = new THREE.BufferGeometry( );
    geometry.setIndex( new THREE.BufferAttribute( new Uint32Array( indices ), 1 ) );
    geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
    geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), 2 ) );
    
    // add multimaterial groups for front, back, framing
    
    const vtc = 4 * ( s + 2 ) * 3;
    geometry.addGroup ( 0, vtc, 0 );
    geometry.addGroup ( vtc , vtc, 1 );
    geometry.addGroup ( 2 * vtc, 2 * vtc + 3, 2 ); 
   
    geometry.computeVertexNormals( );
    
    return geometry;
    
    function makeFronts( s, side, idx ) {
        
        const d0 = side === 1 ? 0 : 1;
        const d1 = side === 1 ? 1 : 0;
        
        let id = 0;
        
        for ( let q = 1; q < 5; q ++ ) { // quadrants
        
            id ++;
            
            for ( let j = 0; j < s + 2; j ++ ) {
        
                indices.push( idx, idx + d0 + id, idx + d1 + id );
                id ++;
                
            }
            
        }

        positions.push( 0, 0, side * d / 2 ); // center
        uvs.push( 0.5, 0.5 );
        
        let x, y, z, sgnX, sgnY;
        let phi = 0;
        const u0 = side === 1 ? 0 : 1;
        
        for ( let q = 1; q < 5; q ++ ) {
        
            sgnX = q === 1 || q === 4 ? 1 : -1;
            sgnY = q < 3 ? 1 : -1 ;
            
            x = Math.cos( phi ) * w / 2;
            y = Math.sin( phi ) * h / 2;
            z = side * d / 2;
            
            positions.push( x, y, z );
            uvs.push( u0 + side * ( 0.5 + x / w ), 0.5 + y / h );
            
            for ( let j = 0; j < s + 1; j ++ ) {
            
                const c = { x: sgnX * ( w / 2 - r ), y: sgnY * ( h / 2 - r ), z: side * d / 2 } // quadrant center
                
                const dPhi = pi / 2 * j / s;
                
                x = c.x + r * Math.cos( phi + dPhi );
                y = c.y + r * Math.sin( phi + dPhi );      
                z = c.z;
                positions.push( x, y, z ); 
                uvs.push( u0 + side * ( 0.5 + x / w ), 0.5 + y / h ); 
            
            }
            
            phi = phi + pi / 2;
             
            x = Math.cos( phi ) * w / 2;
            y = Math.sin( phi ) * h / 2;
            z = side * d / 2;
            
            positions.push( x, y, z );               
            uvs.push( u0 + side * ( 0.5 + x / w ), 0.5 + y / h );
            
        }
        
    }
          
    function makeFrame( s, sidx, sif, sib ) {
    
        let a, b, c, d, xf, yf, zf, xb, yb, zb;
        const pif = sif * 3; // position start index front
        const pib = sib * 3; // position start index back
        
        let idx = sidx;
        
        for ( let q = 1; q < 5; q ++ ) {
        
            for ( let j = 0; j < s + 2; j ++ ) {
            
                a = idx;
                b = idx + 1;
                c = idx + 2;
                d = idx + 3; 
                
                indices.push( a, b, d, a, d, c );
                
                idx += 2;
                
            }
            
            idx += 2;
            
        }
        
        const ls = 2 * r * Math.sin( pi / ( s * 4 ) ); // length of the outer line of a corner segment
        const w2r = w / 2 - r;
        const h2r = h / 2 - r;
        const peri = 4 * w2r + 4 * h2r + 4 * s * ls; // perimeter
        
        let u;
        idx = 0; // reset
        
        for ( let q = 1; q < 5; q ++ ) {
            
            // console.log ( 'qu', qu );
             
            u = qu / 4;
            
            for ( let j = 0; j < s + 3; j ++ ) {   
                
                xf = positions[pif + idx]; 
                yf = positions[pif + idx + 1]; 
                zf = positions[pif + idx + 2];
                
                xb = positions[pib + idx]; 
                yb = positions[pib + idx + 1]; 
                zb = positions[pib + idx + 2];
                
                positions.push( xf, yf, zf, xb, yb, zb );
                
                idx += 3;
                
                // console.log ( 'u ', u );
                
                uvs.push( u , 0, u, 1 );
                
                if ( j === 0 ) { u -= q === 1 || q === 3 ? h2r / peri : w2r / peri; }
                if ( j === s + 1 ) { u -= q === 1 || q === 3 ? w2r / peri : h2r / peri; }
                if ( j > 0 && j < s + 1 ) { u -= ls / peri; }
                                   
            }
            
            qu = 4 - ( ( 5 - qu ) % 4 ); // cyclic next quadrant with respect to u
            
        }
        
    }
    
}

```

---

<div class="post-metadata">

**Author:** ![toufic](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/toufic/32/43799_2.png) [@toufic](https://discourse.threejs.org/u/toufic)\
**Post date:** [January 14, 2024, 2:41pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/4 "2024-01-14T14:41:33Z")

</div>

Hello @hofk and thank you for sharing these! I’m trying to use the **RoundedBoxFlatUV** variant but I can’t seem to be able to apply different textures for the top/bottom, sides. I’m only able to add one Material that gets applied to the top/bottom and to all the sides. I’m very new to threejs, so please do excuse my question if the answer is obvious. Thank you!

**EDIT:**  
I figured out that only 3 textures can be applied (I was trying with 6) and they match, in order:

1. the top (one texture)
2. the bottom (one texture)
3. the sides (one texture only)

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [January 14, 2024, 4:45pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/5 "2024-01-14T16:45:09Z")

</div>

This is correct, see the lines of code

```javascript
   // add multimaterial groups for front, back, framing
    
    const vtc = 4 * ( s + 2 ) * 3;
    geometry.addGroup ( 0, vtc, 0 );
    geometry.addGroup ( vtc , vtc, 1 );
    geometry.addGroup ( 2 * vtc, 2 * vtc + 3, 2 );

```

You can split the material group “framing” if required. The code must be adapted for this.

---

<div class="post-metadata">

**Author:** ![toufic](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/toufic/32/43799_2.png) [@toufic](https://discourse.threejs.org/u/toufic)\
**Post date:** [January 14, 2024, 10:44pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/6 "2024-01-14T22:44:41Z")

</div>

Thanks a lot! I’ve seen your posts and you’ve created amazing stuff helping the community. I’m still learning about 3d graphics and it’s a whole different world! Trying to understand the code and I think I’m beginning to get a hold of it with your help and examples 🙂

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [January 15, 2024, 9:16am UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/7 "2024-01-15T09:16:13Z")

</div>

You can also work with texture parts.

 ![2024-01-15 10.10.05](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/3/33fe6af556e89f2dd134e8a7687e22b49731cb75.jpeg)

_Note: in a real application it would be better to load the 2 textures only once and then use them!_

```javascript

const material = [
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uvgrid01.png' ), wireframe: false} ),
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uv_grid_opengl.jpg' ), wireframe: false} ),
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uvgrid01.png' ), wireframe: false } ),
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uv_grid_opengl.jpg' ), wireframe: false } ),
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uvgrid01.png' ), wireframe: false } ),
    new THREE.MeshBasicMaterial( { map: texturLoader.load( 'uv_grid_opengl.jpg' ), wireframe: false } ),
];

```

```javascript
const vtc = 4 * ( s + 2 ) * 3;

geometry.addGroup ( 0, vtc, 0 );
geometry.addGroup ( vtc , vtc, 1 );

//geometry.addGroup ( 2 * vtc, 2 * vtc + 3, 2 );

geometry.addGroup ( 2 * vtc, vtc / 2, 2 ); 
geometry.addGroup ( 2.5 * vtc, vtc / 2 , 3 ); 
geometry.addGroup ( 3 * vtc, vtc / 2, 4 );
geometry.addGroup ( 3.5 * vtc, vtc / 2 + 3, 5 );

```

---

<div class="post-metadata">

**Author:** ![cfunk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/cfunk/32/45599_2.png) [@cfunk](https://discourse.threejs.org/u/cfunk)\
**Post date:** [August 18, 2024, 7:21pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/8 "2024-08-18T19:21:32Z")

</div>

```javascript
import * as THREE from 'three';

export function RoundEdgedBoxFlat(w, h, t, r, s) { // width, height, thick, radius corner, smoothness

    // helper const's and let's
    const wi = w / 2 - r; // inner width, half
    const hi = h / 2 - r; // inner height, half 
    const w2 = w / 2; // half width
    const h2 = h / 2; // half height

    let ul = r / w; // u left front side
    let ur = (w - r) / w; // u right front side
    const vl = r / h; // v low
    const vh = (h - r) / h;	// v high

    let phia, phib, xc, yc, uc, vc, cosa, sina, cosb, sinb;

    let positions = [];
    let uvs = [];

    // for front side
    let t2 = t / 2; // + half thick
    let u0 = ul;
    let u1 = ur;
    let u2 = 0;
    let u3 = 1;
    let sign = 1;

    for (let k = 0; k < 2; k++) { // front and back side

        positions.push(

            -wi, -h2, t2, wi, -h2, t2, wi, h2, t2,
            -wi, -h2, t2, wi, h2, t2, -wi, h2, t2,
            -w2, -hi, t2, -wi, -hi, t2, -wi, hi, t2,
            -w2, -hi, t2, -wi, hi, t2, -w2, hi, t2,
            wi, -hi, t2, w2, -hi, t2, w2, hi, t2,
            wi, -hi, t2, w2, hi, t2, wi, hi, t2

        );

        uvs.push(

            u0, 0, u1, 0, u1, 1,
            u0, 0, u1, 1, u0, 1,
            u2, vl, u0, vl, u0, vh,
            u2, vl, u0, vh, u2, vh,
            u1, vl, u3, vl, u3, vh,
            u1, vl, u3, vh, u1, vh

        );

        phia = 0;

        for (let i = 0; i < s * 4; i++) {

            phib = Math.PI * 2 * (i + 1) / (4 * s);

            cosa = Math.cos(phia);
            sina = Math.sin(phia);
            cosb = Math.cos(phib);
            sinb = Math.sin(phib);

            xc = i < s || i >= 3 * s ? wi : -wi;
            yc = i < 2 * s ? hi : -hi;

            positions.push(xc, yc, t2, xc + r * cosa, yc + r * sina, t2, xc + r * cosb, yc + r * sinb, t2);

            uc = i < s || i >= 3 * s ? u1 : u0;
            vc = i < 2 * s ? vh : vl;

            uvs.push(uc, vc, uc + sign * ul * cosa, vc + vl * sina, uc + sign * ul * cosb, vc + vl * sinb);

            phia = phib;

        }

        // for back side
        t2 = -t2;	// - half thick
        u0 = ur;	// right left exchange
        u1 = ul;
        u2 = 1;
        u3 = 0;
        sign = -1;

    }

    // framing

    t2 = t / 2;	// + half thick (again)

    positions.push(

        -wi, -h2, t2, -wi, -h2, -t2, wi, -h2, -t2,
        -wi, -h2, t2, wi, -h2, -t2, wi, -h2, t2,
        w2, -hi, t2, w2, -hi, -t2, w2, hi, -t2,
        w2, -hi, t2, w2, hi, -t2, w2, hi, t2,
        wi, h2, t2, wi, h2, -t2, -wi, h2, -t2,
        wi, h2, t2, -wi, h2, -t2, -wi, h2, t2,
        -w2, hi, t2, -w2, hi, -t2, -w2, -hi, -t2,
        -w2, hi, t2, -w2, -hi, -t2, -w2, -hi, t2

    );

    const cf = 2 * ((w + h - 4 * r) + Math.PI * r); // circumference
    const cc4 = Math.PI * r / 2 / cf // circle-circumference / 4 / circumference
    u0 = 0;
    u1 = 2 * wi / cf;
    u2 = u1 + cc4;
    u3 = u2 + 2 * hi / cf;

    const u4 = u3 + cc4;
    const u5 = u4 + 2 * wi / cf;
    const u6 = u5 + cc4;
    const u7 = u6 + 2 * hi / cf;

    uvs.push(

        u0, 1, 0, 0, u1, 0,
        u0, 1, u1, 0, u1, 1,
        u2, 1, u2, 0, u3, 0,
        u2, 1, u3, 0, u3, 1,
        u4, 1, u4, 0, u5, 0,
        u4, 1, u5, 0, u5, 1,
        u6, 1, u6, 0, u7, 0,
        u6, 1, u7, 0, u7, 1

    );

    phia = 0;
    let u, j, j1;
    const ccs = cc4 / s; // partial value according to smoothness

    for (let i = 0; i < s * 4; i++) {

        phib = Math.PI * 2 * (i + 1) / (4 * s);

        cosa = Math.cos(phia);
        sina = Math.sin(phia);
        cosb = Math.cos(phib);
        sinb = Math.sin(phib);

        xc = i < s || i >= 3 * s ? wi : -wi;
        yc = i < 2 * s ? hi : -hi;

        positions.push(xc + r * cosa, yc + r * sina, t2, xc + r * cosa, yc + r * sina, -t2, xc + r * cosb, yc + r * sinb, -t2);
        positions.push(xc + r * cosa, yc + r * sina, t2, xc + r * cosb, yc + r * sinb, -t2, xc + r * cosb, yc + r * sinb, t2);

        u = i < s ? u3 : (i < 2 * s ? u5 : (i < 3 * s ? u7 : u1)); // Attention! different start to front/back

        j = i % s;
        j1 = j + 1;

        uvs.push(u + j * ccs, 1, u + j * ccs, 0, u + j1 * ccs, 0);
        uvs.push(u + j * ccs, 1, u + j1 * ccs, 0, u + j1 * ccs, 1);

        phia = phib;

    }

    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3));
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));

    // add multimaterial groups for front, back, framing

    const vtc = (6 + 4 * s) * 3; // vertex count one side
    geometry.addGroup(0, vtc, 0);
    geometry.addGroup(vtc, vtc, 1);
    geometry.addGroup(2 * vtc, 24 + 2 * 3 * 4 * s, 2);

    return geometry;

}

```

I am testing this with the latest three.js and I get a distorted box, I wanted to ask if this code works with latest since it’s been published a while ago. Thanks

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [August 18, 2024, 7:35pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/9 "2024-08-18T19:35:20Z")

</div>

As far as I know, the elementary geometry definitions (BufferGeometry) have not changed. This can hardly be the reason. A live example like jsfiddle/codepen would be helpful.

---

<div class="post-metadata">

**Author:** ![cfunk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/cfunk/32/45599_2.png) [@cfunk](https://discourse.threejs.org/u/cfunk)\
**Post date:** [August 18, 2024, 9:44pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/10 "2024-08-18T21:44:56Z")

</div>

```javascript
        const geometry = new RoundEdgedBoxFlat(1,5,1,3,1)
        const transparentMaterial = new THREE.MeshBasicMaterial({
            color: 0x000000,
            opacity: 0.5,
            transparent: true
        });
        
        const mesh = new THREE.Mesh(geometry, transparentMaterial);
        this.webGLScene.add(mesh);

```

 ![Three-js-Shader-Example](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/9/c9c74c978b8957a21b06d9ddd2bd5c3d55f4e19e.png)

---

<div class="post-metadata">

**Author:** ![cfunk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/cfunk/32/45599_2.png) [@cfunk](https://discourse.threejs.org/u/cfunk)\
**Post date:** [August 19, 2024, 10:53am UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/11 "2024-08-19T10:53:20Z")

</div>

my guess is that I’m doing something wrong, but I have just moved to making it on blender and importing the obj … thank you anyways

---

<div class="post-metadata">

**Author:** ![Lawrence3DPK](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/lawrence3dpk/32/29184_2.png) [@Lawrence3DPK](https://discourse.threejs.org/u/Lawrence3DPK)\
**Post date:** [August 19, 2024, 11:41am UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/12 "2024-08-19T11:41:17Z")

</div>

Did you cross reference your implementation with the original source [Round-edged box flat - #3 by hofk](https://discourse.threejs.org/t/round-edged-box-flat/30012/3)

---

<div class="post-metadata">

**Author:** ![hofk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/hofk/32/44944_2.png) [@hofk](https://discourse.threejs.org/u/hofk)\
**Post date:** [August 19, 2024, 6:17pm UTC](https://discourse.threejs.org/t/round-edged-box-flat/30012/13 "2024-08-19T18:17:51Z")

</div>

> [@cfunk](#):
>
> `RoundEdgedBoxFlat(1,5,1,3,1)`

Your parameters do not make sense geometrically.

w = 1 // width  
h = 5 // height  
t = 1 // thick

r = 3 // radius corner **=\> double radius of the corners is 6, but the width and height is much smaller**  
s = 1 // smoothness

 ![2024-08-19 20.16.43](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/9/2/92bdc34da3f455060cc03a4d456138d8d6095450.png)

I have not included a check, as nonsensical values sometimes result in interesting things.

See [RoundedRectangle + Squircle](https://discourse.threejs.org/t/roundedrectangle-squircle/28645) (5th and 6th picture)
