Avatar Textures


#1

Does anyone know if it’s possible to change the textures used by your avatar using script at run time. From what I’ve seen I don’t think it’s possible, but wanted to check on here before I gave up trying.

As background I’m wanting to have the ability to switch the texture on my avatars T-Shirt without having to reload the entire avatar. I have switching full avatar with custom textures working, but it’d be much cleaner to be able to have a base avatar and change the textures only.

Thanks, Madders


#2

Yes it is.

Parenting Material Entities. to the avatar or entity allows you to swap material information on, sub-geometry, or replacing a material with anew one. Unfortunately, no official documentation currently has how to use them, and there is no UI for them, but the community has figured them out partially.

More information to follow once I get home to give some demonstrations to the desktop where I have the documentation, but one that uses it is like the material painter gun at TheSpot.


#3

Excellent, that sounds great thanks. One of the last pieces I needed to confirm for my avatar outfit switching app.


#4

Menithal, I don’t suppose you’ve had a chance to find an example of this have you. I’ve been having a mess around, but haven’t been able to work out how to replace just a single texture in the avatar model. Any examples you might have would be a great help thanks.


#5

I just learned how it works, check out:


#6

Thanks I hadn’t spotted that, I’ll give it a try later on.


#7

Yeah, sure, here is a reference script I made for another project, but with truncated info, as it was a commission

material.js

var materialEntityName = MyAvatar.displayName + "-Avatar-Material-Entity";
// Reference:
// http://ctrlaltstudio.com/downloads/hifi-dev/jsdoc/global.html#Material 

var material = Script.require(Script.resolvePath("material.json"));
var ENABLE_UPDATE = false;
var materialName = "Material"; // this must match the material name  used you want to replace on the model.

// Helper Function to create an Material Entity. 
var createAvatarMaterialEntity = function (name) {
    return Entities.addEntity({
        type: "Material",
        name: name,
        position: MyAvatar.position,
        materialData: JSON.stringify(material),
        materialURL: "materialData",
        priority: 1,
        parentMaterialName: "mat::" + materialName,
        parentID: MyAvatar.sessionUUID
    }, true);
}

// Helper Function for removing Material Entity
var clearAllMaterialEntities = function () {
    var entities = Entities.findEntities(MyAvatar.position, 10);
    if (entities.length > 0) {
        for (var index in entities) {
            var entity = Entities.getEntityProperties(entities[index]);
            if (entity.clientOnly &&
                entity.type === "Material" &&
                entity.owningAvatarID === MyAvatar.sessionUUID &&
                entity.name.indexOf("Avatar-Material-Entity") !== -1) {

                Entities.deleteEntity(entity.id);
                console.log("Found a potential Avatar Material Entity. Removing it.")
            }
        }
    }
}



var FPSThrottle = 1 / 24;
var timer = 0;
var currentTimer = 0;
var update = function (dt) {
    timer += dt;
    if (timer > FPSThrottle) {
        currentTimer += dt; // Slow update Pace

        // Can do what ever here with the timer if

        timer = 0;
    }
}
clearAllMaterialEntities();

var materialEntity;
materialEntity = createAvatarMaterialEntity(materialEntityName);

console.log("Created materialEntity", materialEntity);

if (ENABLE_UPDATE) {
    Script.update.connect(update);
}
Script.scriptEnding.connect(function () {
    if (ENABLE_UPDATE) {
        Script.update.disconnect(update);
    }
    clearAllMaterialEntities();
});

A good reference what to add to the json, available
at http://ctrlaltstudio.com/downloads/hifi-dev/jsdoc/global.html#Material

material.json

{

    "materialVersion": 1,
    "materials": {
        "model": "hifi_pbr",
        "albedoMap": "<url>",
        "albedo": [0.001, 0.001, 0.001],
        "metallic": 0.0,
        "roughness": 1 
    }
}

You can then modifiy the material.json, or its output to have albedoMap swapped out to something else, and if wanting to swap to something else, just update the materials.albedoMap field to be something else in script.


#8

Thanks that’s great. Using the two I’ve now got a proof of concept that changes the TShirt texture on my avatar. Just need to wrap a nice interface around it.


#9

First version of swapper script available Avatar Material Swapper


#10

Oh no, A Bug!

I think the createAvatarMaterialEntity function somehow messes with wearable’s

When either of theese scripts run the wearables list fails to populate leaving only the option to cancel, which will result in an arbitrary(sometimes double) number of copy’s of the worn item to be added, I think but they are all named according to

MyAvatar.displayName + “-Avatar-Material-Entity”

needs more investigation

[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {194da8b5-ed04-4c9e-aa0e-2064b9cc9336}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {60ec36f8-8173-4df1-8f97-45d6b423f7a5}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {bc4477f4-19ef-4195-addd-cbb750ae55a5}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {d6dd46bb-6842-40dd-96ae-2cddbe1817b0}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {32ef3116-5e6a-4d6d-bd0d-f274d9b6f512}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {28780388-3805-47a5-a4d6-2d49104f38f5}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {b305e17c-1415-4407-8b4c-7b23b1e1cc88}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {5ad74d63-df57-4212-a1cf-d2cc42273727}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {78093f4d-2937-415d-8d64-191fb0595974}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {9dd41e3b-6353-4f1e-afb3-628c303a0f62}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {54cb9d7c-4370-457e-aff2-f1a1710d5057}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {20813085-f064-4250-87b8-03bedb5e3778}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {3ff863c5-64e2-42d9-b357-2824136d157d}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {232c7b16-df91-40c1-8be1-ea67c57c7fd1}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {7f60654e-0c37-464b-b1aa-a97795db1857}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {5c357210-3c24-4a06-b564-1aa239ad6c17}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {8a7e7e1e-a566-4d67-9270-d86ab3a16cc9}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {202a1d95-2e56-4d07-808d-01f507e6c9b2}
[10/31 21:54:05] [DEBUG] [hifi.scriptengine] [test.js] Removing: spoopy Silverfish-Avatar-Material-Entity {701dc624-1dee-461c-8293-3dc4576aff90}


#11

Will investigate and post update once sorted.


#12

Took a bit of digging but found the issue. The avatar app appears to detect all entities parented to your avatar as wearables. This caused the app to error when it looked at the material as it doesn’t have a modelUrl and it expects all avatarEntities to have one. From looking at avatarapp.js it performs a check on each avatarEntity to see if it’s a valid wearable, by checking a number of properties on the entity.

function isWearable(avatarEntity) {
    return avatarEntity.properties.visible === true && (avatarEntity.properties.parentJointIndex !== INVALID_JOINT_INDEX || avatarEntity.properties.relayParentJoints === true) &&
        (avatarEntity.properties.parentID === MyAvatar.sessionUUID || avatarEntity.properties.parentID === MyAvatar.SELF_ID);
}

The fix was fairly simple, once I found the underlying cause, we just need to make these tests fail.The simplest way to do this is to make the material entity that the createAvatarMaterialEntity generates be set to not visible. The visibility of the material entity doesn’t seem to affect it being used as an override on the avatar, probably since it’s not a model itself, but it does make it be ignored as a wearable.

This fix has been commited to the github sample, and I’ve updated the example. If you’ve previously loaded the example, you may need to open “Running Scripts” from the edit menu and refresh the materialOptions.js script so it downloads the fresh version rather than loading from cache.


Avatar Material Swapper
#13

Eventually Material entities will show up in the avatar app with in the next few releases of the interface. Currently slated for 76 but could be pushed back depending on how other bug fixes, that are depended on, are resolved.


#14

Thanks for the heads up, I’ll keep an eye on the releases to try and keep the code up to date.