How to change material properties in a script?


When you get model.material.attributes you only have a bunch of interface types. How can you chenge for example the diffuse color of a model every frame? Or the metalness?



I tinkered with this so I can give a pseudo answer for anyone curious, at least for a starting point.

Once the game is running all of the design time stuff is gone (null) so you have to grab and change the values being pushed to the rendering pipeline. Changing the color would depend on how you’re giving the color in the first place. If you’re using a texture it’s going to just keep using it, but you could change the texture that it’s using with something like:

var material = model.GetMaterial(0);
material.Passes[0].Parameters.Set(MaterialKeys.DiffuseMap, yourNewTexture);

To do anything more than changing the texture, you will probably need to write your own shader and use that as the diffuse value on the material, and then attach a SyncScript to the entity with the model to change it. A basic shader with a variable to modify would look like this:

shader MyCustomShader : ComputeColor
  cbuffer PerMaterial
    float4 MyColor;

  override float4 Compute()
    return MyColor;

Then inside of the SyncScript in the Update() method, you would do similar to changing the texture:

public override void Update()
    var color = CallSomeLogicToGetAColor();
    material.Passes[0].Parameters.Set(MyCustomShaderKeys.MyColor, color);

To start modifying the color of a texture and not use a solid color for the entire thing I would probably recommend setting the diffuse of the material to a binary operation to multiply the texture * shader. Or you could make your shader more complex and have it inherit from Texturing, and sample the texture, modify the value sampled, and return the modified color.