Material proxies
This page either contains information that is only partially or incorrectly translated, or there isn't a translation yet.
If this page cannot be translated for some reason, or is left untranslated for an extended period of time after this notice is posted, the page should be requested to be deleted.
Also, please make sure the article tries to comply with the alternate languages guide.
使用ChatGPT翻译
材质代理允许游戏的编译C++代码操作材质的属性。许多代理执行特定任务,但也有其他更通用的代理,它们共同在VMT文件中提供基本的脚本支持。[澄清]
可以向材质添加任意数量的代理,它们会按照出现的顺序执行。
用法
该材质有一个 Sine
代理,使其在8秒内逐渐显现和消失:
LightmappedGeneric
{
$basetexture shadertest/LightmappedTexture
Proxies // 代理列在此块内
{
Sine // 产生正弦波的代理
{
resultVar $alpha // 要操作的着色器参数
sineperiod 8
sinemin 0
sinemax 1
}
}
}
变量
材质可以声明自己的变量供内部使用。这些变量必须在Proxies块之外声明,在材质的主体部分,并且必须指定默认值。
这些自定义变量可能用于在代理之间传递结果或向其提交硬编码的数据。它们通常用于将数学函数代理(例如 Add
、Subtract
等)串联成更长的方程式。对于2D/3D/4D向量("[0 0 0]"
),变量名称可以附加[0]
以读取/写入特定索引。写入索引变量时应将其包围在引号中。
引擎使用8位有符号整数对这些自定义变量进行编码。因此,每个材质最多支持128个唯一自定义变量。
以下示例通过错开正弦波的起始位置来扩展上述示例:
LightmappedGeneric
{
$basetexture shadertest/LightmappedTexture
$offset 0 // 声明自定义变量
Proxies
{
EntityRandom
{
resultVar $offset // 写入自定义变量
}
Sine
{
resultVar $alpha
timeoffset $offset // 从自定义变量读取
sineperiod 8
sinemin 0
sinemax 1
}
}
}
现在,每个使用该材质的实体都会按照自己的时间表脉冲。
写入索引变量的其他示例:
$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]"
}
}
使用颜色向量创建“随机”颜色脉冲的示例:
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
}
}
}
动态纹理变换的示例。
分割向量
使用向量时有些特殊之处。并非所有代理都能识别向量分量。如果需要单独处理向量的各个分量,则必须先将它们拆分成不同的变量。
所有代理中的resultVar
都会识别向量分量。
以下代理和仅这些关键字可以识别向量分量:
- Clamp: min, max
- Sine: offset, max, min, period
- LinearRamp: rate, initial value
- UniformNoise: min, max
- GaussianNoise: min, max, mean, halfwidth
- WrapMinMax: min, max
- Exponential: min, max, scale, offset
上述所有代理都可以用于分割向量。 但是Clamp是最便宜的选择:
$pos "[0 0 0]"
$posX .0 //必须为浮点数,否则Clamp无法正确保存值
$posY .0 //必须为浮点数,否则Clamp无法正确保存值
$posZ .0 //必须为浮点数,否则Clamp无法正确保存值
$zero 0
//输出3D向量的代理
PlayerPosition
{
scale 1
resultVar "$pos"
}
//拆分3D向量以便进一步使用
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
}
编写新的代理
创建新的代理很简单。它们仅存在于客户端,并应继承自IMaterialProxy
或其子类。
你需要这些头文件:
"materialsystem/IMaterialProxy.h"
"materialsystem/IMaterialVar.h"
以下函数包含在接口中:
bool Init( IMaterial* pMaterial, KeyValues* pKeyValues )
- 在材质首次预加载时调用。使用此函数初始化变量并获取你将使用的材质变量的引用。成功时返回true,失败时返回false(此时代理将不会执行)。
pKeyValues
包含来自VMT文件的代理参数。
void OnBind( void* pC_BaseEntity )
- 在材质即将应用到实体进行渲染时调用。这里是执行工作的地方。
- 编写此函数时需要记住,所有使用同一材质的实体共享同一个材质对象,若在一个实体上修改了材质,它将在其他所有实体上也发生变化。由于
OnBind()
会在每次渲染实体时被调用,只要每次都重新分配你想要的值就不会有问题。不要因为没有变化而提前返回,也不要在代理中存储输入数据。注意:pC_BaseEntity
并不会指向C_BaseEntity
,而是指向关联的IClientRenderable
。要直接访问实体,最简单的方法是基于CEntityMaterialProxy
(位于proxyentity.h
)并使用其提供的OnBind(C_BaseEntity*)
重载。
void Release()
- 待完善: 代理被移除时调用,但是什么时候呢?
IMaterial* GetMaterial()
- 获取代理所附加的材质。提示:如果你有一个材质变量存储,你可以返回
IMaterialVar::GetOwningMaterial()
,而不是创建一个新的IMaterial
指针。
接口
代理必须通过EXPOSE_INTERFACE
宏向材质暴露其接口:
EXPOSE_INTERFACE( <className>, <interfaceName>, "<proxyName>" IMATERIAL_PROXY_INTERFACE_VERSION );
代理名称和接口版本之间没有逗号,这是故意的。
工具录制
以下代码已被添加到所有代理中,适用于Orange Box:
#include "toolframework_client.h"
void OnBind(...)
{
//...
if ( ToolsEnabled() )
ToolFramework_RecordMaterialParams( GetMaterial() );
}
它可能与Source Filmmaker相关。最好在你的代理中也添加这段代码,以防Filmmaker发布!
CEntityMaterialProxy
会自动进行此调用。另见
外部链接
- 使用代理的动态材质 - NoDraw.net关于使用代理的材质的实践文章