Skia---漸變色著色器

今天介紹的是實際工作中最常用到的著色器:漸變色著色器。

漸變色著色器是一個從一種顏色平滑的過渡到另一種顏色的效果,漸變色著色器的作用主要是增強圖形的視覺吸引力。

線性漸變

Skia 里的線性漸變色著色器是最簡單的漸變色著色器,它用于在 2D 圖形中創建從一點到另一點平滑過渡的顏色效果。它通過在起點和終點之間進行線性插值,實現了兩種或多種顏色之間的平滑漸變。

現在來看一下如何使用線性漸變色著色器來繪制窗口背景,如下代碼所示:

// #include "include/effects/SkGradientShader.h"void drawLinearGradientColor(SkCanvas *canvas)
{SkPaint paint;paint.setAntiAlias(true);SkPoint pts[2]{SkPoint::Make(0, 0), SkPoint::Make(w, h)};SkColor colors[6]{ 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00,0xFF0000FF,0xFF00FF00,0xFFFF0000 };sk_sp<SkShader> shader = SkGradientShader::MakeLinear(pts, colors, nullptr, 6, SkTileMode::kClamp);paint.setShader(shader);canvas->drawPaint(paint);//用線性漸變色繪制圓形//auto x = w / 2;//auto y = h / 2;//auto r = std::min(x - 60, y - 60);//canvas->drawCircle(x, y, r, paint);//用線性漸變色繪制路徑//paint.setStroke(true);//paint.setStrokeWidth(16);//paint.setStrokeJoin(SkPaint::kRound_Join);//SkPath path;//path.moveTo(60, 120);//path.lineTo(180, 60);//path.lineTo(w - 60, 120);//path.lineTo(w - 160, h - 160);//path.lineTo(180, h - 60);//path.close();//canvas->drawPath(path, paint);
}

在這段代碼中使用?SkGradientShader?類型的靜態方法?MakeLinear?創建了一個線性漸變著色器。

MakeLinear?方法的第一個參數是一個只有兩個?SkPoint?元素的數組,數組內存儲的兩個點為線性漸變的起點終點

第二個參數是一個顏色數組,這個數組中存儲的顏色將被分布在線性漸變的起點和終點之間。

第三個參數為一個?SkPoint?數組,這個數組用于控制各個顏色的位置,如果不傳遞這個參數(nullptr),那么顏色將被均勻分布。

第四個參數為第二個數組參數和第三個數組參數的元素數量。

第五個參數?SkTileMode::kClamp?表示如果著色器在起點和終點之外繪制,則超出的區域使用?colors?首尾兩端的顏色進行繪制。

除此之外?SkTileMode?還有一些其他的枚舉項,這里就不一一介紹了。

MakeLinear方法返回一個?SkShader?類型的對象,這個對象可以被設置到?SkPaint?對象中。

SkPaint設置了shader之后,它設置的Color就不再生效,SkPaint優先使用shader

程序運行后的結果如下圖所示:

由于漸變色是在 SkPaint 對象設置的,可以用來繪制任何幾何圖形,

注釋的代碼就是使用這個漸變色繪制圓形和路徑的示例代碼,運行結果如下圖所示:

線性漸變2.png

?

素材:WebGradients?是一個提供了180個線性漸變色的免費網站。?

徑向漸變

徑向漸變允許顏色從中心點向四周以圓形擴散,繪制徑向漸變顏色與繪制線性漸變顏色非常相似,代碼如下所示:

void drawRadialGradientColor(SkCanvas *canvas)
{SkPaint paint;paint.setAntiAlias(true);SkColor colors[6]{ 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00,0xFF0000FF,0xFF00FF00,0xFFFF0000 };auto x = w / 2;auto y = h / 2;auto r = std::min(x - 10, y - 10);auto shader = SkGradientShader::MakeRadial(SkPoint::Make(x, y), r, colors, nullptr, 6, SkTileMode::kClamp);paint.setShader(shader);canvas->drawPaint(paint);
}

使用SkGradientShader類型的MakeRadial方法創建徑向漸變,

這個方法的第一個參數是徑向漸變的圓心,第二個參數是徑向漸變的半徑,其他參數與線性漸變SkGradientShader::MakeLinear方法相同。

程序運行后的結果如下圖所示:

徑向漸變.png

從上圖中可以看出,窗口邊緣的顏色為紅色,這是因為設置了SkTileMode::kClamp,所以超出的區域使用colors數組首尾兩端的顏色進行繪制。

錐形漸變

錐型漸變允許顏色從一個中心點向四周以錐形的方式擴散漸變,這種漸變色常用于繪制光暈或放射效果。如下代碼所示:

void drawConicalGradientColor(SkCanvas* canvas)
{SkPaint paint;auto x = w / 2;auto y = h / 2;SkColor colors[6]{ 0xFF00FFFF, 0xFFFFFF66, 0xFFFF00FF, 0xFF66FFFF, 0xFFFFFF00, 0xFFFF66FF };auto shader = SkGradientShader::MakeTwoPointConical(SkPoint::Make(x, y), y, SkPoint::Make(x, 60.0f), 20.0f,colors, nullptr, 6, SkTileMode::kClamp);paint.setShader(shader);canvas->drawPaint(paint);
}

SkGradientShader::MakeTwoPointConical方法負責創建一個錐型漸變。這個方法接收兩個圓作為參數。

第一個參數為第一個圓的圓心,第二個參數為第一個圓的半徑。

第二個參數為第二個圓的圓心,第三個參數為第二個圓的半徑,其他參數與制作線性漸變顏色相同。

程序運行結果如下圖所示:

錐型漸變.png

旋轉漸變

旋轉漸變把一系列顏色平均分布到360°的角度范圍內(默認情況下以0°開始,以360°結束),如下代碼所示:

void drawSweepGradientColor(SkCanvas* canvas)
{SkPaint paint;auto x = w / 2;auto y = h / 2;SkColor colors[7]{ 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00,0xFF0000FF,0xFF00FF00,0xFFFF0000,0xFF00FFFF };auto shader = SkGradientShader::MakeSweep(x, y, colors, nullptr, 7, 0, nullptr);paint.setShader(shader);canvas->drawPaint(paint);
}

SkGradientShader::MakeSweep方法負責創建旋轉漸變。

此方法前兩個參數為旋轉漸變的圓心,其他參數與制作線性漸變色相同。

為了讓開始顏色和結束顏色更平滑的過度,我把開始顏色和結束顏色設置成了同一個顏色。

?

程序運行結果如下圖所示:

旋轉漸變.png

綜合示例:繪制圓柱體

Skia里的幾何圖形、路徑、顏色和漸變色著色器,運用這些知識繪制一個圓柱體,如下代碼所示:

void drawCylinder(SkCanvas* canvas) {int bodyW{ 160 }, top{60};int x1{ w / 2 - bodyW / 2 }, x2{ w / 2 + bodyW / 2 };SkPath path;SkRect rect;rect.setXYWH(x1, h - 80, bodyW, 40);path.arcTo(rect, 0, 180,true);path.lineTo(x1, top+20);path.lineTo(x2, top+20);path.close();SkPaint paint;paint.setAntiAlias(true);SkPoint pts[2]{ SkPoint::Make(x1, top), SkPoint::Make(x2, top) };SkColor colors[2]{ 0xFF287191, 0xFF85B5CB };sk_sp<SkShader> shader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);paint.setShader(shader);canvas->drawPath(path, paint);rect.setXYWH(x1, top, bodyW, 40);colors[0] = 0xffBDE4F8;colors[1] = 0xffA7CFE6;pts[0] = SkPoint::Make(x1, top + 40);pts[1] = SkPoint::Make(x2, top);shader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);paint.setShader(shader);canvas->drawOval(rect, paint);    
}

在這段代碼中,分兩個步驟來繪制這個圓柱體:

  1. 使用路徑繪制圓柱體的?Body

圓柱體的Body是由一個圓弧和一部分矩形組成的,繪制這個路徑時,使用了一個從左到右的線性漸變色,左側顏色較深,右側顏色較淺。

這個路徑繪制完成之后,得到的結果如下圖所示:

圓柱體0.png

  1. 2,使用橢圓繪制圓柱體的頂面

圓柱體的頂面是一個橢圓,橢圓的橫向中軸線就是圓柱體的Body的頂邊。

同樣也是使用一個線性漸變色繪制這個橢圓,橢圓的左下角顏色較淺,右上角顏色較深。

橢圓繪制完成之后,圓柱體的Body的頂邊就被這個橢圓蓋住了。

最終的繪制結果如下圖所示:

圓柱體.png

在這個示例中,我們使用 2D 圖形繪圖知識繪制了一個 3D 圖形。

要知道無論是 2D 圖形引擎還是 3D 圖形引擎,最終都是在處理像素,交付給客戶的也都是二維平面像素數據(你的顯示器只能承載二維平面像素數據)。3D 圖形只不過看起來是立體的而已。

所以,2D 圖形引擎可以畫 3D 圖形,3D 圖形引擎也可以畫 2D 圖形,只不過這兩個圖形引擎的內部實現原理大相徑庭。

綜合示例:繪制圓錐體

稍稍改動一下圓柱體的繪制代碼,就可以繪制圓錐體了,如下代碼所示:

