Addon. Produces almost infinite many time-varying geometries with functions

@ Mugen87: Thanks for the hint.

That’s how I’m gonna do it.

I had already examined this duplication by the example of the sphere. There I wrote the numbers of the vertices to the wireframe:

In three.js I now searched for the groups. I’m interested in the CylinderBuffer.
There I found .addGroup( groupStart, groupCount, 0 ) for the Torso and 1, 2 for caps.
In the test, the cylinder showed three materials.

But with TorusBuffer these lines are missing. The multi material does not work there.

The search showed .addGroup () only with box, extrude, shape and cylinder?

Yes, not all geometries support multiple materials. The general philosophy of three.js is to keep things simple. Only some selected geometries use groups, where it actually makes sense. For example a Box has six clearly distinct surfaces that should be able to display different materials. But why would you want multiple materials on a sphere or torus? If users actually need these specific geometry data, they have to create them with 3D modeling tools like Blender. So multiple materials are not a must for procedurally generated geometries.

I understand and agree. With modeling tools or an addon :slight_smile:
I could possibly still think hemispheres as clearly distinguishable?

Since my circularly connected variant has no extra vertices, and I do not want to recreate the algorithm, I started with non indexed. But with a different procedure than to make the thing completely new! This works with identical code for Geometry and BufferGeometry.

