DelphiX 提供 DrawAdd(加色/正片疊底)與 DrawSub(減色/減去)兩種進階混合模式,廣泛應用於遊戲特效、UI 高亮、陰影投射等場景。本文通過雙圖層疊加範例,直觀展示兩種模式的視覺差異與數學原理。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DXDraws, StdCtrls, DXClass;
type
TForm1 = class(TForm)
DXDraw1: TDXDraw;
DXImageList1: TDXImageList;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
pic1, pic2: TPictureCollectionItem; // pic1=背景, pic2=前景
procedure TForm1.FormCreate(Sender: TObject);
const
ImgPath1 = 'C:\Temp\Back.jpg'; // 背景圖 (大尺寸)
ImgPath2 = 'C:\Temp\DelphiX.bmp'; // 前景圖 (含透明區域)
begin
DXImageList1.DXDraw := DXDraw1;
// 載入背景圖
pic1 := TPictureCollectionItem(DXImageList1.Items.Add);
pic1.Picture.LoadFromFile(ImgPath1);
// 載入前景圖
pic2 := TPictureCollectionItem(DXImageList1.Items.Add);
pic2.Picture.LoadFromFile(ImgPath2);
Button1.Caption := 'DrawAdd (加色/發光)';
Button2.Caption := 'DrawSub (減色/陰影)';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
r: TRect;
begin
// 計算前景圖居中底部位置
r := Bounds(
(DXDraw1.Width - pic2.Width) div 2,
(DXDraw1.Height - pic2.Height), // 底部對齊
pic2.Width,
pic2.Height
);
DXDraw1.Surface.Fill(0); // 清空背景
// 1. 先繪製背景圖 (拉伸填滿)
pic1.StretchDraw(DXDraw1.Surface, DXDraw1.ClientRect, 0);
// 2. 再用 DrawAdd 繪製前景圖 (加色混合)
pic2.DrawAdd(DXDraw1.Surface, r, 0);
DXDraw1.Flip;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
r: TRect;
begin
r := Bounds(
(DXDraw1.Width - pic2.Width) div 2,
(DXDraw1.Height - pic2.Height),
pic2.Width,
pic2.Height
);
DXDraw1.Surface.Fill(0);
// 1. 繪製背景
pic1.StretchDraw(DXDraw1.Surface, DXDraw1.ClientRect, 0);
// 2. 用 DrawSub 繪製前景 (減色混合)
pic2.DrawSub(DXDraw1.Surface, r, 0);
DXDraw1.Flip;
end;
end.
// 每個顏色通道獨立計算
Result.R = Min(Src.R + Dest.R, 255);
Result.G = Min(Src.G + Dest.G, 255);
Result.B = Min(Src.B + Dest.B, 255);
// 等價公式:Result = Src + Dest (飽和算術)
視覺特徵:
典型應用:
// 每個顏色通道獨立計算
Result.R = Max(Dest.R - Src.R, 0);
Result.G = Max(Dest.G - Src.G, 0);
Result.B = Max(Dest.B - Src.B, 0);
// 等價公式:Result = Dest - Src (飽和算術)
視覺特徵:
典型應用:
背景像素: R=100 G=150 B=200 (淡藍色) 前景像素: R=200 G=100 B=50 (橙紅色) ──────────────────────────────────────────── DrawAdd 結果: R=255 G=250 B=250 (近白色,高亮) DrawSub 結果: R=0 G=50 B=150 (深藍綠,變暗) 普通覆蓋: R=200 G=100 B=50 (前景色完全遮蓋) Alpha 50%: R=150 G=125 B=125 (中間色)
前景圖的透明區域 (由 TransparentColor + Transparent := True 定義) 在混合時會被跳過,不參與運算:
// 確保前景圖透明色正確設定
pic2.Transparent := True;
pic2.TransparentColor := clFuchsia; // 或 clWhite, 視圖片而定
// DrawAdd/DrawSub 會自動跳過透明像素
// 只有非透明像素參與加減色運算
var
PulsePhase: Integer = 0;
UseAddMode: Boolean = True;
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
r: TRect;
Intensity: Byte;
begin
DXDraw1.Surface.Fill(0);
pic1.StretchDraw(DXDraw1.Surface, DXDraw1.ClientRect, 0);
r := Bounds((DXDraw1.Width - pic2.Width) div 2,
(DXDraw1.Height - pic2.Height) div 2,
pic2.Width, pic2.Height);
// 產生 0-255 正弦波脈動
Intensity := 128 + Round(127 * Sin(PulsePhase * Pi / 128));
Inc(PulsePhase, 4); // 速度控制
// 動態調整前景圖亮度 (通過著色實現)
// 注意:DrawAdd/DrawSub 不直接支援強度參數
// 需配合 DrawAddCol/DrawSubCol 或預處理圖片
if UseAddMode then
pic2.DrawAdd(DXDraw1.Surface, r, 0)
else
pic2.DrawSub(DXDraw1.Surface, r, 0);
DXDraw1.Flip;
end;
若需「綠色發光」或「紅色陰影」,使用帶顏色版本:
// 加色 + 著色 (發光顏色可控)
pic2.DrawAddCol(DXDraw1.Surface, r, 0, clLime); // 綠色發光
pic2.DrawAddCol(DXDraw1.Surface, r, 0, clRed); // 紅色發光
// 減色 + 著色 (陰影顏色可控)
pic2.DrawSubCol(DXDraw1.Surface, r, 0, clBlue); // 藍色陰影
pic2.DrawSubCol(DXDraw1.Surface, r, 0, clMaroon); // 暗紅陰影
原理:先將前景圖非透明像素著色為指定顏色,再進行加/減色混合。
| 場景 | 建議模式 | 優化提示 |
|---|---|---|
| 大量粒子發光 | DrawAdd | 批次繪製相同模式粒子;使用點精靈 |
| 全屏陰影/霧效 | DrawSub | 使用單張半透明黑色矩形而非逐像素 |
| UI 按鈕懸停高亮 | DrawAdd | 預先準備高亮版圖片,避免即時混合 |
| 技能範圍指示器 | DrawAddCol | 綠色=可施放,紅色=不可施放 |
| 負面狀態圖示 | DrawSubCol | 紫色=中毒,藍色=冰凍,黑色=沉默 |
| 問題 | 原因 | 解決 |
|---|---|---|
| DrawAdd 後圖片變全白 | 前景圖亮度過高或背景過亮 | 降低前景圖亮度;確保背景有暗部 |
| DrawSub 後圖片變全黑 | 前景圖包含大量白色/高亮像素 | 調整前景圖色調;避免純白像素 |
| 透明區域也參與混合 | Transparent 屬性未設定或顏色不匹配 | 檢查 TransparentColor 與圖片實際透明色 |
| 混合效果與預期不符 | 顏色空間差異 (sRGB vs Linear) | DelphiX 在 sRGB 空間混合,注意圖片色彩配置 |
DrawAdd 與 DrawSub 是 DelphiX 實現專業級視覺特效的核心混合模式。加色 = 發光/能量疊加,減色 = 陰影/能量吸收。結合透明色遮罩、著色變體、動態強度控制,可構建豐富的遊戲特效體系。理解其數學本質(飽和加減法)有助於預測視覺結果並設計更精確的美術資源。