I had a similar problem earlier, in which I needed to be able to change a dynamic property of a material applied to a landscape. This was accomplished, and I was hoping my current problem could be solved with similar code. My current problem is that data for my material is stored in a texture that needs to be modified at runtime. How could I go about modifying this texture or replacing it with a dynamic texture?
I have fixed this problem by modifying the code provided by to modify texture parameters instead of vector parameters. The required code is this:
/**
* Start of code taken from MaterialInstance.cpp
*/
ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER_DECLARE_TEMPLATE(
SetMIParameterValue,ParameterType,
const UMaterialInstance*,Instance,Instance,
FName,ParameterName,Parameter.ParameterName,
typename ParameterType::ValueType,Value,ParameterType::GetValue(Parameter),
{
Instance->Resources[0]->RenderThread_UpdateParameter(ParameterName, Value);
if (Instance->Resources[1])
{
Instance->Resources[1]->RenderThread_UpdateParameter(ParameterName, Value);
}
if (Instance->Resources[2])
{
Instance->Resources[2]->RenderThread_UpdateParameter(ParameterName, Value);
}
});
/**
* Updates a parameter on the material instance from the game thread.
*/
template <typename ParameterType>
void GameThread_UpdateMIParameter(const UMaterialInstance* Instance, const ParameterType& Parameter)
{
ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER_CREATE_TEMPLATE(
SetMIParameterValue,ParameterType,
const UMaterialInstance*,Instance,
FName,Parameter.ParameterName,
typename ParameterType::ValueType,ParameterType::GetValue(Parameter)
);
}
/**
* Cache uniform expressions for the given material.
* @param MaterialInstance - The material instance for which to cache uniform expressions.
*/
void CacheMaterialInstanceUniformExpressions(const UMaterialInstance* MaterialInstance)
{
// Only cache the unselected + unhovered material instance. Selection color
// can change at runtime and would invalidate the parameter cache.
if (MaterialInstance->Resources[0])
{
MaterialInstance->Resources[0]->CacheUniformExpressions_GameThread();
}
}
/**
* End of code taken from MaterialInstance.cpp
*/
void SetTextureParameterValue(ALandscapeProxy* Landscape, FName ParameterName, UTexture* Value)
{
if (Landscape)
{
for (int32 Index = 0; Index < Landscape->LandscapeComponents.Num(); ++Index)
{
if (Landscape->LandscapeComponents[Index])
{
UMaterialInstanceConstant* MIC = Landscape->LandscapeComponents[Index]->MaterialInstance;
if (MIC)
{
/**
* Start of code taken from UMaterialInstance::SetSetVectorParameterValueInternal and adjusted to use MIC instead of this
*/
FTextureParameterValue* ParameterValue = GameThread_FindParameterByName( //from MaterialInstanceSupport.h
MIC->TextureParameterValues,
ParameterName
);
if(!ParameterValue)
{
// If there's no element for the named parameter in array yet, add one.
ParameterValue = new(MIC->TextureParameterValues) FTextureParameterValue;
ParameterValue->ParameterName = ParameterName;
ParameterValue->ExpressionGUID.Invalidate();
// Force an update on first use
//ParameterValue->ParameterValue.B = Value.B - 1.f;
}
ParameterValue->ParameterValue = Value;
// Update the material instance data in the rendering thread.
GameThread_UpdateMIParameter(MIC, *ParameterValue);
CacheMaterialInstanceUniformExpressions(MIC);
/**
* End of code taken from UMaterialInstance::SetSetVectorParameterValueInternal and adjusted to use MIC instead of this
*/
}
}
}
}
}
With this code, I am able to assign a dynamic texture to my landscape material allowing for real-time modification of my grid.
Good job.
Although it came to my mind that you could remove just one single line “check(GIsEditor)” in every UMaterialInstanceConstant::Set*ParameterValueEditorOnly function and you would be able to do the same (with far less code), but at the “cost” of an engine modification.
I don’t know when this was made available but now (I’m currently using 4.24) landscapeProxy have a method setLandscapeMaterialTextureParam (or scalar or vector) Set Landscape Material Texture Parameter Value | Unreal Engine Documentation
It only works if you check “use dynamic material instance” on your landscape actor.
Thank you. Been trying to find out why I couldn’t set parameters on my material.