add support for gltf's KHR_materials_variants (for selectable skins) and KHR_materials_ior extensions

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5927 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-07-01 01:16:23 +00:00
parent df83d72837
commit 6cc5e1762b
3 changed files with 99 additions and 21 deletions

View file

@ -318,7 +318,10 @@ void main ()
col *= factor_base; col *= factor_base;
#define dielectricSpecular 0.04 #ifndef IOR
#define IOR 1.5 //Index Of Reflection.
#endif
#define dielectricSpecular pow(((IOR - 1.0)/(IOR + 1.0)),2.0)
#ifdef SPECULAR #ifdef SPECULAR
vec4 specs = texture2D(s_specular, tc)*factor_spec; vec4 specs = texture2D(s_specular, tc)*factor_spec;
#ifdef ORM #ifdef ORM

View file

@ -331,7 +331,10 @@ void main ()
#endif #endif
// col *= factor_base; // col *= factor_base;
#define dielectricSpecular 0.04 #ifndef IOR
#define IOR 1.5 //Index Of Reflection.
#endif
#define dielectricSpecular pow(((IOR - 1.0)/(IOR + 1.0)),2.0)
#ifdef SPECULAR #ifdef SPECULAR
vec4 specs = texture2D(s_specular, tc);//*factor_spec; vec4 specs = texture2D(s_specular, tc);//*factor_spec;
#ifdef ORM #ifdef ORM

View file