I ask isBufferGeometry and then add the missing arrays as with Geometry (same name, internal use). Then add .addAttribute (‘position’, … etc.
After the calculation I write the values into the buffers, for example:

for ( var f = 0, p = 0; f < faceCount; f ++, p += 9 ) {		
		g.positions[ p ] =  g.vertices[ g.faces[ f ].a ].x; 
		g.positions[ p + 1 ] = g.vertices[ g.faces[ f ].a ].y; 
		g.positions[ p + 2 ] = g.vertices[ g.faces[ f ].a ].z; 			
		g.positions[ p + 3 ] = g.vertices[ g.faces[ f ].b ].x; 
		g.positions[ p + 4 ] = g.vertices[ g.faces[ f ].b ].y; 
		g.positions[ p + 5 ] = g.vertices[ g.faces[ f ].b ].z; 			
		g.positions[ p + 6 ] = g.vertices[ g.faces[ f ].c ].x; 
		g.positions[ p + 7 ] = g.vertices[ g.faces[ f ].c ].y; 
		g.positions[ p + 8 ] = g.vertices[ g.faces[ f ].c ].z; ...

This works quite well, see test:

You can switch between Geometry and BufferGeometry.

The BufferGeometry is always flat shaded. I have read some posts and looked at the three.js code to Geometry, DirectGeometry, BufferGeometry and (from …, .groups) intensively. Because non indexed is a “triangle soup”, smooth shading does not work. There is no information about the common points / connections - right?

If I have understood correctly, this is processed with Geometry in the renderer / shader.

If I try now indexed-BufferGeometry, I have to create (because of uv’s) extra vertices and the construction changes considerably, since I have no simple fixed geometry. The many functions must play together.

On the other hand, with the triangle soup, I can very easily create an exploded representation of the geometry.

How is the opinion :question:

BufferGeometry (was) not completely smooth
(edited see Bottom)

When I started with THREEf, I noticed that my self-made THREE.Geometry cylinder at the seam was not smooth.

The last vertices were however “exactly” in the angle 2 * Math.PI. That is why I then formed the last faces with the first vertices in connected geometries. This works perfectly with Geometry. With BufferGeometry there is however a problem with the uv’s.

To make my addon THREEf as uniform as possible for Geometry, BufferGeometry (indexed, non-indexed), I made some tests. With THREE.CylinderGeometry, the seam is smooth and vertexNormalHelper shows normal at the top oblique.

If I change to CylinderBufferGeometry ( is indexed ), there are two different normals at the seam. The seam is clearly visible. The normals at the top are horizontal.

In three.js I’ve seen that at function CylinderGeometry (… after fromBufferGeometry (… then this.mergeVertices () is executed with an epsilon of 0.0001.

This means that Geometry and BufferGeometry are not identical in appearance.

I am supposed to take BufferGeometry because it is more efficient. But I have a seam. Merge vertices also requires resources. My current method (non-indexed) of working with other arrays first and then writing to buffers is also not very efficient. My non-indexed BufferGeometry is always flat shaded.

(I am now quite uncertain how to do it. :thinking:)

EDIT Mai 21: I have now found: If I remove
the seam is smooth.

I probably have to test further variants!

Pictures of the seam (and German text):,html,js/3d-grafik-webgl-mit-three-js/?q=94096&pg=-1#94096

It took some time.:hourglass_flowing_sand:

Now the extension of THREEf to indexed and non-indexed BufferGeometry is finally finished. On GitHub: GitHub - hofk/THREEf.js: three.js addon, to produce almost infinite many time-varying geometries / buffer geometries with functions (cylindrical coordinates) . The old version is in THREEf_old.

If you do not need Geometry and BufferGeometry, you can delete the corresponding blocks.

That are

or in morphFaces

at the end of the functions

The new version you can test now on (firefox) .
There is a link basic examples / source where you can compare the three variants.

The old examples I have updated. Some figures are now created with BufferGeometry.

There is still a difference between the normals of Geometry and Buffer geometry. Using .computeVertexNormals (); in Geometry the normals are twisted to the left / right at the upper and lower edge.

This results (!waffled) from the different number (1 or 2) of faces left/ right. In BufferGeomety I have balanced this by doubling faces.

For example
vFace.push( fIdx * 3 );
if ( i === 0 ) vFace.push( fIdx * 3 ); // face double (equal number left and right)

Maybe later, I calculate the normal at Geometry itself.

Some more information (only in german language - my english is very bad) and pictures:,html,js/3d-grafik-webgl-mit-three-js/

1 Like

Inspired by the question
Rendering quad mesh and it's edges
I added a quad simulation.


Available on GitHub GitHub - hofk/THREEf.js: three.js addon, to produce almost infinite many time-varying geometries / buffer geometries with functions (cylindrical coordinates)
and test on

It works with Geometry and BufferGeometry.

For this I connected all vertices with a line in zigzag. In my test code this is good to see.

With BufferGeometry it works the same, is only slightly more confusing.:thinking:

lines Geometry: 300, 2358,
BufferGeometry: indexed: 580, 2570 , non indexed 1303, 2945

I have now expanded the vertexNumbersHelper to BufferGeometry.

Since non-indexed BufferGeometry has no vertices / indices, I use the internal array vertexPositions.

The triangles involved are stored in this array for each defined vertex. More specifically, the positions of the respective corners.

So I take the first entry for every vertex n.

vertexNumbers[ n ].position.set( … .vertexPositions[ n ][ 0 ] …

At the new possibility is now integrated.

The extended version is also available on GitHub GitHub - hofk/THREEf.js at master

THREEf.js is now ready. The final version 86.5 is on GitHub

As I wrote in the first post here, I now start with polar / spherical coordinates.

Some initial results are available:


there are other scripts. Variables and // comments in English, more precise explanations only in the German text.

I’m going to bring it to GitHub.


An alpha version of THREEp.js is available on GitHub.

p for polar / spherical coordinates

So far only indexed BufferGeometry is supported.

Two examples are added.

Here is another example:


// geometry
var parameters = {

  equatorGap: 0.05,
  bottomCircle: 7,
  withBottom: true,
  topCircle: 12,
  withTop: true,
  rPhiTheta: function( u, v, t ) { return  1.5 + Math.sin( 4 * Math.PI * u )  },


Nice guys! Keep up the great work!

THREEp.js. - an extended alpha version is now available on GitHub

  • It works with three.js r87.
  • The spherical wedges can be closed at the side (default).
  • The equator gap is now available as a function.

With the equator gap - now as a function - a small monster opens and closes its mouth.
With parameter t - Time.

screenshots exampleA2. html



var parameters = {

equator: 4,

equatorGap: function( u, t ) { return  0.5 *( 1 + Math.cos( 6.28 * u)) *( 0.5 -  u )*( 0.5 -  u ) * ( 1 + Math.sin( t ) ) },
stretchSouth: function ( u, v, t ) { return  ( 1 + Math.cos( 6.28 * u)) *( 0.5 -  u )*( 0.5 -  u ) * ( 1 + Math.sin( t ) ) },

wedges: 11,
usedWedges: 8,

topCircle: 7,
withTop: true,

bottomCircle: 3,
withBottom: true,


:new:I created a sandbox for THREEp. js.:new:

It is available with the latest alpha version on GitHub and on my site.
On is now a selection: THREEf or THREEp.

A nasty bug got me annoyed and took time. He’s been in there a little longer. But it only became visible in certain parameter constellations. So he was able to slip through for some time. The positive side effect is that the vertexNumbersHelper function is now extended to vertexFaceNumbersHelper. Either vertices or faces or both.

The squeeze function is available. It is solved similar to unrolling with the cylinder.


More detailed explanations can be found in the German forum.,html,js/3d-grafik-webgl-mit-three-js/

This is quite cool! It has so many uses! Congratulations sir, you are a genius.

No genius, this text was translated with DeepL Translate because my English is miserable!

I have just updated the alpha version with scaling functions to my page (GitHub will follow later.)


Videos are available on .

For the hemispheres, scaling between start and end function is possible.

For the sphere, however, the scaling works only between the default values 0 and 1.

Several attempts with start and end function led to different positioning errors. Convex and concave functions react differently. If the evenings are getting longer again, I have to delve deeper into the mathematical theory, I’m not a genius. Maybe there is a simple solution - you just have to find it. :eyes:

THREEp’s latest update is now available at GitHub.

During tests I noticed that the sandboxes now also run under the latest browsers Chrome and Opera.

THREEf / sandbox I brought to the stand of three. js r87. This relates to FlatShading.

flatShading =	document.getElementById( "flatShading" ).checked;
	//shading =	flatshading ? THREE.FlatShading : THREE.SmoothShadig;  // old
	//	.flatShading: true or false; // three.js r87

In THREEf is now also the extended helper

function vertexFaceNumbersHelper (mesh, mode, size, color) {)

	mode: 0 nothing, 1 vertex, 2 face, 3 vertex & face

available. For Geometry and BufferGeometry. GitHub and my page.

I wrote some days ago:
If the evenings are getting longer again, I have to delve deeper into the mathematical theory, … Maybe there is a simple solution - you just have to find it.

I almost had the simple solution. No complicated mathematical theory is required.
Again and again I added the same small bug to my variants.:crazy_face:

The simple solution:

in function create()

if ( g.scaleH ) {

	//  ...HSE Hemisphere Start- End
	g.scalePoleHSE = function( u, v, t ) { return  1 - ( g.startPole( u, t ) + ( g.endPole( u, t ) - g.startPole(u, t ) ) * g.scalePoleH( v, t ) ) }
} else {

	// uses the decomposed scale function (South and North)

	g.scalePoleS = function( u, v, t ) { return 2 * ( g.startPole( u, t ) + ( g.endPole( u, t ) - g.startPole( u, t ) ) * g.scalePole(  v / 2, t ) ) }
	g.scalePoleN = function( u, v, t ) { return 2 * ( 1 - g.endPole( u, t ) + ( g.endPole( u, t ) - g.startPole( u, t ) ) * ( 1 - g.scalePole( 1 -  v / 2, t ) ) ) }

in function morphVertices( time )

if ( g.scaleH )  {
	// scaling between pole and equator (start- and endPole) per hemisphere --> south is like north
	theta = south_north * pi2 * g.scalePoleHSE( nji, nih, t );
} else {
	// scaling of the sphere between south and north (start- and endPole) with decomposed function
	theta = south_north * pi2 * ( 1 - ( south_north === SOUTH ? g.scalePoleS( nji, nih, t ) : g.scalePoleN( nji, nih, t ) ) );

Now on my side and GitHub.


1 Like

Just updated the sandbox. sandboxthreep.threejs at In it you can now also create geometries from the three. js “triangle soup” non indexed BufferGeometry.


For non indexed the calculation of the vertex normals is still missing, for indexed the three. js internal function is currently used. However, it leads to unsightly seams and has to be replaced. That gives again an extensive computing as with THREEf.

Not yet on GitHub.

1 Like

The vertex normals are now available. I was able to copy some of THREEf’s stuff.


Now there is also an exploded view. Of course only for non indexed BufferGeometry.

And that was very easy thanks to the existing data.

Since I needed the face normals to calculate the vertex normals, they are stored in the data field g.faceNormal.
If you now add to each position a multiple of these face normals, the triangles will drift apart from the middle.

Since the triangles of bottom, top and wedge have identical normals (parallel) they are shifted in the same way and thus stay together.

Of course, the explode function only works with non-indexed. Note! explode only accepts the time parameter t.
See video at the moment and below the sandbox. You can try it out there.

[ Not yet on GitHub.] UPDATE: Latest Versions on GitHub!

THREEf and THREEp with explode function

Even if THREE. Geometry doesn’t persist in the long run, it is still very much present in the documentation, the questions, the answers and examples. That’s why I extended THREEp to THREE. Geometry. This was not very complicated, because large blocks of indexed BufferGeometry and from THREEf could be copied. I only made the necessary changes.

However, the seams are not as easy to remove as with BufferGeometry. It’s a lot of effort. Or I don’t have the optimal idea yet.

The THREE. Geometry variant is now available in my sandbox - see links above.


Soon also on GitHub.

:b: E T :a:

I put the seams aside and added the specification of the material index per face by string data field. With THREEp it is quite easy to use the order of faces per hemisphere, the strings are for bottom or top (South/North, if available) for each spherical segment and for the top plane and wedge (if available).

Thus, the scope is now similar to THREEf and the beta phase is reached.

The beta version is available on my site and on GitHub.