- Backend update from GZDoom.

This commit is contained in:
Christoph Oelckers 2023-01-15 09:30:01 +01:00
parent 8001c4041f
commit fca0bdf379
16 changed files with 310 additions and 59 deletions

View file

@ -422,7 +422,7 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
{ {
for (int x = 0; x < numtex_x; x++) for (int x = 0; x < numtex_x; x++)
{ {
auto image = new FSheetTexture(sheetBitmaps.Size() - 1, x * width, y * width, width, height); auto image = new FSheetTexture(sheetBitmaps.Size() - 1, x * width, y * height, width, height);
FImageTexture *imgtex = new FImageTexture(image); FImageTexture *imgtex = new FImageTexture(image);
auto gtex = MakeGameTexture(imgtex, nullptr, ETextureType::FontChar); auto gtex = MakeGameTexture(imgtex, nullptr, ETextureType::FontChar);
gtex->SetWorldPanning(true); gtex->SetWorldPanning(true);

View file

@ -235,6 +235,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
float uClipHeight; float uClipHeight;
float uClipHeightDirection; float uClipHeightDirection;
int uShadowmapFilter; int uShadowmapFilter;
int uLightBlendMode;
}; };
uniform int uTextureMode; uniform int uTextureMode;
@ -328,6 +330,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
uniform sampler2D texture9; uniform sampler2D texture9;
uniform sampler2D texture10; uniform sampler2D texture10;
uniform sampler2D texture11; uniform sampler2D texture11;
uniform sampler2D texture12;
// timer data // timer data
uniform float timer; uniform float timer;

View file

@ -91,6 +91,7 @@ void HWViewpointBuffer::Set2D(FRenderState &di, int width, int height, int pll)
matrices.mPalLightLevels = pll; matrices.mPalLightLevels = pll;
matrices.mClipLine.X = -10000000.0f; matrices.mClipLine.X = -10000000.0f;
matrices.mShadowmapFilter = gl_shadowmap_filter; matrices.mShadowmapFilter = gl_shadowmap_filter;
matrices.mLightBlendMode = 0;
matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f); matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f);
matrices.CalcDependencies(); matrices.CalcDependencies();

View file

