Doing it with an array is just as easy. The only difference really is you're setting a value to the array instead of creating the object right away. You could do it in two passes but really it's basically the same as above.
array for each xy
--- array set at (array.curX, array.curY) to noisejs.perlin2(this.curx/this.width*noise_scaling, this.cury/this.height*noise_scaling) + lerp(-1, 1, this.cury/this.height)
array for each xy
--- array set at (array.curX, array.curY) to this.curValue>0
With that it's just one material. For two you could do
array for each xy
--- array set at (array.curX, array.curY) to round(max(this.curValue*2))