I’m creating a 513×513 plane and using a height map to represent terrain. To add some variety to the terrain there are several 256×256px texture files. Here’s a basic example of what I’d like to achieve:
In the example, each square of the 2×2 plane are a different texture (texture_1.png, texture_2.png, etc).
Some context…
I’m trying to recreate levels from a video game called Incoming. Here’s a screenshot from one of the Arctic missions:
As you can see, the terrain is a simple height map which uses various snowy textures; some examples:
I’m able to read the height map data from the game files and produce an accurate plane:
I’ve tried searching for similar topics and found one which mentioned using the addGroup
method, however I was unable to get this to work without terrible performance.
This seems like it should be a relatively straightforward operation - am I missing something?
Considering that on the screenshot there are buildings specifically placed inside the “craters” on the textures - shouldn’t these textures be manually UV mapped onto the terrain - for each level separately, to fit the buildings / enemies / targets?
(You can UV map models quite easily with Blender - especially simple heightmap / subdivided plane geometry.)
That’s correct - the texture data for panning/rotation etc. is stored in a separate file for each level.
Ideally I’d just like to be able to drag/drop the game files straight into a browser window and have it display the terrain with the correct textures. I feel like I’m pretty close already - just unsure how to proceed with specifying a texture index for each segment.
Ah, got it. Would it break any copyright laws if you shared the file structure ? Do you need to blend the textures together, or just place correct texture squares on correct quads in the scene?
[…] or just place correct texture squares on correct quads in the scene?
Exactly.
The texture info for each level is stored in a *.bin
file which is always 32,768 bytes (2 bytes per square × 128×128 grid). Here’s the first 16 bytes of one of these files:
0xA0 0x00
0x20 0x00
0xA0 0x00
0x20 0x00
0xA0 0x00
0x20 0x00
0xA0 0x00
0x20 0x00
Byte 1 contains the texture index in the first four bits and the texture panning in the last four bits (a simple 4-bit bitmask) - i.e. for the first byte, 0xA0
:
0xA0 & 0x0F == 0x0
- texture index 0 (every level has 8 textures)
0xA0 & 0xF0 == 0xA
- texture should be panned so the bottom right quarter is visible
Byte 2 is also a bitmask for flipping vertically/horizontally, rotation, and possibly other things I haven’t figured out yet.
I managed to reverse engineer most of the game’s formats last year and posted what I found on GitHub (there’s a better visual representation of the texture panning there if my example here didn’t make that much sense).
I was hacking around trying to get it to work last night and the following code kind of works in principle:
let x = 0;
// `materials` is an array of THREE.MeshBasicMaterial containing each of the level's 8 textures
for (let i = 0; i < materials.length; i++) {
geometry.addGroup(6 * x++, 6, i);
geometry.addGroup(6 * x++, 6, i);
geometry.addGroup(6 * x++, 6, i);
geometry.addGroup(6 * x++, 6, i);
}
This gives me a strip of terrain with different textures:
I’m pretty sure this is an incredibly inefficient way of using groups, though, so I’m still a bit unsure of how best to proceed.
Bump. Came back to this and still cannot figure it out.