@ -4,6 +4,15 @@
struct HWDrawInfo; struct HWDrawInfo;
enum class ELightBlendMode : uint8_t
{
CLAMP = 0,
CLAMP_COLOR = 1,
NOCLAMP = 2,
DEFAULT = CLAMP,
};
struct HWViewpointUniforms struct HWViewpointUniforms
{ {
VSMatrix mProjectionMatrix; VSMatrix mProjectionMatrix;
@ -19,6 +28,8 @@ struct HWViewpointUniforms
float mClipHeightDirection = 0.f; float mClipHeightDirection = 0.f;
int mShadowmapFilter = 1; int mShadowmapFilter = 1;
int mLightBlendMode = 0;
void CalcDependencies() void CalcDependencies()
{ {
mNormalViewMatrix.computeNormalMatrix(mViewMatrix); mNormalViewMatrix.computeNormalMatrix(mViewMatrix);

View file

@ -570,7 +570,8 @@ void PPColormap::Render(PPRenderState *renderstate, int fixedcm, float flash)
void PPTonemap::UpdateTextures() void PPTonemap::UpdateTextures()
{ {
if (gl_tonemap == Palette && !PaletteTexture.Data) // level.info->tonemap cannot be ETonemapMode::Palette, so it's fine to only check gl_tonemap here
if (ETonemapMode((int)gl_tonemap) == ETonemapMode::Palette && !PaletteTexture.Data)
{ {
std::shared_ptr<void> data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; }); std::shared_ptr<void> data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; });
@ -598,7 +599,9 @@ void PPTonemap::UpdateTextures()
void PPTonemap::Render(PPRenderState *renderstate) void PPTonemap::Render(PPRenderState *renderstate)
{ {
if (gl_tonemap == 0) ETonemapMode current_tonemap = (level_tonemap != ETonemapMode::None) ? level_tonemap : ETonemapMode((int)gl_tonemap);
if (current_tonemap == ETonemapMode::None)
{ {
return; return;
} }
@ -606,14 +609,14 @@ void PPTonemap::Render(PPRenderState *renderstate)
UpdateTextures(); UpdateTextures();
PPShader *shader = nullptr; PPShader *shader = nullptr;
switch (gl_tonemap) switch (current_tonemap)
{ {
default: default:
case Linear: shader = &LinearShader; break; case ETonemapMode::Linear: shader = &LinearShader; break;
case Reinhard: shader = &ReinhardShader; break; case ETonemapMode::Reinhard: shader = &ReinhardShader; break;
case HejlDawson: shader = &HejlDawsonShader; break; case ETonemapMode::HejlDawson: shader = &HejlDawsonShader; break;
case Uncharted2: shader = &Uncharted2Shader; break; case ETonemapMode::Uncharted2: shader = &Uncharted2Shader; break;
case Palette: shader = &PaletteShader; break; case ETonemapMode::Palette: shader = &PaletteShader; break;
} }
renderstate->PushGroup("tonemap"); renderstate->PushGroup("tonemap");
@ -622,7 +625,7 @@ void PPTonemap::Render(PPRenderState *renderstate)
renderstate->Shader = shader; renderstate->Shader = shader;
renderstate->Viewport = screen->mScreenViewport; renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputCurrent(0); renderstate->SetInputCurrent(0);
if (gl_tonemap == Palette) if (current_tonemap == ETonemapMode::Palette)
renderstate->SetInputTexture(1, &PaletteTexture); renderstate->SetInputTexture(1, &PaletteTexture);
renderstate->SetOutputNext(); renderstate->SetOutputNext();
renderstate->SetNoBlend(); renderstate->SetNoBlend();

View file

@ -13,6 +13,19 @@ typedef IntRect PPViewport;
class PPTexture; class PPTexture;
class PPShader; class PPShader;
enum class ETonemapMode : uint8_t
{
None,
Uncharted2,
HejlDawson,
Reinhard,
Linear,
Palette,
NumTonemapModes
};
enum class PPFilterMode { Nearest, Linear }; enum class PPFilterMode { Nearest, Linear };
enum class PPWrapMode { Clamp, Repeat }; enum class PPWrapMode { Clamp, Repeat };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap }; enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap };
@ -541,6 +554,7 @@ private:
class PPTonemap class PPTonemap
{ {
public: public:
void SetTonemapMode(ETonemapMode tm) { level_tonemap = tm; }
void Render(PPRenderState *renderstate); void Render(PPRenderState *renderstate);
void ClearTonemapPalette() { PaletteTexture = {}; } void ClearTonemapPalette() { PaletteTexture = {}; }
@ -554,17 +568,7 @@ private:
PPShader HejlDawsonShader = { "shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} }; PPShader HejlDawsonShader = { "shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} };
PPShader Uncharted2Shader = { "shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} }; PPShader Uncharted2Shader = { "shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} };
PPShader PaletteShader = { "shaders/pp/tonemap.fp", "#define PALETTE\n", {} }; PPShader PaletteShader = { "shaders/pp/tonemap.fp", "#define PALETTE\n", {} };
ETonemapMode level_tonemap = ETonemapMode::None;
enum TonemapMode
{
None,
Uncharted2,
HejlDawson,
Reinhard,
Linear,
Palette,
NumTonemapModes
};
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -840,8 +844,11 @@ public:
PPCustomShaders customShaders; PPCustomShaders customShaders;
void SetTonemapMode(ETonemapMode tm) { tonemap.SetTonemapMode(tm); }
void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight); void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight);
void Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight); void Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight);
}; };
extern Postprocess hw_postprocess; extern Postprocess hw_postprocess;

