In chrome console it says that material as an array has been deprecated.
I want to apply different material to cube's different side.
//convert from SVG
var imageCanvas = document.createElement("canvas");
canvg(imageCanvas, image.svg);
var texture = new THREE.Texture(imageCanvas);
texture.needsUpdate = true;
var geometry = new THREE.CubeGeometry(200, 10, 200);
var cubeMaterial = new THREE.MeshBasicMaterial({
map : texture
});
var cube = new THREE.Mesh(geometry, cubeMaterial);
Like this, all 6 cube's sides have that picture as material. I would like to apply that picture material to only 2 sides an on the rest 4 I would like to put a color.
How can I do that?
And also, is there any other place between this issues list, API Docs and those examples here on GitHub where I can lear Three.js?
Hi Dino4674,
This issue / solution might be what you are looking for: #744
This worked for me:
var materials = [
leftSide, // Left side
rightSide, // Right side
topSide, // Top side
bottomSide, // Bottom side
frontSide, // Front side
backSide // Back side
];
var geometry = new THREE.CubeGeometry(100, 75, 8, 1, 1, 1, materials);
var someMesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial());
http://learningwebgl.com/blog/
Also note that there are two APIs.
The old one is no longer being maintained:
https://github.com/mrdoob/three.js/wiki/API-Reference
This is the new one:
You can see in these two files that every face (3-sided or 4-sided) has a materialIndex.
Line 175:
geometryMaterials = object.geometry.materials;
Line 308:
_face.faceMaterial = face.materialIndex !== null ? geometryMaterials[ face.materialIndex ] : null;
Showing how materialIndex is used to map the array of materials in geometry.
if ( materials !== undefined ) {
if ( materials instanceof Array ) {
this.materials = materials;
} else {
this.materials = [];
for ( var i = 0; i < 6; i ++ ) {
this.materials.push( materials );
}
}
When we create a new THREE.CubeGeometry, the materials argument we provide can be an array of materials, or a single material, which is then turned into an array with six elements, each of which contains the (same) material provided.
mpx = 0; mnx = 1; mpy = 2; mny = 3; mpz = 4; mnz = 5;
this.sides.px && buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, mpx ); // px
this.sides.nx && buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, mnx ); // nx
this.sides.py && buildPlane( 'x', 'z', 1, 1, width, depth, height_half, mpy ); // py
this.sides.ny && buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, mny ); // ny
this.sides.pz && buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, mpz ); // pz
this.sides.nz && buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, mnz ); // nz
function buildPlane( u, v, udir, vdir, width, height, depth, material ) {
Line 123 - 126 (inside buildPlane function):
var face = new THREE.Face4( a + offset, b + offset, c + offset, d + offset );
face.normal.copy( normal );
face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone() );
face.materialIndex = material;
From the three snippets above, we can see that a THREE.CubeGeometry is made out of 6 faces, each with 4 sides (hence THREE.Face4). Each face is given a unique materialIndex, from 0 to 5.
Hmm, seems like maybe the last argument provided to buildPlane could be renamed from material to materialIndex.
function getBufferMaterial( object, geometryGroup ) {
if ( object.material && ! ( object.material instanceof THREE.MeshFaceMaterial ) ) {
return object.material;
} else if ( geometryGroup.materialIndex >= 0 ) {
return object.geometry.materials[ geometryGroup.materialIndex ];
}
};
materialIndex = buffer.materialIndex;
if ( materialIndex >= 0 ) {
material = object.geometry.materials[ materialIndex ];
More examples of the association between materials & materialIndex.
Thank you mrienstra,
that did the trick.
And thank you for long posts :D I'm new to this library so I any help is good for me now :)
So I am trying to figure this:
var cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200, 1, 1, 1, materials), new THREE.MeshFaceMaterial());
If I defined CubeGeometry with it's materials and size, what role does MeshFaceMaterial play here?
I think you are wrong about indices of materials.
Here is my example.
Imagine picture wich has picture on both sides and rest 4 polygons are black.
var pictureMaterial = new THREE.MeshBasicMaterial({
map : texture
});
var borderMaterial = new THREE.MeshBasicMaterial({
color : 0x000000
});
var materials = [borderMaterial, // Left side
borderMaterial, // Right side
pictureMaterial, // Top side ---> THIS IS THE FRONT
pictureMaterial, // Bottom side --> THIS IS THE BACK
borderMaterial, // Front side
borderMaterial // Back side
];
Here I say that my picture is x = 200 wide, y = 10 depth and z = 200 tall.
var cube = new THREE.Mesh(new THREE.CubeGeometry(200, 10, 200, 1, 1, 1, materials), new THREE.MeshFaceMaterial());
Now this is based on a fact that Z-axis represents height which I think is more natural.
I'm still learning myself, the code sample I provided is something I wrote during a hack weekend when I first started playing with three.js. Maybe the demo I was using as a starting point was intended to be looking down on the scene from above, but I saw it as looking at the scene from the side? Who knows! I'll have to take a closer look at it later.
If it's incorrect, I'll try to update that code sample later so it doesn't confuse anyone else. :)
It looks like you were right after all.
I your say
cube.lookAt(camera.position)
you can see exactly which one is the front.
So the answer is that Three looks on Y as height and Z as depth.
Most helpful comment
Hi Dino4674,
This issue / solution might be what you are looking for: #744
This worked for me: