According to various posts at the three.js github, MeshFaceMaterial
will be deprecated eventually.
I currently use this for my terrain. Granted it's not the best way to do it. Actually its pretty crappy. For one I cannot use BufferGeometry
which is not good considering I generally have 2 layers of 128x128 (segmented) planes for terrain. Very high memory usage.
I've adapted all my code to allow for the terrain to be BufferGeometry
except two things don't work. MeshFaceMaterial
and BufferGeometry.merge()
. The merge doesn't work on indexed geometry which to me is weird considering THREE creates this geometry, yet it can merge non-indexed geometry from blender. It cannot merge geometry it creates itself but can merge geometry from external sources... Oh well that's another post there, back to MeshFaceMaterial
.
I currently use a 128x128 "MaterialMap". Each pixel represents a materialIndex
for each face of the plane. This has two serious drawbacks. Squared up sections of terrain (no curves) and harsh distinctions on the borders of textures.
My question is: How can I generate this terrain with multiple textures without using MeshFaceMaterial
. The highest res texture I have is 2048x2048 and zone size can easily be 10000x10000 making repeat necessary (right?).
Ultimately my goal is to use BufferGeometry
and get rid of MeshFaceMaterial
.
MaterialMap example:
Terrain Example (terribly cropped sorry {work pc}):
You helped me out a while back via email with advice on culling meshes so I would like to return the favor (with my humble strategy) :)
If you want to use THREE.PlaneBufferGeometry (which, as you know, is where all geometry in THREE.js is soon headed), then my advice would be to layer different PlaneBufferGeometries right on top of each other. For instance in the above example picture, you could have
var stoneFloorGeometry = new THREE.PlaneBufferGeometry(arenaWidth, arenaHeight, 1, 1);
var stoneFloorMaterial = new THREE.MeshBasicMaterial({
depthWrite: false, // This is always underneath every other object
map: stoneFloorTexture
});
var stoneFloor = new THREE.Mesh(stoneFloorGeometry, stoneFloorMaterial);
stoneFloor.rotation.x = Math.PI / -2; // rotate to be flat in the X-Z plane
stoneFloor.position.set(0, 0, 0);
scene.add(stoneFloor);
// now add the grass plane right on top of that with its own texture and shape
var grassGeometry = new THREE.PlaneBufferGeometry(lawnWidth, lawnHeight, 1, 1);
var grassMaterial = new THREE.MeshBasicMaterial({
depthWrite: false, // this is rendered right on top of the stone floor
map: grassTexture
});
var grass = new THREE.Mesh(grassGeometry, grassMaterial);
grass.rotation.x = Math.PI / -2;
grass.position.set(0, 0, 0);
scene.add(grass);
// finally add the stone path walkway on top of the grass, leading to the castle
var walkwayGeometry = new THREE.PlaneBufferGeometry(walkwayWidth, walkwayHeight, 1, 1);
var walkwayMaterial = new THREE.MeshBasicMaterial({
depthWrite: false, // this is rendered right on top of the grass
map: stoneFloorTexture // uses same texture as large stoneFloor before
});
var walkway = new THREE.Mesh(walkwayGeometry, walkwayMaterial);
walkway.rotation.x = Math.PI / -2;
walkway.position.set(0, 0, 0);
scene.add(walkway);
As long as you layer the level from bottom to top and disable depthWrite, all the various textures will correctly show up on top of each other, and none will Z-fight. So, stoneFloor is added to the scene first, followed by grass, followed by walkway. And since depthTest is still active, your moving game characters will render on top of all these various textures. Initially, it also looked like it worked with just disabling 'depthTest', but the textures ended up rendering over ('above') the characters/models which is incorrect.
Eventually when THREE.js moves ShapeGeometry over to BufferGeometry, it would be nice to define an arbitrary polygonal shape (like an octagon or something) and then texture map that and lay down shapes on top of each other for the game level in a similar manner, thus avoiding the 'square' problem you mentioned.
As for this current solution, on the modern CPU/GPU I don't think you will see much performance cost in creating 3 PlaneBufferGeometries instead of 1 large one with multiple faces/indexes. This way you have the advantages of using THREE's BufferGeometry while still having everything 'looking' like it is all texture-mapped to one large plane.
Hope this helps! -Erich (erichlof on GitHub)