View file

@ -175,6 +175,8 @@ static const char *shaderBindings = R"(
float uClipHeight; float uClipHeight;
float uClipHeightDirection; float uClipHeightDirection;
int uShadowmapFilter; int uShadowmapFilter;
int uLightBlendMode;
}; };
layout(set = 1, binding = 1, std140) uniform MatricesUBO { layout(set = 1, binding = 1, std140) uniform MatricesUBO {
@ -244,6 +246,7 @@ static const char *shaderBindings = R"(
layout(set = 2, binding = 8) uniform sampler2D texture9; layout(set = 2, binding = 8) uniform sampler2D texture9;
layout(set = 2, binding = 9) uniform sampler2D texture10; layout(set = 2, binding = 9) uniform sampler2D texture10;
layout(set = 2, binding = 10) uniform sampler2D texture11; layout(set = 2, binding = 10) uniform sampler2D texture11;
layout(set = 2, binding = 11) uniform sampler2D texture12;
// This must match the PushConstants struct // This must match the PushConstants struct
layout(push_constant) uniform PushConstants layout(push_constant) uniform PushConstants

View file

@ -438,10 +438,12 @@ template<typename I> void MapIteratorSetValue(I * self, expand_types_vm<typename
PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \ PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \
ACTION_RETURN_INT( MapIteratorGetKey(self) ); \ ACTION_RETURN_INT( MapIteratorGetKey(self) ); \
} \ } \
DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_I32_Str , GetValue , MapIteratorGetValue< FMapIterator_I32_Str > ) \ DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_I32_Str , GetValue , MapIteratorGetValueString< FMapIterator_I32_Str > ) \
{ \ { \
PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \ PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \
ACTION_RETURN_STRING( MapIteratorGetValue(self) ); \ FString out; \
MapIteratorGetValueString(self , out); \
ACTION_RETURN_STRING( out ); \
} }
#define DEF_MAP_IT_S_S() \ #define DEF_MAP_IT_S_S() \

View file

@ -133,13 +133,16 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
if (index >= FIRST_USER_SHADER) if (index >= FIRST_USER_SHADER)
{ {
const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER]; const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER];
if (tx->Layers && usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{
if (tx->Layers)
{ {
for (auto& texture : tx->Layers->CustomShaderTextures) for (auto& texture : tx->Layers->CustomShaderTextures)
{ {
if (texture == nullptr) continue; if (texture == nullptr) continue;
mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable.
} }
}
mShaderIndex = index; mShaderIndex = index;
} }
} }

View file

