【UE4】GAMES101 图形学作业4:贝塞尔曲线
阅读原文时间:2021年10月25日阅读:1
  • Bézier 曲线是一种用于计算机图形学的参数曲线。

  • 在本次作业中,你需要实现de Casteljau 算法来绘制由4 个控制点表示的Bézier 曲线(当你正确实现该算法时,你可以支持绘制由更多点来控制的Bézier 曲线)。

  • 你需要修改的函数在提供的main.cpp 文件中。

    • bezier:该函数实现绘制Bézier 曲线的功能。

      它使用一个控制点序列和一个OpenCV::Mat 对象作为输入,没有返回值。它会使t 在0 到1 的范围内进行迭代,并在每次迭代中使t 增加一个微小值。对于每个需要计算的t,将调用另一个函数recursive_bezier,然后该函数将返回在Bézier 曲线上t处的点。最后,将返回的点绘制在OpenCV ::Mat 对象上。

    • recursive_bezier:该函数使用一个控制点序列和一个浮点数t 作为输入,实现de Casteljau 算法来返回Bézier 曲线上对应点的坐标。

  • naive_bezier

    • 数学公式

    • 代码

      void AActor_BezierCuve::naive_bezier()
      {
          FVector& p_0 = m_points[0];
          FVector& p_1 = m_points[1];
          FVector& p_2 = m_points[2];
          FVector& p_3 = m_points[3];
          FVector& p_4 = m_points[4];
          for (double t = 0.0; t <= 1.0; t += 0.001)
          {
              auto point = std::pow(1 - t, 4) * p_0 + 4 * t * std::pow(1 - t, 3) * p_1 +
                  6 * std::pow(t, 2) * std::pow((1 - t), 2) * p_2 + 4 * std::pow(t, 3) * (1 - t) * p_3 + std::pow(t, 4) * p_4;
              DrawDebugPoint(GetWorld(), point, 2.0f, FColor::Green,true,5.0f);
              //UKismetSystemLibrary::PrintString(GetWorld(), point.ToString());
          }
      
      }
  • recursive_bezier

    • De Casteljau 算法说明如下:

    • 代码

      void AActor_BezierCuve::bezier()
      {
          for (double t = 0.0; t <= 1.0; t += 0.001)
          {
              FVector point = recursive_bezier(m_points, t);
              DrawDebugPoint(GetWorld(), point, 2.0f, FColor(10,214,255,255),true,5.0f);
          }
      }
      
      // De Casteljau 算法,递归
      FVector AActor_BezierCuve::recursive_bezier(TArray<FVector>& points, float t)
      {
          if (points.Num() < 3) {
              return (1 - t) * points[0] + t * points[1];
          }
      TArray&lt;FVector&gt; newPoint;
      for (int i = 0; i &lt; points.Num() - 1; i++) {
          newPoint.Add((1 - t) * points[i] + t * points[i + 1]);
      }
      return recursive_bezier(newPoint, t);
      }
  • 最终效果

所有代码

  • Actor_BezierCuve.h

    点击查看代码

      ```cpp
      UCLASS()
      class GAMES101_API AActor_BezierCuve : public AActor
      {
          GENERATED_BODY()
    
      public:
          // Sets default values for this actor's properties
          AActor_BezierCuve();
    
      protected:
          // Called when the game starts or when spawned
          virtual void BeginPlay() override;
    
      public:
          // Called every frame
          virtual void Tick(float DeltaTime) override;
      UFUNCTION(BlueprintCallable)
      void naive_bezier();
    
      UFUNCTION(BlueprintCallable)
          void bezier();
    
      UFUNCTION(BlueprintCallable)
          FVector recursive_bezier(TArray&lt;FVector&gt;&amp; points,float t);
    public: UPROPERTY(VisibleAnywhere) USceneComponent* root; UPROPERTY(VisibleAnywhere) UStaticMeshComponent* point0; UPROPERTY(VisibleAnywhere) UStaticMeshComponent* point1; UPROPERTY(VisibleAnywhere) UStaticMeshComponent* point2; UPROPERTY(VisibleAnywhere) UStaticMeshComponent* point3; UPROPERTY(VisibleAnywhere) UStaticMeshComponent* point4;
      UPROPERTY();
      TArray&lt;FVector&gt; m_points;
    
      UPROPERTY(EditAnywhere);
      bool m_bUseRecursiveBezier;
    }; ```
  • AActor_BezierCuve.cpp

    点击查看代码

    #include "Actor_BezierCuve.h"
    #include "DrawDebugHelpers.h"
    #include <cmath>
    #include "Kismet/KismetSystemLibrary.h"
    
    // Sets default values
    AActor_BezierCuve::AActor_BezierCuve()
    {
         // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
        PrimaryActorTick.bCanEverTick = true;
        root = CreateDefaultSubobject<USceneComponent>(TEXT("root"));
        SetRootComponent(root);
    point0 = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT("point0"));
    point1 = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT("point1"));
    point2 = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT("point2"));
    point3 = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT("point3"));
    point4 = CreateDefaultSubobject&lt;UStaticMeshComponent&gt;(TEXT("point4"));
    
    point0-&gt;SetupAttachment(root);
    point1-&gt;SetupAttachment(root);
    point2-&gt;SetupAttachment(root);
    point3-&gt;SetupAttachment(root);
    point4-&gt;SetupAttachment(root);
    m_points.Init(FVector::ZeroVector, 5);
    
    m_bUseRecursiveBezier = false;
    } // Called when the game starts or when spawned void AActor_BezierCuve::BeginPlay() { Super::BeginPlay(); m_points[0] = point0->GetComponentLocation(); m_points[1] = point1->GetComponentLocation(); m_points[2] = point2->GetComponentLocation(); m_points[3] = point3->GetComponentLocation(); m_points[4] = point4->GetComponentLocation();
    if (!m_bUseRecursiveBezier)
        naive_bezier();
    else
        bezier();
    } // Called every frame void AActor_BezierCuve::Tick(float DeltaTime) { Super::Tick(DeltaTime); } // 多项式 void AActor_BezierCuve::naive_bezier() { FVector& p_0 = m_points[0]; FVector& p_1 = m_points[1]; FVector& p_2 = m_points[2]; FVector& p_3 = m_points[3]; FVector& p_4 = m_points[4]; for (double t = 0.0; t <= 1.0; t += 0.001) { auto point = std::pow(1 - t, 4) * p_0 + 4 * t * std::pow(1 - t, 3) * p_1 + 6 * std::pow(t, 2) * std::pow((1 - t), 2) * p_2 + 4 * std::pow(t, 3) * (1 - t) * p_3 + std::pow(t, 4) * p_4; DrawDebugPoint(GetWorld(), point, 2.0f, FColor::Green,true,5.0f); //UKismetSystemLibrary::PrintString(GetWorld(), point.ToString()); } } void AActor_BezierCuve::bezier() { for (double t = 0.0; t <= 1.0; t += 0.001) { FVector point = recursive_bezier(m_points, t); DrawDebugPoint(GetWorld(), point, 2.0f, FColor(10,214,255,255),true,5.0f); } } // De Casteljau 算法,递归 FVector AActor_BezierCuve::recursive_bezier(TArray<FVector>& points, float t) { if (points.Num() < 3) { return (1 - t) * points[0] + t * points[1]; }
    TArray&lt;FVector&gt; newPoint;
    for (int i = 0; i &lt; points.Num() - 1; i++) {
        newPoint.Add((1 - t) * points[i] + t * points[i + 1]);
    }
    return recursive_bezier(newPoint, t);
    }

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章