- use normals to have proper light attenuation. So far only implemented for walls and flats. Models are planned but need some thinking about how to efficiently collect all required lights for an object.

This commit is contained in:
Christoph Oelckers 2016-10-03 16:09:32 +02:00
parent 2da18bfa56
commit 4eb5f10b02
19 changed files with 122 additions and 24 deletions

View file

@ -442,7 +442,7 @@ VSMatrix::computeNormalMatrix(const FLOATTYPE *aMatrix)
mMat3x3[1] * (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) +
mMat3x3[2] * (mMat3x3[3] * mMat3x3[7] - mMat3x3[4] * mMat3x3[6]);
invDet = 1.0f/det;
invDet = 1.0/det;
mMatrix[0] = (mMat3x3[4] * mMat3x3[8] - mMat3x3[5] * mMat3x3[7]) * invDet;
mMatrix[1] = (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) * invDet;

View file

@ -71,6 +71,7 @@ void FSimpleVertexBuffer::BindVBO()
glEnableVertexAttribArray(VATTR_TEXCOORD);
glEnableVertexAttribArray(VATTR_COLOR);
glDisableVertexAttribArray(VATTR_VERTEX2);
glDisableVertexAttribArray(VATTR_NORMAL);
}
else
{
@ -236,6 +237,7 @@ void FFlatVertexBuffer::BindVBO()
glEnableVertexAttribArray(VATTR_TEXCOORD);
glDisableVertexAttribArray(VATTR_COLOR);
glDisableVertexAttribArray(VATTR_VERTEX2);
glDisableVertexAttribArray(VATTR_NORMAL);
}
else
{

View file

@ -271,6 +271,7 @@ struct FModelVertex
{
float x, y, z; // world position
float u, v; // texture coordinates
unsigned packedNormal; // normal vector as GL_INT_2_10_10_10_REV.
void Set(float xx, float yy, float zz, float uu, float vv)
{
@ -283,7 +284,13 @@ struct FModelVertex
void SetNormal(float nx, float ny, float nz)
{
// GZDoom currently doesn't use normals. This function is so that the high level code can pretend it does.
/*
int inx = int(nx * 512);
int iny = int(ny * 512);
int inz = int(nz * 512);
packedNormal = 0x40000000 | ((inx & 1023) << 20) | ((iny & 1023) << 10) | (inz & 1023);
*/
packedNormal = 0; // Per-pixel lighting for models isn't implemented yet so leave this at 0 for now.
}
};

View file

@ -119,6 +119,7 @@ void FModelVertexBuffer::BindVBO()
glEnableVertexAttribArray(VATTR_VERTEX);
glEnableVertexAttribArray(VATTR_TEXCOORD);
glEnableVertexAttribArray(VATTR_VERTEX2);
glEnableVertexAttribArray(VATTR_NORMAL);
glDisableVertexAttribArray(VATTR_COLOR);
}
else
@ -245,6 +246,7 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x);
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u);
glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x);
glVertexAttribPointer(VATTR_NORMAL, 4, GL_UNSIGNED_INT_2_10_10_10_REV, false, sizeof(FModelVertex), &VMO[frame2].packedNormal);
}
else
{

View file

@ -248,6 +248,7 @@ void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3
FModelVertex vert;
unsigned int indx[4];
vert.packedNormal = 0; // currently this is not being used for voxels.
vert.u = (((col & 15) * 255 / 16) + 7) / 255.f;
vert.v = (((col / 16) * 255 / 16) + 7) / 255.f;
@ -271,6 +272,7 @@ void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3
vert.y = -z3 + PivotZ;
indx[3] = AddVertex(vert, check);
mIndices.Push(indx[0]);
mIndices.Push(indx[1]);
mIndices.Push(indx[3]);

View file

@ -141,6 +141,7 @@ bool FRenderState::ApplyShader()
}
glVertexAttrib4fv(VATTR_COLOR, mColor.vec);
glVertexAttrib4fv(VATTR_NORMAL, mNormal.vec);
activeShader->muDesaturation.Set(mDesaturation / 255.f);
activeShader->muFogEnabled.Set(fogset);
@ -269,12 +270,16 @@ bool FRenderState::ApplyShader()
if (mModelMatrixEnabled)
{
mModelMatrix.matrixToGL(activeShader->modelmatrix_index);
VSMatrix norm;
norm.computeNormalMatrix(mModelMatrix);
mNormalModelMatrix.matrixToGL(activeShader->normalmodelmatrix_index);
activeShader->currentModelMatrixState = true;
}
else if (activeShader->currentModelMatrixState)
{
activeShader->currentModelMatrixState = false;
identityMatrix.matrixToGL(activeShader->modelmatrix_index);
identityMatrix.matrixToGL(activeShader->normalmodelmatrix_index);
}
return true;
}

View file

@ -90,6 +90,7 @@ class FRenderState
float mShaderTimer;
FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer;
FStateVec4 mNormal;
FStateVec4 mColor;
FStateVec4 mCameraPos;
FStateVec4 mGlowTop, mGlowBottom;
@ -119,6 +120,8 @@ public:
VSMatrix mViewMatrix;
VSMatrix mModelMatrix;
VSMatrix mTextureMatrix;
VSMatrix mNormalViewMatrix;
VSMatrix mNormalModelMatrix;
FRenderState()
{
@ -180,6 +183,16 @@ public:
void SetClipHeight(float height, float direction);
void SetNormal(FVector3 norm)
{
mNormal.Set(norm.X, norm.Y, norm.Z, 0.f);
}
void SetNormal(float x, float y, float z)
{
mNormal.Set(x, y, z, 0.f);
}
void SetColor(float r, float g, float b, float a = 1.f, int desat = 0)
{
mColor.Set(r, g, b, a);

View file

@ -374,6 +374,7 @@ void GLFlat::Draw(int pass, bool trans) // trans only has meaning for GLPASS_LIG
}
#endif
gl_RenderState.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y);
switch (pass)
{
@ -502,6 +503,11 @@ inline void GLFlat::PutFlat(bool fog)
void GLFlat::Process(sector_t * model, int whichplane, bool fog)
{
plane.GetFromSector(model, whichplane);
if (whichplane != int(ceiling))
{
// Flip the normal if the source plane has a different orientation than what we are about to render.
plane.plane.FlipVert();
}
if (!fog)
{
@ -641,7 +647,7 @@ void GLFlat::ProcessSector(sector_t * frontsector)
Colormap.CopyFrom3DLight(light);
}
renderstyle = STYLE_Translucent;
Process(frontsector, false, false);
Process(frontsector, sector_t::floor, false);
}
}
@ -700,7 +706,7 @@ void GLFlat::ProcessSector(sector_t * frontsector)
Colormap.CopyFrom3DLight(light);
}
renderstyle = STYLE_Translucent;
Process(frontsector, true, false);
Process(frontsector, sector_t::ceiling, false);
}
}

View file