@ -418,13 +418,16 @@ void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, con
// color, so find a duplicate pair of palette entries, make one of them a // color, so find a duplicate pair of palette entries, make one of them a
// duplicate of color 0, and remap every graphic so that it uses that entry // duplicate of color 0, and remap every graphic so that it uses that entry
// instead of entry 0. // instead of entry 0.
void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap) void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* lastcolormap)
{ {
for (int i = 0; i < 256; i++) Remap[i] = i; for (int i = 0; i < 256; i++) Remap[i] = i;
PalEntry color0 = BaseColors[0]; PalEntry color0 = BaseColors[0];
int i; int i;
// First try for an exact match of color 0. Only Hexen does not have one. // First try for an exact match of color 0. Only Hexen does not have one.
if (!lastcolormap)
{
for (i = 1; i < 256; ++i) for (i = 1; i < 256; ++i)
{ {
if (BaseColors[i] == color0) if (BaseColors[i] == color0)
@ -433,6 +436,18 @@ void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap)
break; break;
} }
} }
}
else
{
for (i = 1; i < 256; ++i)
{
if ((BaseColors[i] == color0) && (lastcolormap[i] == lastcolormap[0]))
{
Remap[0] = i;
break;
}
}
}
// If there is no duplicate of color 0, find the first set of duplicate // If there is no duplicate of color 0, find the first set of duplicate
// colors and make one of them a duplicate of color 0. In Hexen's PLAYPAL // colors and make one of them a duplicate of color 0. In Hexen's PLAYPAL
@ -448,6 +463,8 @@ void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap)
sortcopy[i] = (BaseColors[i] & 0xffffff) | (i << 24); sortcopy[i] = (BaseColors[i] & 0xffffff) | (i << 24);
} }
qsort(sortcopy, 256, 4, sortforremap); qsort(sortcopy, 256, 4, sortforremap);
if (!lastcolormap)
{
for (i = 255; i > 0; --i) for (i = 255; i > 0; --i)
{ {
if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF))
@ -466,6 +483,27 @@ void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap)
} }
} }
} }
else
{
for (i = 255; i > 0; --i)
{
if (((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) && (lastcolormap[sortcopy[i].a] == lastcolormap[sortcopy[i - 1].a]))
{
int new0 = sortcopy[i].a;
int dup = sortcopy[i - 1].a;
if (new0 > dup)
{
// Make the lower-numbered entry a copy of color 0. (Just because.)
std::swap(new0, dup);
}
Remap[0] = new0;
Remap[new0] = dup;
BaseColors[new0] = color0;
break;
}
}
}
}
// If there were no duplicates, InitPalette() will remap color 0 to the // If there were no duplicates, InitPalette() will remap color 0 to the
// closest matching color. Hopefully nobody will use a palette where all // closest matching color. Hopefully nobody will use a palette where all

View file

@ -14,7 +14,7 @@ void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int
// Given an array of colors, fills in remap with values to remap the // Given an array of colors, fills in remap with values to remap the
// passed array of colors to BaseColors. Used for loading palette downconversions of PNGs. // passed array of colors to BaseColors. Used for loading palette downconversions of PNGs.
void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, const uint8_t* useful, int numcolors); void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, const uint8_t* useful, int numcolors);
void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap); void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* cmapdata = nullptr);
// Colorspace conversion RGB <-> HSV // Colorspace conversion RGB <-> HSV
void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v); void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v);

View file

@ -250,6 +250,7 @@ void HWDrawInfo::SetupView(FRenderState &state, float vx, float vy, float vz, bo
SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror); SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror);
SetCameraPos(vp.Pos); SetCameraPos(vp.Pos);
VPUniforms.CalcDependencies(); VPUniforms.CalcDependencies();
VPUniforms.mLightBlendMode = 0;
vpIndex = screen->mViewpoints->SetViewpoint(state, &VPUniforms); vpIndex = screen->mViewpoints->SetViewpoint(state, &VPUniforms);
} }

View file

