<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Sergey Makeev</title>
	<atom:link href="http://sergeymakeev.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://sergeymakeev.com</link>
	<description>записки о геймдеве</description>
	<pubDate>Mon, 30 Aug 2010 11:06:59 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Приклеено : Трансляция в ЖЖ</title>
		<link>http://sergeymakeev.com/?p=322</link>
		<comments>http://sergeymakeev.com/?p=322#comments</comments>
		<pubDate>Sat, 25 Jul 2009 21:51:27 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[разное]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=322</guid>
		<description><![CDATA[Данный блог автоматически транслируется в у меня в ЖЖ, для тех кому его удобнее читать там.

]]></description>
			<content:encoded><![CDATA[<div class="announcement_post"><p>Данный блог автоматически транслируется в <a href="http://joker-ru.livejournal.com/">у меня в ЖЖ</a>, для тех кому его удобнее читать там.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=322</wfw:commentRss>
		</item>
		<item>
		<title>Быстрый HDR, используя только LDR текстуры</title>
		<link>http://sergeymakeev.com/?p=476</link>
		<comments>http://sergeymakeev.com/?p=476#comments</comments>
		<pubDate>Sat, 14 Aug 2010 12:55:00 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=476</guid>
		<description><![CDATA[Итак, нам очень хочется HDR. Но у нас платформа, медленно и плохо работающая с рендертаргетами с бОльшей чем 8 бит на канал глубиной цвета (консоль). Вроде бы логичный выход, делать весь рендер RGBE или любым из его аналогов, но очень не хочется терять альфу. Казалось, что же тут можно придумать?
Будем рассуждать логически, в нашем мире [...]]]></description>
			<content:encoded><![CDATA[<p>Итак, нам очень хочется <strong>HDR</strong>. Но у нас платформа, медленно и плохо работающая с рендертаргетами с бОльшей чем 8 бит на канал глубиной цвета (консоль). Вроде бы логичный выход, делать весь рендер <strong>RGBE</strong> или любым из его аналогов, но очень не хочется терять альфу. Казалось, что же тут можно придумать?</p>
<p>Будем рассуждать логически, в нашем мире обычные фотоаппараты &#8220;мыльницы&#8221; - как раз имеют ярко выраженный эффект, который в играх называют <strong>HDR</strong>. Засвечивают очень яркие области или и полностью затемняют очень темные. При этом если направлять камеру с ярких областей на темные, то отлично видно эффект адаптации &#8220;глаза&#8221; к освещенности. При этом мыльницы получают с матрицы ну максимум по 12 бит на канал, а старые по 8. Как же они это делают?</p>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/digital-camera-2.png"><img class="alignnone size-medium wp-image-505" title="digital-camera-2" src="http://sergeymakeev.com/wp-content/uploads/2010/08/digital-camera-2-300x285.png" alt="" width="300" height="285" /></a></p>
<p>Камера постоянно производит матричный замер экспозиции, используя одно или несколько значений с матрицы, оценивая таким образом общую яркость/контрастность кадра. И используя полученное значение, в зависимости от заданного режима съемки производит коррекцию экспозиции в нужную сторону. Таким образом, камера итеративно подбирает нужное значение экспозиции. Это и есть та самая нужная нам, <em>&#8220;адаптация глаза к свету&#8221;</em>, которую в играх выдают за <strong>HDR</strong> эффект.</p>
<p>Что же мешает делать нам тоже самое, а не использовать дорогой рендер в рендертаргет с плавающей точкой? Правильно, ничего не мешает - давайте попробуем.</p>
<p>Итак алгоритм следующий:</p>
<ul>
<li>Рисуем в рендертаргет <strong>R8G8B8(X8)</strong> все что захотим, с одним отличием - перед тем как вернуть финальный цвет из пиксельшейдера умножаем его коэфицент яркости (Exposure Adjustment)</li>
</ul>
<ul>
<li>После того, как кадр нарисован, производим оценку яркости кадра (основная хитрость как сделать это быстро, об этом ниже)</li>
</ul>
<ul>
<li>В зависимости от посчитанной яркости кадра изменяем Exposure Adjustment, если кадр слишком темный, повышаем наш множитель. Если слишком светлый, понижаем.</li>
</ul>
<ul>
<li>Далее, повторяем все заново.</li>
</ul>
<p>Как видно, алгоритм очень простой. Но нам нужно оценивать яркость отрисованного кадра, для правильного сдвига <strong>Exposure Adjustment</strong>. Обычно, для оценки яркости кадра используется гистограмма, но мы же хотим сделать быстрый <strong>HDR</strong> и желательно без использования <strong>CPU</strong>, а классическая гистограмма для этого не лучший вариант.</p>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/frame.jpg"><img class="alignnone size-medium wp-image-488" title="frame" src="http://sergeymakeev.com/wp-content/uploads/2010/08/frame-300x168.jpg" alt="" width="300" height="168" /></a></p>
<p>Вот мой вариант быстрого экспозамера кадра на <strong>GPU</strong>:</p>
<ul>
<li>Копируем полученный кадр в квадратную текстуру, меньшего размера чем экран, при этом производим оценку яркости каждого пикселя следующим образом: считаем яркость пикселя и в завсисмости от яркости в разные каналы <strong>RGB</strong> кладем разные значения. В <strong>R</strong> канал кладем коэфицент, что пиксель недосвечен, в <strong>B</strong> канал кладем коэфицент, что пиксель пересвечен, в <strong>G</strong> канал кладем нормализованный остаток: <strong>1.0 - R - G</strong>. Таким образом, полностью черный пиксель превратится во <strong>float3(1, 0, 0)</strong> а полностью белый во <strong>float3(0, 0, 1)</strong>. Сумма 3-х компонентов <strong>RGB</strong> всегда нормализованна и равна <strong>1.0</strong>. Фактически это оценка данного пикселя 3 функциями <strong>dark</strong>, <strong>medium</strong> и <strong>light colors</strong> (гистограмма с 3 корзинами). Таким способом, мы получили оценку каждого пикселя отдельно, но нам нужна оценка всей картинки вцелом.</li>
</ul>
<ul>
<li> Входные данные при предыдущем шаге сформированны таким образом, что теперь оценку освещенности для всего кадра, можно сделать очень быстро. Рисуем получившуюся текстуру с коэфицентами, в текстуру с разрешением в два раза меньше (в следующий <strong>mip</strong>). При этом используем <strong>LINEAR</strong> фильтрацию текстур и делаем каждую нашу выборку между текселями. <strong>GPU</strong> при этом автоматически сэмплирует 4 текселя и т.к. мы используем <strong>LINEAR</strong> фильтрацию фактически проведет нормализацию результата<strong> (tex1 + tex2 + tex3 + tex4 * 0.25)</strong>. Результат: оценка яркостной составляющей блока пикселей <strong>2&#215;2</strong>. Повторяем шаг до размера размера текстуры 2&#215;2</li>
</ul>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/resample.jpg"><br />
</a></p>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/resample.jpg"><img class="alignnone size-full wp-image-492" title="resample" src="http://sergeymakeev.com/wp-content/uploads/2010/08/resample.jpg" alt="" width="500" height="203" /></a></p>
<ul>
<li>Теперь у нас есть гистограмма всей картинки (правда всего на 3 корзины) и нам нужно сдвинуть нашу коррекцию экспозиции. Т.к. зачитывать данные от <strong>GPU</strong> к <strong>CPU</strong> не хочется (данных хоть и мало, но синхронизация <strong>GPU</strong> с <strong>CPU</strong> это вообще всегда медленно), заводим текстуру <strong>Exposure Adjustment</strong> размером 1&#215;1 пиксель (по идее надо <strong>float</strong> текстуру заводить, но я попробовал хватает точности и у обычной <strong>8</strong> битной). Данная текстура всегда будет лежать в текстурном кеше <strong>GPU</strong> и фактически является константой. Эту текстуру и используем как множитель <strong>Exposure Adjustment</strong>.</li>
</ul>
<ul>
<li> Теперь у нас есть две текстуры: <strong>1&#215;1</strong> текстура &#8220;множитель&#8221; для<strong> HDR</strong> и текстура <strong>2&#215;2</strong> гистограмма разложенная в <strong>3 buckets</strong>. Оцениваем какая из часть гистограммы &#8220;перекошена&#8221; и сдвигаем значение в текстуре в нужную нам сторону - обычный рендер в текстуру, без зачитывания данных в<strong> CPU</strong>.</li>
</ul>
<ul>
<li> Результат: в зависимости от яркости кадра мы сдвинули <strong>Exposure Adjustment</strong> в нужную нам сторону, очень быстро, полностью на <strong>GPU</strong> и используя только текстуры <strong>8</strong> бит на канал.</li>
</ul>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/histogram.jpg"><img class="alignnone size-medium wp-image-490" title="histogram" src="http://sergeymakeev.com/wp-content/uploads/2010/08/histogram-300x150.jpg" alt="" width="300" height="150" /></a></p>
<p><em>Так выглядит текстура с коэфицентами яркости</em><br />
=================================================</p>
<p>Вот тут, можно <a href="http://sergeymakeev.com/files/HDR_demo.zip" target="_blank">скачать демо со всеми исходниками (37.7Мб)</a> - в котором <strong>HDR</strong> реализован описанным выше способом. Демо работает на <strong>PC</strong> и на <strong>X360</strong> (у кого есть <strong>XDK</strong> + <strong>Devkit</strong> могут тоже потестировать). Там совсем простой алгоритм экспо-коррекции (обычный сдвиг), можно подумать и сделать похитрее. Также, развивая идею дальше: коэфицент <strong>Exposure Adjustment</strong> не обязательно должен быть константным для всего кадра. Мне кажется, если сделать для различных зон экрана разную коррекцию экспозиции (например сеткой <strong>16&#215;16</strong>) то будет еще лучше.</p>
<p><strong>Управление:</strong> зажав правую кнопку мыши можно крутить головой и летать с помощью <strong>WASD</strong>.</p>
<p>Заодно, добавил <a href="http://filmicgames.com/archives/75" target="_blank">ToneMaping как в Uncharted2</a>,  хотя он и не обязателен, можно просто клемпить получившийся результат.</p>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/frame.jpg"><img class="alignnone size-medium wp-image-488" title="frame" src="http://sergeymakeev.com/wp-content/uploads/2010/08/frame-300x168.jpg" alt="" width="300" height="168" /></a></p>
<p><a href="http://sergeymakeev.com/wp-content/uploads/2010/08/pic2.jpg"><img class="alignnone size-medium wp-image-497" title="pic2" src="http://sergeymakeev.com/wp-content/uploads/2010/08/pic2-300x168.jpg" alt="" width="300" height="168" /></a></p>
<p>update: обновил демку, на экран для отладки выводятся результаты анализа картинки и искуственно добавил тормозов для CPU, иначе при FPS &gt; 1000 float дельта тайм себя плохо ведет <img src='http://sergeymakeev.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=476</wfw:commentRss>
		</item>
		<item>
		<title>Ура! Сайт официально запущен</title>
		<link>http://sergeymakeev.com/?p=470</link>
		<comments>http://sergeymakeev.com/?p=470#comments</comments>
		<pubDate>Fri, 23 Jul 2010 08:25:25 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=470</guid>
		<description><![CDATA[Ура! сайт нашей игры наконец то запущен!
http://www.CaptainBloodGame.com/
Всем добро пожаловать!
]]></description>
			<content:encoded><![CDATA[<p>Ура! сайт нашей игры наконец то запущен!</p>
<p><a title="http://www.CaptainBloodGame.com/" href="http://www.CaptainBloodGame.com/" target="_blank">http://www.CaptainBloodGame.com/</a><br />
Всем добро пожаловать!</p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=470</wfw:commentRss>
		</item>
		<item>
		<title>Наша игра</title>
		<link>http://sergeymakeev.com/?p=466</link>
		<comments>http://sergeymakeev.com/?p=466#comments</comments>
		<pubDate>Tue, 29 Jun 2010 08:58:42 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=466</guid>
		<description><![CDATA[Превью нашей игры на GameTrailers


Video Games &#124; Captain Blood &#124; Preview
XBox 360 &#124; Playstation 3 &#124; Nintendo Wii


]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.gametrailers.com/video/preview-hd-captain-blood/701182">Превью нашей игры на GameTrailers</a></p>
<div style="width: 480px;"><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" id="gtembed" width="480" height="392"><param name="allowScriptAccess" value="sameDomain" /><param name="allowFullScreen" value="true" /><param name="movie" value="http://www.gametrailers.com/remote_wrap.php?mid=701181"/><param name="quality" value="high" /><embed src="http://www.gametrailers.com/remote_wrap.php?mid=701181" swLiveConnect="true" name="gtembed" align="middle" allowScriptAccess="sameDomain" allowFullScreen="true" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="480" height="392"></embed></object>
<div style="font-size: 10px; font-family: Verdana; text-align: center; width: 480px; padding-top: 2px; padding-bottom: 2px; background-color: black; height: 32px;">
<div><a style="color:#FFFFFF;" href="http://www.gametrailers.com" title="GameTrailers.com">Video Games</a> | <a style="color:#FFFFFF;" href="http://www.gametrailers.com/game/captain-blood/11621" title="Captain Blood">Captain Blood</a> | <a style="color:#FFFFFF;" href="http://www.gametrailers.com/video/preview-captain-blood/701181" title="Preview">Preview</a></div>
<div style="padding-top: 3px;"><a style="color:#FFFFFF;" href="http://xbox360.gametrailers.com/" title="XBox 360">XBox 360</a> | <a style="color:#FFFFFF;" href="http://ps3.gametrailers.com/" title="PS3">Playstation 3</a> | <a style="color:#FFFFFF;" href="http://wii.gametrailers.com/" title="Wii">Nintendo Wii</a></div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=466</wfw:commentRss>
		</item>
		<item>
		<title>Волшебный блендинг</title>
		<link>http://sergeymakeev.com/?p=396</link>
		<comments>http://sergeymakeev.com/?p=396#comments</comments>
		<pubDate>Mon, 15 Mar 2010 13:01:28 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=396</guid>
		<description><![CDATA[Давненько ничего не писал в блог, буду исправляться потихоньку.
В системах частиц и всяких спецэффектах часто нужно рисовать с различным блендингом,
классически это add blend и alpha blend.
Обычно рисуют сортированные (по эмиттерам или по частицам) партиклы с alpha blend, а потом поверх кладут частицы с add blend (их уже можно не сортировать).
Но, художникам иногда очень хочется нарисовать [...]]]></description>
			<content:encoded><![CDATA[<p>Давненько ничего не писал в блог, буду исправляться потихоньку.</p>
<p>В системах частиц и всяких спецэффектах часто нужно рисовать с различным блендингом,<br />
классически это <strong>add blend</strong> и <strong>alpha blend</strong>.</p>
<p>Обычно рисуют сортированные (по эмиттерам или по частицам) партиклы с <strong>alpha blend</strong>, а потом поверх кладут частицы с <strong>add blend</strong> (их уже можно не сортировать).</p>
<p>Но, художникам иногда очень хочется нарисовать партикл с <strong>add blend</strong>, а поверх него с <strong>alpha blend</strong>.</p>
<p>И уж точно программистам всегда хочется рисовать все частицы за один <strong>batch</strong>, независимо от их блендинга.</p>
<p><em>Итак, немного простой математики:</em><br />
Формула блендинга <strong>destColor = sourcePixel * srcBlend  + screenPixel * dstBlend;</strong></p>
<p>Для <strong>add blend</strong> задают <strong>srcBlend</strong> и <strong>dstBlend</strong> как <strong>one</strong>, получая:</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//blend function</font></i>
<font color="#000000">destColor</font> <font color="#C8003C">=</font> <font color="#000000">sourcePixel</font> <font color="#C8003C">+</font> <font color="#000000">screenPixel</font><font color="#C8003C">;</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p></p>
<p>Для <strong>alpha blend</strong> задают <strong>srcBlend</strong> как <strong>srcAlpha</strong> и <strong>dstBlend</strong> как <strong>invSrcAlpha</strong>, получая:<br />
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//blend function</font></i>
<font color="#000000">destColor</font> <font color="#C8003C">=</font> <font color="#000000">sourcePixel</font> <font color="#C8003C">*</font> <font color="#000000">srcAlpha</font>  <font color="#C8003C">+</font> <font color="#000000">screenPixel</font> <font color="#C8003C">*</font> <font color="#000000">invSrcAlpha</font><font color="#C8003C">;</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p></p>
<p>Так как же совместить эти два режима блендинга в одном ?</p>
<p>Задаем <strong>srcBlend</strong> как <strong>one</strong> и <strong>dstBlend</strong> как <strong>invSrcAlpha</strong>, получаем:</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//blend function</font></i>
<font color="#000000">destColor</font> <font color="#C8003C">=</font> <font color="#000000">sourcePixel</font> <font color="#C8003C">+</font> <font color="#000000">screenPixel</font> <font color="#C8003C">*</font> <font color="#000000">invSrcAlpha</font><font color="#C8003C">;</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p></p>
<p>Теперь, следите за руками <img src='http://sergeymakeev.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> несколько манипуляций в <strong>pixel shader:</strong></p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//0.0 &#1101;&#1090;&#1086; Add blend</font></i>
<i><font color="#808080">//1.0 &#1101;&#1090;&#1086; Alpha blend</font></i>
<font color="#0000FF">float</font> <font color="#000000">addOrBlend</font> <font color="#C8003C">=</font> <font color="#40B440">0.0</font><font color="#C8003C">;</font> 

<font color="#000000">float4</font> <font color="#000000">ps_test</font><font color="#C8003C">(</font> <font color="#000000">PS_INPUT</font> <font color="#000000">pix</font> <font color="#C8003C">)</font> <font color="#C8003C">:</font> <font color="#000000">COLOR0</font>
<font color="#C8003C">{</font>
   <font color="#000000">float4</font> <font color="#000000">texel</font> <font color="#C8003C">=</font> <font color="#000000">tex2D</font><font color="#C8003C">(</font><font color="#000000">baseMap</font><font color="#C8003C">,</font> <font color="#000000">pix</font><font color="#C8003C">.</font><font color="#000000">texCoord0</font><font color="#C8003C">);</font>
   <font color="#000000">texel</font><font color="#C8003C">.</font><font color="#000000">rgb</font> <font color="#C8003C">=</font> <font color="#000000">texel</font><font color="#C8003C">.</font><font color="#000000">rgb</font> <font color="#C8003C">*</font> <font color="#000000">texel</font><font color="#C8003C">.</font><font color="#000000">a</font><font color="#C8003C">;</font>
   <font color="#000000">texel</font><font color="#C8003C">.</font><font color="#000000">a</font> <font color="#C8003C">=</font> <font color="#000000">texel</font><font color="#C8003C">.</font><font color="#000000">a</font> <font color="#C8003C">*</font> <font color="#000000">addOrBlend</font><font color="#C8003C">;</font>
   <font color="#0000FF">return</font> <font color="#000000">texel</font><font color="#C8003C">;</font>
<font color="#C8003C">}</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p>Посмотрим, что же получилось и самое главное, как.</p>
<p>Итак наша формула блендинга <strong>destColor = sourcePixel + screenPixel * invSrcAlpha;</strong><br />
при значении <strong>addOrBlend = 0.0;</strong> получаем (с учетом математики в <strong>pixel shader</strong>):</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//blend function</font></i>
<font color="#000000">destColor</font> <font color="#C8003C">=</font> <font color="#000000">sourcePixel</font> <font color="#C8003C">*</font> <font color="#000000">srcAlpha</font>  <font color="#C8003C">+</font> <font color="#000000">screenPixel</font><font color="#C8003C">;</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p>при значении <strong>addOrBlend = 1.0;</strong> получаем (с учетом математики в <strong>pixel shader</strong>):</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><i><font color="#808080">//blend function</font></i>
<font color="#000000">destColor</font> <font color="#C8003C">=</font> <font color="#000000">sourcePixel</font> <font color="#C8003C">*</font> <font color="#000000">srcAlpha</font>  <font color="#C8003C">+</font> <font color="#000000">screenPixel</font> <font color="#C8003C">*</font> <font color="#000000">invSrcAlpha</font><font color="#C8003C">;</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p>Как видно, <strong>add blend</strong> получается не совсем &#8220;чистый&#8221;, цвет текстуры умножается на альфу, но это дает нам возможность плавно менять <strong>addOrBlend</strong> соответственно плавно изменяя режим блендинга.</p>
<p>Если вдруг нужно только бинарное значение и хочется &#8220;чистый&#8221; блендинг, можно немного изменить наш шейдер: <strong>texel.rgb = texel.rgb * lerp (texel.a, 1.0, addOrBlend);</strong></p>
<p>С помощью данной техники у нас в Приключениях капитана Блада сделаны партиклы.<br />
Партикловый художник может графиком задавать блендинг у каждой частицы, при этом все частицы сортированные и рисуются за один <strong>batch</strong>.</p>
<p>Надеюсь это пригодится и в вашем проекте.</p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=396</wfw:commentRss>
		</item>
		<item>
		<title>C++ reflection - возвращение</title>
		<link>http://sergeymakeev.com/?p=388</link>
		<comments>http://sergeymakeev.com/?p=388#comments</comments>
		<pubDate>Sat, 16 Jan 2010 16:59:47 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=388</guid>
		<description><![CDATA[Как заметили на форуме gamedev.ru, прошлая версия DynamicCast проигрывала стандартной версии при использовании на Intel процессорах, с длинными именами классов (&#62;20 символов) , на AMD же все по прежнему было хорошо, это меня удивило и я стал разбираться.
Профайлер подсказал, что все дело в использовании стандартного strcmp. После использования самописного аналога - Intel и AMD снова [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.gamedev.ru/code/forum/?id=127666#m12" target="_blank">Как заметили на форуме gamedev.ru</a>, прошлая версия DynamicCast проигрывала стандартной версии при использовании на <strong>Intel </strong>процессорах, с длинными именами классов (&gt;20 символов) , на <strong>AMD</strong> же все по прежнему было хорошо, это меня удивило и я стал разбираться.</p>
<p>Профайлер подсказал, что все дело в использовании стандартного <strong>strcmp</strong>. После использования самописного аналога - <strong>Intel</strong> и <strong>AMD </strong>снова работают как и ожидалось. Как приятный бонус скорость DynamicCast подросла почти на 50% и на моем <strong>AMD 3000+</strong> в <strong>4.5</strong> раза быстрее чем стандартный cast.</p>
<p>Так же в качестве бонуса, по подсказке <a href="http://www.gamedev.ru/users/?id=30018" target="_blank">my.name</a>,  сделал автоматическое определение базового класса (без указания его в макросе объявляющим метаданные) и перенес определение рефлекшн аттрибутов в хидер.</p>
<p>В общем вот: <a href="http://sergeymakeev.com/files/public/reflectionLibrary_v2.zip" target="_blank">новая версия reflectionLibrary_v2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=388</wfw:commentRss>
		</item>
		<item>
		<title>Математика / Геометрия</title>
		<link>http://sergeymakeev.com/?p=383</link>
		<comments>http://sergeymakeev.com/?p=383#comments</comments>
		<pubDate>Sun, 10 Jan 2010 00:29:40 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=383</guid>
		<description><![CDATA[Очень неплохая подборка математики, необходимой геймдев программисту. Особенно удобно использовать как справочник, все в одном месте и на понятном языке 
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.geometrictools.com/LibFoundation/Intersection/Intersection.html" target="_blank">Очень неплохая подборка математики</a>, необходимой геймдев программисту. Особенно удобно использовать как справочник, все в одном месте и на понятном языке <img src='http://sergeymakeev.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=383</wfw:commentRss>
		</item>
		<item>
		<title>Unreal Development Kit - лайтмапы</title>
		<link>http://sergeymakeev.com/?p=373</link>
		<comments>http://sergeymakeev.com/?p=373#comments</comments>
		<pubDate>Sat, 07 Nov 2009 20:23:12 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=373</guid>
		<description><![CDATA[Забавно, что в недавно вышедшем UDK текстуры лайтмапов пожаты как я писал в этом посте : Alpha-test высокого качества, только вместо альфы используют текстуры L8. Реально можно сильно сэкономить на разрешении лайтмапов, жалко у нас их нет в движке.
]]></description>
			<content:encoded><![CDATA[<p>Забавно, что в недавно вышедшем UDK текстуры лайтмапов пожаты как я писал в этом посте : <a href="http://sergeymakeev.com/?p=232">Alpha-test высокого качества</a>, только вместо альфы используют текстуры L8. Реально можно сильно сэкономить на разрешении лайтмапов, жалко у нас их нет в движке.</p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=373</wfw:commentRss>
		</item>
		<item>
		<title>C++ reflection с блэк-джеком и шлюхами</title>
		<link>http://sergeymakeev.com/?p=328</link>
		<comments>http://sergeymakeev.com/?p=328#comments</comments>
		<pubDate>Fri, 21 Aug 2009 15:36:48 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=328</guid>
		<description><![CDATA[Отсутствие Reflection в C++ порождает множество проблем, лично у меня, и возможно у многих людей, которые будут читать данный текст.
Первая проблема в том, что все функции оперирующие или выдающие как результат множества объектов должны работать с базовым типом, каким нибудь IEntity. Для примера: выбрали мы из мира с помощю AABB набор игровых объектов и хотим [...]]]></description>
			<content:encoded><![CDATA[<p>Отсутствие <strong>Reflection</strong> в <strong>C++</strong> порождает множество проблем, лично у меня, и возможно у многих людей, которые будут читать данный текст.</p>
<p>Первая проблема в том, что все функции оперирующие или выдающие как результат множества объектов должны работать с базовым типом, каким нибудь <strong>IEntity. </strong><em>Для примера:</em> выбрали мы из мира с помощю AABB набор игровых объектов и хотим нанести урон, всем кто поддерживает интерфейс <strong>IDamageable</strong>, для этого обычно используют <strong>dynamic_cast</strong> или какой нибудь <strong>getType.</strong> На консолях, где RTTI в релизном билде обычно запрещен - приходится изобретать свои методы (<a href="http://nocturnal.insomniacgames.com/index.php/Reflect_Usage" target="_blank">см. библиотеку от Insomniac</a>).</p>
<p>Вторая проблема, отсутсвие в <strong>С++</strong> <strong>P</strong><strong>roperty</strong> и средств для работы с ними. Движки по типу <strong>Unreal Engine3</strong> и <strong>CryEngine</strong> приучают творческих людей работать с набором параметров у любого игрового объекта - будь то объект миссии, текстура или спецэффект, что совершенно логично и удобно.</p>
<p>Но вот незадача, в <strong>C++</strong> отсутсвует возможноть получить какие либо метаданные класса - что бы узнать его поля / свойства и использовать это для управления объектом в реальном времени. Т.е. написание удобного и визуального средства редактирования <strong>C++</strong> классов становится проблемой.</p>
<p>Существует множество вариантов решения, кто-то пишет уникальные редакторы для уникальных объектов, кто-то использует кодогенерацию мета-информации и классов, кто-то просто игнорирует проблему или пишет редактируемые объекты на скриптовых языках с поддержкой <strong>Reflection.</strong></p>
<p>Третья проблема, система автоматического <strong>save</strong> / <strong>load</strong> любых объектов. Делают её обычно банально через <strong>virtual ::save(</strong>file * f<strong>)</strong> и <strong>virtual ::load (</strong>file *f<strong>)</strong> для всех объектов которым нужно уметь сохраняться, и с разной степенью успеха борются с проблемой при загрузке - как, имея имя класса в <strong>const char *</strong> создать экземпляр класса.</p>
<p>Чтобы решить эти проблемы один раз и навсегда, я написал маленькую библиотеку <strong>С++ reflection</strong> (<a href="http://sergeymakeev.com/files/public/reflectionLibrary.zip" target="_blank">скачать тут</a>) которая позволяет удобно добавлять произвольную метаинформацию к любым классам, не требует специального препроцессора или кодогенерации и намного быстрее существующих средств в языке (<strong>dynamic_cast</strong>) или библиотек.</p>
<p>Вот пример объявления метаданных внутри <strong>cpp</strong> файла.</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><font color="#000000">BEGIN_REFLECTION_METADATA</font><font color="#C8003C">(</font><font color="#000000">foo_class</font><font color="#C8003C">,</font> <font color="#000000">base_class</font><font color="#C8003C">)</font>
    <font color="#000000">ATTRIBUTE_FLOAT</font><font color="#C8003C">(</font><font color="#006400">"myFloatProperty"</font><font color="#C8003C">,</font> <font color="#C8003C">&amp;</font><font color="#000000">foo_class</font><font color="#C8003C">::</font><font color="#000000">setFloatFunc</font><font color="#C8003C">,</font> <font color="#C8003C">&amp;</font><font color="#000000">foo_class</font><font color="#C8003C">::</font><font color="#000000">getFloatFunc</font><font color="#C8003C">);</font>
    <font color="#000000">ATTRIBUTE_INT</font><font color="#C8003C">(</font><font color="#006400">"myIntProperty"</font><font color="#C8003C">,</font> <font color="#C8003C">&amp;</font><font color="#000000">foo_class</font><font color="#C8003C">::</font><font color="#000000">setIntFunc</font><font color="#C8003C">,</font> <font color="#C8003C">&amp;</font><font color="#000000">foo_class</font><font color="#C8003C">::</font><font color="#000000">getIntFunc</font><font color="#C8003C">);</font>
<font color="#000000">END_REFLECTION_METADATA</font><font color="#C8003C">(</font><font color="#000000">foo</font><font color="#C8003C">)</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p>Немного макрос-магии и метаданные готовы. Для скорости, все строковые параметры используются вместе с хешами, вычисляемыми на этапе компиляции. Это дает реальный выигрыш в скорости по сравнению с <strong>dynamic_cast</strong> или альтернативами.</p>
<p>Пример использования <strong>dynamic_cast</strong></p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><font color="#000000">base</font> <font color="#C8003C">*</font> <font color="#000000">base_ptr</font> <font color="#C8003C">=</font> <font color="#C8003C">new</font> <font color="#000000">foo</font><font color="#C8003C">();</font>
<font color="#000000">foo</font> <font color="#C8003C">*</font> <font color="#000000">foo_ptr</font> <font color="#C8003C">=</font> <font color="#000000">base_ptr</font><font color="#C8003C">-&gt;</font><font color="#000000">DynamicCast</font><font color="#C8003C">&lt;</font><font color="#000000">foo</font><font color="#C8003C">&gt;();</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p></p>
<p><strong>Плюсы и минусы библиотеки:</strong><br />
+ можно создавать классы по текстовому имени класса<br />
+ получать список всех классов с метаинформацией и создавать их по метаинформации<br />
+ получать список аттрибутов (<strong>property</strong>) для любого класса<br />
+ быстрый <strong>dynamic_cast</strong><br />
+ получать метаинформацию из созданного экземпляра класса<br />
+ аттрибуты поддерживают наследование<br />
+ вся информация строится в compile time</p>
<p>- нужно писать небольшие макросы<br />
- не поддерживается множественное наследование (<em>для меня это фича</em>)<br />
- незначительно увеличивается время компиляции (<em>нужно все таки хеши считать</em>)</p>
<p>Вот несколько примеров скорости работы:</p>
<table width = "100%" bgcolor="#F2F2F2">
<tr>
<td>
<pre><font color="#006400">"Xenon X360 (3.2 GHz)"</font>
<font color="#C8003C">-------------------</font>
<font color="#0000FF">dynamic_cast</font> <font color="#40B440">9.52</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>
<font color="#000000">reflection</font><font color="#C8003C">::</font><font color="#000000">cast</font> <font color="#40B440">18.94</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>

<b><font color="#000000">&#1087;&#1088;&#1080;&#1088;&#1086;&#1089;&#1090;</font></b> <b><font color="#000000">&#1073;&#1099;&#1089;&#1090;&#1088;&#1086;&#1076;&#1077;&#1081;&#1089;&#1090;&#1074;&#1080;&#1103;</font></b> <font color="#000000">x</font> <font color="#40B440">1.99</font>

<font color="#006400">"AMD 64X2 3800+ (2.0GHz)"</font>
<font color="#C8003C">-------------------</font>
<font color="#0000FF">dynamic_cast</font> <font color="#40B440">12.02</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>
<font color="#000000">reflection</font><font color="#C8003C">::</font><font color="#000000">cast</font> <font color="#40B440">35.50</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>

<b><font color="#000000">&#1087;&#1088;&#1080;&#1088;&#1086;&#1089;&#1090;</font></b> <b><font color="#000000">&#1073;&#1099;&#1089;&#1090;&#1088;&#1086;&#1076;&#1077;&#1081;&#1089;&#1090;&#1074;&#1080;&#1103;</font></b> <font color="#000000">x</font> <font color="#40B440">2.95</font>

<font color="#006400">"Core2Duo E6750 (2.66GHz)"</font>
<font color="#C8003C">-------------------</font>
<font color="#0000FF">dynamic_cast</font> <font color="#40B440">26.49</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>
<font color="#000000">reflection</font><font color="#C8003C">::</font><font color="#000000">cast</font> <font color="#40B440">45.70</font><font color="#000000">M</font> <font color="#000000">casts</font> <font color="#000000">per</font> <font color="#000000">second</font>

<b><font color="#000000">&#1087;&#1088;&#1080;&#1088;&#1086;&#1089;&#1090;</font></b> <b><font color="#000000">&#1073;&#1099;&#1089;&#1090;&#1088;&#1086;&#1076;&#1077;&#1081;&#1089;&#1090;&#1074;&#1080;&#1103;</font></b> <font color="#000000">x</font> <font color="#40B440">1.73</font>
</pre>
</td>
</tr>
<tr>
<td align="right"><b><i><a href="http://dobrokot.nm.ru/WinnieColorizer.html"><font color="#727272">_Winnie C++ Colorizer</font></a></i></b></td>
</tr>
</table>
<p></p>
<p>Буду рад мнениям и результатам тестов - скомпилированный тест производительности лежит внутри архива. Повторяю ссылку, что бы не искать её выше по тексту. (<a href="http://sergeymakeev.com/files/public/reflectionLibrary.zip" target="_blank">Библиотека reflection</a>)</p>
<p><strong>UPDATE:</strong> Обновил архив, ускорил получение метаданных из указателя на объект.</p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=328</wfw:commentRss>
		</item>
		<item>
		<title>Миллион батчей в секунду на Xbox360</title>
		<link>http://sergeymakeev.com/?p=286</link>
		<comments>http://sergeymakeev.com/?p=286#comments</comments>
		<pubDate>Fri, 24 Jul 2009 09:55:05 +0000</pubDate>
		<dc:creator>Joker</dc:creator>
		
		<category><![CDATA[игрострой]]></category>

		<guid isPermaLink="false">http://sergeymakeev.com/?p=286</guid>
		<description><![CDATA[Во время очередного витка оптимизации на Xbox360, захотелось очень дешевых по производительности батчей - т.к. батчей в кадре было достаточно много, а CPU времени они кушали еще больше, при тысяче батчей в кадре тратилось 20-25 ms на установку констант и вызов DP. CPU лимит в 40-50 FPS явно не устраивал.
Как потом выяснилось часть оверхеда была [...]]]></description>
			<content:encoded><![CDATA[<p>Во время очередного витка оптимизации на Xbox360, захотелось очень дешевых по производительности батчей - т.к. батчей в кадре было достаточно много, а CPU времени они кушали еще больше, при тысяче батчей в кадре тратилось <strong>20-25 ms</strong> на установку констант и вызов DP. CPU лимит в 40-50 FPS явно не устраивал.</p>
<p>Как потом выяснилось часть оверхеда была от использования <strong>D3D Effects</strong> в качестве шейдерной системы. Большое количество <a href="http://www.gamasutra.com/view/feature/3687/sponsored_feature_common_.php" target="_blank">Load Hit Store</a> и двойное копирование всех констант, были одной из проблем.</p>
<p>Итак, задача: 30 тысяч строк написанных и отлаженых шейдеров которые нельзя менять и желание иметь в runtime подобие <strong>PS3 libGCM</strong> и полностью контролировать генерацию command buffer.<br />
Я начал рыть в сторону PrecompiledCommandBuffer т.к. там явно была возможность записать CommandBuffer и потом отправить его в GPU. К сожалению, изменять параметры у записанного CB можно очень ограниченно, поэтому данный метод не подошел.</p>
<p>В результате экспериментов я получил дамп памяти GPU буфера и стал его разбирать ручками. К счастью, <strong>Xenos</strong> это развитие чипа <strong>ATI R500</strong>, а на R500 <a href="http://www.x.org/docs/AMD/R5xx_Acceleration_v1.3.pdf ">документация открыта</a> (спасибо AMD/ATI). Очень быстро был готов парсер CB, который выдавал полную информацию, о том что лежит в буфере.</p>
<p>Выяснилось, что часть операций которые можно делать из D3D совсем по другому мапяться в железо, да и <strong>Runtime D3D</strong> сохраняет зеркальные стейты GPU, что тоже не бесплатно. Также паралельно выяснилось, что размер CB на каждом батче слишком большой, т.к. частично шейдеры эмбедились в CB и устанавливалось очень много констант (они всегда эмбедятся в буфер).</p>
<p>Как результат всех эксперементов я написал компилятор на входе берущий <strong>D3D Effect</strong> файл и генерирующий из него кусочки CB (кусочки что бы можно было не сабмитить уже установленные в GPU данные), так же runtime ремапинг адресов, сабмишн данных в GPU и всякий дополнительный код.</p>
<p>Теперь рендер батча стал просто заполнением буфера памяти, поборовшись <strong>Load-Hit-Store</strong> на заполнении памяти и сделав кеширование CB в системной памяти (общая память CPU и GPU на X360 и на PC в режиме <strong>WriteCombined</strong>, что отключает все кеши и ведет к разным пенальти из за непоследовательной записи) я получил хороший прирост производительности.</p>
<p>После всех основных оптимизаций, батчи стали стоить до <strong>4ms </strong>на кадр (вместо 25ms), профайлинг показывал узкое место на доступе к памяти (констант было от 200 до 400 на батч). У <strong>ATI GPU</strong> есть очень приятная фича, на вход микрокода вершинного шейдера приходит номер индекса, и сборка вершины происходит в шейдере с возможностью random read из потока вершин. Я переделал большинство констант на vertex stream (данные vertex stream заполнялись в другом cpu потоке) и избавился от <strong>90%</strong> констант при отрисовке, результат: <strong>1-2ms</strong> из секунды это расходы на отрисовку <strong>1000</strong> батчей, на этом и остановился.</p>
<p>В теории успех можно было развить дальше, т.к. можно вести отрисовку с нескольких потоков (при рендере мы просто работаем с памятью, не трогая D3D вообще, D3D нужен только для сабмишена данных в GPU) - но на текущем проекте этого не потребовалось. CPU лимит в миллион батчей в секунду кажется мне достаточным, да и PC такого не переживет - надо все таки и о второй платформе помнить.</p>
<p>Итого:</p>
<p>Было<strong>: D3D Effects + D3D runtime</strong><br />
<strong>0.02</strong><em>ms</em> batch * <strong>1000</strong> = <strong>20</strong><em>ms</em> на кадр (<strong>50000</strong> batches per second)</p>
<p>Стало:<strong> Своя библиотека работы с GPU:</strong><br />
<strong>0.001</strong><em>ms</em> batch * <strong>1000</strong> = <strong>1</strong><em>ms</em> на кадр (<strong>1000000</strong> batches per second)</p>
]]></content:encoded>
			<wfw:commentRss>http://sergeymakeev.com/?feed=rss2&amp;p=286</wfw:commentRss>
		</item>
	</channel>
</rss>
