Advertisement

Spherify a cube

Started by November 28, 2019 05:44 PM
9 comments, last by frob 4 years, 11 months ago

So i use this code

_cube2sphere = function (cube) {
 cube.divideScalar(this.radius);
 var x2 = cube.x*cube.x;
 var y2 = cube.y*cube.y;
 var z2 = cube.z*cube.z;
 var sphere = new THREE.Vector3(
  cube.x*Math.sqrt(1.0 - y2*0.5 - z2*0.5 + y2*z2*0.3333333),
  cube.y*Math.sqrt(1.0 - x2*0.5 - z2*0.5 + x2*z2*0.3333333),
  cube.z*Math.sqrt(1.0 - x2*0.5 - y2*0.5 + x2*y2*0.3333333)
 );

 return sphere.multiplyScalar(this.radius);
};


_spherifyVerts = function (geometry) {
 var verts = geometry.attributes.position.array;
 for (var i = 0; i < verts.length; i += 3) {
  var pos = new THREE.Vector3(verts[i], verts[i + 1], verts[i + 2]);
  pos = _cube2sphere(pos);
  verts[i] = pos.x;
  verts[i + 1] = pos.y;
  verts[i + 2] = pos.z;
 }

to Spherify a cube. It works well when cube is in 0,0,0 coords, otherwise everything goes bananas. What would be the strategy to Spherify a cube that is not in the center?

Translate it to the origin, spherify it, and translate it back.

Advertisement
a light breeze said:

Translate it to the origin, spherify it, and translate it back.

Isn't there something smarter?

There is another way of spherifying a cube, which trivially subdivides the faces and then just calculates the normals and multiplies by the radius. One could argue simpler = smarter.

Your algorithm assumes that the object is in the centre. So, matrix transformations to the rescue, drag it to centre where your algorithm works, then translate it back.

You can, of course, write an algorithm that works at any place but that would be more complicated and slower.

Define "smarter".

You can derive a general formula by writing out the translation->spherification->translation process as a single equation and simplifying. You might get a minor performance boost that way. However:

  • Your formula will probably be less readable, and therefore less maintainable, than if you had used separate translation and spherification steps.
  • There is no guarantee that you will actually get better performance. You could even get worse performance. The effect of this kind of micro-optimization is hard to predict.
  • Even if this approach improves performance, there is nothing preventing the compiler from doing the hard work for you and rewriting your translation->spherification->translation code as a single formula for you. This is the kind of thing that modern optimizing compilers do.
  • This is probably not a chokepoint in your program, and therefore there is probably no need to optimize it at all.
Green_Baron said:

There is another way of spherifying a cube, which trivially subdivides the faces and then just calculates the normals and multiplies by the radius. One could argue simpler = smarter.

Your algorithm assumes that the object is in the centre. So, matrix transformations to the rescue, drag it to centre where your algorithm works, then translate it back.

You can, of course, write an algorithm that works at any place but that would be more complicated and slower.

Could you drop some link or code the another way spherifying a cube?

Advertisement
void EllipsoidCM::simpleCubeToEllipsoid() {
    size_t numVerticesPerFace{ ( m_numSubdivsPerFace + 1 ) * ( m_numSubdivsPerFace + 1 ) };
    m_vertices.resize( 6 * numVerticesPerFace );
    size_t i{ 0 };
    const omath::dvec3 diameter{ 2.0 * m_radii };
    const double step{ 1.0 / m_numSubdivsPerFace };
    for( size_t y{0}; y <= m_numSubdivsPerFace; ++y ) {
        const double yOffset{ static_cast<double>(y) * step - 0.5 };
        for( size_t x{0}; x <= m_numSubdivsPerFace; ++x ) {
            const double xOffset{ static_cast<double>(x) * step - 0.5 };
            m_vertices[i] = omath::normalize( omath::dvec3{ xOffset, yOffset, -0.5 } ) * diameter;
            m_vertices[i + numVerticesPerFace] = omath::normalize( omath::dvec3{ -0.5, xOffset, yOffset } ) * diameter;
            m_vertices[i + 2*numVerticesPerFace] = omath::normalize( omath::dvec3{ 0.5, xOffset, yOffset } ) * diameter;
            m_vertices[i + 3*numVerticesPerFace] = omath::normalize( omath::dvec3{ xOffset, yOffset, 0.5 } ) * diameter;
            m_vertices[i + 4*numVerticesPerFace] = omath::normalize( omath::dvec3{ xOffset, 0.5, yOffset } ) * diameter;
            m_vertices[i + 5*numVerticesPerFace] = omath::normalize( omath::dvec3{ xOffset, -0.5, yOffset } ) * diameter;
            ++i;
        }
    }
}

Still can't edit ..

Calculates all 6 faces of a unit cube at the origin, multiplies by the radii and writes the resulting positions to a vector. Can further be simplified by only calculating one side and moving that around.

Green_Baron said:

Still can't edit ..

Calculates all 6 faces of a unit cube at the origin, multiplies by the radii and writes the resulting positions to a vector. Can further be simplified by only calculating one side and moving that around.

Thanks

While you're addressing geometry, you aren't addressing anything else.

What about surface normals? What about UV coordinates (and ST coordinates)? What about the effects of assorted shaders being applied?

If all you're looking for is the surface vertex positions those few are fine. But if you're doing anything more than the vertex math, you'll need to consider how it affects the art as well.

This topic is closed to new replies.

Advertisement