成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

在iOS中使用OpenGL ES實現繪畫板的方法

瀏覽:5日期:2022-09-17 10:50:38

今天我們使用 OpenGL ES 來實現一個繪畫板,主要介紹在 OpenGL ES 中繪制平滑曲線的實現方案。

首先看一下最終效果:

在iOS中使用OpenGL ES實現繪畫板的方法

在 iOS 中,有很多種方式可以實現一個繪畫板,比如我的另外一個項目 MFPaintView 就是基于 CoreGraphics 實現的。

然而,使用 OpenGL ES 來實現可以獲得更多的靈活性,比如我們可以自定義筆觸的形狀,這是其他實現方式做不到的。

我們知道,OpenGL ES 中只有 點、直線、三角形 這三種圖元。因此, 怎么在 OpenGL ES 中繪制曲線 ,是我們第一個要解決的問題,也是最復雜的問題。

我們會使用比較大的篇幅來講解這個問題。至于繪畫板的其他功能實現,并不是說不重要,只是說其他的繪畫板實現方式,也會有類似的邏輯,所以這部分會放在最后再簡單介紹一下。

一、怎么繪制曲線

在 OpenGL ES 中繪制曲線的方式,就是 將曲線拆分成點序列來繪制

因為要繪制點,所以我們采取的是 點圖元 。即我們要把頂點數據當成 來繪制,并且每個點都要繪制出筆觸的紋理。關鍵步驟如下:

指定圖元類型:

glDrawArrays(GL_POINTS, 0, self.vertexCount);

頂點著色器:

attribute vec4 Position;uniform float Size;void main (void) { gl_Position = Position; gl_PointSize = Size;}

片段著色器:

precision highp float;uniform float R;uniform float G;uniform float B;uniform float A;uniform sampler2D Texture;void main (void) { vec4 mask = texture2D(Texture, vec2(gl_PointCoord.x, 1.0 - gl_PointCoord.y)); gl_FragColor = A * vec4(R, G, B, 1.0) * mask;}

這里的關鍵點在于 gl_PointCoord 這個內置變量,當我們使用點圖元的時候,可以通過這個變量獲取到 當前像素在點圖元中的歸一化坐標

但是這個坐標的原點是在左上角,這和紋理坐標在豎直方向上是相反的。所以從紋理讀取顏色的時候,要做一個 y 坐標的轉換。

接下來,我們通過 UITouch 來獲取觸摸點的位置,然后算出歸一化的頂點坐標。

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; [self addPointWithTouches:touches];}

但是由于 iOS 系統觸摸事件的派發頻率有限,我們最終得到的只能是稀疏的點。如下圖所示,每個觸摸點之間的間隔會比較大。

在iOS中使用OpenGL ES實現繪畫板的方法

二、怎么繪制密集的點

很容易想到,只需要在兩個點之間,按照一定的密度進行插值,就可以繪制出連續的軌跡。

在iOS中使用OpenGL ES實現繪畫板的方法

但是很明顯,我們的繪制結果是折線,并不平滑。

三、怎么使曲線變平滑

解決點連接不平滑的問題,一般是使用貝塞爾曲線。這種方案在 MFPaintView 中也得到了很好的應用。

具體的做法是使用 兩個頂點間的中點一個頂點 ,來構造一條貝塞爾曲線。如下圖,圖中的 3 個 紅點 被用來構造一條貝塞爾曲線。

在iOS中使用OpenGL ES實現繪畫板的方法

于是,我們的問題就變成了 怎么在 OpenGL ES 中繪制貝塞爾曲線 。相當于已知貝塞爾曲線的 3 個關鍵點,反向來求曲線上的點序列。

我們知道貝塞爾曲線的方程是 P = (1 - t)^2 * P0 + 2 * t * (1 - t) * P1 + t^2 * P2 , t 是唯一的變量,其取值范圍是 0 ~ 1 。

所以我們可以采取線性取值的方式,每一條貝塞爾曲線取 n 個點( n 是個確定的常量)。只要依次往方程中代入 1 / n 、 2 / n 、 ... n / n ,就可以得到一個點序列。

在iOS中使用OpenGL ES實現繪畫板的方法

先將 n 取一個比較小的值,這樣比較容易看出存在的問題。我們發現, 點序列的間隔并不均勻 。原因有兩個:

不同貝塞爾曲線的長度不一樣,使用同一個 n 值,算出來的點的疏密程度肯定不同。 由于貝塞爾曲線隨著 t 增長,曲線長度的增長并不是線性的。按照我們上面的算法,最終會得到的結果是 兩頭比較稀疏,中間比較密集

四、怎么生成均勻的點序列

貝塞爾曲線生成均勻的點序列,涉及到了一個經典的「貝塞爾曲線勻速運動」問題。

這個問題的推導和計算比較復雜。如果你有興趣,可以閱讀一下文末的兩篇文章。由于我還不能完全領悟,就不在這里誤導大家了。

簡單來說,就是我們通過一系列的騷操作,封裝了一個方法,只需要傳入貝塞爾曲線的 3 個關鍵點和筆觸尺寸,就可以獲取均勻的點序列。

