Material proxies

From Valve Developer Community
(Redirected from Material Proxy)
Jump to: navigation, search

Material proxies allow a game's compiled C++ code to manipulate the properties of a material. Many proxies perform specific tasks, but there are other more general ones that together provide rudimentary scripting support within VMT files.

Any number of proxies can be added to a material; they will be executed in the order in which they appear.

Bug:
Some users have reported that the tools mode will not run some functional proxies in game. Extent of bug untested so if your proxy does not work in tools mode try testing in game

Usage

This material has a Sine proxy which makes it fade in and out of view over a period of eight seconds:

LightmappedGeneric
{
	$basetexture shadertest/LightmappedTexture
 
	Proxies // proxies are listed inside this block
	{
		Sine // a proxy which produces a sine wave
		{
			resultVar	$alpha // The shader parameter to be manipulated
			sineperiod	8
			sinemin		0
			sinemax		1
		}
	}
}

Variables

Materials can declare their own variables for internal use. Such variables must be declared outside the Proxies block, in the body of the material, and must have default values specified on the right-hand side.

These custom variables might be used to pass results between proxies or to submit hard-coded data to them. They are often employed to chain mathematic function proxies (i.e. Add, Subtract, etc) together into longer equations. For 2D/3D vectors ("[0 0 0]"), the variable name can have [0] suffixed to read/write a specific index.

This example extends the one above by staggering the starting position of the sine wave:

LightmappedGeneric
{
	$basetexture shadertest/LightmappedTexture
 
	$offset 0 // declare custom var
 
	Proxies
	{
		EntityRandom
		{
			resultVar $offset // write to custom var
		}
		Sine
		{
			resultVar	$alpha
			timeoffset	$offset // read from custom var
			sineperiod	8
			sinemin		0
			sinemax		1
		}
	}
}

Now each entity this material is used on pulses to its own schedule.

Writing new proxies

New proxies are easy to create. They exist on the client only and should inherit from IMaterialProxy or one of its descendants.

You will need these #includes:

  • "materialsystem/IMaterialProxy.h"
  • "materialsystem/IMaterialVar.h"

These functions are included in the interface:

bool Init( IMaterial* pMaterial, KeyValues* pKeyValues )
Called when the material is first precached. Use this function to initialise variables and grab references to the material vars you will be using. Return true on success and false on failure (in which case the proxy will not be run).
pKeyValues contains the proxy parameters from the VMT file.
void OnBind( void* pC_BaseEntity )
Called when the material is about to be rendered on an entity. This is where the work is done.
When coding this function it is important to remember that all entities using a material share the same material object, and that if you change it on one entity it changes everywhere else too. Since OnBind() is called every time an entity comes up for rendering this is not a problem so long as you reassign the value you want every time. Don't return early just because there has been no change, and don't store any input data in the proxy.
Note:pC_BaseEntity doesn't lead to a C_BaseEntity as its name suggests, but rather to the associated IClientRenderable. The easiest way to access the entity directly is to base your class on CEntityMaterialProxy (in proxyentity.h) and use the OnBind(C_BaseEntity*) overload it provides.
void Release()
To do: Called when the proxy is removed, but when is that?
IMaterial* GetMaterial()
The material the proxy is attached to.
Tip:If you have a material var stored, you can return IMaterialVar::GetOwningMaterial() here instead of creating a new IMaterial pointer.

Interface

The proxy must expose its interface to materials with the EXPOSE_INTERFACE macro:

EXPOSE_INTERFACE( <className>, <interfaceName>, "<proxyName>" IMATERIAL_PROXY_INTERFACE_VERSION );

The lack of a comma between the proxy name and interface version is intentional.

Tools recording

This code was added to all proxies in the Orange Box:

#include "toolframework_client.h"
 
void OnBind(...)
{
	//...
 
	if ( ToolsEnabled() )
		ToolFramework_RecordMaterialParams( GetMaterial() );
}

It's probably related to the Source Filmmaker. It's a good idea to add it to your proxy too in case the Filmmaker is ever released!

Tip:CEntityMaterialProxy makes the call by itself.

See also

External links