@ -325,7 +325,7 @@ float R_DoomLightingEquation(float light)
// This is a lot more primitive than Doom's lighting... // This is a lot more primitive than Doom's lighting...
float numShades = float(uPalLightLevels & 255); float numShades = float(uPalLightLevels & 255);
float curshade = (1.0 - light) * (numShades - 1.0); float curshade = (1.0 - light) * (numShades - 1.0);
float visibility = max(uGlobVis * uLightFactor * abs(z), 0.0); float visibility = max(uGlobVis * uLightFactor * z, 0.0);
float shade = clamp((curshade + visibility), 0.0, numShades - 1.0); float shade = clamp((curshade + visibility), 0.0, numShades - 1.0);
return clamp(shade * uLightDist, 0.0, 1.0); return clamp(shade * uLightDist, 0.0, 1.0);
} }
@ -344,10 +344,86 @@ float R_DoomLightingEquation(float light)
//=========================================================================== //===========================================================================
// //
// Check if light is in shadow according to its 1D shadow map // Check if light is in shadow
// //
//=========================================================================== //===========================================================================
#ifdef SUPPORTS_RAYTRACING
bool traceHit(vec3 origin, vec3 direction, float dist)
{
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, TopLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, 0.01f, direction, dist);
while(rayQueryProceedEXT(rayQuery)) { }
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
}
vec2 softshadow[9 * 3] = vec2[](
vec2( 0.0, 0.0),
vec2(-2.0,-2.0),
vec2( 2.0, 2.0),
vec2( 2.0,-2.0),
vec2(-2.0, 2.0),
vec2(-1.0,-1.0),
vec2( 1.0, 1.0),
vec2( 1.0,-1.0),
vec2(-1.0, 1.0),
vec2( 0.0, 0.0),
vec2(-1.5,-1.5),
vec2( 1.5, 1.5),
vec2( 1.5,-1.5),
vec2(-1.5, 1.5),
vec2(-0.5,-0.5),
vec2( 0.5, 0.5),
vec2( 0.5,-0.5),
vec2(-0.5, 0.5),
vec2( 0.0, 0.0),
vec2(-1.25,-1.75),
vec2( 1.75, 1.25),
vec2( 1.25,-1.75),
vec2(-1.75, 1.75),
vec2(-0.75,-0.25),
vec2( 0.25, 0.75),
vec2( 0.75,-0.25),
vec2(-0.25, 0.75)
);
float shadowAttenuation(vec4 lightpos, float lightcolorA)
{
float shadowIndex = abs(lightcolorA) - 1.0;
if (shadowIndex >= 1024.0)
return 1.0; // Don't cast rays for this light
vec3 origin = pixelpos.xzy;
vec3 target = lightpos.xzy + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes
vec3 direction = normalize(target - origin);
float dist = distance(origin, target);
if (uShadowmapFilter <= 0)
{
return traceHit(origin, direction, dist) ? 0.0 : 1.0;
}
else
{
vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
vec3 xdir = normalize(cross(direction, v));
vec3 ydir = cross(direction, xdir);
float sum = 0.0;
int step_count = uShadowmapFilter * 9;
for (int i = 0; i <= step_count; i++)
{
vec3 pos = target + xdir * softshadow[i].x + ydir * softshadow[i].y;
sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0;
}
return sum / step_count;
}
}
#else
#ifdef SUPPORTS_SHADOWMAPS #ifdef SUPPORTS_SHADOWMAPS
float shadowDirToU(vec2 dir) float shadowDirToU(vec2 dir)
@ -491,6 +567,7 @@ float shadowAttenuation(vec4 lightpos, float lightcolorA)
return 1.0; return 1.0;
} }
#endif
#endif #endif
float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle)

View file

