Round-edged box 2

geometry

#1

Based on the idea from this post.
A usual geometry, not a buffer one.
Limitation in this version is that smoothness can’t be less than 3, as it uses THREE.SphereGeometry() which has that limitation for its widthSegments parameter.

https://jsfiddle.net/prisoner849/p614jc75/

Criticism is very welcomed.

  function RoundEdgedBox(width, height, depth, radius, widthSegments, heightSegments, depthSegments, smoothness) {

    width = width || 1;
    height = height || 1;
    depth = depth || 1;
    radius = radius || (Math.min(Math.min(width, height), depth) * .25);
    widthSegments = Math.floor(widthSegments) || 1;
    heightSegments = Math.floor(heightSegments) || 1;
    depthSegments = Math.floor(depthSegments) || 1;
    smoothness = Math.max(3, Math.floor(smoothness) || 3);

    let halfWidth = width * .5 - radius;
    let halfHeight = height * .5 - radius;
    let halfDepth = depth * .5 - radius;

    var geometry = new THREE.Geometry();

    // corners - 4 eighths of a sphere
    var corner1 = new THREE.SphereGeometry(radius, smoothness, smoothness, 0, Math.PI * .5, 0, Math.PI * .5);
    corner1.translate(-halfWidth, halfHeight, halfDepth);
    var corner2 = new THREE.SphereGeometry(radius, smoothness, smoothness, Math.PI * .5, Math.PI * .5, 0, Math.PI * .5);
    corner2.translate(halfWidth, halfHeight, halfDepth);
    var corner3 = new THREE.SphereGeometry(radius, smoothness, smoothness, 0, Math.PI * .5, Math.PI * .5, Math.PI * .5);
    corner3.translate(-halfWidth, -halfHeight, halfDepth);
    var corner4 = new THREE.SphereGeometry(radius, smoothness, smoothness, Math.PI * .5, Math.PI * .5, Math.PI * .5, Math.PI * .5);
    corner4.translate(halfWidth, -halfHeight, halfDepth);
    
    geometry.merge(corner1);
    geometry.merge(corner2);
    geometry.merge(corner3);
    geometry.merge(corner4);

    // edges - 2 fourths for each dimension
    // width
    var edge = new THREE.CylinderGeometry(radius, radius, width - radius * 2, smoothness, widthSegments, true, 0, Math.PI * .5);
    edge.rotateZ(Math.PI * .5);
    edge.translate(0, halfHeight, halfDepth);
    var edge2 = new THREE.CylinderGeometry(radius, radius, width - radius * 2, smoothness, widthSegments, true, Math.PI * 1.5, Math.PI * .5);
    edge2.rotateZ(Math.PI * .5);
    edge2.translate(0, -halfHeight, halfDepth);

    // height
    var edge3 = new THREE.CylinderGeometry(radius, radius, height - radius * 2, smoothness, heightSegments, true, 0, Math.PI * .5);
    edge3.translate(halfWidth, 0, halfDepth);
    var edge4 = new THREE.CylinderGeometry(radius, radius, height - radius * 2, smoothness, heightSegments, true, Math.PI * 1.5, Math.PI * .5);
    edge4.translate(-halfWidth, 0, halfDepth);

    // depth
    var edge5 = new THREE.CylinderGeometry(radius, radius, depth - radius * 2, smoothness, depthSegments, true, 0, Math.PI * .5);
    edge5.rotateX(-Math.PI * .5);
    edge5.translate(halfWidth, halfHeight, 0);
    var edge6 = new THREE.CylinderGeometry(radius, radius, depth - radius * 2, smoothness, depthSegments, true, Math.PI * .5, Math.PI * .5);
    edge6.rotateX(-Math.PI * .5);
    edge6.translate(halfWidth, -halfHeight, 0);

    edge.merge(edge2);
    edge.merge(edge3);
    edge.merge(edge4);
    edge.merge(edge5);
    edge.merge(edge6);

    // sides
    // front
    var side = new THREE.PlaneGeometry(width - radius * 2, height - radius * 2, widthSegments, heightSegments);
    side.translate(0, 0, depth * .5);

    // right
    var side2 = new THREE.PlaneGeometry(depth - radius * 2, height - radius * 2, depthSegments, heightSegments);
    side2.rotateY(Math.PI * .5);
    side2.translate(width * .5, 0, 0);

    side.merge(side2);

    geometry.merge(edge);
    geometry.merge(side);

    // duplicate and flip
    var secondHalf = geometry.clone();
    secondHalf.rotateY(Math.PI);
    geometry.merge(secondHalf);

    // top
    var top = new THREE.PlaneGeometry(width - radius * 2, depth - radius * 2, widthSegments, depthSegments);
    top.rotateX(-Math.PI * .5);
    top.translate(0, height * .5, 0);

    // bottom
    var bottom = new THREE.PlaneGeometry(width - radius * 2, depth - radius * 2, widthSegments, depthSegments);
    bottom.rotateX(Math.PI * .5);
    bottom.translate(0, -height * .5, 0);

    geometry.merge(top);
    geometry.merge(bottom);

    geometry.mergeVertices();

    return geometry;
  }

