GridBoxGeometry

This question was asked many times on SO, but there hasn’t been any appropriate and simple solution so far. I can’t say though that mine is just what we need, but anyway, here it is. Based on the method .toGrid() from this showcase Grids of Waves (shaders).

GridBoxGeometry

https://jsfiddle.net/prisoner849/8hqy99jj/

GridBoxGeometry. Takes two parameters.
The first one geometry is of the type THREE.BoxBufferGeometry.
The second one independent is optional boolean. Default value is false. If set to true, the resulting geometry will have a cloned copy of the buffer attribute position from the first parameter, otherwise, it shares this attribute.

Criticism is very welcomed.

  function GridBoxGeometry(geometry, independent) {
    if (!(geometry instanceof THREE.BoxBufferGeometry)) {
      console.log("GridBoxGeometry: the parameter 'geometry' has to be of the type THREE.BoxBufferGeometry");
      return geometry;
    }
    independent = independent !== undefined ? independent : false;

    let newGeometry = new THREE.BoxBufferGeometry();
    let position = geometry.attributes.position;
    newGeometry.attributes.position = independent === false ? position : position.clone();

    let segmentsX = geometry.parameters.widthSegments || 1;
    let segmentsY = geometry.parameters.heightSegments || 1;
    let segmentsZ = geometry.parameters.depthSegments || 1;

    let startIndex = 0;
    let indexSide1 = indexSide(segmentsZ, segmentsY, startIndex);
    startIndex += (segmentsZ + 1) * (segmentsY + 1);
    let indexSide2 = indexSide(segmentsZ, segmentsY, startIndex);
    startIndex += (segmentsZ + 1) * (segmentsY + 1);
    let indexSide3 = indexSide(segmentsX, segmentsZ, startIndex);
    startIndex += (segmentsX + 1) * (segmentsZ + 1);
    let indexSide4 = indexSide(segmentsX, segmentsZ, startIndex);
    startIndex += (segmentsX + 1) * (segmentsZ + 1);
    let indexSide5 = indexSide(segmentsX, segmentsY, startIndex);
    startIndex += (segmentsX + 1) * (segmentsY + 1);
    let indexSide6 = indexSide(segmentsX, segmentsY, startIndex);

    let fullIndices = [];
    fullIndices = fullIndices.concat(indexSide1);
    fullIndices = fullIndices.concat(indexSide2);
    fullIndices = fullIndices.concat(indexSide3);
    fullIndices = fullIndices.concat(indexSide4);
    fullIndices = fullIndices.concat(indexSide5);
    fullIndices = fullIndices.concat(indexSide6);

    newGeometry.setIndex(fullIndices);

    function indexSide(x, y, shift) {
      let indices = [];
      for (let i = 0; i < y + 1; i++) {
        let index11 = 0;
        let index12 = 0;
        for (let j = 0; j < x; j++) {
          index11 = (x + 1) * i + j;
          index12 = index11 + 1;
          let index21 = index11;
          let index22 = index11 + (x + 1);
          indices.push(shift + index11, shift + index12);
          if (index22 < ((x + 1) * (y + 1) - 1)) {
            indices.push(shift + index21, shift + index22);
          }
        }
        if ((index12 + x + 1) <= ((x + 1) * (y + 1) - 1)) {
          indices.push(shift + index12, shift + index12 + x + 1);
        }
      }
      return indices;
    }
    return newGeometry;
  };
3 Likes

Another way to get a GridBox.

Uses THREEg addon https://discourse.threejs.org/t/addon-to-create-special-extended-geometries/1855/3

Try it on http://sandboxthreeg.threejs.hofk.de/gridBoxTHREEg.html
20180307-2003-59694

Add
waffleDeep: function( t ){ return 0.02 },
to parameters0 and you get

20180307-2028-51891

<!DOCTYPE html>
<!--   *** example MagicBox - THREEg - ***
/**
 * @author hofk / http://threejs.hofk.de/
*/
-->
<html lang="de">
<head>
	<title> Magic Box </title>
	<meta charset="utf-8" />
</head>
<body bgcolor="#cccccc " >
</body>
<script src="three.min.90.js"></script>
<script src="OrbitControls.js"></script>
<script src="THREEx.WindowResize.js"></script>
<script src="THREEg.js"></script>
<script>
'use strict'
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set( 1, 2, 3);
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xefefef, 1 );
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
THREEx.WindowResize( renderer, camera );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = true;
var light1 = new THREE.PointLight();
light1.position.set( -2, 2, 4 );
scene.add( light1 ); 
var light2 = new THREE.PointLight();
light2.position.set( -6, -3, -6 );
scene.add( light2 );
var clock  = new THREE.Clock( true );
var time;
var side = THREE.DoubleSide; // material
var materials = [																		// material index:
	new THREE.MeshBasicMaterial( { transparent: true, opacity: 0.45, 	side: side } ),	//  0 transparent
	new THREE.MeshPhongMaterial( { color: 0xff0000, emissive: 0xff0000, side: side } ), //  1 red	
	new THREE.MeshPhongMaterial( { color: 0x444444, emissive: 0x333333, side: side } )	//  2 grey	
];
var parameters0 = {
	sides: [ 7,7,7,7 ],
	materials: [ 2, 2, 2, 2, 2, 2 ],	
	radius: function( t ){ return 0 },
	widthSegments: 8,
	heightSegments: 8,
	depthSegments: 8,
	explode: function( t ){ return 0.01 },
}
var geometry0 = new THREE.BufferGeometry();
geometry0.createMagicBox = THREEg.createMagicBox;
geometry0.createMagicBox( parameters0 );
var mesh0 = new THREE.Mesh( geometry0, materials );
scene.add( mesh0 );
var parameters1 = {
	sides: [ 7,7,7,7 ],
	materials: [ 1, 1, 1, 1, 1, 1 ],	
	radius: function( t ){ return 0 },
	widthSegments: 8,
	heightSegments: 8,
	depthSegments: 8,	
}
var geometry1 = new THREE.BufferGeometry();
geometry1.createMagicBox = THREEg.createMagicBox;
geometry1.createMagicBox( parameters1 );
var mesh1 = new THREE.Mesh( geometry1, materials );
scene.add( mesh1 );
animate();
function animate( ) {	
	requestAnimationFrame( animate );
	time = clock.getElapsedTime( );	
	geometry0.morphVerticesMagicBox( time );
	geometry1.morphVerticesMagicBox( time );
	renderer.render( scene, camera );
	controls.update( );	
}
</script>
</html>

A dynamic example of this
http://sandboxthreeg.threejs.hofk.de/dynamicGridBoxTHREEg.html

2 Likes

Thank you so much!!
I wanted to implement a grid but without the ugly diagonal triangles that come with wireframe: true.

I just made a plane using your method and everything worked smoothly.

However I faced an issue. Writing it here for others facing a similar issue.
I wanted to create a 2d grid using this method, and then inject some custom shader logic into the LineBasicMaterial that is being used.

I was trying to use uv attribute but it was not working by default.

Turns out that you need to clone the uv coordinates from our original geometry and assign it as an attribute to this new geometry that is made using GridBoxGeometry method.