@ -5,11 +5,15 @@ layout(location = 2) in vec4 aColor;
layout(location = 0) out vec4 vTexCoord; layout(location = 0) out vec4 vTexCoord;
layout(location = 1) out vec4 vColor; layout(location = 1) out vec4 vColor;
layout(location = 9) out vec3 vLightmap;
#ifndef SIMPLE // we do not need these for simple shaders #ifndef SIMPLE // we do not need these for simple shaders
layout(location = 3) in vec4 aVertex2; layout(location = 3) in vec4 aVertex2;
layout(location = 4) in vec4 aNormal; layout(location = 4) in vec4 aNormal;
layout(location = 5) in vec4 aNormal2; layout(location = 5) in vec4 aNormal2;
layout(location = 6) in vec3 aLightmap;
layout(location = 7) in vec4 aBoneWeight;
layout(location = 8) in uvec4 aBoneSelector;
layout(location = 2) out vec4 pixelpos; layout(location = 2) out vec4 pixelpos;
layout(location = 3) out vec3 glowdist; layout(location = 3) out vec3 glowdist;
@ -23,6 +27,14 @@ layout(location = 7) out vec4 ClipDistanceA;
layout(location = 8) out vec4 ClipDistanceB; layout(location = 8) out vec4 ClipDistanceB;
#endif #endif
struct BonesResult
{
vec3 Normal;
vec4 Position;
};
BonesResult ApplyBones();
void main() void main()
{ {
float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4;
@ -30,8 +42,10 @@ void main()
vec2 parmTexCoord; vec2 parmTexCoord;
vec4 parmPosition; vec4 parmPosition;
BonesResult bones = ApplyBones();
parmTexCoord = aTexCoord; parmTexCoord = aTexCoord;
parmPosition = aPosition; parmPosition = bones.Position;
#ifndef SIMPLE #ifndef SIMPLE
vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor);
@ -51,6 +65,8 @@ void main()
#endif #endif
#ifndef SIMPLE #ifndef SIMPLE
vLightmap = aLightmap;
pixelpos.xyz = worldcoord.xyz; pixelpos.xyz = worldcoord.xyz;
pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w;
@ -78,14 +94,7 @@ void main()
ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
} }
#ifdef HAS_UNIFORM_VERTEX_DATA vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0);
if ((useVertexData & 2) == 0)
vWorldNormal = NormalModelMatrix * vec4(normalize(uVertexNormal.xyz), 1.0);
else
vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0);
#else
vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0);
#endif
vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0); vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0);
#endif #endif
@ -142,3 +151,66 @@ void main()
gl_PointSize = 1.0; gl_PointSize = 1.0;
} }
#if !defined(SIMPLE)
vec3 GetAttrNormal()
{
#ifdef HAS_UNIFORM_VERTEX_DATA
if ((useVertexData & 2) == 0)
return uVertexNormal.xyz;
else
return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor);
#else
return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor);
#endif
}
void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal)
{
if (weight != 0.0)
{
mat4 transform = bones[uBoneIndexBase + int(boneIndex)];
mat3 rotation = mat3(transform);
position += (transform * aPosition) * weight;
normal += (rotation * aNormal.xyz) * weight;
}
}
BonesResult ApplyBones()
{
BonesResult result;
if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0))
{
result.Position = vec4(0.0);
result.Normal = vec3(0.0);
// We use low precision input for our bone weights. Rescale so the sum still is 1.0
float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w;
float weightMultiplier = 1.0 / totalWeight;
vec4 boneWeight = aBoneWeight * weightMultiplier;
AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal);
AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal);
AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal);
AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal);
result.Position.w = 1.0; // For numerical stability
}
else
{
result.Position = aPosition;
result.Normal = GetAttrNormal();
}
return result;
}
#else
BonesResult ApplyBones()
{
BonesResult result;
result.Position = aPosition;
return result;
}
#endif

View file

@ -59,7 +59,21 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
} }
} }
vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); vec3 frag;
if ( uLightBlendMode == 1 )
{ // COLOR_CORRECT_CLAMPING
vec3 lightcolor = color + desaturate(dynlight).rgb;
frag = material.Base.rgb * ((lightcolor / max(max(max(lightcolor.r, lightcolor.g), lightcolor.b), 1.4) * 1.4));
}
else if ( uLightBlendMode == 2 )
{ // UNCLAMPED
frag = material.Base.rgb * (color + desaturate(dynlight).rgb);
}
else
{
frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
}
if (uLightIndex >= 0) if (uLightIndex >= 0)
{ {

View file

@ -67,8 +67,24 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
} }
} }
if ( uLightBlendMode == 1 )
{ // COLOR_CORRECT_CLAMPING
dynlight.rgb = color + desaturate(dynlight).rgb;
specular.rgb = desaturate(specular).rgb;
dynlight.rgb = ((dynlight.rgb / max(max(max(dynlight.r, dynlight.g), dynlight.b), 1.4) * 1.4));
specular.rgb = ((specular.rgb / max(max(max(specular.r, specular.g), specular.b), 1.4) * 1.4));
}
else if ( uLightBlendMode == 2 )
{ // UNCLAMPED
dynlight.rgb = color + desaturate(dynlight).rgb;
specular.rgb = desaturate(specular).rgb;
}
else
{
dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4); specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4);
}
vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb; vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb;