Too late!!!
It looks like I was able to figure this out, except for 1 mystery.
Here is the working example.
For the benefit of others, here is what I did:
Each grid of squares is defined using the same variables. For Grid1 (the inner grid), these are:
let Grd1 = {
Typ: 1, // Type of Grid - Inner or Outer
RCs: 16, // Rows and Columns - use odd number (for now = divisible by 3)
Siz: GrdSiz, // Size of square
Stp: 4, // Steps
RCi: 0, // Rows and Columns Index (computed)
MZV: [0], // Ground Z Value
MXV: [0], // Ground X Value
Nor: 0, // Max North Square (updated)
Est: 0, // Max East Square (updated)
Num: 0, // Size of array (computed)
Ptr: [0], // Ground Address
Shd: 1, // Shadow enabled
RCF: 0, // N/A
NSA: 0, // N/A
EWA: 0, // N/A
Mat: 0, // N/A
Msh: 0, // Instanced Mesh
Dum: new THREE.Object3D(), // Dummy Variable
Vis: 1 // Visibility Flag
}
To initialize the InstancedMesh for each Grid, I used the following code. Changes relating to Instanced Mesh are marked “IM”. Note: this has been corrected to fix the coding errors noted below.):
// Inner Grid
if (Grd.Typ == 1) {
waves_.WtrNrm.repeat.set(1,1);
WtrGeo = new THREE.PlaneGeometry(Grd.Siz,Grd.Siz,waves_.GrdSeg,waves_.GrdSeg);
WtrGeo.rotateX(-Math.PI * 0.5);
WtrMat = new THREE.MeshPhysicalMaterial({
color: WtrCol,
displacementMap: waves_.WtrDsp,
normalMap: waves_.WtrNrm,
envMap: envMap,
normalScale: new THREE.Vector2(2.5,2.5),
metalness: 1.0, // 1 for max reflection
roughness: 0.7, // 0 for max reflection
reflectivity: 0.5, // 1 for max reflection
envMapIntensity: 5, // max reflection suggested = 5
premultipliedAlpha: true,
});
Grd.Msh = new THREE.InstancedMesh(WtrGeo, WtrMat, Grd.RCs*Grd.RCs); // IM
// Set Starting Position of Squares
let n = 0;
for (let x = 0; x < Grd.RCs; x++) {
for (let z = 0; z < Grd.RCs; z++) {
Grd.Dum.position.set(Grd.MXV[x],-Grd0.MPY-WavMax,-Grd.MZV[z]); // IM
Grd.Dum.updateMatrix(); // IM
Grd.Msh.setMatrixAt(n, Grd.Dum.matrix); // IM
n++;
}
}
scene.add(Grd.Msh); // IM
}
// Outer Grids
else {
waves_.WtrNrm.repeat.set(2,2);
if (Grd.Typ == 3) waves_.WtrNrm.repeat.set(4,4);
geometry = new THREE.PlaneGeometry(Grd.Siz,Grd.Siz);
geometry.rotateX(-Math.PI * 0.5);
material = new THREE.MeshPhysicalMaterial({
color: WtrCol,
normalMap: waves_.WtrNrm,
envMap: envMap,
normalScale: new THREE.Vector2(2.5,2.5),
metalness: 1.0, // 1 for max reflection
roughness: 0.7, // 0 for max reflection
reflectivity: 0.5, // 1 for max reflection
envMapIntensity: 5, // max reflection suggested = 5
premultipliedAlpha: true,
});
Grd.Msh = new THREE.InstancedMesh(geometry, material, Grd.RCs*Grd.RCs); // IM
// Assemble and Set Starting Position of Squares
let n = 0;
for (let x = 0; x < Grd.RCs; x++) {
for (let z = 0; z < Grd.RCs; z++) {
Grd.Dum.position.set(Grd.MXV[x],-Grd0.MPY-WavMax,-Grd.MZV[z]); // IM
Grd.Dum.updateMatrix(); // IM
Grd.Msh.setMatrixAt(n, Grd.Dum.matrix); // IM
n++;
}
}
scene.add(Grd.Msh); // IM
}
To move the squares within each Grid, I used the following:
for (let x = 0; x < Grd.RCs; x++) {
for (let z = 0; z < Grd.RCs; z++) {
Grd.Dum.position.set(Grd.MXV[x],-Grd0.MPY-WavMax,-Grd.MZV[z]); // IM
Grd.Dum.position.y = -Grd0.MPY-WavMax; // IM
Grd.Dum.visible = true; // IM
Grd.Dum.updateMatrix(); // IM
Grd.Msh.setMatrixAt(n, Grd.Dum.matrix); // IM
n++;
}
}
Grd.Vis = 1;
I used the following command to cause the Grids to update:
if (Grd.Typ>1) Grd.Msh.instanceMatrix.needsUpdate = true; // IM s/b All???
This works perfectly. All of the grids update, including Grid1 which has moving squares and animated displacement and normal maps.
However, this is a bit of a mystery. I used that command when I first tried using InstancedMesh for only the outer Grids 2 and 3. But when I change it to:
Grd.Msh.instanceMatrix.needsUpdate = true;
The Grid1 squares display as white spheres!
This is interesting in that this indicates that InstancedMesh works with animated textures, which could be useful for those modeling other kinds of terrain.
It appears to be working faster because I tried using the time savings to increase the segments in each Grid1 square from 256 to 512. Normally, this drops the frame rate below 60fps, but with InstancedMesh, I was able to get a solid 60 fps. (Unfortunately, the change did not yield the anticipated improvement in resolution.)
Any thoughts on why updating the mesh on Grid1 results in spheres? I want to make sure that I have not done something wrong that will be “fixed” later.