+ (NSArray <NSValue *>*)pointsWithFrom:(CGPoint)from to:(CGPoint)tocontrol:(CGPoint)control pointSize:(CGFloat)pointSize;

下面我們固定貝塞爾曲線的 起始點控制點 ,只移動 終止點 ,來驗證一下這個方法是否可靠。

在iOS中使用OpenGL ES實現繪畫板的方法

可以看到,在移動過程中,點和點的距離基本是保持一致的,并且是均勻的。通過這個「神奇」的方法,我們終于畫出了平滑且均勻的曲線。

在iOS中使用OpenGL ES實現繪畫板的方法

五、繪畫板功能實現

終于講完了最麻煩的部分,接下來簡單介紹一下繪畫板基本功能的實現。

1、顏色混合

在以往的例子中,我們在開始一次渲染之前,都會調用 glClear(GL_COLOR_BUFFER_BIT) 來清除畫布,因為我們不希望保留上次的渲染結果。

但是對于一個繪畫板來說,我們要不斷地往畫布上畫東西,所以是希望保留上次結果的。因此,在繪制之前不能執行清除的操作。

另外,由于我們的畫筆可能是半透明的,所以新繪制的顏色需要和畫布上已經存在的顏色進行混合。因此在繪制開始之前,需要開啟混合選項。

glEnable(GL_BLEND);glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

2、筆觸調整

筆觸有 3 個屬性可以調整: 顏色、尺寸、形狀 。它們本質上都是對點圖元的調整,通過 uniform 變量的形式,將顏色、尺寸、紋理傳入著色器并應用。

3、橡皮擦

GLPaintView 在初始化的時候,需要傳入一個背景色參數,當用戶切換到橡皮擦功能的時候,內部只是單純地將畫筆的顏色切換成背景色,于是就產生了橡皮擦的效果。

4、撤銷重做

撤銷重做功能需要依賴兩個棧來實現。我們把用戶的手指從 按下屏幕到離開屏幕 這一過程中產生的數據,定義為一個操作對象,這個操作對象保存了歸一化后的點序列,以及點的屬性。

@interface MFPaintModel : NSObject/// 筆刷尺寸@property (nonatomic, assign) CGFloat brushSize;/// 筆刷顏色@property (nonatomic, strong) UIColor *brushColor;/// 筆刷模式@property (nonatomic, assign) GLPaintViewBrushMode brushMode;/// 筆觸紋理圖片文件名@property (nonatomic, copy) NSString *brushImageName;/// 點序列@property (nonatomic, copy) NSArray<NSValue *> *points;@end

撤銷重做的代碼實現大概像這樣子:

- (void)undo { if ([self.operationStack isEmpty]) { return; } MFPaintModel *model = self.operationStack.topModel; [self.operationStack popModel]; [self.undoOperationStack pushModel:model]; [self reDraw];}- (void)redo { if ([self.undoOperationStack isEmpty]) { return; } MFPaintModel *model = self.undoOperationStack.topModel; [self.undoOperationStack popModel]; [self.operationStack pushModel:model]; [self drawModel:model];}

需要注意的是,由于 撤銷操作 需要先清除畫布,所以每次都需要重繪。而 重做操作 可以利用上次繪制的結果,所以每次只需要繪制一個步驟即可。

源碼

請到 GitHub 上查看完整代碼。