@ -1217,7 +1217,7 @@ void GLEEHorizonPortal::DrawContents()
if (sector->GetTexture(sector_t::ceiling) != skyflatnum)
{
GLHorizonInfo horz;
horz.plane.GetFromSector(sector, true);
horz.plane.GetFromSector(sector, sector_t::ceiling);
horz.lightlevel = gl_ClampLight(sector->GetCeilingLight());
horz.colormap = sector->ColorMap;
if (portal->mType == PORTS_PLANE)
@ -1230,7 +1230,7 @@ void GLEEHorizonPortal::DrawContents()
if (sector->GetTexture(sector_t::floor) != skyflatnum)
{
GLHorizonInfo horz;
horz.plane.GetFromSector(sector, false);
horz.plane.GetFromSector(sector, sector_t::floor);
horz.lightlevel = gl_ClampLight(sector->GetFloorLight());
horz.colormap = sector->ColorMap;
if (portal->mType == PORTS_PLANE)

View file

@ -114,6 +114,7 @@ void FSkyVertexBuffer::BindVBO()
glEnableVertexAttribArray(VATTR_TEXCOORD);
glEnableVertexAttribArray(VATTR_COLOR);
glDisableVertexAttribArray(VATTR_VERTEX2);
glDisableVertexAttribArray(VATTR_NORMAL);
}
else
{

View file

@ -406,6 +406,7 @@ void GLSprite::Draw(int pass)
gl_RenderState.Apply();
FVector3 v[4];
gl_RenderState.SetNormal(0, 0, 0);
CalculateVertices(v);
FQuadDrawer qd;

View file

@ -60,6 +60,15 @@ struct GLSeg
float x1,x2;
float y1,y2;
float fracleft, fracright; // fractional offset of the 2 vertices on the linedef
FVector3 Normal() const
{
// we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim
float x = y2 - y1;
float y = x1 - x2;
float length = sqrt(x*x + y*y);
return FVector3(x / length, 0, y / length);
}
};
struct texcoord

View file

@ -470,7 +470,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2)
}
else
{
hi.plane.GetFromSector(fs, true);
hi.plane.GetFromSector(fs, sector_t::ceiling);
hi.lightlevel = gl_ClampLight(fs->GetCeilingLight());
hi.colormap = fs->ColorMap;
@ -498,7 +498,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2)
}
else
{
hi.plane.GetFromSector(fs, false);
hi.plane.GetFromSector(fs, sector_t::floor);
hi.lightlevel = gl_ClampLight(fs->GetFloorLight());
hi.colormap = fs->ColorMap;

View file

@ -254,14 +254,13 @@ void GLWall::RenderMirrorSurface()
if (GLRenderer->mirrortexture == NULL) return;
// For the sphere map effect we need a normal of the mirror surface,
Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1);
v.Normalize();
FVector3 v = glseg.Normal();
if (!gl.legacyMode)
{
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
tcs[LOLFT].u = tcs[LORGT].u = tcs[UPLFT].u = tcs[UPRGT].u = v.X();
tcs[LOLFT].v = tcs[LORGT].v = tcs[UPLFT].v = tcs[UPRGT].v = v.Z();
tcs[LOLFT].u = tcs[LORGT].u = tcs[UPLFT].u = tcs[UPRGT].u = v.X;
tcs[LOLFT].v = tcs[LORGT].v = tcs[UPLFT].v = tcs[UPRGT].v = v.Z;
gl_RenderState.EnableTextureMatrix(true);
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
@ -414,6 +413,7 @@ void GLWall::RenderTranslucentWall()
//==========================================================================
void GLWall::Draw(int pass)
{
gl_RenderState.SetNormal(glseg.Normal());
switch (pass)
{
case GLPASS_LIGHTSONLY:

View file

@ -179,6 +179,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
glBindAttribLocation(hShader, VATTR_TEXCOORD, "aTexCoord");
glBindAttribLocation(hShader, VATTR_COLOR, "aColor");
glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2");
glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal");
glLinkProgram(hShader);
@ -241,6 +242,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix");
vertexmatrix_index = glGetUniformLocation(hShader, "uQuadVertices");
texcoordmatrix_index = glGetUniformLocation(hShader, "uQuadTexCoords");
normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix");
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
quadmode_index = glGetUniformLocation(hShader, "uQuadMode");
if (!gl.legacyMode && !(gl.flags & RFL_SHADER_STORAGE_BUFFER))
@ -328,14 +331,14 @@ FShader *FShaderManager::Compile (const char *ShaderName, const char *ShaderPath
//
//==========================================================================
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm)
{
Bind();
glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get());
glUniformMatrix4fv(viewmatrix_index, 1, false, view->get());
glUniformMatrix4fv(normalviewmatrix_index, 1, false, norm->get());
}
//==========================================================================
//
//
@ -556,23 +559,26 @@ void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
}
else
{
VSMatrix norm;
norm.computeNormalMatrix(*view);
for (int i = 0; i < 4; i++)
{
mTextureEffects[i]->ApplyMatrices(proj, view);
mTextureEffectsNAT[i]->ApplyMatrices(proj, view);
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm);
}
mTextureEffects[4]->ApplyMatrices(proj, view);
mTextureEffects[4]->ApplyMatrices(proj, view, &norm);
if (gl_fuzztype != 0)
{
mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view);
mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
}
for (unsigned i = 12; i < mTextureEffects.Size(); i++)
{
mTextureEffects[i]->ApplyMatrices(proj, view);
mTextureEffects[i]->ApplyMatrices(proj, view, &norm);
}
for (int i = 0; i < MAX_EFFECTS; i++)
{
mEffectShaders[i]->ApplyMatrices(proj, view);
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
}
if (mActiveShader != NULL) mActiveShader->Bind();
}