@ -713,6 +713,8 @@ typedef struct gltf_s
json_t *r; json_t *r;
int ver; int ver;
unsigned int variations;
int *bonemap;//[MAX_BONES]; //remap skinned bones. I hate that we have to do this. int *bonemap;//[MAX_BONES]; //remap skinned bones. I hate that we have to do this.
struct gltfbone_s struct gltfbone_s
{ {
@ -785,8 +787,21 @@ static json_t *GLTF_FindJSONID_First(struct gltf_s *gltf, const char *restype, j
return GLTF_FindJSONIDParent(gltf, JSON_FindChild(gltf->r, restype), id, idx); return GLTF_FindJSONIDParent(gltf, JSON_FindChild(gltf->r, restype), id, idx);
} }
static int dehex(int i)
{
if (i >= '0' && i <= '9')
return (i-'0');
else if (i >= 'A' && i <= 'F')
return (i-'A'+10);
else if (i >= 'a' && i <= 'f')
return (i-'a'+10);
else
return -1;
}
static void GLTF_RelativePath(const char *base, const char *relative, char *out, size_t outsize) static void GLTF_RelativePath(const char *base, const char *relative, char *out, size_t outsize)
{ {
char *out_start = out;
size_t t; size_t t;
const char *sep; const char *sep;
const char *end = base; const char *end = base;
@ -830,13 +845,27 @@ static void GLTF_RelativePath(const char *base, const char *relative, char *out,
out += t; out += t;
outsize -= t; outsize -= t;
//FIXME: uris should be percent-decoded here. for (; *relative && outsize; outsize--)
t = strlen(relative); {
if (t > outsize) if (*relative == '%' && ((out-out_start>=7 && !strncmp(out_start, "http://", 7)) || (out-out_start>=8 && !strncmp(out_start, "https://", 8))))
t = outsize; {
memcpy(out, relative, t); int high, low;
out += t; char b = *relative++;
outsize -= t; high = dehex(relative[0]);
if (high >= 0)
{
low = dehex(relative[1]);
if (low >= 0 && (high || low))
{
relative += 2;
b = (high<<4) | low;
}
}
*out++ = b;
}
else
*out++ = *relative++;
}
*out = 0; *out = 0;
} }
@ -1961,7 +1990,7 @@ static qboolean GLTF1_LoadMaterial(gltf_t *gltf, json_t *mat, texnums_t *texnums
return true; return true;
} }
static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolean vertexcolours) static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *ret, qboolean vertexcolours)
{ {
qboolean doubleSided; qboolean doubleSided;
int alphaMode; int alphaMode;
@ -1970,7 +1999,6 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
char alphaCutoffmodifier[128]; char alphaCutoffmodifier[128];
quintptr_t materialidx; quintptr_t materialidx;
json_t *mat = GLTF_FindJSONID(gltf, "materials", materialid, &materialidx); json_t *mat = GLTF_FindJSONID(gltf, "materials", materialid, &materialidx);
galiasskin_t *ret;
char tmp[64]; char tmp[64];
const char *t; const char *t;
@ -1998,7 +2026,6 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
Con_Printf(CON_WARNING"%s: unsupported alphaMode: %s\n", gltf->mod->name, t); Con_Printf(CON_WARNING"%s: unsupported alphaMode: %s\n", gltf->mod->name, t);
} }
ret = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret));
ret->numframes = 1; ret->numframes = 1;
ret->skinspeed = 0.1; ret->skinspeed = 0.1;
ret->frame = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret->frame)); ret->frame = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret->frame));
@ -2018,7 +2045,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
skip = 0; skip = 0;
if (mod_gltf_privatematerials->ival && !strchr(shader, '/')) if (mod_gltf_privatematerials->ival && !strchr(shader, '/'))
{ {
Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%s", gltf->mod->name-skip); Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%s/%u", gltf->mod->name-skip, (unsigned)materialidx);
Q_strncatz(ret->frame->shadername, "/", sizeof(ret->frame->shadername)); Q_strncatz(ret->frame->shadername, "/", sizeof(ret->frame->shadername));
} }
else else
@ -2116,6 +2143,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
else if (pbrsg) else if (pbrsg)
{ //if this extension was used, then we can use rgb gloss instead of metalness stuff. { //if this extension was used, then we can use rgb gloss instead of metalness stuff.
json_t *occ = JSON_FindChild(mat, "occlusionTexture.index"); //.r json_t *occ = JSON_FindChild(mat, "occlusionTexture.index"); //.r
float ior = JSON_GetFloat(mat, "extensions.KHR_materials_ior.ior", 1.5); //supposedly still relevant here
ret->frame->texnums.base = GLTF_LoadTexture(gltf, JSON_FindChild(pbrsg, "diffuseTexture.index"), 0); ret->frame->texnums.base = GLTF_LoadTexture(gltf, JSON_FindChild(pbrsg, "diffuseTexture.index"), 0);
ret->frame->texnums.specular = GLTF_LoadTexture(gltf, JSON_FindChild(pbrsg, "specularGlossinessTexture.index"), 0); ret->frame->texnums.specular = GLTF_LoadTexture(gltf, JSON_FindChild(pbrsg, "specularGlossinessTexture.index"), 0);
if (occ) if (occ)
@ -2124,7 +2152,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
Q_snprintf(shader, sizeof(shader), Q_snprintf(shader, sizeof(shader),
"{\n" "{\n"
"%s"//cull "%s"//cull
"program defaultskin#SG#VC%s%s\n" "program defaultskin" "#SG" "#VC" "#IOR=%.02f" "%s"/*occlude*/ "%s"/*alphacutoff*/ "\n"
"{\n" "{\n"
"map $diffuse\n" "map $diffuse\n"
"%s" //blend "%s" //blend
@ -2136,6 +2164,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
"bemode rtlight rtlight_sg\n" "bemode rtlight rtlight_sg\n"
"}\n", "}\n",
doubleSided?"cull disable\n":"", doubleSided?"cull disable\n":"",
ior,
(occ)?"#OCCLUDE":"", (occ)?"#OCCLUDE":"",
alphaCutoffmodifier, alphaCutoffmodifier,
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"", (alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
@ -2162,6 +2191,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
json_t *n; json_t *n;
char occname[MAX_QPATH]; char occname[MAX_QPATH];
char mrtname[MAX_QPATH]; char mrtname[MAX_QPATH];
float ior = JSON_GetFloat(mat, "extensions.KHR_materials_ior.ior", 1.5);
if (JSON_GetInteger(pbrmr, "baseColorTexture.texCoord", 0) != 0) if (JSON_GetInteger(pbrmr, "baseColorTexture.texCoord", 0) != 0)
if (gltf->warnlimit --> 0) if (gltf->warnlimit --> 0)
@ -2198,7 +2228,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
Q_snprintf(shader, sizeof(shader), Q_snprintf(shader, sizeof(shader),
"{\n" "{\n"
"%s"//cull "%s"//cull
"program defaultskin#ORM#VC%s%s\n" "program defaultskin" "#ORM" "#VC" "#IOR=%.02f" "%s"/*occlude*/ "%s"/*alphatest*/ "\n"
"{\n" "{\n"
"map $diffuse\n" "map $diffuse\n"
"%s" //blend "%s" //blend
@ -2210,6 +2240,7 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
"bemode rtlight rtlight_orm\n" "bemode rtlight rtlight_orm\n"
"}\n", "}\n",
doubleSided?"cull disable\n":"", doubleSided?"cull disable\n":"",
ior,
(!occ)?"#NOOCCLUDE":(strcmp(occname,mrtname)?"#OCCLUDE":""), (!occ)?"#NOOCCLUDE":(strcmp(occname,mrtname)?"#OCCLUDE":""),
alphaCutoffmodifier, alphaCutoffmodifier,
(alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"", (alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"",
@ -2237,7 +2268,6 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, qboolea
ret->frame->defaultshader = memcpy(modfuncs->ZG_Malloc(&gltf->mod->memgroup, strlen(shader)+1), shader, strlen(shader)+1); ret->frame->defaultshader = memcpy(modfuncs->ZG_Malloc(&gltf->mod->memgroup, strlen(shader)+1), shader, strlen(shader)+1);
Q_strlcpy(ret->name, ret->frame->shadername, sizeof(ret->name)); Q_strlcpy(ret->name, ret->frame->shadername, sizeof(ret->name));
return ret;
} }
#endif #endif
static const float *QDECL GLTF_AnimateMorphs(const galiasinfo_t *surf, const framestate_t *framestate); static const float *QDECL GLTF_AnimateMorphs(const galiasinfo_t *surf, const framestate_t *framestate);
@ -2461,8 +2491,30 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
} }
#ifndef SERVERONLY #ifndef SERVERONLY
surf->numskins = 1; {
surf->ofsskins = GLTF_LoadMaterial(gltf, JSON_FindChild(prim, "material"), surf->ofs_rgbaub||surf->ofs_rgbaf); json_t *mapping, *var;
surf->numskins = 1+gltf->variations;
surf->ofsskins = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*surf->ofsskins)*surf->numskins);
GLTF_LoadMaterial(gltf, JSON_FindChild(prim, "material"), surf->ofsskins, surf->ofs_rgbaub||surf->ofs_rgbaf);
for (i = 0; i < gltf->variations; i++)
surf->ofsskins[1+i] = surf->ofsskins[0]; //unspecified matches defaults...
for (mapping=JSON_FindIndexedChild(prim, "extensions.KHR_materials_variants.mappings", 0); mapping; mapping = mapping->sibling)
{
i = 0;
for(var = JSON_FindIndexedChild(mapping, "variants", 0); var; var = var->sibling)
{
j = 1+JSON_GetUInteger(var, NULL, ~0u);
if (j < 1 || j >= surf->numskins)
continue; //not valid.
if (!i)
GLTF_LoadMaterial(gltf, JSON_FindChild(mapping, "material"), &surf->ofsskins[j], surf->ofs_rgbaub||surf->ofs_rgbaf);
else
surf->ofsskins[j] = surf->ofsskins[i];
i = j;
}
}
}
#endif #endif
if (!tang.data) if (!tang.data)
@ -3164,17 +3216,22 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
{"KHR_materials_pbrSpecularGlossiness", true, false}, {"KHR_materials_pbrSpecularGlossiness", true, false},
// {"KHR_materials_cmnBlinnPhong", true, true}, // {"KHR_materials_cmnBlinnPhong", true, true},
{"KHR_materials_unlit", true, false}, {"KHR_materials_unlit", true, false},
{"KHR_texture_transform", false, true}, //probably not fatal
{"KHR_draco_mesh_compression", false, true}, //probably fatal
{"KHR_mesh_quantization", true, true}, {"KHR_mesh_quantization", true, true},
{"MSFT_texture_dds", true, false}, {"MSFT_texture_dds", true, false},
{"MSFT_packing_occlusionRoughnessMetallic", true, false}, {"MSFT_packing_occlusionRoughnessMetallic", true, false},
{"KHR_materials_variants", true, false},
{"KHR_materials_ior", true, false},
{"KHR_draco_mesh_compression", false, true}, //probably fatal
{"KHR_texture_transform", false, false}, //requires glsl tweaks, per texmap. can't use tcmod if its only on the bumpmap etc.
{"KHR_materials_sheen", false, false}, //requires glsl tweaks, extra brdf layer in the middle for velvet.
{"KHR_materials_clearcoat", false, false}, //requires glsl tweaks, extra brdf layer over the top for varnish etc.
{NULL} {NULL}
}, *extensions; }, *extensions;
gltf_t gltf; gltf_t gltf;
int pos=0; int pos=0;
quintptr_t j,k; quintptr_t j,k;
json_t *scene, *n, *anim; json_t *scene, *n, *anim, *var;
double rootmatrix[16]; double rootmatrix[16];
double gltfver; double gltfver;
galiasinfo_t *surf; galiasinfo_t *surf;
@ -3297,6 +3354,11 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
} }
gltf.numbones = j; gltf.numbones = j;
gltf.variations = 0;
for (var = JSON_FindIndexedChild(gltf.r, "extensions.KHR_materials_variants.variants", 0); var; var = var->sibling)
gltf.variations++;
JSON_FlagAsUsed(scene, "name"); JSON_FlagAsUsed(scene, "name");
GLTF_FlagExtras(scene); GLTF_FlagExtras(scene);
for (j = 0; ; j++) for (j = 0; ; j++)
@ -3469,6 +3531,16 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
surf->csurface.flags = 0; surf->csurface.flags = 0;
surf->geomset = ~0; //invalid set = always visible. FIXME: set this according to scene numbers? surf->geomset = ~0; //invalid set = always visible. FIXME: set this according to scene numbers?
surf->geomid = 0; surf->geomid = 0;
#ifndef SERVERONLY
if (surf->numskins>1)
{
int i;
Q_snprintf(surf->ofsskins[0].name, sizeof(surf->ofsskins[0].name), "Default");
for (i = 1; i < surf->numskins; i++)
JSON_GetString(JSON_FindIndexedChild(gltf.r, "extensions.KHR_materials_variants.variants", i-1), "name", surf->ofsskins[i].name, sizeof(surf->ofsskins[i].name), surf->ofsskins[i].name);
}
#endif
} }
VectorScale(mod->mins, mod_gltf_scale->value, mod->mins); VectorScale(mod->mins, mod_gltf_scale->value, mod->mins);