|
@@ -0,0 +1,874 @@
|
|
|
|
+<html>
|
|
|
|
+
|
|
|
|
+<head>
|
|
|
|
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
|
|
|
|
+<meta name=Generator content="Microsoft Word 14 (filtered)">
|
|
|
|
+<style>
|
|
|
|
+<!--
|
|
|
|
+ /* Font Definitions */
|
|
|
|
+ @font-face
|
|
|
|
+ {font-family:Wingdings;
|
|
|
|
+ panose-1:5 0 0 0 0 0 0 0 0 0;}
|
|
|
|
+@font-face
|
|
|
|
+ {font-family:"Cambria Math";
|
|
|
|
+ panose-1:2 4 5 3 5 4 6 3 2 4;}
|
|
|
|
+@font-face
|
|
|
|
+ {font-family:Cambria;
|
|
|
|
+ panose-1:2 4 5 3 5 4 6 3 2 4;}
|
|
|
|
+@font-face
|
|
|
|
+ {font-family:Calibri;
|
|
|
|
+ panose-1:2 15 5 2 2 2 4 3 2 4;}
|
|
|
|
+@font-face
|
|
|
|
+ {font-family:Tahoma;
|
|
|
|
+ panose-1:2 11 6 4 3 5 4 4 2 4;}
|
|
|
|
+@font-face
|
|
|
|
+ {font-family:Consolas;
|
|
|
|
+ panose-1:2 11 6 9 2 2 4 3 2 4;}
|
|
|
|
+ /* Style Definitions */
|
|
|
|
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
|
|
|
|
+ {margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:10.0pt;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Calibri","sans-serif";}
|
|
|
|
+h1
|
|
|
|
+ {mso-style-link:"Heading 1 Char";
|
|
|
|
+ margin-top:24.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:14.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#365F91;}
|
|
|
|
+h2
|
|
|
|
+ {mso-style-link:"Heading 2 Char";
|
|
|
|
+ margin-top:10.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:13.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;}
|
|
|
|
+h3
|
|
|
|
+ {mso-style-link:"Heading 3 Char";
|
|
|
|
+ margin-top:10.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;}
|
|
|
|
+h4
|
|
|
|
+ {mso-style-link:"Heading 4 Char";
|
|
|
|
+ margin-top:10.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;
|
|
|
|
+ font-style:italic;}
|
|
|
|
+h5
|
|
|
|
+ {mso-style-link:"Heading 5 Char";
|
|
|
|
+ margin-top:10.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#243F60;
|
|
|
|
+ font-weight:normal;}
|
|
|
|
+h6
|
|
|
|
+ {mso-style-link:"Heading 6 Char";
|
|
|
|
+ margin-top:10.0pt;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ page-break-after:avoid;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#243F60;
|
|
|
|
+ font-weight:normal;
|
|
|
|
+ font-style:italic;}
|
|
|
|
+p.MsoTitle, li.MsoTitle, div.MsoTitle
|
|
|
|
+ {mso-style-link:"Title Char";
|
|
|
|
+ margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:15.0pt;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ border:none;
|
|
|
|
+ padding:0in;
|
|
|
|
+ font-size:26.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#17365D;
|
|
|
|
+ letter-spacing:.25pt;}
|
|
|
|
+p.MsoTitleCxSpFirst, li.MsoTitleCxSpFirst, div.MsoTitleCxSpFirst
|
|
|
|
+ {mso-style-link:"Title Char";
|
|
|
|
+ margin:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ border:none;
|
|
|
|
+ padding:0in;
|
|
|
|
+ font-size:26.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#17365D;
|
|
|
|
+ letter-spacing:.25pt;}
|
|
|
|
+p.MsoTitleCxSpMiddle, li.MsoTitleCxSpMiddle, div.MsoTitleCxSpMiddle
|
|
|
|
+ {mso-style-link:"Title Char";
|
|
|
|
+ margin:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ border:none;
|
|
|
|
+ padding:0in;
|
|
|
|
+ font-size:26.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#17365D;
|
|
|
|
+ letter-spacing:.25pt;}
|
|
|
|
+p.MsoTitleCxSpLast, li.MsoTitleCxSpLast, div.MsoTitleCxSpLast
|
|
|
|
+ {mso-style-link:"Title Char";
|
|
|
|
+ margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:15.0pt;
|
|
|
|
+ margin-left:0in;
|
|
|
|
+ border:none;
|
|
|
|
+ padding:0in;
|
|
|
|
+ font-size:26.0pt;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#17365D;
|
|
|
|
+ letter-spacing:.25pt;}
|
|
|
|
+a:link, span.MsoHyperlink
|
|
|
|
+ {color:blue;
|
|
|
|
+ text-decoration:underline;}
|
|
|
|
+a:visited, span.MsoHyperlinkFollowed
|
|
|
|
+ {color:purple;
|
|
|
|
+ text-decoration:underline;}
|
|
|
|
+p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
|
|
|
|
+ {mso-style-link:"Balloon Text Char";
|
|
|
|
+ margin:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ font-size:8.0pt;
|
|
|
|
+ font-family:"Tahoma","sans-serif";}
|
|
|
|
+p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
|
|
|
|
+ {margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:10.0pt;
|
|
|
|
+ margin-left:.5in;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Calibri","sans-serif";}
|
|
|
|
+p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst
|
|
|
|
+ {margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:.5in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Calibri","sans-serif";}
|
|
|
|
+p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle
|
|
|
|
+ {margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:0in;
|
|
|
|
+ margin-left:.5in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Calibri","sans-serif";}
|
|
|
|
+p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast
|
|
|
|
+ {margin-top:0in;
|
|
|
|
+ margin-right:0in;
|
|
|
|
+ margin-bottom:10.0pt;
|
|
|
|
+ margin-left:.5in;
|
|
|
|
+ line-height:115%;
|
|
|
|
+ font-size:11.0pt;
|
|
|
|
+ font-family:"Calibri","sans-serif";}
|
|
|
|
+span.Heading1Char
|
|
|
|
+ {mso-style-name:"Heading 1 Char";
|
|
|
|
+ mso-style-link:"Heading 1";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#365F91;
|
|
|
|
+ font-weight:bold;}
|
|
|
|
+span.Heading2Char
|
|
|
|
+ {mso-style-name:"Heading 2 Char";
|
|
|
|
+ mso-style-link:"Heading 2";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;
|
|
|
|
+ font-weight:bold;}
|
|
|
|
+span.TitleChar
|
|
|
|
+ {mso-style-name:"Title Char";
|
|
|
|
+ mso-style-link:Title;
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#17365D;
|
|
|
|
+ letter-spacing:.25pt;}
|
|
|
|
+span.Heading3Char
|
|
|
|
+ {mso-style-name:"Heading 3 Char";
|
|
|
|
+ mso-style-link:"Heading 3";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;
|
|
|
|
+ font-weight:bold;}
|
|
|
|
+span.Heading4Char
|
|
|
|
+ {mso-style-name:"Heading 4 Char";
|
|
|
|
+ mso-style-link:"Heading 4";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#4F81BD;
|
|
|
|
+ font-weight:bold;
|
|
|
|
+ font-style:italic;}
|
|
|
|
+span.Heading5Char
|
|
|
|
+ {mso-style-name:"Heading 5 Char";
|
|
|
|
+ mso-style-link:"Heading 5";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#243F60;}
|
|
|
|
+span.Heading6Char
|
|
|
|
+ {mso-style-name:"Heading 6 Char";
|
|
|
|
+ mso-style-link:"Heading 6";
|
|
|
|
+ font-family:"Cambria","serif";
|
|
|
|
+ color:#243F60;
|
|
|
|
+ font-style:italic;}
|
|
|
|
+span.BalloonTextChar
|
|
|
|
+ {mso-style-name:"Balloon Text Char";
|
|
|
|
+ mso-style-link:"Balloon Text";
|
|
|
|
+ font-family:"Tahoma","sans-serif";}
|
|
|
|
+p.Code, li.Code, div.Code
|
|
|
|
+ {mso-style-name:Code;
|
|
|
|
+ mso-style-link:"Code Char";
|
|
|
|
+ margin:0in;
|
|
|
|
+ margin-bottom:.0001pt;
|
|
|
|
+ text-autospace:none;
|
|
|
|
+ font-size:9.5pt;
|
|
|
|
+ font-family:Consolas;}
|
|
|
|
+span.CodeChar
|
|
|
|
+ {mso-style-name:"Code Char";
|
|
|
|
+ mso-style-link:Code;
|
|
|
|
+ font-family:Consolas;}
|
|
|
|
+.MsoChpDefault
|
|
|
|
+ {font-family:"Calibri","sans-serif";}
|
|
|
|
+.MsoPapDefault
|
|
|
|
+ {margin-bottom:10.0pt;
|
|
|
|
+ line-height:115%;}
|
|
|
|
+@page WordSection1
|
|
|
|
+ {size:8.5in 11.0in;
|
|
|
|
+ margin:1.0in 1.0in 1.0in 1.0in;}
|
|
|
|
+div.WordSection1
|
|
|
|
+ {page:WordSection1;}
|
|
|
|
+ /* List Definitions */
|
|
|
|
+ ol
|
|
|
|
+ {margin-bottom:0in;}
|
|
|
|
+ul
|
|
|
|
+ {margin-bottom:0in;}
|
|
|
|
+-->
|
|
|
|
+</style>
|
|
|
|
+
|
|
|
|
+</head>
|
|
|
|
+
|
|
|
|
+<body lang=EN-US link=blue vlink=purple>
|
|
|
|
+
|
|
|
|
+<div class=WordSection1>
|
|
|
|
+
|
|
|
|
+<div style='border:none;border-bottom:solid #4F81BD 1.0pt;padding:0in 0in 4.0pt 0in'>
|
|
|
|
+
|
|
|
|
+<p class=MsoTitle>Texture Modification using Render Targets, with some Stencil
|
|
|
|
+Buffer Action</p>
|
|
|
|
+
|
|
|
|
+</div>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Sometimes you need to modify a texture while your game is
|
|
|
|
+running, and there are a number of ways to do this. One of the first things
|
|
|
|
+newer game programmers often try to do is use Texture2D.GetData to copy the
|
|
|
|
+texture data from the GPU to an array on the CPU, modify the bytes, and then
|
|
|
|
+send it back to the GPU with Texture2D.SetData.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>This is a bad idea on many, levels. Beyond issues with <a
|
|
|
|
+href="http://blogs.msdn.com/b/shawnhar/archive/2008/04/14/stalling-the-pipeline.aspx">pipeline
|
|
|
|
+stalls</a>, GetData and SetData can be slow, especially when working with a
|
|
|
|
+large texture. Any time you’re tempted grab data from the GPU for use on the
|
|
|
|
+CPU you should very carefully consider all of your options. There are often
|
|
|
|
+other solutions that let you keep the data entirely on the GPU and accomplish
|
|
|
|
+the same thing.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>This tutorial will use an example that could be solved with
|
|
|
|
+GetData and SetData, and show you another alternative using render targets and
|
|
|
|
+the stencil buffer that will let you perform the same function entirely on the
|
|
|
|
+GPU.</p>
|
|
|
|
+
|
|
|
|
+<h1>CPU Craters</h1>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Let’s pretend you want to draw 2D planet, and periodically
|
|
|
|
+add a crater to it. You want a hole to appear somewhere on the planet, so it
|
|
|
|
+looks like part of it was removed.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal><img border=0 width=320 height=256 id="Picture 1"
|
|
|
|
+src="Stencil%20Buffer%20Craters_files/image001.jpg"></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> You could do this using the GetData/SetData method by
|
|
|
|
+getting the data from a texture into an array, setting the color to the
|
|
|
|
+background (or alpha to 0) in the shape of the crater, then writing the data
|
|
|
|
+back to the texture. Or you could be a little cleverer and eliminate GetData by
|
|
|
|
+always keeping the data in the array, but you still have to do the SetData to
|
|
|
|
+get it into the texture on the GPU each time it’s changed.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<h1>GPU Craters</h1>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>The method we’ll use to do this entirely on the GPU involves
|
|
|
|
+several steps. First, we need a couple of resources. We’ll use a simple
|
|
|
|
+textured circle for a planet, and a “crater” shaped texture for the crater.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal><img border=0 width=256 height=256 id="Picture 2"
|
|
|
|
+src="Stencil%20Buffer%20Craters_files/image002.jpg"> <img border=0 width=256
|
|
|
|
+height=256 id="Picture 3" src="Stencil%20Buffer%20Craters_files/image003.jpg"></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>It’s important to note that the black areas on these have an
|
|
|
|
+alpha value of 0, meaning completely transparent. For the planet this just lets
|
|
|
|
+us draw the round shape over the background without looking like a square
|
|
|
|
+image. But for the crater image the alpha value is very important since it will
|
|
|
|
+control what part of the crater image is removed from the planet.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Next, we need to set up two render targets (these will be
|
|
|
|
+referred to later as Render Target A, and Render Target B). When we need to add
|
|
|
|
+a crater, one of these will be used as a target for drawing to, while the other
|
|
|
|
+used as a texture. The next time we add a crater they will swap roles – the
|
|
|
|
+texture will become the target, and the target will become the texture. This is
|
|
|
|
+called “ping-ponging” and will be discussed more fully later.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Once we have these resources ready to go, the method for
|
|
|
|
+adding a crater goes like this:</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpFirst style='text-indent:-.25in'>1.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Activate
|
|
|
|
+Render Target A using GraphicsDevice.SetRenderTarget.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpMiddle style='text-indent:-.25in'>2.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Clear
|
|
|
|
+the graphics device, setting the color to solid black, and the stencil buffer
|
|
|
|
+to 0.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpMiddle style='text-indent:-.25in'>3.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Set
|
|
|
|
+up the stencil buffer state so whatever we draw writes a value of 1 to the
|
|
|
|
+stencil buffer.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpMiddle style='text-indent:-.25in'>4.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Set
|
|
|
|
+up the alpha test state so we only draw where the alpha value is zero.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpLast style='text-indent:-.25in'>5.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Draw
|
|
|
|
+the crater texture. Because of the way we’ve set up the graphics device, only
|
|
|
|
+the parts of the crater texture that have alpha = 0 will be drawn, and those
|
|
|
|
+parts will write a 1 to the stencil buffer. So what we have at this point is a
|
|
|
|
+“mask” in the stencil buffer that we can use in the next step. The white area
|
|
|
|
+in the following image represents the stencil mask we’ve set up – the stencil
|
|
|
|
+buffer contains “1” in the white area, and “0” everywhere else.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal><img border=0 width=256 height=256 id="Picture 6"
|
|
|
|
+src="Stencil%20Buffer%20Craters_files/image004.jpg"></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpFirst style='text-indent:-.25in'>6.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Set
|
|
|
|
+up the stencil buffer so when we draw, anything that has a value of 1 in the
|
|
|
|
+stencil buffer will be masked out – meaning it won’t draw.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraphCxSpLast style='text-indent:-.25in'>7.<span
|
|
|
|
+style='font:7.0pt "Times New Roman"'> </span>Draw
|
|
|
|
+the “planet texture”. Because of the way we’ve set up the graphics device,
|
|
|
|
+anything with a 1 in the stencil buffer won’t be drawn – since these 1’s are in
|
|
|
|
+the shape of a crater, that shape will be masked out of the planet texture,
|
|
|
|
+leaving holes that look like craters. </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal><img border=0 width=256 height=256 id="Picture 7"
|
|
|
|
+src="Stencil%20Buffer%20Craters_files/image005.jpg"></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoListParagraph style='text-indent:-.25in'>8.<span style='font:7.0pt "Times New Roman"'>
|
|
|
|
+</span>Set the render target to the backbuffer. We can now access Render
|
|
|
|
+Target A as a texture, and that texture contains the planet texture with a
|
|
|
|
+crater-shaped hole in it.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>From now on, until we need to add another crater, we can
|
|
|
|
+treat Render Target A as a texture and draw it using SpriteBatch, and we’ll
|
|
|
|
+have a nice crater. Now, what if we need to add another crater? This is where
|
|
|
|
+the ping-ponging comes in. Since Render Target A is now the “planet texture”,
|
|
|
|
+we need to be able to draw somewhere else when we’re filling in the stencil
|
|
|
|
+buffer with our crater shape. It just so happens that we set up another place
|
|
|
|
+to draw to, Render Target B. </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>So now, in Step 1, instead of activating Render Target A we
|
|
|
|
+need to activate Render Target B and draw the crater shapes into that. But
|
|
|
|
+what happens when we get to Step 7? Well, the “planet texture” is now in Render
|
|
|
|
+Target A, so we draw that. And in Step 8, Render Target B now contains our new
|
|
|
|
+planet texture with two craters.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>And if we add a third crater then we’re back to where we
|
|
|
|
+started – drawing to Render Target A, and using Render Target B as the source
|
|
|
|
+texture. In other words, we “ping-pong” between the two render targets – each
|
|
|
|
+time we need to modify the texture, one is used for a texture, and one is used
|
|
|
|
+for drawing to, and then those roles are swapped.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>You may have noticed that there’s one issue here. The first
|
|
|
|
+time through, Render Target B has nothing in it, so we can’t use it as the
|
|
|
|
+planet texture. This can be handled by using the actual planet texture the
|
|
|
|
+first time, and the render target thereafter.</p>
|
|
|
|
+
|
|
|
|
+<h1>The Code</h1>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Now let’s walk through the code involved, using XNA 4.0.
|
|
|
|
+You can do this in 3.1, but you’ll have to make significant changes when
|
|
|
|
+creating the render targets and setting the render states. </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>The complete code is in the downloadable project linked at
|
|
|
|
+the end of the tutorial. We’ll just go through the highlights here, referring
|
|
|
|
+to the steps mentioned above as we go.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>The XNA 4.0 API has been changed substantially where render
|
|
|
|
+states are concerned, and for the better. Render states have been grouped by
|
|
|
|
+functionality into several classes. You create instances of these classes to
|
|
|
|
+represent the state you want, then set them on the graphics device, or pass
|
|
|
|
+them to SpriteBatch. So first we need to create these render state objects. </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<h2>Set Up Render State Objects</h2>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>For Step 3, we need to use the DepthStencilState class to
|
|
|
|
+set up the device to always set the stencil buffer to 1. We enable the stencil
|
|
|
|
+buffer, set the stencil function to Always, the pass operation to Replace, and
|
|
|
|
+ReferenceStencil to 1. This means that as we’re drawing, each pixel will Always
|
|
|
|
+pass, and the value in the stencil buffer will be Replaced with 1.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:green'>// set up stencil state to always replace stencil
|
|
|
|
+buffer with 1</span></span></p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways = <span style='color:blue'>new</span> <span
|
|
|
|
+style='color:#2B91AF'>DepthStencilState</span>();</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways.StencilEnable = <span style='color:blue'>true</span>;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways.StencilFunction = <span style='color:#2B91AF'>CompareFunction</span>.Always;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways.StencilPass = <span style='color:#2B91AF'>StencilOperation</span>.Replace;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways.ReferenceStencil = 1;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilAlways.DepthBufferEnable = <span style='color:blue'>false</span>;</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>And for Step 4 we need to use the standard AlphaTestEffect
|
|
|
|
+so we can draw the asteroid texture only where the alpha value is 0.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=Code> // set up alpha test effect</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> <span style='color:#2B91AF'>Matrix</span> projection = <span
|
|
|
|
+style='color:#2B91AF'>Matrix</span>.CreateOrthographicOffCenter(0,
|
|
|
|
+PlanetDataSize, PlanetDataSize, 0, 0, 1);</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> <span style='color:#2B91AF'>Matrix</span> halfPixelOffset =
|
|
|
|
+<span style='color:#2B91AF'>Matrix</span>.CreateTranslation(-0.5f, -0.5f, 0);</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> </p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect = <span style='color:blue'>new</span> <span
|
|
|
|
+style='color:#2B91AF'>AlphaTestEffect</span>(GraphicsDevice);</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.VertexColorEnabled = <span
|
|
|
|
+style='color:blue'>true</span>;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.DiffuseColor = <span style='color:#2B91AF'>Color</span>.White.ToVector3();</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.AlphaFunction = <span style='color:#2B91AF'>CompareFunction</span>.Equal;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.ReferenceAlpha = 0;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.World = <span style='color:#2B91AF'>Matrix</span>.Identity;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.View = <span style='color:#2B91AF'>Matrix</span>.Identity;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> alphaTestEffect.Projection = halfPixelOffset * projection;</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>We first set up an orthographic projection matrix that
|
|
|
|
+matches SpriteBatch. We set AlphaFunction to Equal, and ReferenceAlpha to 0.
|
|
|
|
+This means the alpha test will pass whenever the alpha value we’re drawing is
|
|
|
|
+equal to 0. In our crater texture, the crater area has an alpha value of 0,
|
|
|
|
+while the surrounding area has 1, so only the crater area will be drawn.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>For Step 6 we need a stencil buffer state that allows
|
|
|
|
+drawing only where the stencil buffer contains a 0. We enable the stencil
|
|
|
|
+buffer, set the stencil function to Equal, the pass operation to Keep, and the
|
|
|
|
+reference stencil to 0. This means that when we’re drawing, each pixel will
|
|
|
|
+pass if the value in the stencil buffer is Equal to 0.</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> // set up stencil state to pass if the stencil value is 0</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero = <span style='color:blue'>new</span> <span
|
|
|
|
+style='color:#2B91AF'>DepthStencilState</span>();</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero.StencilEnable = <span style='color:blue'>true</span>;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero.StencilFunction = <span style='color:
|
|
|
|
+#2B91AF'>CompareFunction</span>.Equal;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero.StencilPass = <span style='color:#2B91AF'>StencilOperation</span>.Keep;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero.ReferenceStencil = 0;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> stencilKeepIfZero.DepthBufferEnable = <span
|
|
|
|
+style='color:blue'>false</span>;</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> </p>
|
|
|
|
+
|
|
|
|
+<h2>Create Render Targets</h2>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Now that we have the render state objects created, it’s time
|
|
|
|
+to create the render targets. Both are the same, so just one is shown here.
|
|
|
|
+This creates a render target with a Color format, and a depth format that
|
|
|
|
+includes a stencil buffer.</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> renderTargetA = <span style='color:blue'>new</span> <span
|
|
|
|
+style='color:#2B91AF'>RenderTarget2D</span>(GraphicsDevice, PlanetDataSize,
|
|
|
|
+PlanetDataSize,</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> <span style='color:blue'>false</span>, <span
|
|
|
|
+style='color:#2B91AF'>SurfaceFormat</span>.Color, <span style='color:#2B91AF'>DepthFormat</span>.Depth24Stencil8,</p>
|
|
|
|
+
|
|
|
|
+<p class=Code> 0, <span style='color:#2B91AF'>RenderTargetUsage</span>.DiscardContents);</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<h2>Draw the Crater Mask</h2>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Next up is drawing the crater masks (Steps 2-5). First we
|
|
|
|
+activate the render target, clear it to solid black, and clear the stencil
|
|
|
|
+buffer to 0.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+GraphicsDevice.SetRenderTarget(activeRenderTarget);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+GraphicsDevice.Clear(<span style='color:#2B91AF'>ClearOptions</span>.Target | <span
|
|
|
|
+style='color:#2B91AF'>ClearOptions</span>.Stencil,</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>new</span> <span style='color:#2B91AF'>Color</span>(0,
|
|
|
|
+0, 0, 1), 0, 0);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Next we begin a SpriteBatch, passing in the stencilAlways
|
|
|
|
+and alphaTestEffect objects that we created earlier. Calculate some random
|
|
|
|
+rotation, size the crater texture using a Rectangle, and call SpriteBatch.Draw
|
|
|
|
+to draw the crater.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Begin(<span style='color:#2B91AF'>SpriteSortMode</span>.Immediate, <span
|
|
|
|
+style='color:#2B91AF'>BlendState</span>.Opaque, </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>null</span>, stencilAlways, <span style='color:blue'>null</span>,
|
|
|
|
+alphaTestEffect);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:#2B91AF'>Vector2</span> origin = <span style='color:blue'>new</span>
|
|
|
|
+<span style='color:#2B91AF'>Vector2</span>(craterTexture.Width * 0.5f,</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+craterTexture.Height * 0.5f);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>float</span> rotation = (<span style='color:blue'>float</span>)random.NextDouble()
|
|
|
|
+* <span style='color:#2B91AF'>MathHelper</span>.TwoPi;</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:#2B91AF'>Rectangle</span> r = <span style='color:blue'>new</span>
|
|
|
|
+<span style='color:#2B91AF'>Rectangle</span>((<span style='color:blue'>int</span>)position.X,
|
|
|
|
+(<span style='color:blue'>int</span>)position.Y, 50, 50);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Draw(craterTexture, r, <span style='color:blue'>null</span>, <span
|
|
|
|
+style='color:#2B91AF'>Color</span>.White, rotation, </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+origin, <span style='color:#2B91AF'>SpriteEffects</span>.None, 0);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.End();</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<h2>Draw the Planet Texture</h2>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Now we need to draw the latest planet texture, using the
|
|
|
|
+stencil buffer to mask out the craters (Steps 6-7). We begin a SpriteBatch,
|
|
|
|
+passing in the stencilKeepIfZero object we created earlier. Note that the first
|
|
|
|
+time we draw the actual planet texture, but subsequently we draw using the
|
|
|
|
+texture from the previous iteration.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Begin(<span style='color:#2B91AF'>SpriteSortMode</span>.Immediate, <span
|
|
|
|
+style='color:#2B91AF'>BlendState</span>.Opaque,</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>null</span>, stencilKeepIfZero, <span
|
|
|
|
+style='color:blue'>null</span>, <span style='color:blue'>null</span>);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>if</span> (firstTime)</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+{</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Draw(planetTexture, <span style='color:#2B91AF'>Vector2</span>.Zero,
|
|
|
|
+<span style='color:#2B91AF'>Color</span>.White);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+firstTime = <span style='color:blue'>false</span>;</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+}</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:blue'>else</span></span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Draw(textureRenderTarget, <span style='color:#2B91AF'>Vector2</span>.Zero,
|
|
|
|
+<span style='color:#2B91AF'>Color</span>.White);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.End();</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<h2>Swap Render Targets</h2>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>Finally we activate the backbuffer render target.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+GraphicsDevice.SetRenderTarget(<span style='color:blue'>null</span>);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>And then swap the render targets as discussed previously.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+<span style='color:#2B91AF'>RenderTarget2D</span> t = activeRenderTarget;</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+activeRenderTarget = textureRenderTarget;</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+textureRenderTarget = t;</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>In the main Draw function, you draw the latest cratered
|
|
|
|
+planet using the textureRenderTarget. Of course, you need to deal with using
|
|
|
|
+the planet texture the first time through though. The downloadable code shows
|
|
|
|
+one simple way to do that.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+GraphicsDevice.Clear(<span style='color:#2B91AF'>Color</span>.CornflowerBlue);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Begin();</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.Draw(textureRenderTarget, planetPosition, <span style='color:#2B91AF'>Color</span>.White);</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'>
|
|
|
|
+spriteBatch.End();</span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal style='margin-bottom:0in;margin-bottom:.0001pt;line-height:
|
|
|
|
+normal;text-autospace:none'><span style='font-size:9.5pt;font-family:Consolas'> </span></p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+<h1>Conclusion</h1>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>And there you have it, a powerful technique for altering
|
|
|
|
+textures during your game. Doing this entirely on the GPU is quite a bit more
|
|
|
|
+complex than GetData/SetData, but is well worth the extra trouble. </p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>There are some things you can do to improve this technique. If
|
|
|
|
+you need to add a lot of craters, rather than adding them one at a time you can
|
|
|
|
+batch them up for a while, then in Step 5 draw all of them at once.</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal>I hope you found this tutorial informative. Learning about
|
|
|
|
+render targets and stencil buffers opens up a whole new world of possibilities
|
|
|
|
+beyond just making craters. What other uses can you think of?</p>
|
|
|
|
+
|
|
|
|
+<p class=MsoNormal> </p>
|
|
|
|
+
|
|
|
|
+</div>
|
|
|
|
+
|
|
|
|
+</body>
|
|
|
|
+
|
|
|
|
+</html>
|