Question

I am attempting to create a checkerboard with Three.js for a webpage 3D example. However, my current code assigns three colors, and I need only two colors (black / white). How can I restructure the math to produce the correct checkerboard?

// Geometry
var cbgeometry = new THREE.PlaneGeometry( 500, 500, 8, 8 );

// Materials
var cbmaterials = []; 

cbmaterials.push( new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide }) );
cbmaterials.push( new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide }) );
cbmaterials.push( new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide }) );

// Assign a material to each face (each face is 2 triangles)
var l = cbgeometry.faces.length / 2;

for( var i = 0; i < l; i ++ ) {
    var j = 2 * i;
    cbgeometry.faces[ j ].materialIndex = i % 3;
    cbgeometry.faces[ j + 1 ].materialIndex = i % 3;
}

// Mesh
cb = new THREE.Mesh( cbgeometry, new THREE.MeshFaceMaterial( cbmaterials ) );
scene.add( cb );
Was it helpful?

Solution

EDIT:

In the case that our dev environments are different, I will suggest this code fix:

EDIT-2:

The 'j's in the index selecting portion should be 'i's, I just changed that right now.

Try this:

// Geometry
var cbgeometry = new THREE.PlaneGeometry( 500, 500, 8, 8 );

// Materials
var cbmaterials = []; 

cbmaterials.push( new THREE.MeshBasicMaterial( { color: 0xffffff, side: THREE.DoubleSide }) );
cbmaterials.push( new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide }) );

var l = cbgeometry.faces.length / 2; // <-- Right here. This should still be 8x8 (64)

console.log("This should be 64: " + l);// Just for debugging puporses, make sure this is 64

for( var i = 0; i < l; i ++ ) {
    j = i * 2; // <-- Added this back so we can do every other 'face'
    cbgeometry.faces[ j ].materialIndex = ((i + Math.floor(i/8)) % 2); // The code here is changed, replacing all 'i's with 'j's. KEEP THE 8
    cbgeometry.faces[ j + 1 ].materialIndex = ((i + Math.floor(i/8)) % 2); // Add this line in, the material index should stay the same, we're just doing the other half of the same face
}

// Mesh
cb = new THREE.Mesh( cbgeometry, new THREE.MeshFaceMaterial( cbmaterials ) );
scene.add( cb );

I commented where I did the line changes.

I put the Math.floor(i/8) in the material index to offset every other layer. Otherwise, it would just be vertical lines.

Also, the 3rd material was removed, leaving behind just white and black to work with.

Thanks for this question, it was fun working it out!

OTHER TIPS

What about a THREE.ShaderMaterial()?

vertex shader can be something along the lines of,

varying vec2 vUv;
void main(){
vUv = uv;
gl_FragPosition = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

and then your fragment something like this

varying vec2 vUv;
void main(){
vec2 tileUV = vec2(500.0, 500.0);//say you want to repeat it 500 times in both directions
vec2 repeatedUV = vUv * tileUV ;
repeatedUV -=floor(repeatedUV);

now repeatedUV has a bunch of tiles that are all vec2 within 0-1 range and they repeat

repeatedUV.x = floor(repeatedUV.x * 2.0);//should give black or white stripe in U direction
repeatedUV.y = floor(repeatedUV.y * 2.0);// same in the other way

then this is something like bool algebra

float finalMask = repeatedUV.x + repeatedUV.y;//bottom left 0, bottom right 1, top left 1, top right 2
finalMask *= 1.0 - repeatedUV.x*repeatedUV.y; //all zero except top right
gl_FragColor = vec4(vec3(finalMask), 1.0);

}

expensive way of doing it i guess, but saves you making 5000 triangles. Procedurally generated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top