到此這篇關于在iOS中使用OpenGL ES實現繪畫板的方法的文章就介紹到這了,更多相關iOS 繪畫板內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: IOS
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
小嫩嫩精品导航| 免费欧美在线视频| 亚洲人妖av一区二区| 成人国产亚洲欧美成人综合网| 欧美日韩一级黄| 麻豆精品国产91久久久久久| 久久一区二区三区超碰国产精品| 亚洲国产精品一区二区尤物区| 好吊色欧美一区二区三区视频| 久久影院视频免费| 成人avav在线| 精品国产污网站| 成人黄色综合网站| 日韩欧美国产精品一区| 成人午夜电影小说| 欧美成人综合网站| 国产福利一区二区三区视频 | 国产白丝精品91爽爽久久 | 亚洲欧洲日本国产| 欧美理论电影在线| 亚洲观看高清完整版在线观看| 欧美日韩综合网| 久久亚区不卡日本| 国产在线视频精品一区| 日本电影亚洲天堂一区| 午夜电影网一区| 狠狠色狠狠色综合日日tαg| 久久久久88色偷偷免费| 成人免费黄色在线| 欧美日韩久久久一区| 亚洲一卡二卡三卡四卡| 欧美日本亚洲韩国国产| xfplay精品久久| 国产成人综合自拍| 国产精品亚洲不卡a| 久久综合久色欧美综合狠狠| 国产综合久久久久久鬼色| 91黄色激情网站| 亚洲电影你懂得| 亚洲精品男同| |精品福利一区二区三区| 成人av资源网站| 日韩亚洲电影在线| 丰满少妇久久久久久久| 在线播放国产精品二区一二区四区| 免费在线观看成人| 欧美综合久久久| 免费在线成人网| 色综合久久久久综合体桃花网| 亚洲第一久久影院| 免费日韩精品中文字幕视频在线| 亚洲精品菠萝久久久久久久| 亚洲激情欧美| 亚洲另类中文字| 亚洲三级影院| 国产精品免费视频一区| 女女同性女同一区二区三区91| 精品久久五月天| 欧美在线日韩| 国产精品久久777777| 亚洲精品看片| 亚洲成人激情av| 久久久久看片| 免费在线观看日韩欧美| 欧美色成人综合| 久久电影网站中文字幕 | 色婷婷亚洲精品| 毛片不卡一区二区| 欧美一级夜夜爽| 成人永久aaa| 精品久久久久久亚洲综合网 | 久久99精品国产91久久来源| 在线国产亚洲欧美| 国产裸体歌舞团一区二区| 日韩免费视频一区| 欧美午夜一区| 夜夜嗨av一区二区三区中文字幕| 久久久久久久久久久一区| 男女男精品网站| 欧美一区二区不卡视频| 99久久er热在这里只有精品15| 中文天堂在线一区| 亚洲激情国产| 五月婷婷综合激情| 欧美日韩中文一区| 粉嫩高潮美女一区二区三区| 久久欧美一区二区| 亚洲国产午夜| 看片的网站亚洲| 精品动漫一区二区三区在线观看 | 一区二区精品在线观看| 亚洲二区在线视频| 欧美日韩电影一区| 午夜久久99| 亚洲一本大道在线| 欧美另类变人与禽xxxxx| 96av麻豆蜜桃一区二区| 亚洲裸体在线观看| 欧美伊人精品成人久久综合97| 国产aⅴ综合色| 国产精品区一区二区三| 免费在线观看一区二区| 国产成人高清视频| 亚洲免费在线播放| 欧美色图一区二区三区| 99精品久久免费看蜜臀剧情介绍| 综合久久国产九一剧情麻豆| 欧洲中文字幕精品| 欧美在线91| 天堂久久一区二区三区| 精品区一区二区| 一本不卡影院| 久久精品国产亚洲高清剧情介绍| 日韩欧美成人激情| 亚洲成人在线| 久久国产精品99久久人人澡| 国产欧美视频一区二区| 麻豆av福利av久久av| 国产一区二区三区免费| 精品国产99国产精品| 一本一本久久a久久精品综合妖精| 久久精品国产久精国产| 国产欧美精品国产国产专区| 久久久久国产精品一区二区| 成人动漫视频在线| 亚洲网友自拍偷拍| 91.com视频| 欧美视频亚洲视频| 国产91精品一区二区麻豆网站| 国产精品久久久久一区二区三区| 一本色道久久加勒比精品| 亚洲成av人片一区二区三区| 精品国内二区三区| 国产亚洲激情| 大胆亚洲人体视频| 亚洲国产欧美日韩另类综合| 精品日韩99亚洲| 久久亚洲免费| 欧美搞黄网站| 韩国v欧美v日本v亚洲v| 亚洲免费观看在线视频| 日韩欧美精品三级| 亚洲一区久久| 91猫先生在线| 精品亚洲免费视频| 亚洲免费在线观看视频| 26uuu精品一区二区在线观看| 色成人在线视频| 国产一区视频观看| 韩国女主播一区二区三区| 伊人色综合久久天天人手人婷| 日韩精品一区二区三区四区| 色一区在线观看| 亚洲二区免费| jiyouzz国产精品久久| 亚洲成人1区2区| 中文字幕一区二区三区蜜月| 69堂成人精品免费视频| 蜜桃视频一区| 国产自产精品| 国产91丝袜在线观看| 麻豆视频一区二区| 亚洲综合色丁香婷婷六月图片| 久久亚洲私人国产精品va媚药| 亚洲欧美清纯在线制服| 欧美精品一区二区三区在线看午夜| 裸体一区二区三区| 一卡二卡三卡日韩欧美| 精品国产1区2区3区| 欧美日韩国产免费一区二区| 亚洲欧美日韩在线综合| 狠狠色狠狠色综合日日tαg| 国产福利91精品| 日本欧美一区二区| 亚洲综合丁香婷婷六月香| 国产精品沙发午睡系列990531| 欧美大片在线观看| 欧美三级电影在线看| 久久久999| 亚洲免费一区二区| 亚洲精品无人区| 国产主播一区| 色综合咪咪久久| 久久99精品一区二区三区三区| 亚洲一区二区在线免费观看视频| 国产精品毛片高清在线完整版 | 国产成人亚洲综合a∨猫咪| 日韩avvvv在线播放| 亚洲综合精品自拍| 亚洲嫩草精品久久| 国产精品美女久久久久久久| 国产欧美日韩精品一区| 精品国产欧美一区二区| 日韩欧美一级精品久久| 欧美日韩免费一区二区三区| 91官网在线免费观看| 色一情一伦一子一伦一区| 午夜在线视频观看日韩17c| 国产日韩久久| 99xxxx成人网|