From a question Morphing between two geometries I made a dynamic geometry.
A box is morphed to a sphere and back by any function.
Try it out MorphBoxSphere
// g BufferGeometry, r radius, cs count of segments per side, v norph function, result 0 .. 1
function CubeSphereGeometry( g, r, cs, v ) {
// const sd = r * 1 / Math.sqrt( 2 ); // 1/2 square diagonal
const ss = r * 1 / Math.sqrt( 3 ); // 1/2 square side
const css = cs + 1;
const hvc = css + cs ; // height vertex count
const vertexCount = css * css + cs * cs;
const faceCount = cs * cs * 4;
let a0, b0, c0, a1, b1, c1, le;
const indices = new Uint32Array( faceCount * 3 * 6 );
g.positions = new Float32Array( vertexCount * 3 * 6 );
uvs = new Float32Array( vertexCount * 2 * 6 ); // uvs to positions
g.setIndex( new THREE.BufferAttribute( indices, 1 ) );
g.setAttribute( 'position', new THREE.BufferAttribute( g.positions, 3 ).setUsage( THREE.DynamicDrawUsage) );
g.setAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
g.cube = new Float32Array( vertexCount * 3 * 6 ); // basis positions plane,cube
g.diff = new Float32Array( vertexCount * 3 * 6 ); // difference positions cube sphere
let idx = 0;
let offs = 0;
makeIndices( );
idx = 0; // reset
// ia, ib, ic, sign
makePositions( 0, 1, 2, 1 );
makePositions( 0, 1, 2, -1 );
makePositions( 1, 2, 0, 1 );
makePositions( 1, 2, 0, -1 );
makePositions( 2, 0, 1, 1 );
makePositions( 2, 0, 1, -1 );
idx = 0; // reset
// ia, ib, o1, o2 ia, ib: index o1, o2: orientation
makeUVs( 0, 1, 1, 1 );
makeUVs( 0, 1, -1, 1 );
makeUVs( 1, 0, 1, -1 );
makeUVs( 1, 0, 1, 1 );
makeUVs( 1, 0, 1, -1 );
makeUVs( 1, 0, 1, 1 );
function makeIndices( ) {
let materialIndex = 0;
let startIdx = 0;
let sign = 1;
for ( let k = 0; k < 6; k ++ ) {
for ( let j = 0; j < cs; j ++ ) {
for ( let i = 0; i < cs; i ++ ) {
// 4 faces / segment
a = offs + hvc * j + css + i;
b1 = offs + hvc * j + i; // bottom
c1 = offs + hvc * ( j + 1 ) + i;
b2 = offs + hvc * j + 1 + i; // left
c2 = offs + hvc * j + i;
b3 = offs + hvc * ( j + 1 ) + i; // right
c3 = offs + hvc * ( j + 1 ) + 1 + i;
b4 = offs + hvc * ( j + 1 ) + 1 + i; // top
c4 = offs + hvc * j + 1 + i;
if ( sign === 1 ) {
indices[ idx ] = a; // bottom
indices[ idx + 1 ] = b1;
indices[ idx + 2 ] = c1;
indices[ idx + 3 ] = a; // left
indices[ idx + 4 ] = b2,
indices[ idx + 5 ] = c2;
indices[ idx + 6 ] = a; // right
indices[ idx + 7 ] = b3;
indices[ idx + 8 ] = c3;
indices[ idx + 9 ] = a; // top
indices[ idx + 10 ] = b4,
indices[ idx + 11 ] = c4
}
if ( sign === -1 ) {
indices[ idx ] = a; // bottom
indices[ idx + 1 ] = c1;
indices[ idx + 2 ] = b1;
indices[ idx + 3 ] = a; // left
indices[ idx + 4 ] = c2,
indices[ idx + 5 ] = b2;
indices[ idx + 6 ] = a; // right
indices[ idx + 7 ] = c3;
indices[ idx + 8 ] = b3;
indices[ idx + 9 ] = a; // top
indices[ idx + 10 ] = c4,
indices[ idx + 11 ] = b4
}
idx += 12;
}
}
g.addGroup ( startIdx, idx - startIdx, materialIndex );
materialIndex ++;
startIdx = idx;
offs += hvc * cs + css; // + vertex count one side
sign = -sign;
}
}
function makePositions( ia, ib, ic, sign ) {
for ( let j = 0; j < css; j ++ ) {
for ( let i = 0; i < css; i ++ ) {
a0 = -ss + 2 * ss * j / cs;
b0 = -ss + 2 * ss * i / cs;
c0 = sign * ss;
g.cube[ idx + ia ] = a0;
g.cube[ idx + ib ] = b0;
g.cube[ idx + ic ] = c0;
le = Math.sqrt( a0 * a0 + b0 * b0 + c0 * c0 );
a1 = r * a0 / le;
b1 = r * b0 / le;
c1 = r * c0 / le;
g.diff[ idx + ia ] = a1 - a0;
g.diff[ idx + ib ] = b1 - b0;
g.diff[ idx + ic ] = c1 - c0;
g.positions[ idx + ia ] = a0;
g.positions[ idx + ib ] = b0;
g.positions[ idx + ic ] = c0;
idx += 3;
}
if( j < cs ) {
for ( let i = 0; i < cs; i ++ ) {
a0 = -ss + 2 * ss * ( j + 0.5 ) / cs;
b0 = -ss + 2 * ss * ( i + 0.5 ) / cs;
c0 = sign * ss;
g.cube[ idx + ia ] = a0;
g.cube[ idx + ib ] = b0;
g.cube[ idx + ic ] = c0;
le = Math.sqrt( a0 * a0 + b0 * b0 + c0 * c0 );
a1 = r * a0 / le;
b1 = r * b0 / le;
c1 = r * c0 / le;
g.diff[ idx + ia ] = a1 - a0;
g.diff[ idx + ib ] = b1 - b0;
g.diff[ idx + ic ] = c1 - c0;
g.positions[ idx + ia ] = a0;
g.positions[ idx + ib ] = b0;
g.positions[ idx + ic ] = c0;
idx += 3;
}
}
}
}
function makeUVs( ia, ib, o1, o2 ) {
for ( let j = 0; j < css; j ++ ) {
for ( let i = 0; i < css; i ++ ) {
uvs[ idx + ia ] = o1 === 1 ? j / cs : 1 - j / cs;
uvs[ idx + ib ] = o2 === 1 ? i / cs : 1 - i / cs;
idx += 2;
}
if( j < cs ) {
for ( let i = 0; i < cs; i ++ ) {
uvs[ idx + ia ] = o1 === 1 ? ( j + 0.5 ) / cs : 1 - ( j + 0.5 ) / cs;
uvs[ idx + ib ] = o2 === 1 ? ( i + 0.5 ) / cs : 1 - ( i + 0.5 ) / cs;
idx += 2;
}
}
}
}
g.morph = function morph( t ) {
idx = 0; // reset
// ia, ib, ic ia, ib, ic : index
setPositions( 0, 1, 2 );
setPositions( 0, 1, 2 );
setPositions( 1, 2, 0 );
setPositions( 1, 2, 0 );
setPositions( 2, 0, 1 );
setPositions( 2, 0, 1 );
g.attributes.position.needsUpdate = true;// to change the positions of the vertices
function setPositions( ia, ib, ic ) {
for ( let j = 0; j < css; j ++ ) {
for ( let i = 0; i < css; i ++ ) {
g.positions[ idx + ia ] = g.cube[ idx + ia ] + v( t ) * g.diff[ idx + ia ];
g.positions[ idx + ib ] = g.cube[ idx + ib ] + v( t ) * g.diff[ idx + ib ];
g.positions[ idx + ic ] = g.cube[ idx + ic ] + v( t ) * g.diff[ idx + ic ];
idx += 3;
}
if( j < cs ) {
for ( let i = 0; i < cs; i ++ ) {
g.positions[ idx + ia ] = g.cube[ idx + ia ] + v( t ) * g.diff[ idx + ia ];
g.positions[ idx + ib ] = g.cube[ idx + ib ] + v( t ) * g.diff[ idx + ib ];
g.positions[ idx + ic ] = g.cube[ idx + ic ] + v( t ) * g.diff[ idx + ic ];
idx += 3;
}
}
}
}
}
}