How to make a rounded-edge and rounded-corner cube by BufferGeometry with split vertices?

Viewed 229

I’m pretty new to THREE.JS. I have built a cube by drawing 6 sides. Each side is formed by two triangles, so I defined 6 vertices for each side (the shared vertices are split). Then I uv map the texture to each vertex of the cube. Here is my code:

let cube  = new T.BufferGeometry();
const vertices = new Float32Array([
     //side1, 6vertices, two triangles
    ax_1,ay_1,az_1,bx_1,by_1,bz_1,......dx_1,dy_1,dz_1,
    //side2
    ax_2,ay_2,az_2,......
    ....
]);
cube.setAttribute('position',new T.BufferAttribute(vertices,3));
cube.computeVertexNormals();
const uvs = new Float32Array([
     //side1 (uv for 6 points)
     ua_1,va_1,ub_1,vb_1,uc_1,vc_1,ua_1,va_1,uc_1,vc_1...
    //side2
    ...
]);
cube.setAttribute('uv',new T.BufferAttribute(uvs,2));
const texture = new T.TextureLoader().load(...);
let material = new T.MeshStandardMaterial({map:texture});
let _cube = new T.Mesh(cube,material);

I’m wondering how can I make the edges and corners of the cube rounded. I’m thinking update the corresponding normal vectors but I’m not sure how to do that:(.

Thank you so much!

1 Answers

Normals only affect the lighting, not the shape of the geometry.

The true way to make rounded everything is to make it "physically" rounded. You can do this a variety of ways, like arranging a bunch of cylinders, spheres, and planes to have the same effect as what you want, but it sounds like you're already pretty familiar with creating your own vertex and normal buffers, so you can maybe skip some of that.

To compute the rounded vertices, consider your basic trig functions, sin and cos, which have convenient JavaScript built-ins under the Math library. You can use these to compute a series of points along an arc. In the case of creating a rounded corner, a 90° (PI/2) arc. So to get n points along the arc, you would do something like this:

Note: this is only creating points on a unit circle. You would also need to make adjustments for alignment to your corners.

const numPoints = 6 // points at 0°, 18°, 36°, 54°, 70°, 90°
const positions = [] // will hold the x, y, z, triplets

let x = null, y = null
for(let i = 0; i < numPoints; ++i){
  console.log(`Working on angle: ${Math.round(57.2958*( (Math.PI / 2) / (numPoints - 1) ) * i)}°`)
  x = Math.cos( ( (Math.PI / 2) / (numPoints - 1) ) * i )
  y = Math.sin( ( (Math.PI / 2) / (numPoints - 1) ) * i )
  x = (x < 1e-6)?0:x // tweak
  y = (y < 1e-6)?0:y // tweak
  console.log(`pushing: ${[x, y, 1, x, y, -1].join(', ')}`)
  positions.push(x, y, 1, x, y, -1)
}

Computing the normals for each of these points is actually quite easy, especially if you keep the values within the unit circle at least at first. The normal for the vertex at index i would be computed as:

let normal = new Vector3(x, y, 0)

Boom. Done with the normal. This works because the vertices were generated based on a unit circle (normals are "normalized" to a length of 1). Note that since the vertex generation code above pushes in two points, you will also need to push in two copies of this normal (because vertex and normal buffers are always 1-ot-1).

Use you knowledge of BufferGeometry to build an index that connects all the dots you just created into triangles, and you're in business.

Now you could do these computation for each rounded corner, making adjustments for where on the unit circle the arc should be arranged, OR you could do it once by populating a temporary BufferGeometry with the vertices as calculated for the unit circle, and then use BufferGeometry.applyMatrix4 to apply a transformation matrix to the points and normals to modify the values into the correct position/orientation for a particular edge.

As for the corners, you can use the same technique, except you have to compute points that can tessellate the surface of a sphere. That's a little tougher, but take a look at how SphereGeometry builds its vertices and normals, and you should be on your way.

One final thing to mention: I didn't talk about building the sides at all, because you've already figured most of that out. But one thing to take note of is that these constructed rounded corners will require that the sides not touch each other like a normal cube. Instead, each edge of a side will need to meet the edge of a rounded edge.

Here is a photo from a Blender plugin that shows how rounded corners using a technique like this might end up:

Rounded Corners

Related