#2

yup this is it, the geometry here is perfect


#3

And I have one more idea about a round-edged box geometry :thinking:
Just caught it, going home from work ))


#4

The only problem of the solution with the parts of the sphere is that it is not completely symmetrical.

I drew the following structure. To possibly do it with BufferGeometry. By way of
http://threejs.hofk.de/sphere/00_hemiSphere_n_part.html (or THREEp addon).
But there are a lot of faces!

roundedBox


#5

Yeah, as I used THREE.SphereGeometry(), it’s symmetrical on Y-axis only.
I think, I got what you mean. But we don’t need such precision and complexity.
The concept of this solution is to combine basic geometries and their parts ))


#6

Understood!
But I like to play with structures.

Tried my addon - that could also work.

20171219-2146-05284

easier with 3 divisions

20171219-2158-09397


#7

I’ve noticed already :face_with_monocle:
And this is cool actually. Your work is great :+1:


#8

How complex the code for this? If it’s not a secret, could you provide the link to the module and point to the line of code? ))


#9

That’s not very much. I also don’t find it in the addon itself.
But in the preparatory work it is the main part:
http://threejs.hofk.de/sphere/00_hemiSphere_n_part.html
http://threejs.hofk.de/sphere/00_hemiSphere4.html
At http://threejs.hofk.de/ there are two further variants in the middle of the website


#10

It always takes time with me, but these are the main lines of a variant

    var radius;
    var rs; // rings
    var rvSum; // sum of ring vertices
    var vertexCount;
    var x, y, z;
    var a, b, c;
    var ni, nji; // relative i, j
    var Alpha;
    var sinAlpha;
    var cosAlpha;

    g = new THREE.Geometry(); 
    radius = 50;
    rs = 3; // rings

    vertexCount = 1 + 2 * rs * ( rs + 1 ) ;

    for ( var i = 0; i < vertexCount; i ++ ) { 
    			
    	g.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); 
    		
    }

    // vertex 0: pole
    g.faces.push( new THREE.Face3( 0, 1, 2 ) );
    g.faces.push( new THREE.Face3( 0, 2, 3 ) );	
    g.faces.push( new THREE.Face3( 0, 3, 4 ) );
    g.faces.push( new THREE.Face3( 0, 4, 1 ) );

    rvSum = 1; // only vertex 0

    for ( var i = 1; i < rs; i ++ ) {

    	for ( var q = 0; q < 4; q ++ ) {			// quarter ring
    		
    		for ( var j = 0; j < i + 1 ; j ++ ) {  
    							
    			if ( j === 0 ) {
    			
    				//  first face in quarter 
    				
    				a = rvSum;
    				b = a + 4 * i + q;
    				c = b + 1;
    		
    				g.faces.push( new THREE.Face3( a, b, c ) );
    				
    			} else {
    			
    				//  two faces / vertex
    	
    				a = j + rvSum; 
    				b = a - 1; 
    				c = a + 4 * i + q;
    				if ( q === 3 && j === i ) a = a - 4 * i; // connect to first vertex of circle
    			
    				g.faces.push( new THREE.Face3( a, b, c ) );
    				
    				// a  from first face 
    				b = c; // from first face
    				c = b + 1;
    				
    				if ( q === 3 && j === i ) c = c - 4 * ( i + 1 ); // connect to first vertex of next circle
    										
    				g.faces.push( new THREE.Face3( a, b, c ) );
    				
    			}
    			
    		}
    		
    		rvSum += i;
    	}
    	
    }

    g.vertices[ 0 ].set( 0, radius, 0 ); // pole

    rvSum = 1; // only vertex 0

    for ( var i = 0; i <= rs; i ++ ) {

    	ni = i / rs;
    	Alpha = Math.PI / 2 * ni;
    	sinAlpha = Math.sin( Alpha );
    	cosAlpha = Math.cos( Alpha );
    	
    	for ( var j = 0; j < i * 4; j ++ ) { 
    	
    		nji = j / ( i * 4 );
    				
    		x = radius * sinAlpha * Math.cos( 2 * Math.PI * nji );
    		y = radius * cosAlpha;
    		z = - radius * sinAlpha * Math.sin( 2 * Math.PI * nji );		
    		
    		g.vertices[  rvSum + j ].set( x, y, z );
    		
    	}
    	
    	rvSum += i * 4;
    	
    }

