ขั้นตอนแรกคือการบอกกราฟิกการ์ดว่าเราต้องการบัฟเฟอร์ลายฉลุ ในการทำเช่นนี้เมื่อคุณสร้าง GraphicsDeviceManager เราได้ทำการตั้งค่า PreferredDepthStencilFormat เป็น DepthFormat.Depth24Stencil8 ดังนั้นจึงมี stencil สำหรับเขียน
graphics = new GraphicsDeviceManager(this) {
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
};
AlphaTestEffect ใช้เพื่อตั้งค่าระบบพิกัดและกรองพิกเซลด้วยอัลฟาที่ผ่านการทดสอบอัลฟา เราจะไม่ตั้งค่าตัวกรองใด ๆ และตั้งค่าระบบพิกัดเป็นพอร์ตมุมมอง
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
ต่อไปเราต้องตั้งค่า DepthStencilStates สองรายการ สถานะเหล่านี้กำหนดเมื่อ SpriteBatch แสดงผลเป็น stencil และเมื่อ SpriteBatch แสดงผลเป็น BackBuffer เราสนใจในตัวแปรสองตัวคือ StencilFunction และ StencilPass
- StencilFunction กำหนดเมื่อ SpriteBatch จะวาดแต่ละพิกเซลและเมื่อพวกเขาจะถูกละเว้น
- StencilPass กำหนดเมื่อพิกเซลพิกเซลที่วาดมีผลกับลายฉลุ
สำหรับ DepthStencilState แรกที่เราตั้งค่า StencilFunction ให้เป็น CompareFunction นี่เป็นสาเหตุให้ StencilTest ประสบความสำเร็จและเมื่อ StencilTest SpriteBatch แสดงผลพิกเซลนั้น StencilPass ถูกตั้งค่าเป็น StencilOperation แทนที่ความหมายที่ว่าเมื่อ StencilTest ประสบความสำเร็จพิกเซลนั้นจะถูกเขียนไปที่ StencilBuffer ด้วยค่าของ ReferenceStencil
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
สรุปโดยย่อว่า StencilTest ส่งผ่านเสมอภาพจะถูกวาดไปที่หน้าจอตามปกติและสำหรับพิกเซลที่วาดไปที่หน้าจอค่า 1 จะถูกเก็บไว้ใน StencilBuffer
DepthStencilState ที่สองนั้นซับซ้อนกว่าเล็กน้อย ในครั้งนี้เราต้องการวาดลงบนหน้าจอเมื่อค่าใน StencilBuffer เป็นเท่านั้น เพื่อให้บรรลุผลดังกล่าวเราได้ตั้งค่า StencilFunction ให้เป็น CompareFunction.LessEqual และ ReferenceStencil เป็น 1 ซึ่งหมายความว่าเมื่อค่าในบัฟเฟอร์ stencil เท่ากับ 1 theStarTestTest จะประสบความสำเร็จ การตั้งค่า StencilPass เป็น TencOperation Keep ทำให้ SignatureBuffer ไม่อัปเดต สิ่งนี้ทำให้เราสามารถวาดได้หลายครั้งโดยใช้มาสก์เดียวกัน
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
กล่าวโดยสรุปเครื่องมือตรวจสอบ StencilTest จะส่งผ่านเฉพาะเมื่อ StencilBuffer น้อยกว่า 1 (พิกเซลอัลฟาจากมาสก์) และจะไม่มีผลกับเครื่องมือนี้
ตอนนี้เราได้ตั้งค่า DepthStencilStates ของเราแล้ว จริงๆแล้วเราสามารถวาดโดยใช้หน้ากาก เพียงวาดหน้ากากโดยใช้ DepthStencilState ตัวแรก สิ่งนี้จะมีผลกับทั้ง BackBuffer และ StencilBuffer ตอนนี้บัฟเฟอร์ stencil มีค่าเป็น 0 ซึ่งคุณ mask มีความโปร่งใสและ 1 ซึ่งมีสีที่เราสามารถใช้ StencilBuffer เพื่อปกปิดรูปภาพในภายหลัง
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
SpriteBatch ตัวที่สองใช้ DepthStencilStates ตัวที่สอง ไม่ว่าคุณจะวาดอะไรมีเพียงพิกเซลที่กำหนดให้ TencelBuffer เป็น 1 เท่านั้นที่จะผ่านการทดสอบ stencil และวาดลงบนหน้าจอ
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();
ด้านล่างนี้คือรหัสทั้งหมดในวิธีการวาดอย่าลืมตั้งค่า PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8 ใน Constructor ของเกม
GraphicsDevice.Clear(ClearOptions.Target
| ClearOptions.Stencil, Color.Transparent, 0, 0);
var m = Matrix.CreateOrthographicOffCenter(0,
graphics.GraphicsDevice.PresentationParameters.BackBufferWidth,
graphics.GraphicsDevice.PresentationParameters.BackBufferHeight,
0, 0, 1
);
var a = new AlphaTestEffect(graphics.GraphicsDevice) {
Projection = m
};
var s1 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
var s2 = new DepthStencilState {
StencilEnable = true,
StencilFunction = CompareFunction.LessEqual,
StencilPass = StencilOperation.Keep,
ReferenceStencil = 1,
DepthBufferEnable = false,
};
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s1, null, a);
spriteBatch.Draw(huh, Vector2.Zero, Color.White); //The mask
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, s2, null, a);
spriteBatch.Draw(color, Vector2.Zero, Color.White); //The background
spriteBatch.End();