/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* movements.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/20 16:01:59 by tomoron #+# #+# */ /* Updated: 2025/03/18 17:00:17 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "RT.hpp" glm::vec3 Renderer::hermiteInterpolate(glm::vec3 points[4], double alpha) { double tension; double bias; glm::vec3 tang[2]; double alphaSqr[2]; glm::vec3 coef[4]; tension = 0; bias = 0; alphaSqr[0] = alpha * alpha; alphaSqr[1] = alphaSqr[0] * alpha; tang[0] = (points[1] - points[0]) * glm::vec3(1 + bias) * glm::vec3(1 - tension) / glm::vec3(2); tang[0] += (points[2] - points[1]) * glm::vec3(1 - bias) * glm::vec3(1 - tension) / glm::vec3(2); tang[1] = (points[2] - points[1]) * glm::vec3(1 + bias) * glm::vec3(1 - tension) / glm::vec3(2); tang[1] += (points[3] - points[2]) * glm::vec3(1 - bias) * glm::vec3(1 - tension) / glm::vec3(2); coef[0] = glm::vec3(2 * alphaSqr[1] - 3 * alphaSqr[0] + 1); coef[1] = glm::vec3(alphaSqr[1] - 2 * alphaSqr[0] + alpha); coef[2] = glm::vec3(alphaSqr[1] - alphaSqr[0]); coef[3] = glm::vec3(-2 * alphaSqr[1] + 3 * alphaSqr[0]); return(coef[0] * points[1] + coef[1] * tang[0] + coef[2] * tang[1] + coef[3] * points[2]); } glm::vec2 Renderer::bezierSphereInterpolate(glm::vec4 control, glm::vec2 from, glm::vec2 to, float time) { glm::vec2 delta; glm::vec2 p1, p2; float t; p1 = glm::vec2(control.x, control.y); p2 = glm::vec2(control.z, control.w); t = time; for(int i = 0; i < 5; i++) { float currentX = 3.0f * ((1 - t) * (1 - t)) * t * p1.x + 3.0f * (1 - t) * (t * t) * p2.x + (t * t * t); if(abs(currentX - time) < 0.00001f) { break; } glm::vec2 derivative = glm::vec2( 3.0f * (1 - t) * (1 - t) * p1.x + 6.0f * (1.0f - t) * t * (p2.x - p1.x) + 3.0f * t * t * (1.0f - p2.x), 3.0f * (1 - t) * (1 - t) * p1.y + 6.0f * (1.0f - t) * t * (p2.y - p1.y) + 3.0f * t * t * (1.0f - p2.y) ); if(abs(derivative.x) > 0.00001f){ t = t - (currentX - time) / derivative.x; t = glm::clamp(t, 0.0f, 1.0f); } } t = 3.0f * ((1 - t) * (1 - t)) * t * p1.y + 3.0f * (1 - t) * (t * t) * p2.y + (t * t * t); delta = to - from; return(from + glm::vec2(delta.x * t, delta.y * t)); } t_pathPoint Renderer::createNextPoint(t_pathPoint from, t_pathPoint to) { t_pathPoint res; res.pos = to.pos + (to.pos - from.pos); res.dir = to.dir + (to.dir - from.dir); res.time = to.time + (to.time - from.time); return (res); } void Renderer::getInterpolationPoints(t_pathPoint &prev, t_pathPoint &from, t_pathPoint &to, t_pathPoint &next) { from = _path[_curPathIndex]; to = _path[_curPathIndex + 1]; if(!_curPathIndex) prev = from; else if (_curPathIndex && _path[_curPathIndex - 1].time == _path[_curPathIndex].time) prev = createNextPoint(to, from); else prev = _path[_curPathIndex - 1]; if((size_t)_curPathIndex + 2 >= _path.size()) next = to; else if ((size_t)_curPathIndex + 2 < _path.size() && _path[_curPathIndex + 2].time == _path[_curPathIndex + 1].time) next = createNextPoint(from, to); else next = _path[_curPathIndex + 2]; } void Renderer::interpolateMovement(float time, glm::vec3 *pos, glm::vec2 *dir) { t_pathPoint prev; t_pathPoint from; t_pathPoint to; t_pathPoint next; float pathTime; float normalTime; bool smallDistPrev; bool smallDistNext; float splitTime; glm::vec4 bezierControl; std::cout << "current time : " << time << std::endl; while(_curPathIndex < _path.size() - 2 && (_path[_curPathIndex + 1].time * 60) < time) _curPathIndex++; splitTime = time - (_path[_curPathIndex].time * 60); getInterpolationPoints(prev, from, to, next); pathTime = (to.time - from.time) * 60; normalTime = 1 - ((pathTime - splitTime) / pathTime); glm::vec3 points[4] = {prev.pos, from.pos, to.pos, next.pos}; *pos = hermiteInterpolate(points, normalTime); smallDistPrev = glm::distance((to.dir - from.dir) / glm::vec2(pathTime), (from.dir - prev.dir) / glm::vec2((from.time - prev.time) * 60)) < 40; smallDistNext = glm::distance((to.dir - from.dir) / glm::vec2(pathTime), (next.dir - to.dir) / glm::vec2((next.time - to.time) * 60)) < 40; bezierControl.x = 0.2f; bezierControl.y = !_curPathIndex || smallDistPrev ? .1f : .0f; bezierControl.z = 0.8f; bezierControl.w = (size_t)_curPathIndex + 2 >= _path.size() || smallDistNext ? .9f : 1.0f; *dir = bezierSphereInterpolate(bezierControl, from.dir, to.dir, normalTime); if(std::isnan(dir->x) || std::isnan(dir->y)) *dir = from.dir; if(splitTime >= pathTime) { *pos = to.pos; *dir = to.dir; _curPathIndex++; } } void Renderer::makeMovement(float time) { glm::vec2 dir; glm::vec3 pos; Camera *cam; interpolateMovement(time, &pos, &dir); cam = _scene->getCamera(); cam->setPosition(pos); cam->setDirection(dir.x, dir.y); _win->setFrameCount(0); if(_curPathIndex == _destPathIndex) { _destPathIndex = 0; if(!_testMode) endRender(0); } }