void drawCone(SkCanvas* canvas) {int bodyW{ 160 }, top{ 60 };int x1{ w / 2 - bodyW / 2 }, x2{ w / 2 + bodyW / 2 };SkPath path;SkRect rect;rect.setXYWH(x1, h - 80, bodyW, 40);path.arcTo(rect, 0, 180, true);path.lineTo(x1+bodyW/2, top + 20);path.close();SkPaint paint;paint.setAntiAlias(true);SkColor colors[2]{ 0xFF00FF00, 0xFF000000 };auto shader = SkGradientShader::MakeSweep(w/2, top + 20, colors, nullptr,2,SkTileMode::kClamp, 50.0, 130.0, 0,nullptr);paint.setShader(shader);canvas->drawPath(path, paint);
}

?

這段代碼去除了圓柱體的頂面和圓柱體 Body 的頂邊,在繪制路徑時,使用了旋轉漸變顏色。

旋轉漸變的起始角度為 50 度,結束角度為 130 度,順時針從綠色漸變到黑色。

這兩個角度之差大于圓錐頂角值,超出圓錐(扇形)表面的顏色將不會被繪制到窗口中。

程序運行后,繪制結果如下圖所示:

圓錐.png

?

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

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

相關文章

2025.07.09華為機考真題解析-第二題200分

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍OJ 02. 地鐵線路故障預警系統 問題描述 LYA 負責管理一個城市的地鐵網絡系統。地鐵網絡由 n n n

數學建模:非線性規劃:凸規劃問題

一、定義凸集定義??&#xff1a;設Ω是n維歐氏空間的一點集&#xff0c;若任意兩點x?∈Ω&#xff0c;x?∈Ω&#xff0c;其連線上的所有點αx?(1-α)x?∈Ω&#xff0c;(0≤α≤1)&#xff0c;則稱Ω為凸集。??凸函數定義??&#xff1a;給定函數f(x)(x∈D?R?)&…

ISIS | 廣播網絡中的 ISIS 偽節點 LSP

注&#xff1a;本文為 “ISIS | 偽節點 LSP” 相關合輯。 英文引文&#xff0c;機翻未校。 中文引文&#xff0c;略作重排。 如有內容異常&#xff0c;請看原文。 ISIS in Broadcast Network and Pseudonode LSP 廣播網絡中 的 ISIS 偽節點 LSP ISIS in broadcast network is…

ARIA UWB安全雷達主要產品型號與核心功能全解析

ARIA UWB雷達擁有LT系列與AHM系列兩大產品線。LT103 XBT、LT102 V2、LT103 OEM等代表型號具備高精度定位、低功耗和強穿透能力&#xff0c;適用于工業自動化與物聯網。AHM3D、AHM2D、AHM3DSC則專注三維檢測和智能計算&#xff0c;廣泛服務于醫療健康、安防監控等場景。Hydrogen…

NLP自然語言處理04 transformer架構模擬實現

總體架構輸入部分代碼實現:導包# -*-coding:utf-8-*- import matplotlib.pyplot as plt import numpy as np import torch import torch.nn as nn # -*-coding:utf-8-*- import copy import torch.nn.functional as F import math位置編碼器部分詞嵌入WordEmbedding# todo 作用…

記錄一本書: Python機器學習:基于PyTorch和Scikit-Learn

記錄一本書&#xff1a; Python機器學習&#xff1a;基于PyTorch和Scikit-Learn 作者&#xff1a;&#xff08;美&#xff09;塞巴斯蒂安拉施卡(Sebastian Raschka)&#xff08;美&#xff09;劉玉溪&#xff08;海登&#xff09;(Yuxi(Hayden)Liu) &#xff08;美&#xff09;…

Datomic數據庫簡介(TBC)

Datomic 數據庫詳細介紹 Datomic 是一個由 Rich Hickey&#xff08;Clojure 語言創始人&#xff09;設計的 不可變、時間感知、分布式數據庫&#xff0c;專為現代應用程序設計&#xff0c;強調 數據不變性&#xff08;immutability&#xff09;、查詢靈活性和可審計性。它結合…

xformers 完整安裝教程【pip conda】(解決 conda 版本 pytorch 自適應安裝 xformers)

我個人喜歡用 mamba&#xff08;conda&#xff09;創建環境&#xff0c;然后用 mamba 安裝 pytorch CUDA&#xff08;如果需要使用 CUDA 編譯&#xff09;&#xff0c;還有一些比如 gcc/g 等與 python 無關的一些工具。 但是最近我在擴充環境的時候&#xff0c;發現需要額外安…

VM虛擬機全版本網盤+免費本地網絡穿透端口映射實時同步動態家庭IP教程

VM虛擬機全版本秘鑰&#xff0c;文章末尾。 首先網絡穿透的意義是讓公網可以直接訪問家庭電腦&#xff0c;這樣本地電腦的硬件性能得以完全發揮&#xff0c;特別是在云服務器貴性能又沒家庭電腦好&#xff0c;專線寬帶又貴&#xff0c;第三方網絡穿透貴的場景下。一般第三方網…

