Material proxies

From Valve Developer Community
Jump to navigation Jump to search
English (en)Português do Brasil (pt-br)中文 (zh)Translate (Translate)
Pendência:  Traduza o resto

Material proxiespermita o codigo C++ compilado manipular as propiedades de um material(en). Muitos proxies performan tarefas especificas, mas existem outros mais gerais(en) que juntas providem um suporte para codigo rudimentar nos arquivos VMT. [Clarify]

Qualquer numero de proxies podem ser adicionado para um material; eles serão excetuados na ordem que eles aparecerem.

Icon-Bug.pngErro:Alguns usuarios reportaram que o modo de ferramentas não roda algumas funcionalidades do proxies dentro do jogo  [todo tested in?]
Icon-Bug.pngErro:Usar alguns proxies de material em partículas criadas dinamicamente, por exemplo env_smokestack(en), fará com que o jogo trave ao carregar o mapa.  [todo tested in?]

Como usar

Este material tem um proxy Sine que o faz desaparecer dentro e fora de vista(en) durante um período de oito segundos:

LightmappedGeneric
{
	$basetexture shadertest/LightmappedTexture

	Proxies // proxies estão listados dentro deste bloco
	{
		Sine //um proxy que produz uma onda senoidal
		{
			resultVar	$alpha //O parâmetro shader a ser manipulado
			sineperiod	8
			sinemin		0
			sinemax		1
		}
	}
}

Variáveis

Os materiais podem declarar suas próprias variáveis ​​para uso interno. Tais variáveis ​​devem ser declaradas fora do bloco Proxies, no corpo do material, e devem ter valores padrão especificados no lado direito.

Essas variáveis ​​personalizadas podem ser usadas para transmitir resultados entre proxies ou para enviar dados codificados para eles. Eles são frequentemente empregados para encadear proxies de funções matemáticas (ou seja, Adicionar, Subtrair, etc) em equações mais longas. Para vetores 2D/3D ("[0 0 0]"), o nome da variável pode ter [0] com sufixo para ler/gravar um índice específico. As gravações em variáveis ​​indexadas devem ser colocadas entre aspas.

O mecanismo codifica essas variáveis ​​personalizadas usando um número inteiro assinado de 8 bits. Portanto, há um limite de 128 variáveis ​​personalizadas exclusivas por material.

Este exemplo estende o exemplo acima escalonando a posição inicial da onda senoidal:

LightmappedGeneric
{
	$basetexture shadertest/LightmappedTexture

	$offset 0 // declare custom var
	
	Proxies
	{
		EntityRandom
		{
			resultVar $offset // escreva na custom var
		}
		Sine
		{
			resultVar	$alpha
			timeoffset	$offset // leia da custom var
			sineperiod	8
			sinemin		0
			sinemax		1
		}
	}
}

Agora cada entidade utiliza esse material em pulsos de acordo com sua própria programação.

Outros exemplos para escrever em variáveis ​​indexadas:

	$color "[0 0 0]"

	proxies
	{
		sine
		{
			sineperiod	1.3
			sinemin		0
			sinemax		1
			timeoffset	0
			resultvar	"$color[0]"
		}
		sine
		{
			sineperiod	1.7
			sinemin		0
			sinemax		1
			timeoffset	0
			resultvar	"$color[1]"
		}
		sine
		{
			sineperiod	2.3
			sinemin		0
			sinemax		1
			timeoffset	0
			resultvar	"$color[2]"
		}
	}

An example of using a color vector to create 'random' color pulses.

UnlitGeneric
{
	$basetexture "dev\gradient_dif"
	$color "[1 .8 .6]"

	$detail "dev\noise_512x32"
	$detailscale 1
	$detailblendmode 0
	$detailblendfactor 4.0

	$additive 1
	$nocull 1

	$cvar "[.5 .5]"
	$svar "[1 .25]"
	$rvar 0
	$tvar "[0 0]"

	$sine1 0
	$sine2 0

	proxies
	{
		linearramp
		{
			rate .3
			initialvalue 0
			resultvar "$tvar[1]"
		}
		sine
		{
			sineperiod 1.3
			sinemin -.004
			sinemax .002
			timeoffset 0
			resultvar $sine1
		}
		sine
		{
			sineperiod 1.7
			sinemin -.003
			sinemax .007
			timeoffset .2
			resultvar $sine2
		}
		add
		{
			srcvar1 $sine1
			srcvar2 $sine2
			resultvar "$tvar[0]"
		}
		texturetransform
		{
			centervar $cvar
			scalevar $svar
			rotatevar $rvar
			translatevar $tvar
			resultvar $detailtexturetransform
		}
	}
}

Um exemplo de transformação de textura dinâmica.

Dividindo um vetor

Usar vetores é peculiar. Nem todos os proxies reconhecem componentes vetoriais. Se os componentes de um vetor precisarem ser processados ​​separadamente, eles precisam primeiro ser divididos em variáveis ​​diferentes.

Os seguintes proxies, e apenas estes valores-chave, podem reconhecer componentes de vetor:

  • Clamp: min, max
  • Sine: desvio , max, min, periodo
  • LinearRamp: taxa, valor inicial
  • UniformNoise: min, max
  • GaussianNoise: min, max, mean, meia largura
  • WrapMinMax: min, max
  • Exponential: min, max, escala ,desvio

Todos os itens acima podem ser usados ​​para dividir um vetor. No entanto, Clamp é o mais barato(en) para usar:

        $pos "[0 0 0]"
        $posX .0        //must be float or Clamp will not save the value properly
        $posY .0        //must be float or Clamp will not save the value properly
        $posZ .0        //must be float or Clamp will not save the value properly
        
        $zero 0
        
        //Proxy that outputs a 3d vector
        PlayerPosition
        {
                scale                    1
                resultVar               "$pos"
        }
        
        //Split the 3d vector for further use
        Clamp
        {
            srcVar1                      $zero
            min                         "$pos[0]"
            max                         "$pos[0]"
            resultVar                    $posX
        }
        
        Clamp
        {
            srcVar1                      $zero
            min                         "$pos[1]"
            max                         "$pos[1]"
            resultVar                    $posY
        }
        
        Clamp
        {
            srcVar1                      $zero
            min                         "$pos[2]"
            max                         "$pos[2]"
            resultVar                    $posZ
        }
Warning.pngAtenção:Quotes are needed when addressing a vector's component, or when defining a vector.

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(en) Init( IMaterial(en)* pMaterial, KeyValues(en)* pKeyValues )
Called when the material is first precache(en)d. 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.pngNota:pC_BaseEntity doesn't lead to a C_BaseEntity(en) as its name suggests, but rather to the associated IClientRenderable(en). 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()
Pendência: Called when the proxy is removed, but when is that?
IMaterial(en)* GetMaterial()
The material the proxy is attached to.
Tip.pngDica: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(en). It's a good idea to add it to your proxy too in case the Filmmaker is ever released!

Tip.pngDica:CEntityMaterialProxy makes the call by itself.

See also

External links