Отрисовка индикатора направления ImGui

DaniilPovetkin

Известный
Автор темы
13
1
Всем привет, вопрос скорее к знатокам математических функций. Пишу отрисовку текста в пространстве SAMP, и хочу сделать, что когда игрок не смотрит на этот текст, то ему указывалось направление иконкой, например если точка сзади, то внизу экрана и так по всей его плоскости. Но сейчас работает коряво, вроде слева отображается, справа тоже, а когда спиной стою никак :(


C++:
ImVec2 CalculateEdgePosition(ImVec2 originalPos, ImVec2 screenSize)
{
    const float margin = 10.0f; // Отступ от края
    const float imageSize = 32.0f;

    // Определяем, в каком направлении находится точка за пределами экрана
    bool left = originalPos.x < 0;
    bool right = originalPos.x > screenSize.x;
    bool top = originalPos.y < 0;
    bool bottom = originalPos.y > screenSize.y;

    // Вычисляем позицию на краю экрана
    float x = originalPos.x;
    float y = originalPos.y;

    if (left) x = margin;
    else if (right) x = screenSize.x - margin - imageSize;
    else x = std::clamp(x, margin, screenSize.x - margin - imageSize);

    if (top) y = margin;
    else if (bottom) y = screenSize.y - margin - imageSize;
    else y = std::clamp(y, margin, screenSize.y - margin - imageSize);

    return ImVec2(x, y);
}

void СTooltipManager::RenderTooltip()
{
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    auto drawlist = ImGui::GetBackgroundDrawList();

    CVector targetPosition{ 2760.6069f,-2420.8516f,21.7059f };

    CPlayerPed* pLocalPed = FindPlayerPed(-1);
    CVector cameraPosition = pLocalPed->GetPosition();
    CVector cameraForward = pLocalPed->GetForward();

    float fDistance = DistancePointToPoint(cameraPosition, targetPosition);
    CVector screenPosition = Utils::ConvertGameCoordsToScreen(targetPosition);

    ImVec2 screenSize = ImGui::GetIO().DisplaySize;
    ImVec2 pos = ImVec2(screenPosition.x, screenPosition.y);

    ImVec2 posForward = ImVec2(screenPosition.x, screenPosition.y);

    bool isVisibleOnScreen = (screenPosition.x >= 0.0f && screenPosition.x <= screenSize.x) &&
        (screenPosition.y >= 0.0f && screenPosition.y <= screenSize.y);

    if (isVisibleOnScreen) {
        // Оригинальный рендеринг, когда точка в поле зрения
        char distanse[50];
        sprintf(distanse, "%.0f м.", fDistance);

        ImGui::PushFont(fontToolTip);

        float textWidth = ImGui::CalcTextSize(utf8(std::string(distanse))).x;
        ImVec2 textPos = ImVec2(pos.x - textWidth * 0.5f, pos.y);
        drawlist->AddText(textPos, IM_COL32(255, 255, 255, 255), utf8(std::string(distanse)));

        ImVec2 imagePos = ImVec2(pos.x - 16.0f, pos.y + 15.0f);
        drawlist->AddImage((void*)iconToolTip, imagePos, ImVec2(imagePos.x + 32.0f, imagePos.y + 32.0f));

        std::string tet = "Добыча камня";
        float text2Width = ImGui::CalcTextSize(utf8(tet)).x;
        ImVec2 text2Pos = ImVec2(pos.x - text2Width * 0.5f, pos.y + 32.0f + 15.0f);
        drawlist->AddText(text2Pos, IM_COL32(255, 255, 255, 255), utf8(tet));

        ImGui::PopFont();
    }
    else {
        ImVec2 edgePos = CalculateEdgePosition(pos, screenSize);
        ImVec2 imageSize = ImVec2(32.0f, 32.0f);
        drawlist->AddImage((void*)iconToolTip, edgePos, ImVec2(edgePos.x + imageSize.x, edgePos.y + imageSize.y));
    }

    ImGui::EndFrame();
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
}
Что-то типо такого в итоге, только просто иконкой в направлении к координатам

Изображение
 
Последнее редактирование:
24
3
C++:
#include <algorithm>

bool IsPointInFrontOfCamera(const CVector& cameraPos, const CVector& cameraForward, const CVector& targetPos) {
    CVector directionToTarget = targetPos - cameraPos;
    directionToTarget.Normalize();
    return (cameraForward.x * directionToTarget.x +
            cameraForward.y * directionToTarget.y +
            cameraForward.z * directionToTarget.z) > 0.1f;
}

ImVec2 CalculateEdgePosition(const CVector& targetPos, const CVector& cameraPos, const CVector& cameraForward, ImVec2 screenSize) {
    const float margin = 10.0f;
    const float imageSize = 32.0f;
    bool isInFront = IsPointInFrontOfCamera(cameraPos, cameraForward, targetPos);

    CVector dirToTarget = targetPos - cameraPos;
    dirToTarget.Normalize();
    CVector2D screenDir(dirToTarget.x, dirToTarget.y);

    float aspectRatio = screenSize.x / screenSize.y;
    ImVec2 screenCenter(screenSize.x * 0.5f, screenSize.y * 0.5f);
    ImVec2 projectedPoint = ImVec2(
        screenCenter.x + screenDir.x * screenCenter.x * aspectRatio,
        screenCenter.y - screenDir.y * screenCenter.y
    );

    if (!isInFront) {
        projectedPoint.x = screenCenter.x * 2 - projectedPoint.x;
        projectedPoint.y = screenCenter.y * 2 - projectedPoint.y;
    }

    float x = std::clamp(projectedPoint.x, margin, screenSize.x - margin - imageSize);
    float y = std::clamp(projectedPoint.y, margin, screenSize.y - margin - imageSize);

    if (!isInFront) {
        x = (projectedPoint.x < screenCenter.x) ? margin : screenSize.x - margin - imageSize;
        y = (projectedPoint.y < screenCenter.y) ? margin : screenSize.y - margin - imageSize;
    }

    return ImVec2(x, y);
}

void СTooltipManager::RenderTooltip() {
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    auto drawlist = ImGui::GetBackgroundDrawList();
    CVector targetPosition{2760.6069f,-2420.8516f,21.7059f};

    CPlayerPed* pLocalPed = FindPlayerPed(-1);
    CVector cameraPosition = pLocalPed->GetPosition();
    CVector cameraForward = pLocalPed->GetForward();
    
    CVector screenPosition = Utils::ConvertGameCoordsToScreen(targetPosition);
    ImVec2 screenSize = ImGui::GetIO().DisplaySize;

    bool isInFront = IsPointInFrontOfCamera(cameraPosition, cameraForward, targetPosition);
    bool isVisibleOnScreen = isInFront &&
                           (screenPosition.x >= 0 && screenPosition.x <= screenSize.x) &&
                           (screenPosition.y >= 0 && screenPosition.y <= screenSize.y);

    if (isVisibleOnScreen) {
        char distanse[50];
        sprintf(distanse, "%.0f м.", DistancePointToPoint(cameraPosition, targetPosition));

        ImGui::PushFont(fontToolTip);
        ImVec2 textPos = ImVec2(
            screenPosition.x - ImGui::CalcTextSize(distanse).x * 0.5f,
            screenPosition.y
        );
        drawlist->AddText(textPos, IM_COL32_WHITE, distanse);

        ImVec2 imagePos(screenPosition.x - 16.0f, screenPosition.y + 15.0f);
        drawlist->AddImage((void*)iconToolTip, imagePos, ImVec2(imagePos.x + 32.0f, imagePos.y + 32.0f));

        const char* text = "Добыча камня";
        ImVec2 text2Pos = ImVec2(
            screenPosition.x - ImGui::CalcTextSize(text).x * 0.5f,
            screenPosition.y + 47.0f
        );
        drawlist->AddText(text2Pos, IM_COL32_WHITE, text);
        ImGui::PopFont();
    }
    else {
        ImVec2 edgePos = CalculateEdgePosition(targetPosition, cameraPosition, cameraForward, screenSize);
        drawlist->AddImage((void*)iconToolTip, edgePos, ImVec2(edgePos.x + 32.0f, edgePos.y + 32.0f));
    }

    ImGui::EndFrame();
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
}

Попробуй так