C++ - 仿 RabbitMQ 實現消息隊列--項目介紹與環境搭建

目錄 項目介紹 開發環境 技術選型 環境搭建 安裝 wget(一般情況下默認會自帶) 更換國內軟件源 安裝 lrzsz 傳輸工具 安裝編譯器 安裝項目構建工具 make 安裝調試器 安裝 git 安裝 cmake 安裝 Protobuf 安裝 Muduo 安裝 SQLite3 安裝 Gtest 項目介紹 首先說一下…

《目標檢測模塊實踐手冊:從原理到落地的嘗試與分享》第一期

大家好&#xff0c;歡迎來到《目標檢測模塊實踐手冊》系列的第一篇。從今天開始&#xff0c;我想以一種 “實踐記錄者” 的身份&#xff0c;和大家聊聊在目標檢測任務中那些形形色色的模塊。這些內容沒有權威結論&#xff0c;更多的是我在實際操作中的一些嘗試、發現和踩過的坑…

C++11笑傳之引用

C11前言列表初始化{}進行初始化initializer_list右值引用和移動語義左值與右值左值引用與右值引用引用延長生命周期右值引用和移動語義的使用場景左值引用移動構造和移動賦值右值引用在容器插入的提效引用折疊萬能折疊完美轉發前言 C11是C繼98后的更新&#xff0c;其更新了許多…

瀚高數據庫提交數據后,是否需要COMMIT(APP)

文章目錄環境癥狀問題原因解決方案報錯編碼環境 系統平臺&#xff1a; 版本&#xff1a;5.6.5,4.5 癥狀 瀚高數據庫提交數據后&#xff0c;是否需要commit&#xff0c;瀚高數據庫是否有配置項。 問題原因 瀚高數據庫默認自動COMMIT&#xff08;提交數據&#xff09;&#…

深大計算機游戲開發實驗三

主要步驟主角飛船的創建和移動邊界設置以及護盾設置創建敵機自動生成敵機圖層設置彈丸設置武器創建不同發射模式管理競態條件擊敗敵機掉落升級道具不同敵機的生成分值顯示實現退出游戲界面之后進入游戲的最高記錄重置游戲界面失敗后重新加載最記錄不會重置任何時候在游戲界面按…

詳解緩存淘汰策略:LRU

文章目錄緩存淘汰策略LRU核心結構核心操作流程局限性源碼走讀AddGet緩存淘汰策略 緩存淘汰策略的存在是為了解決 緩存容量有限性 和 高緩存命中率 之間的矛盾。其核心目標是在有限的緩存空間內&#xff0c;盡可能提高緩存命中率 緩存容量有限性&#xff1a;緩存&#xff08;例…

什么是 Bootloader?怎么把它移植到 STM32 上?

一、Bootloader 是啥&#xff1f;它都干了些啥&#xff1f;想象一下你的 MCU&#xff08;比如 STM32&#xff09;是一個小機器人&#xff0c;上電之后第一件事&#xff0c;它不會立馬開始“干正事”&#xff08;運行你的主程序&#xff09;&#xff0c;而是先去運行一個“開場引…

無人機避障——感知篇(Ego_Planner_v2中的滾動窗口實現動態實時感知建圖grid_map ROS節點理解與參數調整影響)

處理器&#xff1a;Orin nx 雙目視覺傳感器&#xff1a;ZED2 實時感知建圖方法&#xff1a;Vins Fusion Raycast &#xff08;VIO與射線投影法感知定位加建圖方法&#xff09; 項目地址&#xff1a;https://github.com/ZJU-FAST-Lab/EGO-Planner-v2 【注意】&#xff1a;建…

26-計組-尋址方式

指令尋址與PC自增一、指令尋址方式定義&#xff1a;尋找下一條將要執行的指令地址的過程。 核心部件&#xff1a;程序計數器&#xff08;PC&#xff09;&#xff0c;用于指示待執行指令的地址。 執行流程&#xff1a;CPU根據PC值從主存取指令。取指后&#xff0c;PC自動自增&am…

生成式對抗網絡(GAN)模型原理概述

生成對抗網絡&#xff08;Generative Adversarial Network, GAN&#xff09;是一種通過對抗訓練生成數據的深度學習模型&#xff0c;由生成器&#xff08;Generator&#xff09;和判別器&#xff08;Discriminator&#xff09;兩部分組成&#xff0c;其核心思想源于博弈論中的零…

Vue和Element的使用

文章目錄1.vue 腳手架創建步驟2.vue項目開發流程3.vue路由4.Element1.vue 腳手架創建步驟 創建一個文件夾 vue雙擊進入文件夾,在路徑上輸入cmd輸入vue ui, 目的:調出圖形化用戶界面點擊創建 9. 10.在vscode中打開 主要目錄介紹 src目錄介紹 vue項目啟動 圖形化界面中沒有npm…