facecam2d/src/modelpart.cpp
Epicalert b1571c0dc9
Fix extreme eye movement when face is scaled small
Offset needs to be multiplied by scale, otherwise the effect will be
disproportionately pronounced when the face is scaled down.
2021-07-04 03:35:31 +08:00

110 lines
3.3 KiB
C++

#include <GL/glew.h>
#include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <graphics.hpp>
#include <modelpart.hpp>
#include <iostream>
std::map<std::string, int> bindStringToNum {
{"null", BIND_NULL},
{"head", BIND_HEAD},
{"face", BIND_FACE},
{"offset-eyes", OFFSET_EYES},
};
std::map<std::string, bool> triggerStringToNum {
{"null", TRIGGER_NULL},
{"mouth-open", TRIGGER_MOUTH_OPEN},
};
ModelPart::ModelPart() {
//create vbo, ebo, vao
initBuffers(&vao);
empty = false;
}
void ModelPart::bindAndDraw() {
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, tex[texSelection]);
glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(transMatrix));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
void ModelPart::setBind(std::string bindName) {
bind = bindStringToNum[bindName];
}
void ModelPart::setFollowTarget(std::string followTarget) {
follow = bindStringToNum[followTarget];
}
void ModelPart::setOffsetBind(std::string bindName) {
offsetBind = bindStringToNum[bindName];
}
void ModelPart::smoothTransform(glm::vec2 position, float rotation, float scale) {
histPositions[histI] = position;
histRotations[histI] = rotation;
histScales[histI] = scale;
histI++;
histI = histI % SMOOTHING_FRAMES;
glm::vec2 smoothedPosition(0,0);
float smoothedRotation = 0;
float smoothedScale = 0;
for(size_t i = 0; i < SMOOTHING_FRAMES; i++) {
smoothedPosition += histPositions[i];
smoothedRotation += histRotations[i];
smoothedScale += histScales[i];
}
smoothedPosition /= SMOOTHING_FRAMES;
smoothedRotation /= SMOOTHING_FRAMES;
smoothedScale /= SMOOTHING_FRAMES;
setTransform(smoothedPosition, smoothedRotation, smoothedScale);
}
void ModelPart::setTransform(glm::vec2 position, float rotation, float scale) {
transMatrix = glm::ortho(-windowAspectRatio, windowAspectRatio, -1.0f, 1.0f);
transMatrix = glm::translate(transMatrix, glm::vec3(position.x, -position.y, 0.0f) + glm::vec3(posOffset, 0.0f));
transMatrix = glm::rotate(transMatrix, rotation * rotFactor, glm::vec3(0.0f, 0.0f, 1.0f));
transMatrix = glm::scale(transMatrix, glm::vec3(1,1,1) + (scale - 1 + glm::vec3(scaleOffset, 0.0f)) * scaleFactor);
transMatrix = glm::translate(transMatrix, glm::vec3(-origin, 0.0f));
}
void ModelPart::processFaceData(struct FaceData faceData) {
// calculate position
glm::vec2 bindPosition = faceData.positions[bind];
glm::vec2 followPosition = faceData.positions[follow];
glm::vec2 followDirection = followPosition - bindPosition;
glm::vec2 offset = faceData.positions[offsetBind] * offsetFactor * faceData.scale;
glm::vec2 newPosition = bindPosition + offset + (followDirection * factor);
smoothTransform(newPosition, faceData.headRotation, faceData.scale);
// change textures
selectTexture(0); // if none are triggered, use the first one
for (size_t i = 0; i < texCount; i++) {
if (faceData.triggers[texTriggers[i]]) {
selectTexture(i);
break; // if several textures are triggered, the first one defined in model.toml will get priority
}
}
}
void ModelPart::addTexture(unsigned char* texBuffer, size_t texLength, size_t slot, std::string triggerName) {
initTexture(&tex[slot], texBuffer, texLength);
texTriggers[slot] = triggerStringToNum[triggerName];
texCount++;
}
void ModelPart::selectTexture(size_t slot) {
texSelection = slot;
}