View file

@ -285,7 +285,9 @@ class FShader
int lights_index;
int projectionmatrix_index;
int viewmatrix_index;
int normalviewmatrix_index;
int modelmatrix_index;
int normalmodelmatrix_index;
int texturematrix_index;
public:
int vertexmatrix_index;
@ -318,7 +320,7 @@ public:
bool Bind();
unsigned int GetHandle() const { return hShader; }
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm);
};

View file

@ -1,6 +1,8 @@
in vec4 pixelpos;
in vec2 glowdist;
in vec4 vWorldNormal;
in vec4 vEyeNormal;
in vec4 vTexCoord;
in vec4 vColor;
@ -121,6 +123,37 @@ float R_DoomLightingEquation(float light)
return lightscale;
}
//===========================================================================
//
// Standard lambertian diffuse light calculation
//
//===========================================================================
float diffuseContribution(vec3 lightDirection, vec3 normal)
{
return max(dot(normal, lightDirection), 0.0f);
}
//===========================================================================
//
// Calculates the brightness of a dynamic point light
// Todo: Find a better way to define which lighting model to use.
// (Specular mode has been removed for now.)
//
//===========================================================================
float pointLightAttenuation(vec4 lightpos)
{
float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w;
#if 0
return attenuation;
#else
vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz);
float diffuseAmount = diffuseContribution(lightDirection, normalize(vWorldNormal.xyz));
return attenuation * diffuseAmount;
#endif
}
//===========================================================================
//
// Calculate light
@ -196,7 +229,7 @@ vec4 getLightColor(float fogdist, float fogfactor)
vec4 lightpos = lights[i];
vec4 lightcolor = lights[i+1];
lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w;
lightcolor.rgb *= pointLightAttenuation(lightpos);
dynlight.rgb += lightcolor.rgb;
}
//
@ -207,7 +240,7 @@ vec4 getLightColor(float fogdist, float fogfactor)
vec4 lightpos = lights[i];
vec4 lightcolor = lights[i+1];
lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w;
lightcolor.rgb *= pointLightAttenuation(lightpos);
dynlight.rgb -= lightcolor.rgb;
}
}
@ -289,7 +322,7 @@ void main()
vec4 lightpos = lights[i];
vec4 lightcolor = lights[i+1];
lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w;
lightcolor.rgb *= pointLightAttenuation(lightpos);
addlight.rgb += lightcolor.rgb;
}
frag.rgb = clamp(frag.rgb + desaturate(addlight).rgb, 0.0, 1.0);

View file

@ -4,8 +4,12 @@ in vec2 aTexCoord;
in vec4 aColor;
#ifndef SIMPLE // we do not need these for simple shaders
in vec4 aVertex2;
in vec4 aNormal;
out vec4 pixelpos;
out vec2 glowdist;
out vec4 vWorldNormal;
out vec4 vEyeNormal;
#endif
out vec4 vTexCoord;
@ -54,6 +58,9 @@ void main()
gl_ClipDistance[3] = -((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y;
gl_ClipDistance[4] = worldcoord.y + ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
}
vWorldNormal = NormalModelMatrix * aNormal;
vEyeNormal = NormalViewMatrix * vWorldNormal;
#endif
#ifdef SPHEREMAP

View file

@ -56,5 +56,7 @@ uniform int uQuadMode;
uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ModelMatrix;
uniform mat4 NormalViewMatrix;
uniform mat4 NormalModelMatrix;
uniform mat4 TextureMatrix;