#11

Danke schoen!
I’ll look at it as soon as I can )


#12

In the current version of THREEp it is a little bit hidden, I had to search for it myself.:dark_sunglasses:

uWed are the used wedges

var wed = g.wedges;
var uWed = g.usedWedges;

With wed = 4 and uWed = 1 you get the required round corner.

view-source:http://sandboxthreep.threejs.hofk.de/THREEp.js

197 in function:
 function create() {...
---------------------
538
// faces south hemisphere

...

561 - 605 
vIdx = g.southVertex;

for ( var i = bottomS === 0 ? 1 : bottomS; i < topS; i ++ ) {
	
	for ( var w = 0; w < uWed; w ++ ) {
		
		for ( var j = 0; j < i + 1 ; j ++ ) {  
			
			if ( j === 0 ) {
				
				//  first face in wedge 
				
				a = vIdx;
				b = a + uWed * i + w + 2;
				c = b - 1;
				
				pushFaceAndUv()
				
			} else {
			
				//  two faces / vertex
				
				a = j + vIdx; 
				b = a + uWed * i + w + 1;
				c = a - 1;
				
				pushFaceAndUv()
				
				// a  from first face 
				b++; // b from first face
				c = b - 1;
				
				pushFaceAndUv()
				
			}
			
		}
		
		vIdx += i;
		
	}
	
	vIdx ++;

}


2075 in  function:
function morphVertices(...
------------------------
2158
function xyzCalculation(... 
...
2207 
if (  g.style === "complete" && g.squeezeDefault ) {
			
	r = g.radius * g.rAzimuthPole( nji, ni, t );
			
	x = r * Math.cos( theta ) * Math.cos( phi ) + g.radius * g.moveX( nji, ni, t );	
			
	y =  r * Math.sin( theta ); 
	y *= ( sn === SOUTH ? g.stretchSouth( nji, nih, t ) : g.stretchNorth( nji, nih, t ) );
	y += g.radius * ( sn * g.equatorGap( nji, t ) / 2 + g.moveY( nji, ni, t ) );
			
	z = -r * Math.cos( theta ) * Math.sin( phi ) + g.radius * g.moveZ( nji, ni, t );
			
}

#13

My mind kinda melts when reading this code. Does it even create the full rounded box, if not what is being discussed here? :slight_smile:


#14

For what it’s worth, my attempt can be found at http://webglworkshop.com/demos/fillet/filletBox.html

I use BoxGeometry and convert it to a sphere as an intermediate step.


#15

A very similar idea :+1:


#16

i love this one, you actually mapped it!