580 lines
21 KiB
C++
580 lines
21 KiB
C++
#include "Character.h"
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include "GameConstants.h"
|
|
#include "Environment.h"
|
|
|
|
namespace ZL {
|
|
|
|
const float ATTACK_COOLDOWN_TIME = 3.0f;
|
|
|
|
void Character::loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
|
auto& data = animations[state];
|
|
data.model.LoadFromFile(filename, zipFile);
|
|
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
|
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
|
} else {
|
|
data.totalFrames = 1;
|
|
}
|
|
}
|
|
void Character::loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
|
auto& data = animations[state];
|
|
data.model.LoadFromBinaryFile(filename, zipFile);
|
|
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
|
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
|
}
|
|
else {
|
|
data.totalFrames = 1;
|
|
}
|
|
}
|
|
/*void Character::setTexture(std::shared_ptr<Texture> tex) {
|
|
texture = tex;
|
|
}*/
|
|
|
|
void Character::setTarget(const Eigen::Vector3f& target,
|
|
std::function<void()> onArrived) {
|
|
walkTarget = target;
|
|
onArrivedCallback = std::move(onArrived);
|
|
}
|
|
|
|
AnimationState Character::resolveActiveState() const {
|
|
|
|
if (animations.count(currentState)) return currentState;
|
|
return AnimationState::STAND;
|
|
}
|
|
|
|
void Character::update(int64_t deltaMs) {
|
|
//std::cout << "update called with deltaMs: " << deltaMs << std::endl;
|
|
// Move toward walk target on the XZ plane
|
|
Eigen::Vector3f toTarget = walkTarget - position;
|
|
toTarget.y() = 0.f;
|
|
float dist = toTarget.norm();
|
|
|
|
if (dist > WALK_THRESHOLD) {
|
|
Eigen::Vector3f dir = toTarget / dist;
|
|
float moveAmount = walkSpeed * static_cast<float>(deltaMs) / 1000.f;
|
|
if (moveAmount >= dist) {
|
|
position = walkTarget;
|
|
position.y() = 0.f;
|
|
} else {
|
|
position += dir * moveAmount;
|
|
}
|
|
targetFacingAngle = atan2(dir.x(), -dir.z());
|
|
if (battle_state == 0 && currentState == AnimationState::STAND)
|
|
{
|
|
currentState = AnimationState::WALK;
|
|
}
|
|
} else {
|
|
if (battle_state == 0 &&
|
|
currentState == AnimationState::WALK
|
|
)
|
|
{
|
|
currentState = AnimationState::STAND;
|
|
}
|
|
if (onArrivedCallback) {
|
|
auto cb = std::move(onArrivedCallback);
|
|
onArrivedCallback = nullptr;
|
|
cb();
|
|
}
|
|
}
|
|
|
|
if (battle_state == 1 && attack == 1 && attackTarget != nullptr)
|
|
{
|
|
targetFacingAngle = atan2(attackTarget->position.x() - position.x(), -(attackTarget->position.z() - position.z()));
|
|
}
|
|
|
|
// Rotate toward target facing angle at constant angular speed
|
|
float angleDiff = targetFacingAngle - facingAngle;
|
|
while (angleDiff > static_cast<float>(M_PI)) angleDiff -= 2.f * static_cast<float>(M_PI);
|
|
while (angleDiff < -static_cast<float>(M_PI)) angleDiff += 2.f * static_cast<float>(M_PI);
|
|
float rotStep = rotationSpeed * static_cast<float>(deltaMs) / 1000.f;
|
|
if (std::fabs(angleDiff) <= rotStep) {
|
|
facingAngle = targetFacingAngle;
|
|
} else {
|
|
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
|
}
|
|
|
|
if (canAttack && attackTarget != nullptr)
|
|
{
|
|
float distToGhost = (attackTarget->position - position).norm();
|
|
if (distToGhost >= 10.f)
|
|
{
|
|
if (isPlayer)
|
|
{
|
|
setTarget(attackTarget->position);
|
|
}
|
|
if (battle_state != 0)
|
|
{
|
|
battle_state = 0;
|
|
}
|
|
}
|
|
else if (distToGhost < 10.0f && distToGhost >= 1.f) {
|
|
setTarget(attackTarget->position);
|
|
if (battle_state != 0)
|
|
{
|
|
battle_state = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setTarget(position);
|
|
if (battle_state != 1)
|
|
{
|
|
battle_state = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (attackTarget == nullptr)
|
|
{
|
|
if (battle_state != 0)
|
|
{
|
|
battle_state = 0;
|
|
attack = 0;
|
|
}
|
|
}
|
|
|
|
if (battle_state == 1)
|
|
{
|
|
if (currentState == AnimationState::STAND || currentState == AnimationState::WALK) {
|
|
currentState = AnimationState::STAND_TO_ACTION;
|
|
resetAnim = true;
|
|
}
|
|
|
|
if (canAttack && attack == 0 && attack_cooldown < 0.f && currentState == AnimationState::ACTION_IDLE)
|
|
{
|
|
attack = 1;
|
|
attack_cooldown = ATTACK_COOLDOWN_TIME;
|
|
}
|
|
if (canAttack && attack_cooldown >= 0.f)
|
|
{
|
|
attack_cooldown = attack_cooldown - deltaMs / 1000.f;
|
|
}
|
|
|
|
if (attack == 1 && currentState == AnimationState::ACTION_IDLE)
|
|
{
|
|
currentState = AnimationState::ACTION_ATTACK;
|
|
resetAnim = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (currentState == AnimationState::STAND_TO_ACTION
|
|
|| currentState == AnimationState::ACTION_IDLE
|
|
|| currentState == AnimationState::ACTION_ATTACK
|
|
) {
|
|
currentState = AnimationState::ACTION_TO_STAND;
|
|
resetAnim = true;
|
|
}
|
|
}
|
|
|
|
auto it = animations.find(currentState);
|
|
if (it == animations.end()) return;
|
|
|
|
auto& anim = it->second;
|
|
|
|
if (resetAnim)
|
|
{
|
|
resetAnim = false;
|
|
anim.currentFrame = 0;
|
|
}
|
|
anim.currentFrame += static_cast<float>(deltaMs) / 24.f;
|
|
//std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl;
|
|
int frms = anim.model.animations[0].keyFrames[anim.model.animations[0].keyFrames.size() - 1].frame;
|
|
if (static_cast<int>(anim.currentFrame) >= frms) {
|
|
anim.currentFrame = anim.model.startingFrame;
|
|
|
|
if (currentState == AnimationState::STAND_TO_ACTION)
|
|
{
|
|
currentState = AnimationState::ACTION_IDLE;
|
|
resetAnim = true;
|
|
}
|
|
if (currentState == AnimationState::ACTION_TO_STAND)
|
|
{
|
|
currentState = AnimationState::STAND;
|
|
resetAnim = true;
|
|
}
|
|
|
|
if (currentState == AnimationState::ACTION_ATTACK)
|
|
{
|
|
currentState = AnimationState::ACTION_IDLE;
|
|
resetAnim = true;
|
|
attack = 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
|
|
if (useGpuSkinning) {
|
|
anim.model.ComputeSkinningMatrices(static_cast<int>(anim.currentFrame), anim.skinningMatrices);
|
|
} else {
|
|
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
|
}
|
|
anim.lastFrame = static_cast<int>(anim.currentFrame);
|
|
}
|
|
}
|
|
|
|
void Character::draw(Renderer& renderer) {
|
|
if (useGpuSkinning) {
|
|
drawGpuSkinning(renderer);
|
|
return;
|
|
}
|
|
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end() || !texture) return;
|
|
|
|
renderer.shaderManager.PushShader(defaultShaderName);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
|
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
auto& anim = it->second;
|
|
anim.modelMutable.AssignFrom(anim.model.mesh);
|
|
anim.modelMutable.RefreshVBO();
|
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
|
renderer.DrawVertexRenderStruct(anim.modelMutable);
|
|
|
|
renderer.PopMatrix();
|
|
renderer.PopProjectionMatrix();
|
|
renderer.shaderManager.PopShader();
|
|
}
|
|
|
|
void Character::prepareGpuSkinningVBOs(AnimationData& anim) {
|
|
if (anim.gpuSkinningPrepared)
|
|
{
|
|
|
|
return;
|
|
}
|
|
|
|
anim.model.PrepareGpuSkinningData();
|
|
|
|
// Upload bind-pose mesh (static, done once)
|
|
anim.bindPoseMutable.AssignFrom(anim.model.startMesh);
|
|
|
|
auto& gpu = anim.model.gpuBoneData;
|
|
|
|
anim.boneIndices0VBO = std::make_shared<VBOHolder>();
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices0.size() * sizeof(Eigen::Vector4f),
|
|
gpu.boneIndices0.data(), GL_STATIC_DRAW);
|
|
|
|
anim.boneIndices1VBO = std::make_shared<VBOHolder>();
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices1.size() * sizeof(Eigen::Vector2f),
|
|
gpu.boneIndices1.data(), GL_STATIC_DRAW);
|
|
|
|
anim.boneWeights0VBO = std::make_shared<VBOHolder>();
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights0.size() * sizeof(Eigen::Vector4f),
|
|
gpu.boneWeights0.data(), GL_STATIC_DRAW);
|
|
|
|
anim.boneWeights1VBO = std::make_shared<VBOHolder>();
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights1.size() * sizeof(Eigen::Vector2f),
|
|
gpu.boneWeights1.data(), GL_STATIC_DRAW);
|
|
|
|
anim.gpuSkinningPrepared = true;
|
|
}
|
|
|
|
void Character::drawGpuSkinning(Renderer& renderer) {
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end() || !texture)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto& anim = it->second;
|
|
prepareGpuSkinningVBOs(anim);
|
|
|
|
if (anim.skinningMatrices.empty())
|
|
{
|
|
return;
|
|
}
|
|
static const std::string skinningShaderName = "skinning";
|
|
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
|
|
|
renderer.shaderManager.PushShader(skinningShaderName);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
|
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
// Upload bone skinning matrices
|
|
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
|
static_cast<int>(anim.skinningMatrices.size()), false,
|
|
anim.skinningMatrices[0].data());
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
|
|
|
// Bind VAO (desktop only)
|
|
#ifndef EMSCRIPTEN
|
|
#ifndef __ANDROID__
|
|
if (anim.bindPoseMutable.vao) {
|
|
glBindVertexArray(anim.bindPoseMutable.vao->getBuffer());
|
|
renderer.shaderManager.EnableVertexAttribArrays();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// Bind position and texcoord VBOs
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.positionVBO->getBuffer());
|
|
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
|
|
|
if (anim.bindPoseMutable.texCoordVBO) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.texCoordVBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
|
}
|
|
|
|
// Bind bone index VBOs
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
|
|
|
// Bind bone weight VBOs
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(anim.bindPoseMutable.data.PositionData.size()));
|
|
|
|
renderer.PopMatrix();
|
|
renderer.PopProjectionMatrix();
|
|
renderer.shaderManager.PopShader();
|
|
}
|
|
|
|
// ==================== Shadow depth pass ====================
|
|
|
|
void Character::drawShadowDepth(Renderer& renderer) {
|
|
if (useGpuSkinning) {
|
|
drawShadowDepthGpuSkinning(renderer);
|
|
} else {
|
|
drawShadowDepthCpu(renderer);
|
|
}
|
|
}
|
|
|
|
void Character::drawShadowDepthCpu(Renderer& renderer) {
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end()) return;
|
|
|
|
// The caller has already pushed the shadow_depth shader and the
|
|
// light's projection + view onto the renderer stacks.
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
auto& anim = it->second;
|
|
anim.modelMutable.AssignFrom(anim.model.mesh);
|
|
anim.modelMutable.RefreshVBO();
|
|
renderer.DrawVertexRenderStruct(anim.modelMutable);
|
|
|
|
renderer.PopMatrix();
|
|
}
|
|
|
|
void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end()) return;
|
|
|
|
auto& anim = it->second;
|
|
prepareGpuSkinningVBOs(anim);
|
|
if (anim.skinningMatrices.empty()) return;
|
|
|
|
static const std::string shadowSkinningShader = "shadow_depth_skinning";
|
|
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
|
|
|
// Switch to the skinning depth shader (caller has the static depth shader active).
|
|
renderer.shaderManager.PushShader(shadowSkinningShader);
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
|
static_cast<int>(anim.skinningMatrices.size()), false,
|
|
anim.skinningMatrices[0].data());
|
|
|
|
#ifndef EMSCRIPTEN
|
|
#ifndef __ANDROID__
|
|
if (anim.bindPoseMutable.vao) {
|
|
glBindVertexArray(anim.bindPoseMutable.vao->getBuffer());
|
|
renderer.shaderManager.EnableVertexAttribArrays();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.positionVBO->getBuffer());
|
|
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
|
|
|
if (anim.bindPoseMutable.texCoordVBO) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.texCoordVBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(anim.bindPoseMutable.data.PositionData.size()));
|
|
|
|
renderer.PopMatrix();
|
|
renderer.shaderManager.PopShader();
|
|
}
|
|
|
|
// ==================== Main pass with shadows ====================
|
|
|
|
void Character::drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
|
if (useGpuSkinning) {
|
|
drawGpuSkinningWithShadow(renderer, lightFromCamera, shadowMapTex, lightDirCamera);
|
|
} else {
|
|
drawCpuWithShadow(renderer, lightFromCamera, shadowMapTex, lightDirCamera);
|
|
}
|
|
}
|
|
|
|
void Character::drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end() || !texture) return;
|
|
|
|
static const std::string shadowShader = "default_shadow";
|
|
|
|
renderer.shaderManager.PushShader(shadowShader);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
renderer.RenderUniform1i("uShadowMap", 1);
|
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
|
renderer.RenderUniform3fv("uLightDir", lightDirCamera.data());
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
auto& anim = it->second;
|
|
anim.modelMutable.AssignFrom(anim.model.mesh);
|
|
anim.modelMutable.RefreshVBO();
|
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
|
renderer.DrawVertexRenderStruct(anim.modelMutable);
|
|
|
|
renderer.PopMatrix();
|
|
renderer.PopProjectionMatrix();
|
|
renderer.shaderManager.PopShader();
|
|
}
|
|
|
|
void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
|
AnimationState drawState = resolveActiveState();
|
|
auto it = animations.find(drawState);
|
|
if (it == animations.end() || !texture) return;
|
|
|
|
auto& anim = it->second;
|
|
prepareGpuSkinningVBOs(anim);
|
|
if (anim.skinningMatrices.empty()) return;
|
|
|
|
static const std::string skinningShadowShader = "skinning_shadow";
|
|
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
|
|
|
renderer.shaderManager.PushShader(skinningShadowShader);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
renderer.RenderUniform1i("uShadowMap", 1);
|
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
|
renderer.RenderUniform3fv("uLightDir", lightDirCamera.data());
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
renderer.ScaleMatrix(modelScale);
|
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
|
|
|
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
|
static_cast<int>(anim.skinningMatrices.size()), false,
|
|
anim.skinningMatrices[0].data());
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
|
|
|
#ifndef EMSCRIPTEN
|
|
#ifndef __ANDROID__
|
|
if (anim.bindPoseMutable.vao) {
|
|
glBindVertexArray(anim.bindPoseMutable.vao->getBuffer());
|
|
renderer.shaderManager.EnableVertexAttribArrays();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.positionVBO->getBuffer());
|
|
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
|
|
|
if (anim.bindPoseMutable.texCoordVBO) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.texCoordVBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
|
}
|
|
|
|
// Bind normals for diffuse lighting (skinning_shadow shader skins them)
|
|
if (anim.bindPoseMutable.normalVBO) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.normalVBO->getBuffer());
|
|
renderer.VertexAttribPointer3fv("vNormal", 0, NULL);
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
|
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
|
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(anim.bindPoseMutable.data.PositionData.size()));
|
|
|
|
renderer.PopMatrix();
|
|
renderer.PopProjectionMatrix();
|
|
renderer.shaderManager.PopShader();
|
|
}
|
|
|
|
} // namespace ZL
|