Sphere without use of trigonometric functions

In general, trigonometric functions are used when calculating circles and spheres.

But it is also very easy without these functions.

The construction of the sphere is made of 8 parts similar to my magic sphere in the addon THREEg. Addon to create special / extended geometries
20190401-2107-53395 The basis is the logo of discourse. threejs. org
Here I have now used indexed BufferGeometry.20190401-2048-31168


Correction April 15th

Working on an example, I looked at the sphere again. I noticed a mistake. Since I often only worked with THREE.DoubleSide and wireframe: true, I didn’t notice it.
Half of the octants have the front inside! :frowning_face:

I have to reverse the order of the indices there.

I have corrected the function indicesPartSphere( p ) and use
spin = ( p === 0 || p === 2 || p === 5 || p === 7 ) ? true : false;


Here you can find it in the collection.
http://discourse.threejs.hofk.de/2019/SphereWithoutTrigonometry/SphereWithoutTrigonometry.html


The complete code:

<head>
	<title> SphereWithoutTrigonometry </title>
	<meta charset="utf-8" />
</head>
<body> 	</body>
<script src="../js/three.min.103.js"></script>
<script src="../js/OrbitControls.js"></script>

<script>

// @author hofk

'use strict';

const sumNN = ( n ) => ( n * ( n + 1 ) / 2 );	// Sum natural numbers
const sumON = ( n ) => ( n * n );		// Sum odd numbers

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 0, 1, 8 );
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdddddd, 1 );
const container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement ); 
const controls = new THREE.OrbitControls( camera, renderer.domElement );

const tex1 = new THREE.TextureLoader().load( 'uvgrid01.png' );
//const material = new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } );
const tex2 = new THREE.TextureLoader().load( 'dahlia.png' );

const material = [
	new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } ),
	new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide, wireframe: true } ),
	new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.DoubleSide } ),
	new THREE.MeshBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide, wireframe: true } ),
	new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
	new THREE.MeshBasicMaterial( { map: tex2, side: THREE.DoubleSide, wireframe: false } ),
	new THREE.MeshBasicMaterial( { color: 0x33ff55, side: THREE.DoubleSide } ),
	new THREE.MeshBasicMaterial( { map: tex1, side: THREE.DoubleSide } )
];

const g = new THREE.BufferGeometry( );

//SphereWithoutTrigonometry( g, 2.5, 10, [ 1,1,0,0, 1,0,1,0 ] );  //  ( BufferGeometry, radius, equator, parts )
	//equator = half of height segments = quarter of equatorial segments
SphereWithoutTrigonometry( g, 3,18 );
const mesh = new THREE.Mesh( g, material );
scene.add( mesh );

animate();

function animate() {
	
	requestAnimationFrame( animate );
	renderer.render( scene, camera );
	controls.update();
	
}

function SphereWithoutTrigonometry( g, r, eqt, parts ) { //  ( BufferGeometry, optional: radius, equator, parts )

	r = r !== undefined ? r : 1;
	eqt = eqt !== undefined ? eqt : 8;
	
	// parts array, value 1 for octant, otherwise arbitrary - upper counterclockwise, lower clockwise seen from below 
	parts = parts !== undefined ? parts : [ 1,1,1,1, 1,1,1,1 ];
	
	let pCount = 0;
	
	for ( let p = 0; p < 8; p ++ ) {
		
		pCount += parts[ p ] === 1 ? 1 : 0; 
		
	}
	
	let posIdx = 0;	// position index
	let uvIdx = 0;	// uv index
	let fIdx = 0;	// face index
	
	const vertexCount = sumNN( eqt + 1 ) * pCount;
	const faceCount = sumON( eqt ) * pCount;
	
	g.faceIndices = new Uint32Array( faceCount * 3 );
	g.vertices = new Float32Array( vertexCount * 3 );
	g.uvs = new Float32Array( vertexCount * 2 );
	
	g.setIndex( new THREE.BufferAttribute( g.faceIndices, 1 ) );
	g.addAttribute( 'position', new THREE.BufferAttribute( g.vertices, 3 ) );
	g.addAttribute( 'uv', new THREE.BufferAttribute( g.uvs, 2 ) );
	
	pCount = 0;
	
	for ( let p = 0; p < 8; p ++ ) {
		
		if (  parts[ p ] === 1 ) {
			
			indicesPartSphere( p );
			verticesUVsPartSphere( p );
			pCount += 1;
			
		}
		
	}
	
	function indicesPartSphere( p ) {
		
		let a0, a1, b0, b1;	// indices
	let spin = ( p === 0 || p === 2 || p === 5 || p === 7 ) ? true : false;
	
		a0 = sumNN( eqt + 1 ) * pCount; // start vertex index per part
		
		g.addGroup( fIdx, sumON( eqt ) * 3, p ); // write groups for multi material
		
		for ( let i = 0; i < eqt; i ++ ) {
			
			a1 = a0 + 1;
			b0 = a0 + i + 1; //  below ( i ) 
			b1 = b0 + 1;
			
			// each two faces
			
			for ( let j = 0; j < i; j ++ ) {
			
			g.faceIndices[ fIdx     ] = j + a0;			// left face
			g.faceIndices[ fIdx + 1 ] = j + ( spin ? b1 : b0 );
			g.faceIndices[ fIdx + 2 ] = j + ( spin ? b0 : b1 );
			
			g.faceIndices[ fIdx + 3 ] = j + a0;			// right face
			g.faceIndices[ fIdx + 4 ] = j + ( spin ? a1 : b1 );
			g.faceIndices[ fIdx + 5 ] = j + ( spin ? b1 : a1 );	
				
				fIdx += 6;
				
			}
		
		g.faceIndices[ fIdx     ] = i + a0;	// last face in row ( like a left face )
		g.faceIndices[ fIdx + 1 ] = i + ( spin ? b1 : b0 );
		g.faceIndices[ fIdx + 2 ] = i + ( spin ? b0 : b1 );
			
			fIdx += 3;
			
			a0 += i + 1; // next start index
			
		}
	
	}
	
	function verticesUVsPartSphere( p ) {
		
		const signX = ( p === 0 || p === 3 || p === 4 || p === 7 ) ? 1 : -1;
		const signY = p < 4 ? 1 : -1; 
		const signZ = ( p === 2 || p === 3 || p === 6 || p === 7 ) ? 1 : -1;
		
		let xp, yp, zp, len;
		
		let ux = 0.5;	
		let du = 1 / eqt;
		let uy = 1 + du;	
		
		for ( let i = 0 ; i <= eqt; i ++ ) {
			
			yp =  1 -  i / eqt;
			
			ux =  0.5 + signX * signY * signZ * ( i + 2 ) * du / 2;
			uy -= du;
			
			for ( let j = 0; j <= i ; j ++ ) {
				
				xp =  ( i -  j ) / eqt;
				zp =  j / eqt;
				
				len = Math.sqrt( xp * xp + yp * yp + zp * zp ); // to normalize
				
				g.vertices[ posIdx     ] = r * signX * xp / len;
				g.vertices[ posIdx + 1 ] = r * signY * yp / len;
				g.vertices[ posIdx + 2 ] = r * signZ * zp / len;
				
				posIdx += 3;
				
				ux += -signX * signY * signZ * du;
				
				g.uvs[ uvIdx ] = ux;
				g.uvs[ uvIdx + 1 ] = uy;
				
				uvIdx  += 2;		
						
			}
				
		}
		
	}
	
 }

</script>

</html>
2 Likes

You can do this with three.js:

const box = new THREE.BoxGeometry(1,1,1,12,12,12)
const sphere =  box.clone().vertices.forEach(vertex=>vertex.normalize())
1 Like

Yes, but it’s not identical. It’s also not a buffer geometry.

20190416-1829-51318

const g = new THREE.BufferGeometry( );
SphereWithoutTrigonometry( g, 1,12 );
const mesh = new THREE.Mesh( g, material );
scene.add( mesh );

const box = new THREE.BoxGeometry(1,1,1,12,12,12);
//const sphere = box.clone().vertices.forEach(vertex=>vertex.normalize());
// console.log( sphere ); //  I get undefined

const sphere = box.clone(); //.vertices.forEach(vertex=>vertex.normalize());
sphere.vertices.forEach(vertex=>vertex.normalize());

const mesh1 = new THREE.Mesh( box, material );
scene.add( mesh1 );
mesh1.position.x = 2;

const mesh2 = new THREE.Mesh( sphere, material );
scene.add( mesh2 );
mesh2.position.x = -2;

Right, but i was just illustrating that you don’t need trig to spherify something.