You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
861 lines
32 KiB
C++
861 lines
32 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "Cry3DEngine_precompiled.h"
|
|
#include "IShader.h"
|
|
#include "MaterialHelpers.h"
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* These functions are used in Cry3DEngine, CrySystem, CryRenderD3D11,
|
|
* Editor, ResourceCompilerMaterial and more
|
|
*/
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
namespace
|
|
{
|
|
static struct
|
|
{
|
|
EEfResTextures slot;
|
|
const char* ename;
|
|
bool adjustable;
|
|
const char* name;
|
|
const char* description;
|
|
const char* suffix;
|
|
}
|
|
s_TexSlotSemantics[] =
|
|
{
|
|
// NOTE: must be in order with filled holes to allow direct lookup
|
|
{ EFTT_DIFFUSE, "EFTT_DIFFUSE", true, "Diffuse" , "Base surface color. Alpha mask is contained in alpha channel." , "_diff" },
|
|
{ EFTT_NORMALS, "EFTT_NORMALS", true, "Bumpmap" , "Normal direction for each pixel simulating bumps on the surface. Smoothness map contained in alpha channel." , "_ddn" }, // Ideally "Normal" but need to keep backwards-compatibility
|
|
{ EFTT_SPECULAR, "EFTT_SPECULAR", true, "Specular" , "Reflective and shininess intensity and color of reflective highlights" , "_spec" },
|
|
{ EFTT_ENV, "EFTT_ENV", true, "Environment" , "Deprecated" , "_cm" },
|
|
{ EFTT_DETAIL_OVERLAY, "EFTT_DETAIL_OVERLAY", true, "Detail" , "Increases micro and macro surface bump, diffuse and gloss detail. To use, enable the 'Detail Mapping' shader gen param. " , "_detail" },
|
|
{ EFTT_SECOND_SMOOTHNESS, "EFTT_SECOND_SMOOTHNESS", false, "SecondSmoothness" , "" , "" },
|
|
{ EFTT_HEIGHT, "EFTT_HEIGHT", true, "Heightmap" , "Height for offset bump, POM, silhouette POM, and displacement mapping defined by a Grayscale texture" , "_displ" },
|
|
{ EFTT_DECAL_OVERLAY, "EFTT_DECAL_OVERLAY", true, "Decal" , "" , "" }, // called "DecalOverlay" in the shaders
|
|
{ EFTT_SUBSURFACE, "EFTT_SUBSURFACE", true, "SubSurface" , "" , "_sss" }, // called "Subsurface" in the shaders
|
|
{ EFTT_CUSTOM, "EFTT_CUSTOM", true, "Custom" , "" , "" }, // called "CustomMap" in the shaders
|
|
{ EFTT_CUSTOM_SECONDARY, "EFTT_CUSTOM_SECONDARY", true, "[1] Custom" , "" , "" },
|
|
{ EFTT_OPACITY, "EFTT_OPACITY", true, "Opacity" , "SubSurfaceScattering map to simulate thin areas for light to penetrate" , "" },
|
|
{ EFTT_SMOOTHNESS, "EFTT_SMOOTHNESS", false, "Smoothness" , "" , "_ddna" },
|
|
{ EFTT_EMITTANCE, "EFTT_EMITTANCE", true, "Emittance" , "Multiplies the emissive color with RGB texture. Emissive alpha mask is contained in alpha channel." , "_em" },
|
|
{ EFTT_OCCLUSION, "EFTT_OCCLUSION", true, "Occlusion" , "Grayscale texture to mask diffuse lighting response and simulate darker areas" , "" },
|
|
{ EFTT_SPECULAR_2, "EFTT_SPECULAR_2", true, "Specular2" , "" , "_spec" },
|
|
|
|
// Backwards compatible names are found here and mapped to the updated enum
|
|
{ EFTT_NORMALS, "EFTT_BUMP", false, "Normal" , "" , "" }, // called "Bump" in the shaders
|
|
{ EFTT_SMOOTHNESS, "EFTT_GLOSS_NORMAL_A", false, "GlossNormalA" , "" , "" },
|
|
{ EFTT_HEIGHT, "EFTT_BUMPHEIGHT", false, "Height" , "" , "" }, // called "BumpHeight" in the shaders
|
|
|
|
// This is the terminator for the name-search
|
|
{ EFTT_UNKNOWN, "EFTT_UNKNOWN", false, NULL , "" },
|
|
};
|
|
|
|
#if 0
|
|
static class Verify
|
|
{
|
|
public:
|
|
Verify()
|
|
{
|
|
for (int i = 0; s_TexSlotSemantics[i].name; i++)
|
|
{
|
|
if (s_TexSlotSemantics[i].slot != i)
|
|
{
|
|
throw std::runtime_error("Invalid texture slot lookup array.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
s_VerifyTexSlotSemantics;
|
|
#endif
|
|
}
|
|
|
|
// This should be done per shader (hence, semantics lookup map should be constructed per shader type)
|
|
EEfResTextures MaterialHelpers::FindTexSlot(const char* texName) const
|
|
{
|
|
for (int i = 0; s_TexSlotSemantics[i].name; i++)
|
|
{
|
|
if (azstricmp(s_TexSlotSemantics[i].name, texName) == 0)
|
|
{
|
|
return s_TexSlotSemantics[i].slot;
|
|
}
|
|
}
|
|
|
|
return EFTT_UNKNOWN;
|
|
}
|
|
|
|
const char* MaterialHelpers::FindTexName(EEfResTextures texSlot) const
|
|
{
|
|
for (int i = 0; s_TexSlotSemantics[i].name; i++)
|
|
{
|
|
if (s_TexSlotSemantics[i].slot == texSlot)
|
|
{
|
|
return s_TexSlotSemantics[i].name;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char* MaterialHelpers::LookupTexName(EEfResTextures texSlot) const
|
|
{
|
|
assert((texSlot >= 0) && (texSlot < EFTT_MAX));
|
|
return s_TexSlotSemantics[texSlot].name;
|
|
}
|
|
|
|
const char* MaterialHelpers::LookupTexDesc(EEfResTextures texSlot) const
|
|
{
|
|
assert((texSlot >= 0) && (texSlot < EFTT_MAX));
|
|
return s_TexSlotSemantics[texSlot].description;
|
|
}
|
|
|
|
const char* MaterialHelpers::LookupTexEnum(EEfResTextures texSlot) const
|
|
{
|
|
assert((texSlot >= 0) && (texSlot < EFTT_MAX));
|
|
return s_TexSlotSemantics[texSlot].ename;
|
|
}
|
|
|
|
const char* MaterialHelpers::LookupTexSuffix(EEfResTextures texSlot) const
|
|
{
|
|
assert((texSlot >= 0) && (texSlot < EFTT_MAX));
|
|
return s_TexSlotSemantics[texSlot].suffix;
|
|
}
|
|
|
|
bool MaterialHelpers::IsAdjustableTexSlot(EEfResTextures texSlot) const
|
|
{
|
|
assert((texSlot >= 0) && (texSlot < EFTT_MAX));
|
|
return s_TexSlotSemantics[texSlot].adjustable;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [Shader System TO DO] - automate these lookups to be data driven!
|
|
bool MaterialHelpers::SetGetMaterialParamFloat(IRenderShaderResources& pShaderResources, const char* sParamName, float& v, bool bGet) const
|
|
{
|
|
EEfResTextures texSlot = EFTT_UNKNOWN;
|
|
|
|
if (!azstricmp("emissive_intensity", sParamName))
|
|
{
|
|
texSlot = EFTT_EMITTANCE;
|
|
}
|
|
else if (!azstricmp("shininess", sParamName))
|
|
{
|
|
texSlot = EFTT_SMOOTHNESS;
|
|
}
|
|
else if (!azstricmp("opacity", sParamName))
|
|
{
|
|
texSlot = EFTT_OPACITY;
|
|
}
|
|
|
|
if (!azstricmp("alpha", sParamName))
|
|
{
|
|
if (bGet)
|
|
{
|
|
v = pShaderResources.GetAlphaRef();
|
|
}
|
|
else
|
|
{
|
|
pShaderResources.SetAlphaRef(v);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if (texSlot != EFTT_UNKNOWN)
|
|
{
|
|
if (bGet)
|
|
{
|
|
v = pShaderResources.GetStrengthValue(texSlot);
|
|
}
|
|
else
|
|
{
|
|
pShaderResources.SetStrengthValue(texSlot, v);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool MaterialHelpers::SetGetMaterialParamVec3(IRenderShaderResources& pShaderResources, const char* sParamName, Vec3& v, bool bGet) const
|
|
{
|
|
EEfResTextures texSlot = EFTT_UNKNOWN;
|
|
|
|
if (!azstricmp("diffuse", sParamName))
|
|
{
|
|
texSlot = EFTT_DIFFUSE;
|
|
}
|
|
else if (!azstricmp("specular", sParamName))
|
|
{
|
|
texSlot = EFTT_SPECULAR;
|
|
}
|
|
else if (!azstricmp("emissive_color", sParamName))
|
|
{
|
|
texSlot = EFTT_EMITTANCE;
|
|
}
|
|
|
|
if (texSlot != EFTT_UNKNOWN)
|
|
{
|
|
if (bGet)
|
|
{
|
|
v = pShaderResources.GetColorValue(texSlot).toVec3();
|
|
}
|
|
else
|
|
{
|
|
pShaderResources.SetColorValue(texSlot, ColorF(v, 1.0f));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetTexModFromXml(SEfTexModificator& pTextureModifier, const XmlNodeRef& modNode) const
|
|
{
|
|
// Modificators
|
|
float f;
|
|
uint8 c;
|
|
|
|
modNode->getAttr("TexMod_RotateType", pTextureModifier.m_eRotType);
|
|
modNode->getAttr("TexMod_TexGenType", pTextureModifier.m_eTGType);
|
|
modNode->getAttr("TexMod_bTexGenProjected", pTextureModifier.m_bTexGenProjected);
|
|
|
|
for (int baseu = 'U', u = baseu; u <= 'W'; u++)
|
|
{
|
|
char RT[] = "Rotate?";
|
|
RT[6] = u;
|
|
|
|
if (modNode->getAttr(RT, f))
|
|
{
|
|
pTextureModifier.m_Rot [u - baseu] = Degr2Word(f);
|
|
}
|
|
|
|
char RR[] = "TexMod_?RotateRate";
|
|
RR[7] = u;
|
|
char RP[] = "TexMod_?RotatePhase";
|
|
RP[7] = u;
|
|
char RA[] = "TexMod_?RotateAmplitude";
|
|
RA[7] = u;
|
|
char RC[] = "TexMod_?RotateCenter";
|
|
RC[7] = u;
|
|
|
|
if (modNode->getAttr(RR, f))
|
|
{
|
|
pTextureModifier.m_RotOscRate [u - baseu] = Degr2Word(f);
|
|
}
|
|
if (modNode->getAttr(RP, f))
|
|
{
|
|
pTextureModifier.m_RotOscPhase [u - baseu] = Degr2Word(f);
|
|
}
|
|
if (modNode->getAttr(RA, f))
|
|
{
|
|
pTextureModifier.m_RotOscAmplitude[u - baseu] = Degr2Word(f);
|
|
}
|
|
if (modNode->getAttr(RC, f))
|
|
{
|
|
pTextureModifier.m_RotOscCenter [u - baseu] = f;
|
|
}
|
|
|
|
if (u > 'V')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
char TL[] = "Tile?";
|
|
TL[4] = u;
|
|
char OF[] = "Offset?";
|
|
OF[6] = u;
|
|
|
|
if (modNode->getAttr(TL, f))
|
|
{
|
|
pTextureModifier.m_Tiling [u - baseu] = f;
|
|
}
|
|
if (modNode->getAttr(OF, f))
|
|
{
|
|
pTextureModifier.m_Offs [u - baseu] = f;
|
|
}
|
|
|
|
char OT[] = "TexMod_?OscillatorType";
|
|
OT[7] = u;
|
|
char OR[] = "TexMod_?OscillatorRate";
|
|
OR[7] = u;
|
|
char OP[] = "TexMod_?OscillatorPhase";
|
|
OP[7] = u;
|
|
char OA[] = "TexMod_?OscillatorAmplitude";
|
|
OA[7] = u;
|
|
|
|
if (modNode->getAttr(OT, c))
|
|
{
|
|
pTextureModifier.m_eMoveType [u - baseu] = c;
|
|
}
|
|
if (modNode->getAttr(OR, f))
|
|
{
|
|
pTextureModifier.m_OscRate [u - baseu] = f;
|
|
}
|
|
if (modNode->getAttr(OP, f))
|
|
{
|
|
pTextureModifier.m_OscPhase [u - baseu] = f;
|
|
}
|
|
if (modNode->getAttr(OA, f))
|
|
{
|
|
pTextureModifier.m_OscAmplitude [u - baseu] = f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static SEfTexModificator defaultTexMod;
|
|
static bool defaultTexMod_Initialized = false;
|
|
|
|
void MaterialHelpers::SetXmlFromTexMod(const SEfTexModificator& pTextureModifier, XmlNodeRef& node) const
|
|
{
|
|
if (!defaultTexMod_Initialized)
|
|
{
|
|
ZeroStruct(defaultTexMod);
|
|
defaultTexMod.m_Tiling[0] = 1;
|
|
defaultTexMod.m_Tiling[1] = 1;
|
|
defaultTexMod_Initialized = true;
|
|
}
|
|
|
|
if (memcmp(&pTextureModifier, &defaultTexMod, sizeof(pTextureModifier)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XmlNodeRef modNode = node->newChild("TexMod");
|
|
if (modNode)
|
|
{
|
|
// Modificators
|
|
float f;
|
|
uint16 s;
|
|
uint8 c;
|
|
|
|
modNode->setAttr("TexMod_RotateType", pTextureModifier.m_eRotType);
|
|
modNode->setAttr("TexMod_TexGenType", pTextureModifier.m_eTGType);
|
|
modNode->setAttr("TexMod_bTexGenProjected", pTextureModifier.m_bTexGenProjected);
|
|
|
|
for (int baseu = 'U', u = baseu; u <= 'W'; u++)
|
|
{
|
|
char RT[] = "Rotate?";
|
|
RT[6] = u;
|
|
|
|
if ((s = pTextureModifier.m_Rot [u - baseu]) != defaultTexMod.m_Rot [u - baseu])
|
|
{
|
|
modNode->setAttr(RT, Word2Degr(s));
|
|
}
|
|
|
|
char RR[] = "TexMod_?RotateRate";
|
|
RR[7] = u;
|
|
char RP[] = "TexMod_?RotatePhase";
|
|
RP[7] = u;
|
|
char RA[] = "TexMod_?RotateAmplitude";
|
|
RA[7] = u;
|
|
char RC[] = "TexMod_?RotateCenter";
|
|
RC[7] = u;
|
|
|
|
if ((s = pTextureModifier.m_RotOscRate [u - baseu]) != defaultTexMod.m_RotOscRate [u - baseu])
|
|
{
|
|
modNode->setAttr(RR, Word2Degr(s));
|
|
}
|
|
if ((s = pTextureModifier.m_RotOscPhase [u - baseu]) != defaultTexMod.m_RotOscPhase [u - baseu])
|
|
{
|
|
modNode->setAttr(RP, Word2Degr(s));
|
|
}
|
|
if ((s = pTextureModifier.m_RotOscAmplitude[u - baseu]) != defaultTexMod.m_RotOscAmplitude[u - baseu])
|
|
{
|
|
modNode->setAttr(RA, Word2Degr(s));
|
|
}
|
|
if ((f = pTextureModifier.m_RotOscCenter [u - baseu]) != defaultTexMod.m_RotOscCenter [u - baseu])
|
|
{
|
|
modNode->setAttr(RC, f);
|
|
}
|
|
|
|
if (u > 'V')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
char TL[] = "Tile?";
|
|
TL[4] = u;
|
|
char OF[] = "Offset?";
|
|
OF[6] = u;
|
|
|
|
if ((f = pTextureModifier.m_Tiling [u - baseu]) != defaultTexMod.m_Tiling [u - baseu])
|
|
{
|
|
modNode->setAttr(TL, f);
|
|
}
|
|
if ((f = pTextureModifier.m_Offs [u - baseu]) != defaultTexMod.m_Offs [u - baseu])
|
|
{
|
|
modNode->setAttr(OF, f);
|
|
}
|
|
|
|
char OT[] = "TexMod_?OscillatorType";
|
|
OT[7] = u;
|
|
char OR[] = "TexMod_?OscillatorRate";
|
|
OR[7] = u;
|
|
char OP[] = "TexMod_?OscillatorPhase";
|
|
OP[7] = u;
|
|
char OA[] = "TexMod_?OscillatorAmplitude";
|
|
OA[7] = u;
|
|
|
|
if ((c = pTextureModifier.m_eMoveType [u - baseu]) != defaultTexMod.m_eMoveType [u - baseu])
|
|
{
|
|
modNode->setAttr(OT, c);
|
|
}
|
|
if ((f = pTextureModifier.m_OscRate [u - baseu]) != defaultTexMod.m_OscRate [u - baseu])
|
|
{
|
|
modNode->setAttr(OR, f);
|
|
}
|
|
if ((f = pTextureModifier.m_OscPhase [u - baseu]) != defaultTexMod.m_OscPhase [u - baseu])
|
|
{
|
|
modNode->setAttr(OP, f);
|
|
}
|
|
if ((f = pTextureModifier.m_OscAmplitude [u - baseu]) != defaultTexMod.m_OscAmplitude [u - baseu])
|
|
{
|
|
modNode->setAttr(OA, f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetTexturesFromXml(SInputShaderResources& pShaderResources, const XmlNodeRef& node) const
|
|
{
|
|
const char* texmap = "";
|
|
const char* fileName = "";
|
|
|
|
XmlNodeRef texturesNode = node->findChild("Textures");
|
|
if (texturesNode)
|
|
{
|
|
for (int c = 0; c < texturesNode->getChildCount(); c++)
|
|
{
|
|
XmlNodeRef texNode = texturesNode->getChild(c);
|
|
texmap = texNode->getAttr("Map");
|
|
|
|
// [Shader System TO DO] - this must become per shader (and not global) according to the parser
|
|
uint8 texSlot = MaterialHelpers::FindTexSlot(texmap);
|
|
|
|
// [Shader System TO DO] - in the new system simply gather texture slot names, then identify name usage
|
|
// and accordingly match the slot (dynamically associated per shader by the parser).
|
|
if (texSlot == EFTT_UNKNOWN)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
fileName = texNode->getAttr("File");
|
|
|
|
// legacy. Some textures used to be referenced using "engine\\" or "engine/" - this is no longer valid
|
|
if (
|
|
(strlen(fileName) > 7) &&
|
|
(azstrnicmp(fileName, "engine", 6) == 0) &&
|
|
((fileName[6] == '\\') || (fileName[6] == '/'))
|
|
)
|
|
{
|
|
fileName = fileName + 7;
|
|
}
|
|
|
|
// legacy: Files were saved into a mtl with many leading forward or back slashes, we eat them all here. We want it to start with a rel path.
|
|
const char* actualFileName = fileName;
|
|
while ((actualFileName[0]) && ((actualFileName[0] == '\\') || (actualFileName[0] == '/')))
|
|
{
|
|
++actualFileName;
|
|
}
|
|
fileName = actualFileName;
|
|
|
|
// Next insert the texture resource if did not exist
|
|
TexturesResourcesMap* pTextureReourcesMap = pShaderResources.GetTexturesResourceMap();
|
|
SEfResTexture* pTextureRes = &(*pTextureReourcesMap)[texSlot];
|
|
|
|
pTextureRes->m_Name = fileName;
|
|
texNode->getAttr("IsTileU", pTextureRes->m_bUTile);
|
|
texNode->getAttr("IsTileV", pTextureRes->m_bVTile);
|
|
texNode->getAttr("TexType", pTextureRes->m_Sampler.m_eTexType);
|
|
|
|
int filter = pTextureRes->m_Filter;
|
|
if (texNode->getAttr("Filter", filter))
|
|
{
|
|
pTextureRes->m_Filter = filter;
|
|
}
|
|
|
|
// Next look for modulation node - add it only if exist
|
|
XmlNodeRef modNode = texNode->findChild("TexMod");
|
|
if (modNode)
|
|
SetTexModFromXml( *(pTextureRes->AddModificator()), modNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static SInputShaderResources defaultShaderResource; // for comparison with the default values
|
|
static SEfResTexture defaultTextureResource; // for comparison with the default values
|
|
|
|
void MaterialHelpers::SetXmlFromTextures( SInputShaderResources& pShaderResources, XmlNodeRef& node) const
|
|
{
|
|
// Save texturing data.
|
|
XmlNodeRef texturesNode = node->newChild("Textures");
|
|
|
|
for (auto& iter : *(pShaderResources.GetTexturesResourceMap()) )
|
|
{
|
|
EEfResTextures texId = static_cast<EEfResTextures>(iter.first);
|
|
const SEfResTexture* pTextureRes = &(iter.second);
|
|
if (pTextureRes && !pTextureRes->m_Name.empty() && IsAdjustableTexSlot(texId))
|
|
{
|
|
XmlNodeRef texNode = texturesNode->newChild("Texture");
|
|
|
|
texNode->setAttr("Map", MaterialHelpers::LookupTexName(texId));
|
|
texNode->setAttr("File", pTextureRes->m_Name.c_str());
|
|
|
|
if (pTextureRes->m_Filter != defaultTextureResource.m_Filter)
|
|
{
|
|
texNode->setAttr("Filter", pTextureRes->m_Filter);
|
|
}
|
|
if (pTextureRes->m_bUTile != defaultTextureResource.m_bUTile)
|
|
{
|
|
texNode->setAttr("IsTileU", pTextureRes->m_bUTile);
|
|
}
|
|
if (pTextureRes->m_bVTile != defaultTextureResource.m_bVTile)
|
|
{
|
|
texNode->setAttr("IsTileV", pTextureRes->m_bVTile);
|
|
}
|
|
if (pTextureRes->m_Sampler.m_eTexType != defaultTextureResource.m_Sampler.m_eTexType)
|
|
{
|
|
texNode->setAttr("TexType", pTextureRes->m_Sampler.m_eTexType);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Save texture modificators Modificators
|
|
//////////////////////////////////////////////////////////////////////////
|
|
SetXmlFromTexMod( *pTextureRes->GetModificator(), texNode);
|
|
}
|
|
/* [Shader System] - TO DO: test to see if slots can be removed
|
|
else
|
|
{
|
|
AZ_Assert(!pTextureRes->m_Name.empty(), "Shader resource texture error - Texture exists without a name");
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetVertexDeformFromXml(SInputShaderResources& pShaderResources, const XmlNodeRef& node) const
|
|
{
|
|
if (defaultShaderResource.m_DeformInfo.m_eType != pShaderResources.m_DeformInfo.m_eType)
|
|
{
|
|
node->setAttr("vertModifType", pShaderResources.m_DeformInfo.m_eType);
|
|
}
|
|
|
|
XmlNodeRef deformNode = node->findChild("VertexDeform");
|
|
if (deformNode)
|
|
{
|
|
int deform_type = eDT_Unknown;
|
|
deformNode->getAttr("Type", deform_type);
|
|
pShaderResources.m_DeformInfo.m_eType = (EDeformType)deform_type;
|
|
deformNode->getAttr("DividerX", pShaderResources.m_DeformInfo.m_fDividerX);
|
|
deformNode->getAttr("NoiseScale", pShaderResources.m_DeformInfo.m_vNoiseScale);
|
|
|
|
XmlNodeRef waveX = deformNode->findChild("WaveX");
|
|
if (waveX)
|
|
{
|
|
int type = eWF_None;
|
|
waveX->getAttr("Type", type);
|
|
pShaderResources.m_DeformInfo.m_WaveX.m_eWFType = (EWaveForm)type;
|
|
waveX->getAttr("Amp", pShaderResources.m_DeformInfo.m_WaveX.m_Amp);
|
|
waveX->getAttr("Level", pShaderResources.m_DeformInfo.m_WaveX.m_Level);
|
|
waveX->getAttr("Phase", pShaderResources.m_DeformInfo.m_WaveX.m_Phase);
|
|
waveX->getAttr("Freq", pShaderResources.m_DeformInfo.m_WaveX.m_Freq);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetXmlFromVertexDeform(const SInputShaderResources& pShaderResources, XmlNodeRef& node) const
|
|
{
|
|
int vertModif = pShaderResources.m_DeformInfo.m_eType;
|
|
node->setAttr("vertModifType", vertModif);
|
|
|
|
if (pShaderResources.m_DeformInfo.m_eType != eDT_Unknown)
|
|
{
|
|
XmlNodeRef deformNode = node->newChild("VertexDeform");
|
|
|
|
deformNode->setAttr("Type", pShaderResources.m_DeformInfo.m_eType);
|
|
deformNode->setAttr("DividerX", pShaderResources.m_DeformInfo.m_fDividerX);
|
|
deformNode->setAttr("NoiseScale", pShaderResources.m_DeformInfo.m_vNoiseScale);
|
|
|
|
XmlNodeRef waveX = deformNode->newChild("WaveX");
|
|
waveX->setAttr("Type", pShaderResources.m_DeformInfo.m_WaveX.m_eWFType);
|
|
waveX->setAttr("Amp", pShaderResources.m_DeformInfo.m_WaveX.m_Amp);
|
|
waveX->setAttr("Level", pShaderResources.m_DeformInfo.m_WaveX.m_Level);
|
|
waveX->setAttr("Phase", pShaderResources.m_DeformInfo.m_WaveX.m_Phase);
|
|
waveX->setAttr("Freq", pShaderResources.m_DeformInfo.m_WaveX.m_Freq);
|
|
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static inline ColorF ToCFColor(const Vec3& col)
|
|
{
|
|
return ColorF(col);
|
|
}
|
|
|
|
void MaterialHelpers::SetLightingFromXml(SInputShaderResources& pShaderResources, const XmlNodeRef& node) const
|
|
{
|
|
// Load lighting data.
|
|
Vec3 vColor;
|
|
Vec4 vColor4;
|
|
if (node->getAttr("Diffuse", vColor4))
|
|
{
|
|
pShaderResources.m_LMaterial.m_Diffuse = ColorF(vColor4.x, vColor4.y, vColor4.z, vColor4.w);
|
|
}
|
|
else if (node->getAttr("Diffuse", vColor))
|
|
{
|
|
pShaderResources.m_LMaterial.m_Diffuse = ToCFColor(vColor);
|
|
}
|
|
if (node->getAttr("Specular", vColor4))
|
|
{
|
|
pShaderResources.m_LMaterial.m_Specular = ColorF(vColor4.x, vColor4.y, vColor4.z, vColor4.w);
|
|
}
|
|
else if (node->getAttr("Specular", vColor))
|
|
{
|
|
pShaderResources.m_LMaterial.m_Specular = ToCFColor(vColor);
|
|
}
|
|
if (node->getAttr("Emittance", vColor4))
|
|
{
|
|
pShaderResources.m_LMaterial.m_Emittance = ColorF(vColor4.x, vColor4.y, vColor4.z, vColor4.w);
|
|
}
|
|
|
|
node->getAttr("Shininess", pShaderResources.m_LMaterial.m_Smoothness);
|
|
node->getAttr("Opacity", pShaderResources.m_LMaterial.m_Opacity);
|
|
node->getAttr("AlphaTest", pShaderResources.m_AlphaRef);
|
|
node->getAttr("VoxelCoverage", pShaderResources.m_VoxelCoverage);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static inline Vec3 ToVec3(const ColorF& col)
|
|
{
|
|
return Vec3(col.r, col.g, col.b);
|
|
}
|
|
|
|
static inline Vec4 ToVec4(const ColorF& col)
|
|
{
|
|
return Vec4(col.r, col.g, col.b, col.a);
|
|
}
|
|
|
|
void MaterialHelpers::SetXmlFromLighting(const SInputShaderResources& pShaderResources, XmlNodeRef& node) const
|
|
{
|
|
// Save ligthing data.
|
|
if (defaultShaderResource.m_LMaterial.m_Diffuse != pShaderResources.m_LMaterial.m_Diffuse)
|
|
{
|
|
node->setAttr("Diffuse", ToVec4(pShaderResources.m_LMaterial.m_Diffuse));
|
|
}
|
|
if (defaultShaderResource.m_LMaterial.m_Specular != pShaderResources.m_LMaterial.m_Specular)
|
|
{
|
|
node->setAttr("Specular", ToVec4(pShaderResources.m_LMaterial.m_Specular));
|
|
}
|
|
if (defaultShaderResource.m_LMaterial.m_Emittance != pShaderResources.m_LMaterial.m_Emittance)
|
|
{
|
|
node->setAttr("Emittance", ToVec4(pShaderResources.m_LMaterial.m_Emittance));
|
|
}
|
|
|
|
if (defaultShaderResource.m_LMaterial.m_Opacity != pShaderResources.m_LMaterial.m_Opacity)
|
|
{
|
|
node->setAttr("Opacity", pShaderResources.m_LMaterial.m_Opacity);
|
|
}
|
|
if (defaultShaderResource.m_LMaterial.m_Smoothness != pShaderResources.m_LMaterial.m_Smoothness)
|
|
{
|
|
node->setAttr("Shininess", pShaderResources.m_LMaterial.m_Smoothness);
|
|
}
|
|
|
|
if (defaultShaderResource.m_AlphaRef != pShaderResources.m_AlphaRef)
|
|
{
|
|
node->setAttr("AlphaTest", pShaderResources.m_AlphaRef);
|
|
}
|
|
if (defaultShaderResource.m_VoxelCoverage != pShaderResources.m_VoxelCoverage)
|
|
{
|
|
node->setAttr("VoxelCoverage", pShaderResources.m_VoxelCoverage);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetShaderParamsFromXml(SInputShaderResources& pShaderResources, const XmlNodeRef& node) const
|
|
{
|
|
int nA = node->getNumAttributes();
|
|
if (!nA)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < nA; i++)
|
|
{
|
|
const char* key = NULL, * val = NULL;
|
|
node->getAttributeByIndex(i, &key, &val);
|
|
|
|
// try to set existing param first
|
|
bool bFound = false;
|
|
|
|
for (int j = 0; j < pShaderResources.m_ShaderParams.size(); j++)
|
|
{
|
|
SShaderParam* pParam = &pShaderResources.m_ShaderParams[j];
|
|
|
|
if (pParam->m_Name == key)
|
|
{
|
|
bFound = true;
|
|
|
|
switch (pParam->m_Type)
|
|
{
|
|
case eType_BYTE:
|
|
node->getAttr(key, pParam->m_Value.m_Byte);
|
|
break;
|
|
case eType_SHORT:
|
|
node->getAttr(key, pParam->m_Value.m_Short);
|
|
break;
|
|
case eType_INT:
|
|
node->getAttr(key, pParam->m_Value.m_Int);
|
|
break;
|
|
case eType_FLOAT:
|
|
node->getAttr(key, pParam->m_Value.m_Float);
|
|
break;
|
|
case eType_FCOLOR:
|
|
case eType_FCOLORA:
|
|
{
|
|
Vec3 vValue;
|
|
node->getAttr(key, vValue);
|
|
|
|
pParam->m_Value.m_Color[0] = vValue.x;
|
|
pParam->m_Value.m_Color[1] = vValue.y;
|
|
pParam->m_Value.m_Color[2] = vValue.z;
|
|
}
|
|
break;
|
|
case eType_VECTOR:
|
|
{
|
|
Vec4 vValue;
|
|
if (node->getAttr(key, vValue))
|
|
{
|
|
pParam->m_Value.m_Color[0] = vValue.x;
|
|
pParam->m_Value.m_Color[1] = vValue.y;
|
|
pParam->m_Value.m_Color[2] = vValue.z;
|
|
pParam->m_Value.m_Color[3] = vValue.w;
|
|
}
|
|
else
|
|
{
|
|
Vec3 vValue3;
|
|
if (node->getAttr(key, vValue3))
|
|
{
|
|
pParam->m_Value.m_Color[0] = vValue3.x;
|
|
pParam->m_Value.m_Color[1] = vValue3.y;
|
|
pParam->m_Value.m_Color[2] = vValue3.z;
|
|
pParam->m_Value.m_Color[3] = 1.0f;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
assert(val && key);
|
|
|
|
SShaderParam Param;
|
|
Param.m_Name = key;
|
|
Param.m_Value.m_Color[0] = Param.m_Value.m_Color[1] = Param.m_Value.m_Color[2] = Param.m_Value.m_Color[3] = 0;
|
|
|
|
int res = azsscanf(val, "%f,%f,%f,%f", &Param.m_Value.m_Color[0], &Param.m_Value.m_Color[1], &Param.m_Value.m_Color[2], &Param.m_Value.m_Color[3]);
|
|
assert(res);
|
|
|
|
pShaderResources.m_ShaderParams.push_back(Param);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void MaterialHelpers::SetXmlFromShaderParams(const SInputShaderResources& pShaderResources, XmlNodeRef& node) const
|
|
{
|
|
for (int i = 0; i < pShaderResources.m_ShaderParams.size(); i++)
|
|
{
|
|
const SShaderParam* pParam = &pShaderResources.m_ShaderParams[i];
|
|
switch (pParam->m_Type)
|
|
{
|
|
case eType_BYTE:
|
|
node->setAttr(pParam->m_Name.c_str(), (int)pParam->m_Value.m_Byte);
|
|
break;
|
|
case eType_SHORT:
|
|
node->setAttr(pParam->m_Name.c_str(), (int)pParam->m_Value.m_Short);
|
|
break;
|
|
case eType_INT:
|
|
node->setAttr(pParam->m_Name.c_str(), (int)pParam->m_Value.m_Int);
|
|
break;
|
|
case eType_FLOAT:
|
|
node->setAttr(pParam->m_Name.c_str(), (float)pParam->m_Value.m_Float);
|
|
break;
|
|
case eType_FCOLOR:
|
|
node->setAttr(pParam->m_Name.c_str(), Vec3(pParam->m_Value.m_Color[0], pParam->m_Value.m_Color[1], pParam->m_Value.m_Color[2]));
|
|
break;
|
|
case eType_VECTOR:
|
|
node->setAttr(pParam->m_Name.c_str(), Vec3(pParam->m_Value.m_Vector[0], pParam->m_Value.m_Vector[1], pParam->m_Value.m_Vector[2]));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// [Shader System TO DO] - the following function supports older version of data
|
|
// and converts them.
|
|
// This needs to go away soon!
|
|
//------------------------------------------------------------------------------
|
|
void MaterialHelpers::MigrateXmlLegacyData(SInputShaderResources& pShaderResources, const XmlNodeRef& node) const
|
|
{
|
|
float glowAmount;
|
|
|
|
// Migrate glow from 3.8.3 to emittance
|
|
if (node->getAttr("GlowAmount", glowAmount) && glowAmount > 0)
|
|
{
|
|
SEfResTexture* pTextureRes = pShaderResources.GetTextureResource(EFTT_DIFFUSE);
|
|
if (pTextureRes && (pTextureRes->m_Sampler.m_eTexType == eTT_2D))
|
|
{
|
|
// The following line will create and insert a new texture data slot if did not exist.
|
|
pShaderResources.m_TexturesResourcesMap[EFTT_EMITTANCE].m_Name = pTextureRes->m_Name;
|
|
}
|
|
const float legacyHDRDynMult = 2.0f;
|
|
const float legacyIntensityScale = 10.0f; // Legacy scale factor 10000 divided by 1000 for kilonits
|
|
|
|
// Clamp this at EMISSIVE_INTENSITY_SOFT_MAX because some previous glow parameters become extremely bright.
|
|
pShaderResources.m_LMaterial.m_Emittance.a = min(powf(glowAmount * legacyHDRDynMult, legacyHDRDynMult) * legacyIntensityScale, EMISSIVE_INTENSITY_SOFT_MAX);
|
|
|
|
std::string materialName = node->getAttr("Name");
|
|
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, "Material %s has had legacy GlowAmount automatically converted to Emissive Intensity. The material parameters related to Emittance should be manually adjusted for this material.", materialName.c_str());
|
|
}
|
|
|
|
// In Lumberyard version 1.9 BlendLayer2Specular became a color instead of a single float, so it needs to be updated
|
|
XmlNodeRef publicParamsNode = node->findChild("PublicParams");
|
|
if (publicParamsNode && publicParamsNode->haveAttr("BlendLayer2Specular"))
|
|
{
|
|
// Check to see if the BlendLayer2Specular is a float
|
|
AZStd::string blendLayer2SpecularString(publicParamsNode->getAttr("BlendLayer2Specular"));
|
|
|
|
// If there are no commas in the string representation, it must be a single float instead of a color
|
|
if (blendLayer2SpecularString.find(',') == AZStd::string::npos)
|
|
{
|
|
float blendLayer2SpecularFloat = 0.0f;
|
|
publicParamsNode->getAttr("BlendLayer2Specular", blendLayer2SpecularFloat);
|
|
publicParamsNode->setAttr("BlendLayer2Specular", Vec4(blendLayer2SpecularFloat, blendLayer2SpecularFloat, blendLayer2SpecularFloat, 0.0));
|
|
}
|
|
}
|
|
}
|