diff --git a/engine/client/merged.h b/engine/client/merged.h index 7d8e75986..566e4b629 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -388,6 +388,8 @@ typedef struct texnums_s { texid_t reflectmask; //2d, defines how reflective it is (for cubemap reflections) texid_t displacement; //2d, alternative to bump.a, eg R16[F] for offsetmapping or tessellation texid_t occlusion; //2d, occlusion map... only red is used. + texid_t transmission; //2d, multiplier for transmissionfactor... only red is used. + texid_t thickness; //2d, multiplier for thicknessfactor... only green is used. //the material's pushconstants. vulkan guarentees only 128 bytes. so 8 vec4s. note that lmscales should want 4 of them... /*struct diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 443f0d9b4..21916c842 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1307,6 +1307,18 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass) else t = r_whiteimage; break; + case T_GEN_TRANSMISSION: + if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->transmission)) + t = shaderstate.curtexnums->transmission; + else + t = r_whiteimage; + break; + case T_GEN_THICKNESS: + if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->thickness)) + t = shaderstate.curtexnums->thickness; + else + t = r_whiteimage; + break; case T_GEN_SHADOWMAP: t = shaderstate.curshadowmap; break; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 0aaec107a..e3523dc09 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1415,6 +1415,8 @@ const struct sh_defaultsamplers_s sh_defaultsamplers[] = {"s_reflectmask", 1u< 1 @@ -2627,7 +2629,7 @@ static void Shader_ReflectCube(parsestate_t *ps, const char **ptr) static void Shader_ReflectMask(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); - unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); + unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB); ps->s->defaulttextures->reflectmask = Shader_FindImage(ps, token, flags); } @@ -2675,6 +2677,18 @@ static void Shader_DisplacementMap(parsestate_t *ps, const char **ptr) unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB); ps->s->defaulttextures->displacement = Shader_FindImage(ps, token, flags); } +static void Shader_TransmissionMap(parsestate_t *ps, const char **ptr) +{ + char *token = Shader_ParseSensString(ptr); + unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB); + ps->s->defaulttextures->transmission = Shader_FindImage(ps, token, flags); +} +static void Shader_ThicknessMap(parsestate_t *ps, const char **ptr) +{ + char *token = Shader_ParseSensString(ptr); + unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB); + ps->s->defaulttextures->thickness = Shader_FindImage(ps, token, flags); +} static void Shaderpass_QF_Material(parsestate_t *ps, const char **ptr) { //qf_material BASETEXTURE NORMALMAP SPECULARMAP @@ -2835,6 +2849,23 @@ static void Shader_FactorEmit(parsestate_t *ps, const char **ptr) shader->factors[MATERIAL_FACTOR_EMIT][2] = Shader_ParseFloat(shader, ptr, 1); shader->factors[MATERIAL_FACTOR_EMIT][3] = Shader_ParseFloat(shader, ptr, 1); } +static void Shader_FactorTransmission(parsestate_t *ps, const char **ptr) +{ + shader_t *shader = ps->s; + shader->factors[MATERIAL_FACTOR_TRANSMISSION][0] = Shader_ParseFloat(shader, ptr, 1); +// shader->factors[MATERIAL_FACTOR_TRANSMISSION][1] = the volume distance; + shader->factors[MATERIAL_FACTOR_TRANSMISSION][2] = 0; + shader->factors[MATERIAL_FACTOR_TRANSMISSION][3] = 0; +} +static void Shader_FactorVolume(parsestate_t *ps, const char **ptr) +{ + shader_t *shader = ps->s; + shader->factors[MATERIAL_FACTOR_VOLUME][0] = Shader_ParseFloat(shader, ptr, 1); //r + shader->factors[MATERIAL_FACTOR_VOLUME][1] = Shader_ParseFloat(shader, ptr, 1); //g + shader->factors[MATERIAL_FACTOR_VOLUME][2] = Shader_ParseFloat(shader, ptr, 1); //b + shader->factors[MATERIAL_FACTOR_VOLUME][3] = Shader_ParseFloat(shader, ptr, 1); //factor + shader->factors[MATERIAL_FACTOR_TRANSMISSION][1] = Shader_ParseFloat(shader, ptr, 1); //distance +} static void Shader_BEMode(parsestate_t *ps, const char **ptr) { @@ -2965,11 +2996,15 @@ static shaderkey_t shaderkeys[] = {"lowermap", Shader_LowerMap, "fte"}, {"reflectmask", Shader_ReflectMask, "fte"}, {"displacementmap", Shader_DisplacementMap, "fte"}, + {"transmissionmap", Shader_TransmissionMap, "fte"}, + {"thicknessmap", Shader_ThicknessMap, "fte"}, {"portalfboscale", Shader_PortalFBOScale, "fte"}, //portal/mirror/refraction/reflection FBOs are resized by this scale {"basefactor", Shader_FactorBase, "fte"}, //material scalers for glsl {"specularfactor", Shader_FactorSpec, "fte"}, //material scalers for glsl {"fullbrightfactor", Shader_FactorEmit, "fte"}, //material scalers for glsl + {"fte_transmissionfactor",Shader_FactorTransmission,"fte"}, //material scalers for glsl + {"fte_volumefactor", Shader_FactorVolume, "fte"}, //material scalers for glsl //TODO: PBR textures... // {"albedomap", Shader_DiffuseMap, "fte"}, //rgb(a) @@ -4775,16 +4810,18 @@ static void Shader_FixupProgPasses(parsestate_t *ps, shaderpass_t *pass) {T_GEN_REFLECTMASK, 0}, //10 {T_GEN_DISPLACEMENT, SHADER_HASDISPLACEMENT},//11 {T_GEN_OCCLUSION, 0}, //12 + {T_GEN_TRANSMISSION, 0}, //13 + {T_GEN_THICKNESS, 0}, //14 // {T_GEN_REFLECTION, SHADER_HASREFLECT}, // // {T_GEN_REFRACTION, SHADER_HASREFRACT}, // // {T_GEN_REFRACTIONDEPTH, SHADER_HASREFRACTDEPTH},// // {T_GEN_RIPPLEMAP, SHADER_HASRIPPLEMAP}, // //batch - {T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //13 - {T_GEN_DELUXMAP, 0}, //14 - //more lightmaps //15,16,17 - //mode deluxemaps //18,19,20 + {T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //15 + {T_GEN_DELUXMAP, 0}, //16 + //more lightmaps //17,18,19 + //mode deluxemaps //20,21,22 }; #ifdef HAVE_MEDIA_DECODER @@ -5976,16 +6013,18 @@ done:; {T_GEN_REFLECTMASK, 0}, //10 {T_GEN_DISPLACEMENT, SHADER_HASDISPLACEMENT},//11 {T_GEN_OCCLUSION, 0}, //12 + {T_GEN_TRANSMISSION, 0}, //13 + {T_GEN_THICKNESS, 0}, //14 // {T_GEN_REFLECTION, SHADER_HASREFLECT}, // // {T_GEN_REFRACTION, SHADER_HASREFRACT}, // // {T_GEN_REFRACTIONDEPTH, SHADER_HASREFRACTDEPTH},// // {T_GEN_RIPPLEMAP, SHADER_HASRIPPLEMAP}, // //batch - {T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //13 - {T_GEN_DELUXMAP, 0}, //14 - //more lightmaps //15,16,17 - //mode deluxemaps //18,19,20 + {T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //15 + {T_GEN_DELUXMAP, 0}, //16 + //more lightmaps //17,18,19 + //mode deluxemaps //20,21,22 }; #ifdef HAVE_MEDIA_DECODER @@ -8086,6 +8125,8 @@ static char *Shader_DecomposeSubPass(char *o, shader_t *s, shaderpass_t *p, qboo case T_GEN_REFLECTMASK: Shader_DecomposeSubPassMap(o, s, "map $reflectmask", s->defaulttextures[0].reflectmask); break; case T_GEN_DISPLACEMENT: Shader_DecomposeSubPassMap(o, s, "map $displacement", s->defaulttextures[0].displacement); break; case T_GEN_OCCLUSION: Shader_DecomposeSubPassMap(o, s, "map $occlusion", s->defaulttextures[0].occlusion); break; + case T_GEN_TRANSMISSION: Shader_DecomposeSubPassMap(o, s, "map $transmission", s->defaulttextures[0].transmission); break; + case T_GEN_THICKNESS: Shader_DecomposeSubPassMap(o, s, "map $thickness", s->defaulttextures[0].thickness); break; case T_GEN_CURRENTRENDER: sprintf(o, "map $currentrender "); break; case T_GEN_SOURCECOLOUR: sprintf(o, "map $sourcecolour"); break; case T_GEN_SOURCEDEPTH: sprintf(o, "map $sourcedepth"); break; diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 38eab475e..7a0b53103 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1491,14 +1491,24 @@ static const char *glsl_hdrs[] = #endif #endif "#if defined(ORM) || defined(SG)\n" - "uniform vec4 factors[3];\n" + "uniform vec4 factors[5];\n" "#define factor_base factors[0]\n" "#define factor_spec factors[1]\n" "#define factor_emit factors[2]\n" + "#define factor_transmission factors[3].r\n" + "#define factor_volume_distance factors[3].g\n" +// "#define factor_? factors[3].b\n" +// "#define factor_? factors[3].a\n" + "#define factor_volume_rgb factors[4].rgb\n" + "#define factor_volume_thickness factors[4].a\n" "#else\n" "#define factor_base vec4(1.0)\n" "#define factor_spec vec4(1.0)\n" "#define factor_emit vec4(1.0)\n" + /*"#define factor_transmission 0.0\n" + "#define factor_volume_distance 0.0\n" + "#define factor_volume_rgb vec3(1.0)\n" + "#define factor_volume_thickness 0.0\n"*/ "#endif\n" "#ifdef USEUBOS\n" "layout(std140) uniform u_lightinfo\n" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 66b16ca73..d32374012 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -274,6 +274,8 @@ typedef struct shaderpass_s { T_GEN_REFLECTMASK, //dpreflectcube mask T_GEN_DISPLACEMENT, //displacement texture (probably half-float or something so higher precision than normalmap.a) T_GEN_OCCLUSION, //occlusion mask (instead of baking it into the texture itself, required for correct pbr) + T_GEN_TRANSMISSION, //.r fancy opacity mask (still contributes its own colour over the top, for KHR_materials_transmission) + T_GEN_THICKNESS, //.g depth mask (could be replaced with raytracing, for KHR_materials_volume) T_GEN_CURRENTRENDER,//copy the current screen to a texture, and draw that @@ -698,7 +700,9 @@ struct shader_s #define MATERIAL_FACTOR_BASE 0 #define MATERIAL_FACTOR_SPEC 1 #define MATERIAL_FACTOR_EMIT 2 -#define MATERIAL_FACTOR_COUNT 3 +#define MATERIAL_FACTOR_TRANSMISSION 3 +#define MATERIAL_FACTOR_VOLUME 4 +#define MATERIAL_FACTOR_COUNT 5 vec4_t factors[MATERIAL_FACTOR_COUNT]; //arranged as a series of vec4s @@ -877,15 +881,17 @@ enum S_REFLECTMASK = 10, S_DISPLACEMENT = 11, S_OCCLUSION = 12, - S_LIGHTMAP0 = 13, - S_DELUXEMAP0 = 14, + S_TRANSMISSION = 13, + S_THICKNESS = 14, + S_LIGHTMAP0 = 15, + S_DELUXEMAP0 = 16, #if MAXRLIGHTMAPS > 1 - S_LIGHTMAP1 = 15, - S_LIGHTMAP2 = 16, - S_LIGHTMAP3 = 17, - S_DELUXEMAP1 = 18, - S_DELUXEMAP2 = 19, - S_DELUXEMAP3 = 20, + S_LIGHTMAP1 = 17, + S_LIGHTMAP2 = 18, + S_LIGHTMAP3 = 19, + S_DELUXEMAP1 = 20, + S_DELUXEMAP2 = 21, + S_DELUXEMAP3 = 22, #endif }; extern const struct sh_defaultsamplers_s diff --git a/engine/shaders/glsl/defaultskin.glsl b/engine/shaders/glsl/defaultskin.glsl index 18dfac34e..ee918a3af 100644 --- a/engine/shaders/glsl/defaultskin.glsl +++ b/engine/shaders/glsl/defaultskin.glsl @@ -14,6 +14,8 @@ !!samps !EIGHTBIT diffuse normalmap specular fullbright upper lower reflectmask reflectcube !!samps =EIGHTBIT paletted 1 !!samps =OCCLUDE occlusion +!!samps =USE_TRANSMISSION transmission //only .r valid, multiplier for factor_transmission +!!samps =USE_VOLUME thickness //only .g valid, multiplier for factor_volume_thickness, combined with factor_volume_rgb+factor_volume_distance(average distance travelled in metres) //!!permu VC // adds rgba vertex colour multipliers //!!permu SPECULAR // auto-added when gl_specular>0 //!!permu OFFSETMAPPING // auto-added when r_glsl_offsetmapping is set diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 5d1645899..54fd10818 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1588,10 +1588,14 @@ static texid_t SelectPassTexture(const shaderpass_t *pass) return r_blackcubeimage; //FIXME case T_GEN_REFLECTMASK: return shaderstate.curtexnums->reflectmask; - case T_GEN_OCCLUSION: - return shaderstate.curtexnums->occlusion; case T_GEN_DISPLACEMENT: return shaderstate.curtexnums->displacement; + case T_GEN_OCCLUSION: + return shaderstate.curtexnums->occlusion; + case T_GEN_TRANSMISSION: + return shaderstate.curtexnums->transmission; + case T_GEN_THICKNESS: + return shaderstate.curtexnums->thickness; case T_GEN_ANIMMAP: return pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]; @@ -3172,6 +3176,10 @@ static qboolean BE_SetupMeshProgram(program_t *p, shaderpass_t *pass, unsigned i BE_SetupTextureDescriptor(shaderstate.curtexnums->displacement, r_whiteimage, set, descs, desc++, img++); if (p->defaulttextures & (1u<occlusion, r_whiteimage, set, descs, desc++, img++); + if (p->defaulttextures & (1u<transmission, r_whiteimage, set, descs, desc++, img++); + if (p->defaulttextures & (1u<thickness, r_whiteimage, set, descs, desc++, img++); //batch if (p->defaulttextures & (1u<warnlimit --> 0) + Con_Printf(CON_WARNING"%s: KHR_materials_volume without KHR_materials_transmission\n", gltf->mod->name); + volume = NULL; + } + if (transmission && (unlit || pbrsg || blinn) && !pbrmr) + { + if (gltf->warnlimit --> 0) + Con_Printf(CON_WARNING"%s: KHR_materials_transmission without pbrMetallicRoughness\n", gltf->mod->name); + transmission = volume = NULL; + } + doubleSided = JSON_GetInteger(mat, "doubleSided", false); alphaCutoff = JSON_GetFloat(mat, "alphaCutoff", 0.5); t = JSON_GetString(mat, "alphaMode", tmp, sizeof(tmp), "OPAQUE"); @@ -1757,10 +1774,30 @@ static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *re else //else depend upon specularfactor ret->frame->texnums.specular = modfuncs->GetTexture("$whiteimage", NULL, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA, NULL, NULL, 0, 0, TF_INVALID); + if (transmission) + { + n = JSON_FindChild(transmission, "transmissionTexture.index"); //.r = factor + if (n) + ret->frame->texnums.transmission = GLTF_LoadTexture(gltf, n, IF_NOSRGB); + else + ret->frame->texnums.transmission = modfuncs->GetTexture("$whiteimage", NULL, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA, NULL, NULL, 0, 0, TF_INVALID); + + if (volume) + { + n = JSON_FindChild(volume, "thicknessTexture.index"); //.g = thicknessFactor + if (n) + ret->frame->texnums.transmission = GLTF_LoadTexture(gltf, n, IF_NOSRGB); + else + ret->frame->texnums.transmission = modfuncs->GetTexture("$whiteimage", NULL, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA, NULL, NULL, 0, 0, TF_INVALID); + } + } +#ifndef INFINITY //C99. +#define INFINITY (1.0/0.0) +#endif Q_snprintf(shader, sizeof(shader), "{\n" "%s"//cull - "program defaultskin" "#ORM" "#VC" "#IOR=%.02f" "%s"/*occlude*/ "%s"/*alphatest*/ "\n" + "program defaultskin" "#ORM" "#VC" "#IOR=%.02f" "%s"/*occlude*/ "%s"/*transmission*/ "%s"/*volume*/ "%s"/*alphatest*/ "\n" "{\n" "map $diffuse\n" "%s" //blend @@ -1769,11 +1806,16 @@ static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *re "fte_basefactor %f %f %f %f\n" "fte_specularfactor %f %f %f 1.0\n" "fte_fullbrightfactor %f %f %f 1.0\n" + "fte_transmissionfactor %f\n" + "fte_volumefactor %f %f %f %f %f\n" + "bemode rtlight rtlight_orm\n" "}\n", doubleSided?"cull disable\n":"", ior, (!occ)?"#NOOCCLUDE":(strcmp(occname,mrtname)?"#OCCLUDE":""), + (transmission?"#USE_TRANSMISSION":""), + (volume?"#USE_VOLUME":""), alphaCutoffmodifier, (alphaMode==1)?"":(alphaMode==2)?"blendfunc blend\n":"", vertexcolours?"rgbgen vertex\nalphagen vertex\n":"", @@ -1786,7 +1828,13 @@ static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *re JSON_GetFloat(pbrmr, "roughnessFactor", 1), JSON_GetFloat(mat, "emissiveFactor.0", 0), JSON_GetFloat(mat, "emissiveFactor.1", 0), - JSON_GetFloat(mat, "emissiveFactor.2", 0) + JSON_GetFloat(mat, "emissiveFactor.2", 0), + JSON_GetFloat(transmission, "transmissionFactor", 0), + JSON_GetFloat(volume, "attenuationColor.0", 1), + JSON_GetFloat(volume, "attenuationColor.1", 1), + JSON_GetFloat(volume, "attenuationColor.2", 1), + JSON_GetFloat(volume, "thicknessFactor", 0), + JSON_GetFloat(volume, "attenuationDistance", INFINITY) ); } if (!ret->frame->texnums.bump) @@ -2970,14 +3018,18 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize, {"KHR_materials_variants", true, false}, {"KHR_materials_ior", true, false}, + {"KHR_materials_transmission", true, true}, //FIXME: requires glsl tweaks. + {"KHR_materials_volume", true, true}, //FOXME: requires glsl tweaks. + #ifdef HAVE_DRACO {"KHR_draco_mesh_compression", true, false}, //probably fatal #else {"KHR_draco_mesh_compression", false, false}, //probably fatal #endif - {"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. + {"KHR_texture_transform", false, true}, //requires glsl tweaks, per texmap. can't use tcmod if its only on the bumpmap etc. + {"KHR_materials_sheen", false, true}, //requires glsl tweaks, extra brdf layer in the middle for velvet. + {"KHR_materials_clearcoat", false, true}, //requires glsl tweaks, extra brdf layer over the top for varnish etc. + {NULL} }, *extensions; gltf_t gltf;