mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
Stabilize player shadows and improve foot contact
This commit is contained in:
parent
54eac50c4d
commit
ee9efa3478
3 changed files with 110 additions and 30 deletions
|
|
@ -57,7 +57,7 @@ public:
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
void render(const Camera& camera, const glm::mat4& view, const glm::mat4& projection);
|
void render(const Camera& camera, const glm::mat4& view, const glm::mat4& projection);
|
||||||
void renderShadow(GLuint shadowShaderProgram);
|
void renderShadow(const glm::mat4& lightSpaceMatrix);
|
||||||
|
|
||||||
void setInstancePosition(uint32_t instanceId, const glm::vec3& position);
|
void setInstancePosition(uint32_t instanceId, const glm::vec3& position);
|
||||||
void setInstanceRotation(uint32_t instanceId, const glm::vec3& rotation);
|
void setInstanceRotation(uint32_t instanceId, const glm::vec3& rotation);
|
||||||
|
|
@ -176,6 +176,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Shader> characterShader;
|
std::unique_ptr<Shader> characterShader;
|
||||||
|
GLuint shadowCasterProgram = 0;
|
||||||
pipeline::AssetManager* assetManager = nullptr;
|
pipeline::AssetManager* assetManager = nullptr;
|
||||||
|
|
||||||
// Fog parameters
|
// Fog parameters
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,82 @@ bool CharacterRenderer::initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* shadowVertSrc = R"(
|
||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec4 aBoneWeights;
|
||||||
|
layout (location = 2) in ivec4 aBoneIndices;
|
||||||
|
layout (location = 4) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
uniform mat4 uLightSpaceMatrix;
|
||||||
|
uniform mat4 uModel;
|
||||||
|
uniform mat4 uBones[200];
|
||||||
|
|
||||||
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
mat4 boneTransform = mat4(0.0);
|
||||||
|
boneTransform += uBones[aBoneIndices.x] * aBoneWeights.x;
|
||||||
|
boneTransform += uBones[aBoneIndices.y] * aBoneWeights.y;
|
||||||
|
boneTransform += uBones[aBoneIndices.z] * aBoneWeights.z;
|
||||||
|
boneTransform += uBones[aBoneIndices.w] * aBoneWeights.w;
|
||||||
|
vec4 skinnedPos = boneTransform * vec4(aPos, 1.0);
|
||||||
|
vTexCoord = aTexCoord;
|
||||||
|
gl_Position = uLightSpaceMatrix * uModel * skinnedPos;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char* shadowFragSrc = R"(
|
||||||
|
#version 330 core
|
||||||
|
in vec2 vTexCoord;
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
uniform bool uAlphaTest;
|
||||||
|
void main() {
|
||||||
|
if (uAlphaTest && texture(uTexture, vTexCoord).a < 0.5) discard;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto compileStage = [](GLenum type, const char* src) -> GLuint {
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
glShaderSource(shader, 1, &src, nullptr);
|
||||||
|
glCompileShader(shader);
|
||||||
|
GLint ok = 0;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
char log[512];
|
||||||
|
glGetShaderInfoLog(shader, sizeof(log), nullptr, log);
|
||||||
|
LOG_ERROR("Character shadow shader compile error: ", log);
|
||||||
|
glDeleteShader(shader);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint shVs = compileStage(GL_VERTEX_SHADER, shadowVertSrc);
|
||||||
|
GLuint shFs = compileStage(GL_FRAGMENT_SHADER, shadowFragSrc);
|
||||||
|
if (!shVs || !shFs) {
|
||||||
|
if (shVs) glDeleteShader(shVs);
|
||||||
|
if (shFs) glDeleteShader(shFs);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowCasterProgram = glCreateProgram();
|
||||||
|
glAttachShader(shadowCasterProgram, shVs);
|
||||||
|
glAttachShader(shadowCasterProgram, shFs);
|
||||||
|
glLinkProgram(shadowCasterProgram);
|
||||||
|
GLint linked = 0;
|
||||||
|
glGetProgramiv(shadowCasterProgram, GL_LINK_STATUS, &linked);
|
||||||
|
glDeleteShader(shVs);
|
||||||
|
glDeleteShader(shFs);
|
||||||
|
if (!linked) {
|
||||||
|
char log[512];
|
||||||
|
glGetProgramInfoLog(shadowCasterProgram, sizeof(log), nullptr, log);
|
||||||
|
LOG_ERROR("Character shadow shader link error: ", log);
|
||||||
|
glDeleteProgram(shadowCasterProgram);
|
||||||
|
shadowCasterProgram = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Create 1x1 white fallback texture
|
// Create 1x1 white fallback texture
|
||||||
uint8_t white[] = { 255, 255, 255, 255 };
|
uint8_t white[] = { 255, 255, 255, 255 };
|
||||||
glGenTextures(1, &whiteTexture);
|
glGenTextures(1, &whiteTexture);
|
||||||
|
|
@ -215,6 +291,10 @@ void CharacterRenderer::shutdown() {
|
||||||
models.clear();
|
models.clear();
|
||||||
instances.clear();
|
instances.clear();
|
||||||
characterShader.reset();
|
characterShader.reset();
|
||||||
|
if (shadowCasterProgram) {
|
||||||
|
glDeleteProgram(shadowCasterProgram);
|
||||||
|
shadowCasterProgram = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CharacterRenderer::loadTexture(const std::string& path) {
|
GLuint CharacterRenderer::loadTexture(const std::string& path) {
|
||||||
|
|
@ -1151,25 +1231,26 @@ void CharacterRenderer::render(const Camera& camera, const glm::mat4& view, cons
|
||||||
glEnable(GL_CULL_FACE); // Restore culling for other renderers
|
glEnable(GL_CULL_FACE); // Restore culling for other renderers
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterRenderer::renderShadow(GLuint shadowShaderProgram) {
|
void CharacterRenderer::renderShadow(const glm::mat4& lightSpaceMatrix) {
|
||||||
if (instances.empty() || shadowShaderProgram == 0) {
|
if (instances.empty() || shadowCasterProgram == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint modelLoc = glGetUniformLocation(shadowShaderProgram, "uModel");
|
glUseProgram(shadowCasterProgram);
|
||||||
GLint useTexLoc = glGetUniformLocation(shadowShaderProgram, "uUseTexture");
|
|
||||||
GLint texLoc = glGetUniformLocation(shadowShaderProgram, "uTexture");
|
GLint lightSpaceLoc = glGetUniformLocation(shadowCasterProgram, "uLightSpaceMatrix");
|
||||||
GLint alphaTestLoc = glGetUniformLocation(shadowShaderProgram, "uAlphaTest");
|
GLint modelLoc = glGetUniformLocation(shadowCasterProgram, "uModel");
|
||||||
GLint opacityLoc = glGetUniformLocation(shadowShaderProgram, "uShadowOpacity");
|
GLint texLoc = glGetUniformLocation(shadowCasterProgram, "uTexture");
|
||||||
GLint useBonesLoc = glGetUniformLocation(shadowShaderProgram, "uUseBones");
|
GLint alphaTestLoc = glGetUniformLocation(shadowCasterProgram, "uAlphaTest");
|
||||||
if (modelLoc < 0) {
|
GLint bonesLoc = glGetUniformLocation(shadowCasterProgram, "uBones[0]");
|
||||||
|
if (lightSpaceLoc < 0 || modelLoc < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
glUniformMatrix4fv(lightSpaceLoc, 1, GL_FALSE, &lightSpaceMatrix[0][0]);
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
glEnable(GL_CULL_FACE);
|
||||||
if (opacityLoc >= 0) glUniform1f(opacityLoc, 1.0f);
|
glCullFace(GL_FRONT);
|
||||||
if (useBonesLoc >= 0) glUniform1i(useBonesLoc, 0);
|
|
||||||
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
|
@ -1183,14 +1264,9 @@ void CharacterRenderer::renderShadow(GLuint shadowShaderProgram) {
|
||||||
: getModelMatrix(instance);
|
: getModelMatrix(instance);
|
||||||
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, &modelMat[0][0]);
|
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, &modelMat[0][0]);
|
||||||
|
|
||||||
bool useBones = !instance.boneMatrices.empty();
|
if (!instance.boneMatrices.empty() && bonesLoc >= 0) {
|
||||||
if (useBonesLoc >= 0) glUniform1i(useBonesLoc, useBones ? 1 : 0);
|
|
||||||
if (useBones) {
|
|
||||||
int numBones = std::min(static_cast<int>(instance.boneMatrices.size()), MAX_BONES);
|
int numBones = std::min(static_cast<int>(instance.boneMatrices.size()), MAX_BONES);
|
||||||
GLint bonesLoc = glGetUniformLocation(shadowShaderProgram, "uBones[0]");
|
glUniformMatrix4fv(bonesLoc, numBones, GL_FALSE, &instance.boneMatrices[0][0][0]);
|
||||||
if (bonesLoc >= 0) {
|
|
||||||
glUniformMatrix4fv(bonesLoc, numBones, GL_FALSE, &instance.boneMatrices[0][0][0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(gpuModel.vao);
|
glBindVertexArray(gpuModel.vao);
|
||||||
|
|
@ -1205,13 +1281,9 @@ void CharacterRenderer::renderShadow(GLuint shadowShaderProgram) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useTexture = (texId != 0 && texId != whiteTexture);
|
bool alphaCutout = (texId != 0 && texId != whiteTexture);
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, useTexture ? 1 : 0);
|
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, alphaCutout ? 1 : 0);
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, useTexture ? 1 : 0);
|
glBindTexture(GL_TEXTURE_2D, texId ? texId : whiteTexture);
|
||||||
if (opacityLoc >= 0) glUniform1f(opacityLoc, 1.0f);
|
|
||||||
if (useTexture) {
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texId);
|
|
||||||
}
|
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES,
|
glDrawElements(GL_TRIANGLES,
|
||||||
batch.indexCount,
|
batch.indexCount,
|
||||||
|
|
@ -1219,8 +1291,8 @@ void CharacterRenderer::renderShadow(GLuint shadowShaderProgram) {
|
||||||
(void*)(batch.indexStart * sizeof(uint16_t)));
|
(void*)(batch.indexStart * sizeof(uint16_t)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (useTexLoc >= 0) glUniform1i(useTexLoc, 0);
|
|
||||||
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
if (alphaTestLoc >= 0) glUniform1i(alphaTestLoc, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, whiteTexture);
|
||||||
glDrawElements(GL_TRIANGLES,
|
glDrawElements(GL_TRIANGLES,
|
||||||
static_cast<GLsizei>(gpuModel.data.indices.size()),
|
static_cast<GLsizei>(gpuModel.data.indices.size()),
|
||||||
GL_UNSIGNED_SHORT,
|
GL_UNSIGNED_SHORT,
|
||||||
|
|
@ -1229,6 +1301,7 @@ void CharacterRenderer::renderShadow(GLuint shadowShaderProgram) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 CharacterRenderer::getModelMatrix(const CharacterInstance& instance) const {
|
glm::mat4 CharacterRenderer::getModelMatrix(const CharacterInstance& instance) const {
|
||||||
|
|
|
||||||
|
|
@ -1749,7 +1749,13 @@ void Renderer::renderShadowPass() {
|
||||||
|
|
||||||
// Render characters into shadow map
|
// Render characters into shadow map
|
||||||
if (characterRenderer) {
|
if (characterRenderer) {
|
||||||
characterRenderer->renderShadow(shadowShaderProgram);
|
// Character shadows need less caster bias to avoid "floating" away from feet.
|
||||||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
characterRenderer->renderShadow(lightSpaceMatrix);
|
||||||
|
glCullFace(GL_FRONT);
|
||||||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
glPolygonOffset(2.0f, 4.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore state
|
// Restore state
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue