初識貝塞爾(bezier)曲線

文章目錄

  • 資料援引
  • 貝塞爾曲線的用途
  • 一階貝塞爾(bezier)曲線
  • 二階貝塞爾(bezier)曲線
  • 三階貝塞爾(bezier)曲線
  • 高階貝塞爾(bezier)曲線
  • 三階貝塞爾曲線求插值(Slerp)


資料援引

B站視頻:wow,神奇的貝塞爾曲線!

博客:貝塞爾曲線簡單介紹

知乎:曲線篇: 貝塞爾曲線


貝塞爾曲線的用途

  • 基于對汽車的的車身結構進行流體化設計而誕生
  • 處理視頻狀態點之間的圖像變化
  • 隨心所欲繪制曲線,比如:

在這里插入圖片描述

在這里插入圖片描述


一階貝塞爾(bezier)曲線

在這里插入圖片描述

如上,P0P_0P0?P1P_1P1? 兩點構成了一條線段,而我們可以通過一個函數——線性插值(lerp),來根據一個 ttt 值(t∈[0,1]t \in [0,1]t[0,1] 得到線段上一點 PPP(圖中一直在滑動的點)。而 PPP 的運動軌跡(紅線),便是一階貝塞爾線段(曲線)。線性插值的數學形式(一階貝塞爾曲線公式)為:

P=lerp(P0,P1,t)=(1?t)P0+tP1P=lerp(P_0,P_1,t)=(1-t)P_0 + tP_1P=lerp(P0?P1?t)=(1?t)P0?+tP1?

一階貝塞爾曲線有兩個端點P0P_0P0?P1P_1P1? ),0個控制點


二階貝塞爾(bezier)曲線

在這里插入圖片描述

如上,假設現在有點 P2P_2P2? ,它與 P1P_1P1? 構成了新的線段,我們得到兩個 一階插值點(Q1Q_1Q1?Q2Q_2Q2?,它們構成了綠色線段,值得注意的是,兩個插值點具有相同的 ttt 值。

而此時我們在綠色線段上生成一個 二階插值點(PPP,并讓它具有 與兩個一階插值點相同的ttt 值。 那么該點的運動軌跡就是 二階貝塞爾曲線。其公式推導為:

  • 綠色線段左端點的運動軌跡:

Q1=(1?t)P0+tP1Q_1 = (1-t)P_0 + tP_1 Q1?=(1?t)P0?+tP1?

  • 綠色線段右端點的運動軌跡:

Q2=(1?t)P1+tP2Q_2 = (1-t)P_1 + tP_2Q2?=(1?t)P1?+tP2?

  • 二階貝塞爾曲線公式:

P=(1?t)Q1+tQ2P = (1-t)Q_1 + tQ_2P=(1?t)Q1?+tQ2?
=(1?t)((1?t)P0+tP1)+t((1?t)P1+tP2)=(1-t)((1-t)P_0 + tP_1) + t((1-t)P_1 + tP_2)=(1?t)((1?t)P0?+tP1?)+t((1?t)P1?+tP2?)
=(1?t)2P0+2t(t?1)P1+t2P2=(1-t)^2P_0+2t(t-1)P_1+t^2P_2=(1?t)2P0?+2t(t?1)P1?+t2P2?

二階貝塞爾曲線有兩個端點P0P_0P0?P2P_2P2?),一個控制點P1P_1P1?)。


三階貝塞爾(bezier)曲線

在這里插入圖片描述

經過對一階、二階貝塞爾曲線的研究學習,我們能知道貝塞爾曲線通過在兩點之間再采點的方式實現降階,每一次選點都是一次的降階。

  • P0P_0P0?P1P_1P1?P2P_2P2?P3P_3P3? 通過生成插值點 Q1Q_1Q1?Q2Q_2Q2?Q3Q_3Q3? 來構成二階貝塞爾(綠色線段)
  • 在此基礎上生成插值點 O1O_1O1?O2O_2O2? 來構成一階貝塞爾(藍色線段)
  • 之后以 O1O_1O1?O2O_2O2? 上的插值點 PPP 的運動軌跡來生成三階貝塞爾曲線。

公式推導過程同二階貝塞爾曲線,因此不做贅述,直接貼出公式:

P=(1?t)3P0+3t(1?t)2P1+3t2(1?t)P2+t3P3P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3P=(1?t)3P0?+3t(1?t)2P1?+3t2(1?t)P2?+t3P3?

三階貝塞爾曲線有兩個端點P0P_0P0?P3P_3P3?),兩個控制點P1P_1P1?P2P_2P2?)。


高階貝塞爾(bezier)曲線

  • 四階貝塞爾曲線示意圖:

在這里插入圖片描述

  • 五階貝塞爾曲線示意圖:

在這里插入圖片描述

  • 高階貝塞爾曲線公式:

P(t)=∑i=0nPiBi,n(t),t∈[0,1]P(t)=\sum_{i=0}^{n}P_iB_{i,n}(t),t \in [0,1]P(t)=i=0n?Pi?Bi,n?(t)t[0,1]

Bi,n(t)=Cniti(1?t)n?i=n!i!(n?i)!ti(1?t)n?i,【i=0,1,...,n】B_{i,n}(t)=C_n^it^i(1-t)^{n-i}=\frac{n!}{i!(n-i)!}t^i(1-t)^{n-i},【i=0,1,...,n】Bi,n?(t)=Cni?ti(1?t)n?i=i!(n?i)!n!?ti(1?t)n?i,【i=0,1,...,n


三階貝塞爾曲線求插值(Slerp)

在熟悉了貝塞爾曲線的相關概念之后,我們來了解一下它的具體應用。通常它的應用場景是:

已知兩個端點和兩個控制點的情況下,根據 動畫進度向量 PxP_xPx?ttt,再由 ttt 確認的曲線求 PyP_yPy?

回顧一下三階貝塞爾曲線公式:
P=(1?t)3P0+3t(1?t)2P1+3t2(1?t)P2+t3P3P=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3P=(1?t)3P0?+3t(1?t)2P1?+3t2(1?t)P2?+t3P3?

公式中的 P0P_0P0?P1P_1P1? 等都是二維向量,由兩個一維向量 PxP_xPx?PyP_yPy? 構成。而我們根據 tttPPP,本質上是根據 ttt 來求一個坐標 (x,y)(x,y)(x,y)。因此,可將公式拆解在兩個一維向量上:
y=(1?t)3Py0+3t(1?t)2Py1+3t2(1?t)Py2+t3Py3y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3}y=(1?t)3Py0?+3t(1?t)2Py1?+3t2(1?t)Py2?+t3Py3?

x=(1?t)3Px0+3t(1?t)2Px1+3t2(1?t)Px2+t3Px3x=(1-t)^3P_{x0}+3t(1-t)^2P_{x1}+3t^2(1-t)P_{x2}+t^3P_{x3}x=(1?t)3Px0?+3t(1?t)2Px1?+3t2(1?t)Px2?+t3Px3?

而由于我們在處理動畫時通常起點 P0P_0P0? 和終點 P3P_3P3? 都是可以確定的【P0(0,0)、P3(1,1)P_0(0,0)、P_3(1,1)P0?(0,0)P3?(1,1)】,因此上述公式可以化簡為(以 xxx 舉例,yyy 同理):

x=3t(1?t)2Py1+3t2(1?t)Py2+t3x=3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3x=3t(1?t)2Py1?+3t2(1?t)Py2?+t3

完全展開:
=3Py1t?6Py1t2+3Py1t3+3Py2t2?3Py2t3+t3=3P_{y1}t-6P_{y1}t^2+3P_{y1}t^3+3P_{y2}t^2-3P_{y2}t^3+t^3=3Py1?t?6Py1?t2+3Py1?t3+3Py2?t2?3Py2?t3+t3

提取三次方系數 aaa
a=3Py1?3Py2+1a=3P_{y1}-3P_{y2}+1a=3Py1??3Py2?+1

提取二次方系數 bbb
b=3Py2?6Py1b=3P_{y2}-6P_{y1}b=3Py2??6Py1?

提取一次方系數 ccc
c=3Py1c=3P_{y1}c=3Py1?

將公式簡化為:
x=at3+bt2+ctx=at^3+bt^2+ctx=at3+bt2+ct

移動 xxx,將公式變為一元三次方程:
at3+bt2+ct?x=0at^3+bt^2+ct-x=0at3+bt2+ct?x=0

此時,就可以通過卡爾丹公式根據 xxx 求出來 ttt。之后根據 ttt 可以求得 yyy
y=(1?t)3Py0+3t(1?t)2Py1+3t2(1?t)Py2+t3Py3y=(1-t)^3P_{y0}+3t(1-t)^2P_{y1}+3t^2(1-t)P_{y2}+t^3P_{y3}y=(1?t)3Py0?+3t(1?t)2Py1?+3t2(1?t)Py2?+t3Py3?

代碼實現:

double SlerpWithCubicBazier(double pX1, double pY1, double pX2, double pY2, double x) {// x為動畫進度,并不是t,t只是一個參數,先根據x求t,再由t確認的曲線上求y// 參考 https://github.com/gre/bezier-easing/blob/master/src/index.jsdouble t = 0.0;if (x <= 0.0) {t = 0.0;}else if (x >= 1.0) {t = 1.0;}else {// x = (1-t)^3*P0x + 3*(1-t)^2*t*P1x + 3*(1-t)*t^2*P2x + t^3*P3x// 提取系數:double a = 0.0 + 3 * pX1 - 3 * pX2 + 1.0;double b = 3 * 0.0 - 6 * pX1 + 3 * pX2;double c = 0.0 + 3 * pX1;// 公式可化簡為: x = at^3 + bt^2 + ct// 轉換為基于 t 的一元三次方程:at^3 + bt^2 + ct - x = 0double d = 0 - x;// 那么就可以通過 SolveCubic 函數根據a、b、c、d四個系數來求解一元三次方程的一個實根// 可能該一元三次方程的根不止一個,但不重要,即使有多個根我們也只需要其中之一,且要求這個根是在 0~1 之間的,符合 t 的取值范圍要求,如果沒有根/沒有符合要求的根我們會返回 -1double tTemp = SolveCubic(a, b, c, d);if (tTemp == -1) {return -1;}t = tTemp;}// Gy(t) = P0*(1-t)^3 + 3*P1*t*(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3  t[0,1]// PY0=0.0 PY3=1.0double coef1 = 0.0 * (1.0 - t) * (1.0 - t) * (1.0 - t);double coef2 = pY1 * 3 * t * (1.0 - t) * (1.0 - t);double coef3 = pY2 * 3 * t * t *  (1.0 - t);double coef4 = 1.0 * t * t * t;double gt = coef1 + coef2 + coef3 + coef4;return gt;
}

SolveCubic 函數的具體實現如下,值得注意的是,并不能簡單的將此函數的作用等同于求解一元三次方程,本函數的本質作用是貝塞爾曲線中根據 x 求出 t,這兩者有什么區別呢?舉個具體的例子,下面的代碼第 5 行有這樣的語句:

if (d == 0) return 0;
  • 在 d=0 的情況下,普通一元三次方程是可以繼續求解的;
  • 但是在 SlerpWithCubicBazier 調用 SolveCubic 時,是以 d=0?xd=0-xd=0?x 的形式傳值的,d=0d=0d=0 代表 x=0x=0x=0,此時曲線位于起點,t 的值可以確定,無需通過解方程獲得,即 t=0t=0t=0
double FCPSolveCubic(double a, double b, double c, double d) {/* a=0 視為一元二次方程式 */if (a == 0) return FCPSolveQuadratic(b, c, d);/* d=0表明x=0,則t=0*/if (d == 0) return 0;/* 將三次方的系數變為1,方便后續判別式中的計算,即不用考慮 a^2 這一項了 */b /= a;c /= a;d /= a;/* q和r對應求根公式中的p和q,dis即是求根公式的判別式 △ */double q = (3.0 * c - FCPSquared(b)) / 9.0;double r = (-27.0 * d + b * (9.0 * c - 2.0 * FCPSquared(b))) / 54.0;double disc = FCPCubed(q) + FCPSquared(r);double term1 = b / 3.0;if (disc > 0) {/* 運用卡爾丹公式求得一個實根 */double s = r + sqrtf(disc);s = (s < 0) ? - FCPCubicRoot(-s) : FCPCubicRoot(s);double t = r - sqrtf(disc);t = (t < 0) ? - FCPCubicRoot(-t) : FCPCubicRoot(t);double result = -term1 + s + t;if (result >= 0 && result <= 1) return result;} else if (disc == 0) {double r13 = (r < 0) ? - FCPCubicRoot(-r) : FCPCubicRoot(r);double result = -term1 + 2.0 * r13;if (result >= 0 && result <= 1) return result;result = -(r13 + term1);if (result >= 0 && result <= 1) return result;} else {q = -q;double dum1 = q * q * q;dum1 = acosf(r / sqrtf(dum1));double r13 = 2.0 * sqrtf(q);double result = -term1 + r13 * cos(dum1 / 3.0);if (result >= 0 && result <= 1) return result;result = -term1 + r13 * cos((dum1 + 2.0 * M_PI) / 3.0);if (result >= 0 && result <= 1) return result;result = -term1 + r13 * cos((dum1 + 4.0 * M_PI) / 3.0);if (result >= 0 && result <= 1) return result;}return -1;
}

上面代碼中用到的知識:

  • 一元三次方程判別式:

△=q24+p227△ = \frac{q^2}{4} + \frac{p^2}{27}=4q2?+27p2?

  • 標準型方程中卡爾丹公式的一個實根:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443680.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443680.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443680.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python代碼測試 vim_用 Hypothesis 快速測試你的 Python 代碼

點擊上方“Python編程時光”&#xff0c;選擇“加為星標”第一時間關注Python技術干貨&#xff01;介紹無論你使用哪種編程語言或框架&#xff0c;測試都非常重要。Hypothesis是 Python 的一個高級測試庫。它允許編寫測試用例時參數化&#xff0c;然后生成使測試失敗的簡單易懂…

Mac 下 CMake 的配置與使用

文章目錄安裝與配置編譯單個源文件編譯前的準備開始編譯編譯多個源文件多個源文件在同一目錄下多個源文件在不同目錄下math 目錄下的 CMakeLists.txt根目錄的 CMakeLists.txtoption 選項導入外部庫本地導入&#xff08;find_package&#xff09;外部導入&#xff08;FetchConte…

五軸編程_沙井萬豐數控數控編程五軸編程那個軟件好用

沙井萬豐數控數控編程五軸編程那個軟件好用設計需要掌握很高很全面的知識和技能&#xff0c;模具做的好&#xff0c;產品質量好&#xff0c;模具結構合理&#xff0c;生產效率高&#xff0c;工廠效益好。正因如此&#xff0c;模具技術工在外打工的工資都非常的高。少則每月幾千…

Linux學習:第二章-Linux安裝

一虛擬機使用 VMware主要特點&#xff1a; 1、不需要分區或重新開機就能在同一臺PC上使用兩種以上的操作系統 2、本機系統可以與虛擬機系統網絡通信 3、可以設定并且隨時修改虛擬機操作系統的硬件環境 二安裝方式 圖形安裝&#xff1a;直接回車 字符安裝&#xff1a;linux tex…

keil3如何放大字體_國潮海報不會做?送你國風字體+圖案筆刷+PSD素材+包裝樣機...

有很多朋友都問帶魚&#xff0c;國潮風的海報到底應該怎么做呢&#xff1f;首先你要知道什么是國潮風&#xff1a;國潮風就是現代文化和古代文化的碰撞&#xff0c;是年輕人的態度&#xff01;那么應該如何構圖如何設計呢&#xff1f;如何配色如何搭配字體呢&#xff1f;這些方…

Google 開源項目風格指南學習筆記——C++篇

文章目錄前言0. 縮寫名詞解釋1. 頭文件1.1. Self-contained 頭文件1.2. 頭文件保護1.3. 前置聲明1.4 內聯函數1.5. #include 的路徑及順序2. 作用域2.1. 命名空間2.2. 非成員函數、靜態成員函數和全局函數2.3. 局部變量2.4. 靜態和全局變量3. 類3.1. 構造函數的職責3.2. 隱式類…

hiveserver2啟動不起來_給愛車配個充電寶,70邁汽車應急啟動電源,讓你遠離搭電小廣告...

說到汽車應急啟動其實我有切身的痛&#xff0c;在哈爾濱零下35的嚴冬&#xff0c;晚上帶著女神吃完飯&#xff0c;高高興興地吃完以后一上車&#xff0c;發現電瓶被凍沒電了&#xff0c;天知道當時有多尷尬。馬上叫了保險公司過來給搭電&#xff0c;結果在飯店從晚上8點一直等到…

Windows 下 VS 配置 OpenGL 環境

文章目錄前言獲取 GLFW打開 VS前言 感謝B站同學搬運YouTube上的教學視頻。 獲取 GLFW 從官網上下載GLFW macOS下64位二進制文件 打開 VS 新建解決方案 OpenGL test&#xff0c;并在解決方案中新建文件夾 Dependencies&#xff1a; 從下載好的 glfw 文件夾中找到最新版鏈接…

ubuntu 網卡雙網口 配置_無線網卡m2 ngff keya keye、minipcie接口改轉多口有線網卡實現軟路...

小型主板及筆記本中的無線網卡m2ngffkeyakeye接口&#xff08;CNVI除外&#xff09;通過m2ngffkeyae轉接pcie1x轉接板&#xff0c;或者無線網卡的minipcie接口&#xff0c;通過minipcie轉接pcie1x轉接板可以改裝有線網卡板卡&#xff0c;來實現軟路由功能。m2ngffkeyae轉接pcie…

OpenGL | 通過繪制一個三角形來入門 OpenGL 圖形渲染管線

文章目錄前言什么是 OpenGl &#xff1f;回顧openGL 的 Object顯存結構工作階段通過頂點緩沖對象將頂點數據初始化至緩沖中標準化設備坐標頂點緩沖對象 VBOglGenBuffersglBindBufferglBufferData建立了一個頂點和一個片段著色器著色器是什么&#xff1f;為什么需要使用著色器&a…

javascript特效_如何在網頁添加鼠標點擊特效

經常有同學問我怎么做到的&#xff0c;本論壇屬于DZ當然用的是插件啦。偶然在網上找到一個關于wordpress的特效代碼&#xff0c;分享給大家。WordPress 添加鼠標點擊特效實際上這種教程在網上搜索一下有一大堆&#xff0c;已經是各大博主玩爛的東西了。不過既然給自己的博客加上…

Android |雙鎖單例模式中使用Context如何避免內存泄露的 Warning 提示

文章目錄問題解決方法拓展問題 在Android開發中&#xff0c;經常會將工具類以單例模式的方法實現&#xff0c;而工具類中又總不可避免的用到 Context &#xff0c;例如&#xff1a; public class MySingleton {private static volatile MySingleton instance;private final C…

android nio debug模式正常 release包crash_Flutter包大小治理上的探索與實踐

Flutter作為一種全新的響應式、跨平臺、高性能的移動開發框架&#xff0c;在性能、穩定性和多端體驗一致上都有著較好的表現&#xff0c;自開源以來&#xff0c;已經受到越來越多開發者的喜愛。但是&#xff0c;Flutter的引入往往帶來包體積的增大&#xff0c;給很多研發團隊帶…

Linux學習:第三章-Linux常用命令-1

提示符&#xff1a; [rootlocalhost ~]# [登錄用戶名主機名 當前所在目錄]提示符 ~家目錄 /root /home/aa 提示符&#xff1a; #超級用戶 $普通用戶 一 linux命令的格式1、命令 [選項] [參數]lslist顯示目錄下內容 ①命令名稱&#xff1a;ls 命令英文原意&#xff1a;list 命令…

Leetcode每日一題:使括號有效的最少添加(括號匹配)

文章目錄題目解析貪心趣解題目 只有滿足下面幾點之一&#xff0c;括號字符串才是有效的&#xff1a; 它是一個空字符串&#xff0c;或者它可以被寫成 AB &#xff08;A 與 B 連接&#xff09;, 其中 A 和 B 都是有效字符串&#xff0c;或者它可以被寫作 (A)&#xff0c;其中 …

yolov5搭建環境_Yolov5環境配置和訓練私有數據,YOLOv5,以及,私人

1.使用anaconda安裝python3.8的環境conda create -n yolo5 python3.8#anaconda下載地址: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/2.安裝pytorch1.6 torchvision0.7conda install pytorch1.6 torchvision0.7 cudatoolkit10.13.安裝相關包pip install opencv-py…

sam格式的結構和意義_各種格式的練字本,對寫字真有幫助嗎

圖片來源于筆勢通各種格式的練字本現在越來越多&#xff0c;目的主要是便于學生把握好筆畫的位置和布局&#xff0c;從而把整個字的結構處理好&#xff0c;常見的有米字格&#xff0c;回宮格等。這些練字本對于初學者來說肯定是有幫助的&#xff0c;特別是低年級學生。當然隨著…

硬件結構圖_那曲地表水電子除垢儀結構圖

那曲地表水電子除垢儀結構圖水處理設備也應斷電停止使用&#xff0c;系統長期停止運行或季節性停止運行&#xff0c;在系統停止運行前&#xff0c;在水中投加適量緩蝕劑&#xff0c;并采取滿水濕保護的措施&#xff0c;以減小腐蝕&#xff0c;保護系統。開啟進水閥檢查無誤后電…

dtm文件生成等高線 lisp_南方cass如何用圖面高程點生成等高線

展開全部1、首先點擊cass菜單欄中的等高線菜單下的建立DTM&#xff0c;彈出對話框。可以有兩種方式建32313133353236313431303231363533e58685e5aeb931333431356665立DTM&#xff0c;由數據文件生成或者由圖面高程點生成&#xff0c;第一種直接在對話框中選擇相應的數據文件&am…

postgresql興建用戶_PostgreSQL 12.2, 11.7, 10.12, 9.6.17, 9.5.21, 和 9.

### **譯者&#xff1a;朱君鵬**### **發表于2020年2月13日 作者&#xff1a;PostgreSQL全球開發小組**#### 全球開發小組已發布的更新涵蓋所有支持的版本&#xff0c;包括12.2&#xff0c;11.7&#xff0c;10.12&#xff0c;9.6.17&#xff0c;9.5.21和9.4.26。該版本修正了一…