Game Development Community

T3D 1.1 Beta 3 - TerrainMaterial and mapTo issues and potential fix

by Daniel Eden · in Torque 3D Professional · 10/03/2010 (1:57 pm) · 0 replies

I've been porting over a bunch of older TGE1.4 code into T3D and have run into a number of issues with how Materials and TerrainMaterials interact in the code. The most noticable result of this is with certain texture filenames (like those containing more than a single period), there is no way to map a Material to the TerrainMaterial -- which results in collision calls always returning the warning material.

This means that any attempts to get key fields (showDust, effectColor, footstepSoundId, etc) from such a collision check will almost always fail. In my particular case this became a huge headache when trying to use a raycast to determine whether or not to show dust effects on the terrain.

Given that the existing terrain material mapping code doesn't seem to fit with how materials are mapped in T3D (we're moving away from mapping things based on the diffuse texture name, right?), I figured I'd work out some code that fixes the problem and brings the terrain material stuff into line with the ts code.

So... The following little bit of code alters how the terrain file maps materials, changing it to use the actual TerrainMaterial internal object names in favour of whichever diffuse texture was used for the material. This allows you to map materials to the terrain much more easily (especially if you've got more than a single period in your filenames).

At line 238 of terrain/terrFile.cpp, replace the existing initMaterialInstMapping method with:

void TerrainFile::_initMaterialInstMapping()
{
    // Clear the material instance list.
    mMaterialInstMapping.clearMatInstList();

    // Iterate through the terrain materials...
    for (U32 i = 0; i < mMaterials.size(); ++i)
    {
        // Get the internal name for the material (if any).
        String sName = mMaterials[i]->getInternalName();

        // If there's an internal name...
        if (!sName.isEmpty())
        {
            // Push the internal name into the material instance mapping list.
            mMaterialInstMapping.push_back(sName);
        }
        else
        {
            // Otherwise, just push the diffuse map filename into the material list.
            mMaterialInstMapping.push_back(Torque::Path(mMaterials[i]->getDiffuseMap()).getFileName());
        }
    }

    // Map the materials.
    mMaterialInstMapping.mapMaterials();
}


Which brings me to a little bit of a how-to guide for those of you who're wanting to get dust and footprints and stuff working without too much hassle using this code snippet. It's a pretty simple set up: you create a TerrainMaterial in the terrain painter and then you use the material editor or edit the scripts to create a material that maps to that particular TerrainMaterial.

Below is one of the TerrainMaterials from the Deathball Desert mission. If you're wanting to get any kind of material effects working, the thing to take not of here is the TerrainMaterial's "internalName" field. In this particular case, it's set to "sediment_02".

new TerrainMaterial()
{
   diffuseMap = "art/terrains/sediment_02/sediment_02_base";
   normalMap = "art/terrains/sediment_02/sediment_02_nrm";
   detailMap = "art/terrains/sediment_02/sediment_02_detail";
   internalName = "sediment_02";
   detailSize = "15";
   detailStrength = "0.8";
   detailDistance = "350";
   useSideProjection = "1";
};


If you want to map a Material to that TerrainMaterial, you create a new Material and simple use that "internalName" value as the "mapTo" field. For example:

singleton Material(MAT_Terrain_Sediment_02)
{
   mapTo = "sediment_02";
   showDust = true;
   showFootprints = true;
   effectColor[0] = "1 0 0.0235294 1";
};

This particular example material maps to the terrain material, enables the showing of dust and footprints, and specifies an effect colour to use for particles and so on.