Quantcast
Channel: Статьи Intel Developer Zone
Viewing all 156 articles
Browse latest View live

Оптимизация игр для Ultrabook™

$
0
0

Download as PDF

Автор: Ли Бэмбер (Lee Bamber)

1. Введение

Недавно я занимался подготовкой игрового движка, над которым я работал для конференции Games Developer Conference. Учитывая значимость этого мероприятия, было важно, чтобы игра достаточно быстро работала на трех устройствах, которые были у меня под рукой: от современного Ultrabook™до системы на два поколения старше.

В этой статье вы узнаете, как увеличить скорость трехмерной игры, и поймете, на что нужно обращать внимание при переносе своих приложений на Ultrabook. Будь вы опытным разработчиком игр, или же программирование для вас просто хобби — в любом случае вы наверняка понимаете важность высокой производительности. Игра, идущая плавно и с высокой кадровой скоростью, будет восприниматься как намного более качественная и профессиональная, нежели игра, спотыкающаяся на несчастных пяти кадрах в секунду. Никакая сколь угодно захватывающая графика не скроет тот факт, что игра просто тормозит, дергается на экране (из-за постоянного рассогласования с вертикальной разверткой монитора), а о сколько-нибудь приемлемой реализации физики и говорить нечего. В этом примере с настоящим игровым проектом я постараюсь рассказать о возможных проблемах при переносе игры на разные платформы и способах решения таких проблем.


Рисунок 1. Если у вашей игры красивые снимки экрана, это поможет поднять продажи, но за низкую кадровую скорость расплачиваться придется уже вам!

В этой статье описывается несколько распространенных причин потери производительности. Разработчикам игр предлагается полезная информация по переносу высококачественных трехмерных игр высшего уровня на Ultrabook с нужным уровнем производительности. Для работы таких игр с комфортной скоростью зачастую требуется мощный дискретный видеоадаптер, а нагрузка на GPU весьма высока. Здесь может пригодиться понимание архитектурных различий между выделенными и интегрированными GPU, но лучший способ повышения производитель¬ности графической подсистемы — анализ конвейера обработки графики для выявления узких мест с дальнейшей оптимизацией этих областей без снижения качества изображения.

Требуется базовое понимание вызовов графических API в целом, знание компонентов, образую¬щих типичные трехмерные игры, а также некоторое знание или опыт использования Ultrabook.

2. Почему важна производительность?

Число игроков на рынке приложений и игр постоянно растет, поэтому уникальные полезные особенности ваших продуктов становятся все более важными для коммерческого успеха, а хорошая производительность сейчас рассматривается не как некий желаемый результат, а как строго необходимый атрибут любой программы или игры. Современные пользователи даже не будут считать вашу игру законченной, если она не будет работать достаточно гладко и комфортно на их устройстве, и не будут возвращаться к игре, если с самого начала о ней сложится отрицательное впечатление.

Это обстоятельство крайне важно. Если же учесть еще и быстрый рост рынка мобильных телефонов, планшетов и ноутбуков, окажется, что производительность имеет первостепенное значение. Вы можете удовольствоваться адаптацией игры к Ultrabook, учитывая высокую вычислительную мощность этих устройств по сравнению с остальными, но пользователи всегда будут требовать высших стандартов и ожидать максимального удобства.


Рисунок 2. Ultrabook раскрывает немалую мощь в умелых руках.

С точки зрения выработки полезных навыков все, что вы сейчас можете сделать для оптимиза¬ции и улучшения кода игры, вы сможете применять и во всех дальнейших проектах, повысив свою квалификацию разработчика.

3. Зачем оптимизировать?

Многие разработчики используют для создания и тестирования трехмерных игр настольные ПК. Из-за наличия выделенного графического адаптера иногда возникает ощущение безграничности вычислительных ресурсов, а это приводит к появлению в коде игр таких алгоритмов и шейдеров, которые работают на самом пределе возможностей GPU. Если же запустить такую игру на менее мощной платформе, она может работать гораздо медленнее. Ultrabook — это исключительно мощные мобильные устройства, но по «грубой силе» обработки графики они все же немало уступают мощным современным графическим процессорам. Кроме того, Ultrabook предназначены для мобильного использования, поэтому может оказаться, что в процессе игры Ultrabook будет работать от аккумулятора: конвейер отрисовки должен быть очень эффективным, чтобы избежать быстрого израсходования всей электроэнергии. Все эти факты необходимо учитывать при создании игровой графики.


Рисунок 3. Варианты использования успешного приложения.

При разработке приложений программисты обычно двигаются «сверху вниз»: сначала создают приложение, а потом стараются адаптировать его для как можно большего количества устройств в рамках отведенного на разработку времени.

Простейший подход — разрабатывать игру на Ultrabook, а затем переносить ее на настольный компьютер с выделенным графическим адаптером: при этом для переноса игры не требуется практически никаких действий. Тем не менее, вашими конкурентами могут стать игры, для которых планка качества установлена гораздо выше. Преимущество у такого подхода только одно: вы с самого начала учитываете время работы системы от аккумулятора и с большей вероятностью разработаете игру, которая будет снижать потребление ресурсов в определенные моменты, например во время заставок или на экранах настроек. Более распространенный подход — разработка на настольном ПК с последующей оптимизацией для Ultrabook: в этом случае, как правило, достигается более высокое качество, поскольку изначально концепция разработки нацелена именно на это.

4. С настольного компьютера на Ultrabook: пример битвы за производительность.

Мой рассказ начинается за много недель до крупного мероприятия — конференции GDC. Моя игра работает на достаточно современном графическом адаптере стоимостью около двухсот долларов с интерфейсом PCI Express* 3.0. При наивысшем качестве графики моя игра выдавала порядка 60 кадров в секунду. Это был вовсе не сверхмощный игровой компьютер, но я мог запускать любые трехмерные игры с самым высоким качеством графики без сколько-нибудь ощутимых проблем с производительностью. В моем распоряжении было шесть ядер, 6 гигабайт системной памяти и массив крайне быстрых твердотельных дисков. Я знал, что на конфе¬ренции в моем распоряжении не будет настольных компьютеров, и не собирался везти с собой через полмира здоровенный стационарный компьютер. Следующим по мощности устройством был мой Ultrabook, который вполне годился для поездки: именно его я и решил взять с собой.


Рисунок 4. GDC 2014 — одна из крупнейших конференций разработчиков.

Мой Ultrabook оснащен процессором Intel® Core™ 4-го поколения с графикой Intel® HD Graphics 4000™: это мое любимое устройство, когда я не на работе. Результаты первого теста оказались, прямо скажем, катастрофическими: кадровая скорость упала настолько, что вообще вся затея начала казаться мне чересчур смелой. Используемая сборка трехмерного игрового движка широко использовала шейдеры и отрисовку множества объектов одновременно. Игра просто глотала циклы CPU, как конфетки, стараясь дотянуться до всех доступных ресурсов. Разумеется, с таким подходом моей игре было крайне далеко до экономных и дружественных приложений, подходящих мобильным устройствам.

Несмотря на очевидную наглость моего плана, я все же знал, что современные Ultrabook — это вполне мощные игровые системы, при правильном подходе они не отстают от настольных компьютеров по производительности, существенно опережая их в удобстве. Кроме того, мне приходилось играть во множество игр на Ultrabook, поэтому я знал, что моя задача вполне выполнима: я решил добиться от игры 60 кадров в секунду.

Написанием кодов я занимаюсь очень давно: я научился программировать задолго до появле-ния анализаторов производительности и графических отладчиков, поэтому основной способ обнаружения узких мест состоял в том, чтобы удалять огромные фрагменты движка до тех пор, пока производительность не повысилась бы. Затем, возвращая по очереди важные фрагменты кода обратно в игру, я мог определить, какие части движка работали медленнее всего. После определения узких мест (а просто взять и удалить их было невозможно) начинался осторожный процесс снижения ресурсоемкости компонентов. Примеры такого подхода: исключение обычного расчета карты в шейдерах для пикселей за пределом определенного расстояния от игрока; пропуск вызовов обновления искусственного интеллекта в каждом втором цикле, чтобы снизить издержки на эти процессы. Это незначительные улучшения, но в сумме они дают весомый эффект, и уже довольно скоро игровой движок стал работать намного быстрее практически без потерь в качестве изображения.

Программистам, для которых отладка производительности является относительно новой областью, я искренне рекомендую не прибегать к такому способу обнаружения узких мест. Можно исполь¬зовать множество инструментов, помогающих выявлять проблемы производитель¬ности вашего приложения, причем эти средства не только выявляют узкие места, но и указывают на природу проблемы. Один из таких бесплатных инструментов — пакет Intel® Graphics Performance Analyzers. Это решение профилирует ваше приложения в ходе его работы и предоставляет снимок всей деятельности программы: что именно она делает и сколько времени это занимает. При демонстрации игры на конференции я обнаружил несколько проблем, которые я впослед¬ствии исправил, чтобы повысить производительность и плавность игры.


Рисунок 5. До и после: снимки экрана игры до и после оптимизации.

Как видно на рисунке 5, мне удалось повысить скорость с 20 до 62 кадров в секунду при крайне незначительных различиях в качестве графики. На снимке экрана «после» удалено мощное динамическое освещение вокруг игрока, а также применен менее агрессивный шейдер фрагментов.

«Голодные» шейдеры

Мы быстро определили, что наибольшее снижение производительности было на этапе отрисовки графики.


Рисунок 6. Панель метрики производительности из начальной версии с низкой кадровой скоростью.

Как видно на рисунке 6, горизонтальная строка, отмеченная как «Отрисовка», потребляла большую часть доступных циклов. При более подробном анализе выяснилось, что крайне много ресурсов расходовалось на отрисовку объектов на экране. После этого стало понятно, что сцена, состоящая из сотен тысяч полигонов (причем для каждого используется ресурсо-емкий шейдер фрагментов), резко снижает производительность. Но насколько именно? Добавив к шейдерам параметры MEDIUM и LOWEST, а также несколько ограничив «аппетит» отрисовки пикселей, нам удалось добиться шестикратного повышения производительности.

Чтобы определить, как на самом деле работают параметры LOWEST и MEDIUM, сначала нужно было определить «наименьший общий знаменатель» для компонентов игры. Определив, какие компоненты для игры совершенно необходимы, и убрав все остальное, я создал в шейдере новый параметр LOWEST. Были удалены почти все элементы: все тени, обычные карты, динамическое освещение, перекрытие текстур, зеркальное отображение и т. п. Поскольку я «обрубил все под корень», можно было запустить игру и понять, какой производительности можно добиться на Ultrabook в наилучшем для этого шейдера случае. Сравнив снимки экрана с параметром HIGHEST и с параметром LOWEST, я обнаружил самый важный отсутствующий компонент, который вызвал бы отрицательную реакцию пользователей при снижении качества графики. Шейдер содержал тени и перекрытия текстур. При отсутствии каждого из этих элементов качество изображения резко снижалось. Вернуть перекрытие текстур можно было без особых затрат. Чтобы протестировать, насколько больше ресурсов будет потреблять игра, я просто вернул код шейдера для этого элемента и снова запустил игру. С тенями все было гораздо сложнее: это касалось и их создания в другой части игрового движка, и их использования в самом шейдере. Учитывая важность этого аспекта для сохранения высокого качества изображения, я потратил достаточное количество времени на изучение различных подходов и наконец, обнаружил достаточно быстрое решение, которое я описываю ниже.

Создать параметр MEDIUM для шейдера было довольно просто: нужно было написать шейдер, промежуточный по качеству между самым высоким и самым низким качеством графики, но всегда склоняясь в пользу производительности. Цель этого параметра — достижение всех преимуществ по скорости, присущих параметру LOWEST, но с добавлением наименее ресурсоемких эффектов, таких как фонарик игрока, динамическое освещение и чуть более высокое качество теней.

Если бы я просто снизил качество всех графических элементов до минимума в режиме LOWEST, мне бы за один прием удалось добиться наибольшей производительности, но игроки относятся к плохой графике столь же отрицательно, как к плохой производительности. Я постарался сохранить 90 % качества изображения на самых высоких настройках и выделить элементы, которые можно было бы исключить или ограничить. Так мне удалось добиться значительного повышения скорости с минимальными потерями качества. С 5 кадров в секунду мне удалось перешагнуть за 40 — неплохое достижение.

Чтобы узнать, почему ваша игра для настольного ПК так медленно работает на Ultrabook, я настоятельно рекомендую разложить по полочкам весь ваш конвейер отрисовки графики и постараться понять, на что тратится время. Для этого можно использовать мой «хирурги-ческий» метод и удалять целые уровни функциональности до тех пор, пока не повысится скорость, или же применить более современный подход и задействовать средства анализа производительности. Какой бы метод вы ни выбрали, после обнаружения проблемы следующая задача — придумать такое решение, при котором возрастает скорость работы, но не снижается качество изображения.

Вот некоторые методики, которые я применил для устранения обнаруженных узких мест производительности.

Тени без затрат

Чтобы решить упомянутую выше проблему с тенями, мне пришлось найти альтернативные решения методики так называемых «каскадных карт теней». Я не стану подробно описывать эту методику, но дополнительные сведения о ней вы найдете здесь: http://msdn.microsoft.com/en-gb/library/windows/desktop/ee416307(v=vs.85).aspx. Работает она примерно так: в поле зрения камеры игрока немедленно рисуются четыре цели отрисовки с тенями всех объектов, каждая с разным уровнем детализации.


Рисунок 7. Каскадные карты теней — представление отладчика игрового движка.

Затем шейдер получает инструкции изменить цвет того или иного пикселя на экране на основании того, попадает ли этот пиксель в область предварительно вычисленной тени. Проблема в том, что это очень ресурсоемкий эффект шейдера, потребляющий много видеопамяти. Ниже приведен код шейдера фрагментов. Обратите внимание, что несколько раз используется ветвление IF, а производительность некоторых графических процессоров ощутимо падает для каждой новой ветви IF. В крайних случаях некоторые системы вычисляют все изменения каждого выходного пикселя, то есть ветвление кода не дает вообще никаких преимуществ.

fPercentLit = 0.0f;
if ( iCurrentCascadeIndex==0 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap1,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
else
{
	if ( iCurrentCascadeIndex==1 )
	{
		fPercentLit += vShadowTexCoord.z > tex2D(DepthMap2,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
	}
	else
	{
		if ( iCurrentCascadeIndex==2 )
		{
			fPercentLit += vShadowTexCoord.z > tex2D(DepthMap3,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
		}
		else
		{
			if ( iCurrentCascadeIndex==3 && vShadowTexCoord.z<1.0 )
			{
				fPercentLit += vShadowTexCoord.z > tex2D(DepthMap4,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
			}
		}
	}
}

Необходимо снизить нагрузку на видеопамять и зависимость от ветвей IF. Решение (одно из возможных) — создать единую очень большую текстуру теней и поместить в эту цель отрисовки результаты самого низкого уровня детализации.

Я написал новую, менее ресурсоемкую методику, которая просто считывала данные из этой большой текстуры без всяких ветвлений. Особенности такого подхода выходят за рамки этой статьи, но общий смысл в том, что сначала нужно выявить причину снижения производительности, а затем придумать такое решение, которое работало бы быстрее, но давало бы изображение такого же качества.

Поддержание качества изображения

При оптимизации игрового движка необходимо следить за сохранением качества изображения на всех этапах разработки игры. Нетрудно просто вырезать все красивые, но ресурсоемкие эффекты ради прироста производительности, но лучше рассматривать каждую проблему как возможность повышения производительности с сохранением требуемого качества картинки. При этом вы не только добьетесь желаемых результатов, но и игра будет еще лучше работать на мощных компьютерах, что дает вам возможность добавлять новые компоненты и элементы при дальнейшем развитии игры.


Рисунок 8. Сравнение игровой сцены при чрезмерном снижении качества изображения.

Разрабатывая игру на настольном ПК, вы наверняка захотите использовать сложные шейдеры фрагментов для создания разнообразных эффектов поверхностей. Если просто удалить их из игры, изображение ухудшится настолько, что станет совсем не похоже на исходное. Для сохранения целостности игры важно поддерживать однородный визуальный стиль для всех методик работы шейдеров. Новые пользователи могут сначала впечатлиться великолепным снимком экрана в интернет-обзоре игры, но будут разочарованы, когда запустят вашу игру и увидят на экране что-то совсем иное.

Во всех возможных случаях старайтесь применять методики, воспроизводящие эффекты ресурсоемких шейдеров с меньшими затратами. Например, можно использовать заранее наложенные текстуры или применять ресурсоемкие пиксельные эффекты только в самой близкой к игроку области.

Уделяйте больше внимания своим близким.

Звучит как хороший жизненный совет, но это еще и неплохая стратегия для оптимизации шейдеров на Ultrabook. Одной инструкции ветвления IF достаточно, чтобы определить, насколько близко к игроку находится вычисляемый пиксель. Если близко, то можно, как и ранее, использовать ресурсоемкий эффект пиксельного шейдера, но если далеко, можно использовать намного менее затратную имитацию или заранее просчитанные эффекты.


Рисунок 9. Эффект смешения в действии: обратите внимание на эффекты карты нормалей вблизи.

Вместе с описанной выше методикой также можно использовать смешение, а если добавить одну дополнительную ветвь IF, можно проверять, на каком расстоянии между двумя точками удаления от игрока находится каждый пиксель. Вблизи игрока (ближе первой точки) можно использовать ресурсоемкие эффекты, а за пределами второй точки можно применять эффекты попроще. Между первой и второй точками следует вычислять смешанный эффект, промежуточный между первым и вторым подходами. Важно, чтобы расстояние между этими двумя точками было сравнительно небольшим, чтобы избежать удвоенного расхода вычислительных ресурсов. Расстояние смешения должно быть настолько большим, чтобы переход остался не замеченным игроком. В приведенном ниже фрагменте кода каждый пиксель обрабатывается в зависимости от его расстояния от камеры обзора: если расстояние составляет от 400 до 600 единиц, вычисляются обе ветви кода.

float4 lighting = float4(0,0,0,0);
float4 viewspacePos = mul(IN.WPos, View);
if ( viewspacePos.z < 600.0f )
{
	// work out surface normal per pixel
	lighting = lit(pow(0.5*(dot(Ln,Nb))+0.5,2),dot(Hn,Nb),24);
}
if ( viewspacePos.z > 400.0f )
{
	// cheapest directional lighting
	lighting = lerp ( lighting, cheaplighting, min((viewspacePos.z-400.0f)/200.0f,1.0f) );
}

Результат получается на удивление хороший, а переход очень плавный и совершенно незаметный при отрисовке. При этом в 90 % сцены теперь используется весьма экономный с точки зрения нагрузки эффект, поэтому скорость игры значительно повышается.

Обработка на лету и предварительная обработка

На оптимизацию игры было затрачено немало времени и усилий, но все равно скорость пока еще отставала от заветных 60 кадров в секунду. Баланс между качеством изображения и возможным повышением производительности был достигнут, но другие части игрового движка, помимо системы шейдеров, образовывали немалый объем вычислительных издержек и снижали скорость игры.

В игровом движке была внутренняя система оценки производительности, которая грубо измеряла каждый крупный сегмент всего конвейера отрисовки. В дополнение к графике, движок также измеряет ресурсы, затрачиваемые на вычисление искусственного интеллекта, физики, оружия, отладки, объемного света и т. п. Один из счетчиков следил за отрисовкой травы в реальном времени: такая методика использовалась в игре для формирования иллюзии бесконечного травяного поля. Снизив ресурсоемкость обработки графики, мы обнаружили, что относительная ресурсоемкость процесса отрисовки травы резко возросла и стала следующей по величине во всем конвейере. При оптимизации нужно всегда следить за такими пиками, а если обнаружится, что они используют слишком много игровых циклов, нужно повнимательнее их изучить. Следует знать, какой уровень потребления ресурсов для того или иного компонента графики является разумным, а какой — явно чрезмерным. В данном случае трава явно не должна была расходовать свыше 10 % всех циклов, особенно с учетом крайнего их дефицита. На настольном ПК это было не столь заметно, но на Ultrabook это существенно повлияло на скорость. Помимо роста потребления ресурсов было замечено, что при игре, всякий раз, когда перед игроком происходила отрисовка новой травы, кадровая скорость резко падала, поскольку пиковая нагрузка мешала обычному плавному выполнению игры.


Рисунок 10. Зеленая, зеленая трава: отрисовка травы в реальном времени может оказаться чрезвычайно ресурсоемкой.

Решение состояло в том, чтобы перенести всю систему отрисовки травы на этап предвари-тельной обработки, происходящий еще до запуска самой игры. Вместо формирования травы «на лету» ее просто переместили перед игроком, причем на глаз практически никакой разницы не было заметно. Теперь ничего не требовалось создавать на лету: траву нужно было всего лишь передвигать. Мой Ultrabook вздохнул с облегчением, поскольку удалось высвободить очень много драгоценных циклов CPU для всего остального игрового движка. Я, в свою очередь, тоже вздохнул с облегчением, поскольку удалось достичь волшебных 60 кадров в секунду, игра пошла с нужной скоростью.

Загадочное дело таинственной неравномерности

Добившись идеальной скорости игры и проехав через полмира, чтобы представить игру и ее движок на конференции, я обнаружил, что на демонстрационных устройствах игра работает неравно¬мерно: то и дело происходят рывки, игра словно спотыкается. На настольных компьютерах этих рывков не было, как не было их и на Ultrabook, который я использовал для тестирования. Рывки возникали только на этих устройствах, причем, что интересно, они были мощнее, чем те устройства, на которых я вполне успешно тестировал игру.

После длительных обсуждений и изучения эту проблему удалось связать с так называемым «разрешением внутреннего таймера». Коротко говоря, во всех играх, скорость действия в которых не зависит от компьютера (то есть, к примеру, персонажу игры нужно одинаковое количество времени, чтобы пробежать из точки А в точку Б вне зависимости от того, на каком компьютере запущена игра), так вот, во всех таких играх требуется доступ к команде GetTime(). Существует несколько команд этого семейства, но самой популярной является команда timeGetTime(), возвращающая количество миллисекунд с момента включения компьютера. При этом предполагается, что результат дается с разрешением в 1 миллисекунду, и действи¬тельно, на многих настольных компьютерах время передается именно с такой точностью. Оказывается, на Ultrabook и других мобильных устройствах, где во главу угла ставится экономия электроэнергии, это разрешение не фиксировано, оно может составлять не 1 миллисекунду, а 10—15. Если вы используете этот таймер для управления физикой в игре, как это было в нашем игровом движке, игра начнет «дергаться» и «спотыкаться» совершенно произвольным образом, поскольку вызовы обновления физики будут хаотично перепрыгивать с одного полученного времени к другому.

Причина перехода от разрешения в 1 мс к 10—15 мс в том, что некоторые системы могут сократить потребление электроэнергии, снизив частоту работы процессора, а из-за этого и частота тактовых импульсов может непредсказуемо измениться. Для этой проблемы существует несколько решений. Мы рекомендуем использовать команду QueryPerformanceTimer(), гарантирующую точность возвращаемого значения времени за счет второй команды, возвращающей частоту работы таймера.

5. Подсказки и советы

Что нужно сделать

  • Дополняйте шейдеры добавочными технологиями, а не заменяйте их при оптимизации для Ultrabook. Ваша игра должна работать и на настольных компьютерах, и на Ultrabook; процесс распространения игры намного проще, если вся игра упакована в один двоичный файл. Шейдеры DirectX* и OpenGL* позволяют создавать разные технологии в рамках одного шейдера. Поскольку ваша игра содержит все необходимое, код игры может определять, на какой платформе игра запущена в данный момент, и выбирать оптимальную процедуру отрисовки, которая на этой платформе даст наибольшую скорость и наивысшее возможное качество.
  • Предложите пользователям экран настроек, где можно выбрать нужный уровень производительности и качества. В подавляющем большинстве случаев компьютерные игроки рассчитывают на наличие таких настроек. Всегда хорошо определять и заранее устанавливать настройки, оптимальные для данной конкретной системы, но у пользователя должна быть возможность изменять эти настройки; кроме того, выбранные вами настройки по умолчанию должны всегда быть работоспособными в системе пользователя.

Чего не стоит делать

  • Не исходите из того, что ваша игра обязана работать со скоростью 60 кадров в секунду. На большинстве современных устройств можно настроить интервал обновления экрана, чтобы пропускать один или даже три сигнала вертикальной развертки: при этом сохранится нужная плавность игры, но при скорости в 30 кадров в секунду. Разумеется, все будет не настолько чудесно, как при 60 кадрах в секунду, но если правильно отрегули¬ровать синхронизацию, игра все же будет восприниматься очень хорошо.
  • При разработке игры не следует недооценивать ресурсоемкость шейдеров фрагментов, особенно если предполагается использовать не самое мощное графическое оборудование. Если скорость игры недопустимо низка, откажитесь от использования шейдеров или ограничьте их использование, действуя методом исключения.
  • Не следует заранее выбирать разрешение экрана вместо пользователя: выбранное вами разрешение может не поддерживаться экраном устройства. Используйте API Windows* API для опроса устройства и получения совместимого разрешения по умолчанию.
  • • Не полагайтесь на то, что timeGetTime() возвращает время с интервалами в 1 милли-секунду. На Ultrabook при включенных технологиях экономии электроэнергии интервалы могут составлять 10—15 мс!

6. Краткие советы по работе с Ultrabook

Дальнейший текст может показаться цитированием очевидного, но тем не менее: предлагаю краткое и полезное руководство по тестированию, запуску и демонстрации ваших игр и трехмерных приложений на Ultrabook.

Экономия электроэнергии

При демонстрации для большой аудитории, если вы хотите показать свою игру в лучшем виде, обязательно подключите Ultrabook к электросети. Не работайте от аккумулятора: для экономии электроэнергии система будет ограничивать производительность оборудования, тогда как вам требуется полная мощность.


Рисунок 11. Управление электропитанием на Ultrabook.

На всякий случай найдите «Управление электропитанием» на панели управления и убедитесь, что при питании компьютера от сети все меры экономии электроэнергии отключены, а все возможные параметры установлены на максимум.

Графика

На панели управления есть еще один раздел, где вы можете управлять ускорением графичес-кого адаптера устройства. Вы найдете параметры, отвечающие за работу GPU и драйвера в режиме экономии электроэнергии. Нужно выбрать режим наибольшей производительности (или эквивалентный ему), чтобы гарантировать наиболее быструю работу графического процессора.


Рисунок 12. :Параметры ускорения обработки графики на Ultrabook™

Необходимость таких действий может вызвать недоумение, но помните, что во главу угла при разработке Ultrabook ставится экономия электроэнергии везде и всегда, где это возможно, что позволяет таким устройствам подолгу работать без подзарядки. Самый простой и действен¬ный способ достижения максимальной производительности Ultrabook — включить его в розетку и выставить все настройки на максимум.

Фоновые задачи

Опытные разработчики, да и опытные пользователи согласятся с этим простым, но эффектив-ным советом: нужно посмотреть, какие фоновые задачи запускаются на Ultrabook при загрузке Windows. Предполагалось, что фоновые программы будут полезными, и при этом не будут потреблять слишком много ресурсов, но когда их много, они имеют нехорошую тенденцию довольно серьезно загружать CPU.

Сколь бы важными ни были эти задачи, когда вы демонстрируете, насколько быстро ваша трехмерная игра может работать на Ultrabook, разумно отключить вообще все задачи, которые не нужны непосредственно для этой цели. За фоновые задачи не беспокойтесь, при следующей загрузке Ultrabook они снова появятся, но зато сейчас в течение всего оставшегося сеанса Windows все ресурсы устройства будут предоставлены одному-единственному приложению — вашему!

7. Выводы

Тема оптимизации игр весьма обширна. Разработчики должны рассматривать оптимизацию как неотъемлемую часть своей повседневной работы. Цель в том, чтобы вашу игру можно было запускать на как можно более широком наборе оборудования. Для достижения этой цели потребуется весь ваш опыт, все знания и умения. Применяя такие средства Intel®, как VTune™ Analyzer и Intel Graphics Performance Analyzers, можно ускорить решение этой задачи. Статьи, подобные этой, подскажут возможные решения, но в конечном итоге все зависит от вашей сообразительности. Как можно добиться этого же результата другим способом? Можно ли сделать это быстрее? Можно ли сделать это умнее? Вот с таких вопросов следует начинать, и чем чаще вы станете их задавать, тем эффективнее сможете оптимизировать свои игры и приложения. Как я предположил в начале этой статьи, вы не только станете выпускать более качественный код, но и расширите свои позиции на стремительно растущем рынке!

Другие материалы по теме

Codemasters GRID 2* on 4th Generation Intel® Core™ Processors - Game development case study
Not built in a day - lessons learned on Total War: ROME II
Developer's Guide for Intel® Processor Graphics for 4th Generation Intel® Core™ Processors
PERCEPTUAL COMPUTING: Augmenting the FPS Experience

Об авторе

Во время, свободное от написания статей, Ли Бэмбер руководит британской компанией The Game Creators (http://www.thegamecreators.com)), которая специализируется на разработке и распространении средств создания компьютерных игр. Эта компания ведет свою историю с 1999 года. Среди плодов работы этой компании вместе с окружающим ее разработчиком игр — множество популярных брендов, в том числе Dark Basic, FPS Creator, а также App Game Kit (AGK). Ли также ведет хронику своей повседневной работы разработчика вместе со снимками экрана и видеороликами: http://fpscreloaded.blogspot.co.uk




 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.

Any software source code reprinted in this document is furnished under a software license and may only be used or copied in accordance with the terms of that license.
Intel, the Intel logo, Ultrabook, and VTune are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.


Развивающие игры для детей на основе Intel® Perceptual Computing. Разработка «Приключений Клифорда» для сенсорного компьютера-моноблока (AIO).

$
0
0

Download PDF

Введение

В этой статье освещается разработка серии интерактивных развивающих игр для детей младшего возраста «Приключения Клифорда»от компании Scholastic Interactive. Разноплановое использование жестов и голоса в этой игре стали возможными благодаря технологии Intel® Perceptual Computing SDK 2013. Здесь обсуждаются новые методы распознавания жестов и голоса с помощью технологий Perceptual Computing (естественные методы взаимодействия с компьютером), методика решения проблем с SDK, а также вопросы поддержки портативных компьютеров-моноблоков (AIO).


Рисунок 1. Пес Клифорд*

Концепция развивающей игры.

Scholastic Interactive — это подразделение Scholastic, международной медиа-, образовательной и издательской компании. Миссия Scholastic Interactive — создание игр, которые не просто были бы развлечением для детей, но и способствовали бы их развитию. Для компании методы естественных взаимодействий с компьютером — это новое направление в развива¬ющих играх для малышей, ведь ребенок осваивает их сам интуитивно, а не через предвари¬тельное обучение. Интеграция платформы Perceptual Computing со средствами распознавания голоса и жестов дает детям от трех лет возможность участвовать в приклю¬чениях вместе с Клифордом и его друзьями.

В этой серии из четырех интерактивных эпизодов про Клифордаигроки просматривают сюжет и взаимодействуют с ним посредством речи и сенсорного экрана своего компьютера. Игра вовлекает детей в сюжет, предлагая различными способами «помогать» Клифорду посредством определенных жестов и высказываний.


Рисунок 2. Приключения Клифорда. Меню.

Интерактивное эмпирическое обучение.

Благодаря интерактивной технологии Scholastic Клифордреагирует на голос и движения детей. В ходе сюжета игры они смотрят анимированные отрывки каждого приключения и активно содействуют героям, прикасаясь к экрану или произнося ответы на вопросы. Сюжет развивается по мере взаимодействия ребенка с игрой. Каждая игра рассчитана на развитие базовых навыков грамотности и может повторяться сколько угодно раз.

Intel Perceptual Computing SDK 2013 включает в себя API, образцы кода, а также руководства по программной интерпретации жестов и речи ребенка, взаимодействующего с игрой. Разработчики могут без труда сочетать возможности SDK по распознаванию речи, жестов руки и пальцев, мимики, технологии дополненной реальности и вычитания фона, создавая ПО для новейших планшетов, компьютеров Intel Ultrabook™ и сенсорных моноблоков. Использование микрофона, камеры, сенсорного экрана, функций определения положения в пространстве и геолокации, широко распространенных на планшетах, ноутбуках трансформерах и компьютерах-моноблоках повышает многомерность восприятия новых приложений.


Рисунок 3. Intel® Perceptual Computing SDK.

Команда разработчиков.

Специалисты Scholastic изучили видение нескольких коллективов разработчиков относительно концепции игры, интерактивного взаимодействия и основных вопросов пригодности программных продуктов для детей. В итоге Scholastic установила партнерские отношения с Symbio, чьи специалисты имеют большой опыт в создании средств распознавания голоса и жестов, игр, образовательных программ для детей, а также в вопросах детской эргономики.

Разработки на основе Intel® Perceptual Computing Platform.

Адаптация технологий Perceptual Computing к анализу движений и голоса детей несет в себе ряд сложностей. Scholastic всесторонне протестировала каждый прототип, чтобы оценить дизайн игры и реальность прохождения ее уровней. Это помогло выявить потенциальные проблемы, с которыми могла столкнуться целевая аудитория, и найти для них решения.

Некоторые аспекты проведенной работы могут представить особый интерес с точки зрения технологии Perceptual computing. Они приводятся ниже.

 

Калибровка распознавания голоса.

Чтобы обеспечить приемлемое качество распознавания голоса, потребовалось провести ряд проверок. Голос ребенка изменяется по мере взросления, особенно в том возрасте, на который рассчитана серия «Клифорд». Поэтому необходимо было добиться такого уровня калибровки, чтобы детский голос и речевые конструкции распознавались правильно.


Рисунок 4. Эпизод игры, требующий речевого участия игрока.

Распознавание и локализация жестов.

В одной из игр «Приключений Клифорда»от ребенка требуется помочь собаке ловить игрушки, падающие с дерева. Для этого нужно касанием руки «схватить» корзину на экране и двигать ее в разные стороны. 


Рисунок 5. Дерево игрушек Клифорда.

Были разработаны специальные алгоритмы, распознающие жесты и сопоставляющие их с координатами касания, чтобы корзина на экране двигалась вслед за рукой ребенка. В тестировании с удовольствием принимали участие маленькие игроки. Ранее разработчики ошибочно полагали, что у ребенка жесты удержания объекта на экране не будут сильно отличаться от жестов взрослого. Но работа с детьми заставила пересмотреть дизайн игры таким образом, чтобы она воспринимала их нечеткие движения. Научить сенсоры понимать размашистые, часто ошибочные и хаотичные жесты ребенка, состоящие из множества касаний, было непросто. Требовалось много работы по определению прототипов жестов и отбору их наиболее общих конфигураций. Область регистрации касаний была расширена, чтобы даже неточный жест распознавался и вызывал нужную реакцию приложения.

К примеру, в другой мини-игре дети помогают Клифорду убрать из сада сорняки. Вместо того, чтобы заставлять игроков брать сорняк и двигать руку вверх, вытягивая его, разработчики выбрали движения захвата и раскрытия ладони, обозначающие выдергивание и выбрасывание. Адаптация к уровню развития детской моторики позволила сделать игровое приложение более успешным.


Рисунок 6. Ребенок помогает Клифорду убирать сорняки.

Ниже приведен фрагмент кода игры, калибрующий жесты игрока в обучающем упражнении, где требуется вращать руками мячик. В эпизоде, изображенном на рисунке 7, для более точного контроля объекта и легкости движений применили экспоненциальное сглаживание (exponential smoothing). Оно вычленяет или, по крайней мере, приблизительно вычисляет случайные движения игрока, которые программа должна игнорировать.


Рисунок 7:Вращение мяча.


Figure 8:Пример кода для вращения мяча.

Решение проблем с Intel® Perceptual Computing SDK

Благодаря многомерному восприятию, которое возможно с SDK от Intel, игроки получают немедленную реакцию программы на их действия. Это создает ощущение физического участия в происходящем. Однако разработчики столкнулись с некоторыми ограничениями в возможностях распознавания сложных движений и голосовых реакций детей.

 

Жесты

Камера, воспринимающая жесты, сфокусирована на расстоянии около 60–90 см. Поэтому мелкие движения регистрируются лучше, чем размашистые или комплексные, выходящие за пределы данного диапазона.

Оптимальный набор жестов был определен методом проб и ошибок. Специалистам пришлось подумать о различных условиях окружающей среды, освещении и расстоянии до камеры.

С точки зрения SDK, API и других используемых технологий, разработать первоначальные вари-анты жестов несложно, потому что обучающие упражнения, образцы кода и используемые структуры имеются в SDK. После настройки среды разработки можно выполнять обучающее упражнение, например отслеживание пальцев, чтобы изучить взаимодействие сенсоров и кода в SDK.


Рисунок 9. Взаимодействие сенсоров жестов и кода в Intel® Perceptual Computing SDK 2013.

Программисты обнаружили, что в SDK не хватает различных систем координат для жестов. Это пришлось восполнить собственными разработками. 


Рисунок 10:Визуальная схема координат жестов.

Изначально команда разработчиков использовала подход node[8].positionImage.x/y, игнорируя данные о глубине, т. к. они не требовались для интерпретации жестов. Но впоследствии был найден более оптимальный подход. Использовалось «глубинное изображение» и отыскивался ближайший пиксель, на основе чего эффективно определялся жест. Затем было добавлено экспоненциальное сглаживание.

Распознавание голоса.

Распознавание голоса в игре сильно зависело от устройств и сюжета. На одних устройствах и в одних ситуациях оно работало хорошо, в других условиях не работало совсем.

Игра должна подсказывать детям команду, которую нужно произнести, чтобы она была записана с помощью микрофона. Функция должна работать даже на фоне посторонних звуков и музыкального сопровождения игры. Распознавание голоса может работать в режиме детектирования речи, когда программа пытается определить, что вы сказали, или в режиме словаря, когда сказанное сопоставляется с вашим словарем, который определяется в случае данной игры пользователем.

Сначала специалисты попробовали первый режим и настроили его на учет любых звуков, основываясь на том, что речь маленьких детей не всегда четко артикулируется. Но результаты оказались неудовлетворительными. Тогда было решено перейти к режиму словаря. Он хорошо работает, если слова произносятся отчетливо. Разработчики попробовали добавить в словарь варианты слов, чтобы увеличить вероятность их распознавания (например, трактор — тлактол — тъяктол). Однако режим словаря не дал ожидаемых результатов, потому что чем больше в словаре единиц, тем выше вероятность ошибки. Пришлось искать компромисс между величиной списка слов и потенциальной долей ошибок. В конечном варианте список допустимых слов был сведен к минимуму, чтобы оставить возможность простого взаимодействия ребенка с игрой.

Влияние размера экрана. Сенсорные компьютеры-моноблоки.

С развитием сенсорных экранов на рынке начинают появляться модели с большой диагональю. «Приключения Клифорда» созданы с учетом этой тенденции. Большие сенсорные экраны применяются, в частности, в компьютерах-моноблоках AIO.

Такие компьютеры состоят из монитора (от 18 до 55 дюймов) и материнской платы, встроенной позади него. У них высокопроизводительные процессоры, высокое разрешение (1080p/720p), они снабжаются беспроводными (Bluetooth*) клавиатурой и мышью и емкой встроенной батареей, что делает устройство портативным и способным к автономной работе. Это одна из самых быстроразвивающихся разновидностей компьютеров. Моноблоки популярны благодаря тому, что на них можно делать все, что возможно на обычном компьютере: играть в игры, просматривать веб-сайты, телепрограммы и фильмы, делать домашнюю работу, вести семейный бюджет, общаться с друзьями и т. д.

Многие из современных моноблоков являются портативными, что еще более расширяет область их применения. Портативные моноблоки имеют огромные преимущества для игр благодаря своему большому экрану, поддерживающему множественные касания, высокопроизводительному сетевому подключению, а также компактному корпусу. Они могут устанавливаться как под наклоном, так и горизонтально. Встроенные батарея и адаптер Wi Fi и позволяют пользоваться компьютером из любой точки квартиры или дома. Большой HD монитор с поддержкой множественных касаний и графический процессор высокого класса превращают работу с таким компьютером в удовольствие. Все эти качества делают моноблок очень привлекательной базой для разработчиков, желающих выйти за рамки мобильных устройств для одного пользователя.

Создателям «Клифорда» очень хотелось видеть свою игру на больших экранах, и поэтому они позаботились о том, чтобы она подходила для разрешения 1920 x 1080.

Заключение

Стадия тестирования прошла весело. Разработчики получили ценный опыт, работая с детьми, конечными пользователями приложения. И еще приятнее было увидеть готовую игру в использовании. Один из наших старших специалистов показал ее своей трехлетней дочери, и все мы были очень рады услышать, что девочка играла в «Приключения Клифорда» с огромным интересом и азартом. Ура!


Рисунок 11.Клифорд и его друзья.

Теперь Scholastic не терпится применить свои технологии в новых проектах. Совместно с Symbio ведется работа над новой игрой на основе Intel® RealSense™ 3D SDK, которую планируется выпустить осенью 2014 года.


Рисунок 12:Игра готова.

Технология Intel® Real-Sense™

Анонсированная на выставке CES 2014, технология Intel® RealSense™ — это новый образ Intel® Perceptual Computing, SDK с интуитивным пользовательским интерфейсом и функциями распознавания речи, жестов, движений руки и мимики. Эти технологии компания Intel представила еще в 2013 г. Intel RealSense предоставляет разработчикам дополнительные возможности, такие как сканирование, редактирование, 3D-печать, распространение, а также технологии дополненной реальности. Благодаря им пользователи могут манипулировать отсканированными 3D объектами с помощью новейшей технологии сенсорного управления.

Ссылки и полезные материалы

Об авторе

Тим Дункан — один из наших инженеров. Друзья называют его «мистер Гаджет». В настоящее время он помогает разработчикам применять в их продуктах новые технологии Intel. Тим обладает многолетним опытом работы в отрасли и знаком со многими ее сторонами: от производства микросхем до интеграции целых систем. Вы можете найти его на сайте Intel® Developer Zone: Tim Duncan (Intel).

 

Примечания

Исходный код предоставлен Scholastic Interactive LLC для метода экспоненциального сглаживания для приложений, использующих технологию Intel Perceptual Computing, созданных для платформы Windows 8. 

Scholastic Sample Source License

Copyright (c) 2014, Scholastic Interactive LLC. Code pertaining to exponential smoothing functionality contained in the Clifford’s Reading Adventures 1.0 game (“Sample Code”). All rights reserved.

Redistribution and use in source and binary forms of the Sample Code, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The name of the Sample Code, Clifford’s Reading Adventures or any names or trademarks contained therein, the name of the copyright holder or its affiliates or the names of contributors to the Sample Code may be used to endorse or promote products derived from this software, or in any other manner, without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  FOR THE AVOIDANCE OF DOUBT, THE ONLY RIGHTS GRANTED UNDER THIS LICENSE ARE LIMITED TO THE SOFTWARE SPECIFICALLY DESCRIBED ABOVE, AND ANY USERS OF THE SAMPLE CODE SHALL HAVE NO LICENSE OR RIGHTS IN OR TO (A) ANY OTHER SOURCE OR BINARY CODE, OR ANY OTHER SOFTWARE OR TOOLS, THAT MAKES UP OR IS EMBEDDED IN THE CLIFFORD’S READING ADVENTURES GAME, OR (B) ANY OTHER INTELLECTUAL PROPERTY OF THE COPYRIGHT HOLDER OR ITS AFFILIATES.

Clifford Artwork © Scholastic Entertainment Inc.  CLIFFORD THE BIG RED DOG and associated logos are trademarks of Norman Bridwell.  All rights reserved.

 

Intel, the Intel logo, and RealSense are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

 

Разработка многопользовательских приложений для моноблоков и планшетов

$
0
0

Создание многопользовательского интерфейса с поддержкой сенсорного управления для Windows*






 

Скачать PDF

Введение

Моноблоки впервые появились в середине 1990-х годов и с тех пор широко используются в различных сферах. Эти устройства были призваны освободить рабочее пространство от громоздкого монитора, системного блока и устройств ввода, и потому на них возлагали большие надежды. Однако поначалу они не были слишком популярными, так как сильно уступали в производительности традиционным настольным ПК и отличались высокой стоимостью. К счастью, современные моноблочные компьютеры избавлены от этих недостатков.

В качестве устройства для дома пользователи, как правило, выбирают модели с экраном диагональю 55 дюймов. Их легко разместить на рабочем столе, и они удобны в работе. Благодаря моноблокам пользователи открыли для себя новые возможности цифрового мира, чем не преминули воспользоваться разработчики приложений, предлагая новые уникальные приложения, рассчитанные на несколько игроков.

К сожалению, в настоящий момент интерфейс прикладного программирования (API) Windows не располагает достаточными средствами для создания приложений для двух или более пользователей. Однако это не значит, что разработчики не могут использовать свои собственные. При разработке интерфейса самое главное сделать так, чтобы приложением было легко пользоваться и чтобы оно правильно воспринимало команды ввода.

Ниже мы рассмотрим, какие средства API Windows можно использовать для разработки приложений с сенсорным управлением, а также продемонстрируем, как с их помощью создать простую многопользовательскую игру.

Создание пользовательского интерфейса

Современные сенсорные экраны не способны определить, кто из пользователей (если их нес-колько) коснулся дисплея. В каких-то случаях этим можно пренебречь. Например, в настольной игре совсем не важно, кто из игроков перемещает фишки по полю, так как за этим следят сами пользователи.

Другое дело, когда необходимо правильно определять команды, поступающие от каждого игрока (как на рис. 1), и обеспечить одновременное взаимодействие с интерфейсом. В этом случае разработчик должен создать наиболее эффективный способ определения того, кто из игроков коснулся экрана. Как правило, для этого делят экран на несколько частей (каждая часть для одного игрока). Пользователи должны сами следить за тем, чтобы не выходить за границы своей зоны. Естественно, существуют и другие методы создания многопользовательского интерфейса (например, с помощью эвристических средств), однако в этой статье они не освещаются.

API Windows

Windows поддерживает два основных формата сенсорных команд. Первый — это сообщения WM_TOUCH. Они отвечают только за первичные данные, поэтому приложение должно само обработать и выполнить поступающие команды.

Второй формат — WM_GESTURE. Это сообщение генерируется при использовании одного из жестов управления Windows, например масштабирования с помощью разведения и сведения пальцев, перетаскивания элементов и т. д. Благодаря их наличию задача разработчика существенно упрощается, поскольку операционная система может сама распознавать жесты управления и касания экрана и передавать их приложению в удобном для обработки виде.

В настоящий момент в Windows поддерживаются только сенсорные команды, поступающие от одного пользователя (руки), поэтому использовать сообщения WM_GESTURE для распознава¬ния касаний нескольких игроков в нашем приложении не получится.

Кроме того, важно помнить, что API-интерфейс определяет координаты касаний по отношению ко всему экрану (они измеряются в сотых долях пикселя), а не только внутри окна программы. Если нужно получить именно координаты в окне, следует конвертировать их с помощью функции ScreenToClient().

Пример приложения

В качестве примера мы решили воссоздать классический симулятор настольного тенниса — игру Pong, и наделить ее сенсорным управлением. Игровой процесс состоит в том, что игроки передвигают ракетки по вертикали, отбивая мячик на сторону соперника. Когда мячик достигает одной из границ поля (по вертикали), игрок на противоположной стороне получает очко.

Мячик двигается по экрану по диагонали. После каждого движения приложение проверяет, не встретил ли он препятствие. Если мячик ударяется о верхнюю или нижнюю границы игрового поля, его вертикальная траектория изменяется в соответствии с углом столкновения. Если он ударяется о ракетку или о вертикальную границу окна, его горизонтальная траектория также изменяется на противоположную.

Обработка перемещения мяча происходит в отдельном потоке самого приложения для обеспечения плавности движения во время выполнения сенсорных команд.

Рендеринг графики осуществляется стандартными вызовами интерфейса графических устройств (GDI) Windows. В качестве ракеток служат обычные прямоугольники, в качестве мяча — круг. Счет матча отображается как текст на фоне. При создании этого приложения не использовались растровые отображения объектов или другие графические средства. Пример интерфейса показан на рисунке ниже. Нажмите на него, чтобы просмотреть видеоролик о работе приложения.

Рисунок 1.Стандартный интерфейс для двух пользователей.

Интерфейс для двух пользователей с поддержкой сенсорного управления

Чтобы игра воспринимала касания каждого пользователя, мы разделили экран на две части: игрок 1 находится слева, игрок 2 — справа.

Каждый раз, когда происходит событие WM_TOUCH, программа получает полный список точек касания (пример кода 1). В нем может содержаться от одной до нескольких записей (максимальное количество точек зависит от возможностей устройства). Затем производится итерация, которая позволяет определить координаты каждого касания по осям X и Y:

…
	                bret = GetTouchInputInfo(
				(HTOUCHINPUT)lparam,
				data.geometry_data.touch_inputs_count,
				data.geometry_data.touch_inputs,
				sizeof(TOUCHINPUT)
				);
			assert(bret != FALSE);
	//-----------------------------------------------------------------
	// обработка сенсорных команд
	//-----------------------------------------------------------------
			for(i = 0; i < data.geometry_data.touch_inputs_count; i++)
	                   {
				touch_input = &data.geometry_data.touch_inputs[i];
	//-----------------------------------------------------------------
	//преобразование сотых долей пикселя в пиксели
	//-----------------------------------------------------------------
				x = touch_input->x / 100;
				y = touch_input->y / 100;)
	                   {…

Пример кода 1.

Далее необходимо определить, с какой стороны произошло касание, после чего обновить вертикальное расположение ракетки так, чтобы оно совпадало с положением пальца игрока (пример кода 2). Таким образом будет происходить перемещение ракетки по полю.

…
	if (x < (ULONG)((data.graphic_data.rect.right – data.graphic_data.rect.left) /          2))
	   {
	//-----------------------------------------------------------------
	// разделение экрана для двух пользователей
	//-----------------------------------------------------------------
	   Data.geometry_data.p1y = y;
	   }else{
	   Data.geometry_data.p2y = y;
	   }
	bret = move_paddles(&data);
	assert(bret == TRUE);
	   {

Пример кода 2.

Так как приложение обрабатывает все команды ввода, игроки могут не только одновременно нажимать на экран, но и выполнять несколько касаний. При этом положение ракетки будет определяться по последнему зарегистрированному касанию.

Адаптация приложения для четырех пользователей

Чтобы адаптировать приложение для четырех пользователей, необходимо изменить игровое поле и активные зоны игроков.

Мы добавили две ракетки и два табло со счетом внизу и вверху экрана. Разграничительные линии игровых зон приобрели форму буквы «Х», разделив окно приложения на четыре треугольника (рисунок 2).

Рисунок 2.Разделение игровых зон для четырех игроков.

На рисунке 3 показано, как приложение определяет, в какой из зон произошло касание экрана.



 

Рисунок 3.Определение зоны сенсорной команды.

При разделении экрана на четыре зоны определить, в какой из них произошло касание, становится сложнее (пример кода 3).

…
	   if(touch_point.y > (LONG)(((float)data.graphic_data.rect.bottom / data.graphic_data.rect.right) * touch_point.x)) {
	     if(touch_point.y > (LONG)((((float)data.graphic_data.rect.bottom /  data.graphic_data.rect.right) * -1) * touch_point.x) + data.graphic_data.rect.bottom){
	       data.geometry_data.p4x = touch_point.x;
	       }else{
	       data.geometry_data.p1y = touch_point.y;}
	   }else{
	   if(touch_point.y < (LONG)((((float)data.graphic_data.rect.bottom / data.graphic_data.rect.right) * -1) * touch_point.x) + data.graphic_data.rect.bottom)
	   {
	   data.geometry_data.p3x = touch_point.x;
	   }else{
	   data.geometry_data.p2y = touch_point.y;
	   }
	}…

Пример кода 3.

Пример интерфейса игры для четырех пользователей показан на рисунке ниже. Нажмите на него, чтобы просмотреть видеоролик о работе приложения.

Рисунок 4.Игра для четырех пользователей, запущенная на устройстве с 55-дюймовом экраном.

Заключение

При создании многопользовательских приложений с сенсорным управлением для Windows 7 и более поздних версий используйте сообщения WM_TOUCH и WM_GESTURES. Если вы найдете наиболее эффективный способ, как определить, в какой из игровых зон происходит касание, разработка приложения даже для четырех одновременно играющих пользователей не составит большого труда.

Об авторах

Стивен Роджерс работает в компании Intel более 20 лет. Он специализируется на настройке систем и управлении лабораториями. Стивен является техническим инженером-маркетологом в группе PLSE (развертывание платформ и проектирование масштабирования), где отвечает за отраслевые приложения.

Олден Сотелл участвует в программе «Компьютерные и информационные науки» в Портленд¬ском общинном колледже. В Intel работает по договору. Специализируется на настройке и обс¬луживании аппаратного обеспечения серверов для предприятий, сетевых устройств и ПО в лаборатории PLSE.

Жамель Тейебработает в группе Intel по разработке программного обеспечения и служб. Он получил степень кандидата компьютерных наук в Университете Валансьена и теперь занимается разработкой ПО.






 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.






 

Intel, the Intel logo, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.






 

Управление режимами вычислений с плавающей запятой при использовании Intel® Threading Building Blocks

$
0
0

В Intel® Threading Building Blocks (Intel® TBB) 4.2, обновление 4, появилась расширенная поддержка управления параметрами вычислений с плавающей запятой. Теперь эти параметры можно указать при вызове большинства параллельных алгоритмов (включая flow::graph). В этом блоге мне бы хотелось рассказать о некоторых особенностях, новых функциях и общей поддержке вычислений с плавающей запятой в Intel TBB. Этот блог не посвящен общей поддержке вычислений с плавающей запятой в ЦП. Если вы незнакомы с поддержкой вычислений с плавающей запятой в ЦП, рекомендую начать с раздела Операции с плавающей запятойв справочном руководстве Intel® C++ Compiler. Для получения дополнительных сведений о сложностях арифметики с плавающей запятой рекомендую классику “Все, что необходимо знать об арифметике с плавающей запятой”.

В Intel TBB предлагается два способа, при помощи которых можно задать нужные параметры вычислений с плавающей запятой для задач, выполняемых планировщиком задач Intel TBB:

  1. Когда планировщик задач инициализируется для заданного потока приложения, он получает текущие параметры вычислений с плавающей запятой этого потока;
  2. У класса task_group_context есть метод для получения текущих параметров вычислений с плавающей запятой.

Рассмотрим первый подход. Такой подход, по сути, является неявным: планировщик задач всегда и безусловно получает параметры вычислений с плавающей запятой в момент своей инициализации. Затем сохраненные параметры используются для всех задач, связанных с этим планировщиком задач. Другими словами, такой подход можно рассматривать как свойство планировщика задач. Поскольку это свойство планировщика задач, мы можем применять и управлять параметрами вычислений с плавающей запятой в нашем приложении двумя способами:

  1. Планировщик задач создается для каждого потока, поэтому мы можем запустить новый поток, задать нужные параметры, а затем инициализировать для этого потока новый планировщик задач (явно или неявно), который получит параметры вычислений с плавающей запятой;
  2. Если поток уничтожает планировщик задач и инициализирует новый, можно будет получить новые параметры. Можно указать новые параметры вычислений с плавающей запятой перед повторным созданием планировщика. При создании нового планировщик задач параметры будут применены для всех задач.

Я попробую показать некоторые особенности в следующих примерах:

Обозначения:

  • “fp0”, “fp1” and “fpx” – состояния, описывающие параметры вычислений с плавающей запятой;
  • “set_fp_settings( fp0 )” и “set_fp_settings( fp1 )” – указание параметров вычислений с плавающей запятой для текущего потока;
  • “get_fp_settings( fpx )” – получение параметров вычислений с плавающей запятой из текущего потока и сохранение этих параметров в “fpx”.

Пример #1. Планировщик задач по умолчанию.

// Suppose fp0 is used here.
// Every Intel TBB algorithm creates a default task scheduler which also captures floating-point
// settings when initialized.
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp0 will be used for all iterations on any Intel TBB worker thread.
} );
// There is no way anymore to destroy the task scheduler on this thread.

Пример #2. Настраиваемый планировщик задач.

// Suppose fp0 is used here.
tbb::task_scheduler_init tbb_scope;
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp0 will be used for all iterations on any Intel TBB worker thread.
} );

В целом, пример 2 действует так же, как пример 1, но зато предоставляет способ вручную завершить работу планировщика задач.

Пример #3. Повторная инициализация планировщика задач.

// Suppose fp0 is used here.
{
    tbb::task_scheduler_init tbb_scope;
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // fp0 will be used for all iteration on any Intel TBB worker thread.
    } );
} // the destructor calls task_scheduler_init::terminate() to destroy the task scheduler
set_fp_settings( fp1 );
{
    // A new task scheduler will capture fp1.
    tbb::task_scheduler_init tbb_scope;
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // fp1 will be used for all iterations on any Intel TBB worker
        // thread.
    } );
}

Пример #4. Еще один поток.

void thread_func();
int main() {
    // Suppose fp0 is used here.
    std::thread thr( thread_func );
    // A default task scheduler will capture fp0
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // fp0 will be used for all iterations on any Intel TBB worker thread.
    }
    thr.join();
}
void thread_func() {
    set_fp_settings( fp1 );
    // Since it is another thread, Intel TBB will create another default task scheduler which will
    // capture fp1 here. The new task scheduler will not affect floating-point settings captured by
    // the task scheduler created on the main thread.
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // fp1 will be used for all iterations on any Intel TBB worker thread.
    }
}

Обратите внимание, что Intel TBB может повторно использовать одни и те же рабочие потоки для обоих parallel_for, несмотря на то, что они вызваны из разных потоков. При этом гарантируется, что все итерации parallel_for в главном потоке будут использовать fp0, а все итерации второго parallel_for — fp1.

Пример #5. Изменение параметров вычислений с плавающей запятой в потоке пользователя.

// Suppose fp0 is used here.
// A default task scheduler will capture fp0.
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp0 will be used for all iterations on any Intel TBB worker thread.
} );
set_fp_settings( fp1 );
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp0 will be used despite the floating-point settings are changed before Intel TBB parallel
    // algorithm invocation since the task scheduler has already captured fp0 and these settings
    // will be applied to all Intel TBB tasks.
} );
// fp1 is guaranteed here.

Второй parallel_for оставит fp1 неизменным в пользовательском потоке (несмотря на то, что для всех итераций используется fp0), поскольку в Intel TBB гарантируется отсутствие изменений параметров вызывающего потока вызовом любого параллельного алгоритма Intel TBB, даже если алгоритм выполняется с другими параметрами.

Пример #6. Изменение параметров вычислений с плавающей запятой в задаче Intel TBB.

// Suppose fp0 is used here.
// A default task scheduler will capture fp0
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    set_fp_settings( fp1 );
    // Setting fp1 inside the task will lead undefined behavior. There are no guarantees about
    // floating-point settings for any following tasks of this parallel_for and other algorithms.
} );
// No guarantees about floating-point settings here and following algorithms.

Если вам очень нужно использовать внутри задачи другие параметров вычислений с плавающей запятой, следует записать предыдущие параметры, а в конце задачи восстановить их:

// Suppose fp0 is used here.
// A default task scheduler will capture fp0
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    get_fp_settings( fpx );
    set_fp_settings( fp1 );
    // ... some calculations.
    // Restore captured floating-point settings before the end of the task.
    set_fp_settings( fpx );
}
// fp0 is guaranteed here.

Для решения большей части проблем можно использовать подход с применением планировщика задач для управления параметров вычислений с плавающей запятой. Но представьте себе ситуацию, когда для каждой из двух частей вычисления требуются разные параметры. Разумеется, можно использовать подходы, показанные в примерах 3 и 4. Но при этом могут возникнуть определенные затруднения:

  1. Реализация затруднена: в примере 3 невозможно управлять жизненным циклом объекта планировщика задач, а в примере 4 может потребоваться синхронизация между потоками;
  2. Влияние на производительность: в примере 3 нужно заново инициализировать планировщик задач, тогда как ранее этого не требовалось, а в примере 4 может возникнуть проблема избыточной подписки.

Что происходит с вложенными вычислениями при разных параметрах вычислений с плавающей запятой? Применение планировщика задач в этом случае затрудняется, поскольку потребуется писать много бесполезного кода.

В Intel TBB 4.2 U4 появился новый подход на основе task_group_context: функциональность task_group_context была расширена для управления параметрами вычислений с плавающей запятой для задач, связанных с ним, с помощью нового метода

void task_group_context::capture_fp_settings();

получающего эти параметры из вызывающего потока и передающего их своим задачам. Таким образом, вы можете без труда задать нужные параметры для того или иного параллельного алгоритма:

Пример #7. Задание параметров вычислений с плавающей запятой для определенного алгоритма.

// Suppose fp0 is used here.
// The task scheduler will capture fp0.
task_scheduler_init tbb_scope;
tbb::task_group_context ctx;
set_fp_settings( fp1 );
ctx.capture_fp_settings();
set_fp_settings( fp0 );
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // In spite of the fact the task scheduler captured fp0 when initialized and the parallel
    // algorithm is called from thread with fp0, fp1 will be here for all iterations on any
    // Intel TBB worker  thread since task group context (with captured fp1) is specified for this
    // parallel algorithm.
}, ctx );

Пример 7 не особенно интересен, поскольку можно добиться такого же результата, если указать fp1 до инициализации планировщика задач. Рассмотрим гипотетическую проблему, когда для двух частей вычисления требуются разные параметры. Эту проблему можно решить так:

Пример #8. Задание параметров вычислений с плавающей запятой для разных частей вычислений.

// Suppose fp0 is used here.
// The task scheduler will capture fp0.
task_scheduler_init tbb_scope;
tbb::task_group_context ctx;
set_fp_settings( fp1 );
ctx.capture_fp_settings();
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // In spite of the fact that floating-point settings are fp1 on the main thread, fp0 will be
    // here for all iterations on any Intel TBB worker thread since the task scheduler captured fp0
    // when initialized.
} );
// fp1 will be used here since TBB algorithms do not change floating-point settings which were set
// before calling.
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp1 will be here since the task group context with captured fp1 is specified for this
    // parallel algorithm.
}, ctx );
// fp1 will be used here.

Я уже продемонстрировал одно свойство подхода на основе контекста группы задач в примерах 7 и 8: заданные таким способом параметры имеют более высокий приоритет, чем параметры, заданные с помощью планировщика задач, когда контекст указывается для параллельного алгоритма Intel TBB. При этом подходе наследуется еще одно свойство: вложенные параллельные алгоритмы наследуют параметры вычислений с плавающей запятой из контекста группы задач, указанного для внешнего параллельного алгоритма.

Пример #9. Вложенные параллельные алгоритмы.

// Suppose fp0 is used.
// The task scheduler will capture fp0.
task_scheduler_init tbb_scope;
tbb::task_group_context ctx;
set_fp_settings( fp1 );
ctx.capture_fp_settings();
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp1 will be here
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // Although the task group context is not specified for the nested parallel algorithm and
        // the task scheduler has captured fp0, fp1 will be here.
    }, ctx );
} );
// fp1 will be used here.

Если нужно использовать планировщик задач внутри вложенного алгоритма, можно использовать контекст изолированной группы задач:

Пример #10. Вложенный параллельный алгоритм с изолированным контекстом группы задач.

// Suppose fp0 is used.
// The task scheduler will capture fp0.
task_scheduler_init tbb_scope;
tbb::task_group_context ctx;
set_fp_settings( fp1 );
ctx.capture_fp_settings();
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // fp1 will be used here.
    tbb::task_group_context ctx2( tbb::task_group_context::isolated );
    tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
        // ctx2 is an isolated task group context so it will have fp0 inherited from the task
        // scheduler. That’s why fp0 will be used here.
    }, ctx2 );
}, ctx );
// fp1 will be used here.

В одном блоге невозможно продемонстрировать все возможности поддержки вычислений с плавающей запятой в Intel TBB. Но приведенные примеры демонстрируют основные идеи управления параметрами таких вычислений в Intel TBB для применения в реальных приложениях.

Основные принципы параметров вычислений с плавающей запятой можно объединить в следующий список:

  • Эти параметры можно задать для всех параллельных алгоритмов Intel TBB с помощью планировщика задач или для отдельных алгоритмов Intel TBB с помощью контекста группы задач;
  • Параметры, полученные контекстом группы задач, имеют приоритет над параметрами, полученными при инициализации планировщика задач;
  • По умолчанию все вложенные алгоритмы наследуют такие параметры с внешнего уровня, если не указан ни контекст группы задач с полученными параметрами, ни изолированный контекст группы задач;
  • При вызове параллельного алгоритма Intel TBB параметры вычислений с плавающей запятой вызывающего потока не изменяются, даже если алгоритм выполняется с другими параметрами;
  • Параметры, заданные после инициализации планировщика задач, недоступны для параллельных алгоритмов Intel TBB, если не используется подход с контекстом группы задач или не выполняется повторная инициализация планировщика задач;
  • Пользовательский код в задаче не должен менять эти параметры либо должен восстанавливать прежние параметры до окончания задачи.

P.S. Отложенный планировщик задач получает параметры с плавающей запятой при вызове метода инициализации.

Пример #11: Явная инициализация планировщика задач.

set_fp_settings( fp0 );
tbb::task_scheduler_init tbb_scope( task_scheduler_init::deferred );
set_fp_settings( fp1 );
init.initialize();
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    // The task scheduler is declared when fp0 is set but it will capture fp1 since it is
    // initialized when fp1 is set.
} );
// fp1 will used be here.

P.P.S. Будьте осторожны, если вы используете функцию автоматической записи в планировщике задач. Она не будет работать, если вызов вашей функции осуществляется внутри другого параллельного алгоритма Intel TBB.

Пример #12. Еще одно предупреждение: берегитесь библиотечных функций.

Фрагмент кода 1. Слегка измененный пример 1. Это работоспособный код, здесь нет ошибок.

set_fp_settings( fp0 );
// Run with the hope that Intel TBB parallel algorithm will create a default task scheduler which
// will also capture floating-point settings when initialized.
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {...} );

Фрагмент кода 2. Достаточно вызвать фрагмент кода 1 как библиотечную функцию.

set_fp_settings( fp1 );
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> & ) {
    call “code snippet 1”;
}
// Possibly, you will want to have fp1 here but see the second bullet below.

Этот пример выглядит вполне безобидным, поскольку фрагмент кода 1 задаст нужные параметры и будет выполнять вычисления с fp0. Но в этом примере есть две проблемы:

  1. К моменту вызова фрагмента кода 1 планировщик задач уже будет инициализирован и уже получит fp1. Поэтому фрагмент кода 1 будет выполнять вычисления с fp1, не учитывая параметры fp0;
  2. Изоляция пользовательских параметров вычислений с плавающей запятой нарушается, поскольку фрагмент кода 1 изменяет эти параметры внутри задачи Intel TBB, но не восстанавливает первоначальные параметры. Поэтому нет никаких гарантий относительно параметров вычислений с плавающей запятой после выполнения параллельного алгоритма Intel TBB во фрагменте кода 2.

Фрагмент кода 3. Исправленное решение.

Исправим фрагмент кода 1:

// Capture the incoming fp settings.
get_fp_settings( fpx );
set_fp_settings( fp0 );
tbb::task_group_context ctx;
ctx.capture_fp_settings();
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> &r ) {
    // Here fp0 will be used for all iterations on any Intel TBB worker thread.
}, ctx );
// Restore fp settings captured before setting fp0.
set_fp_settings( fpx );

Фрагмент кода 2 остается неизменным.

set_fp_settings( fp1 );
tbb::parallel_for( tbb::blocked_range<int>( 1, 10 ), []( const tbb::blocked_range<int> &r ) {
    call “fixed code snip 1”.
} );
// fp1 will be used here since the “fixed code snippet 1” does not change the floating-point
// settings visible to “code snippet 2”.

 

Игра Legend of Xuan Yuan: высшее качество игры на трансформерах, с сенсорным управлением и акселерометром

$
0
0

Download PDF

Аннотация

Компания Tencent решила повысить удобство игры на ультрабуках и трансформерах. Игра Legend of Xuan Yuan и так была весьма успешной, но в использовании этих систем разработчики Tencent увидели новую возможность. Сейчас на рынке представлено немало трансформеров, то есть систем, которые могут работать и в режиме обычного ноутбука, и в режиме планшета. Разработчики Tencent совместно с инженерами Intel работали над отбором моделей планшетов и ноутбуков, поддерживающих изменение состояния игры. Пользовательский интерфейс игры был обновлен для поддержки сенсорного управления, которое стало одной из важнейших и удобнейших функций на планшетах. И наконец, благодаря датчикам появилась возможность по-новому управлять игрой: для выполнения определенных действий можно было встряхнуть планшет.

Первая трехмерная многопользовательская сетевая игра MMOPRG на китайском рынке

Компания Tencent — крупнейший разработчик игр в Китае. Поскольку количество трансформеров на китайском рынке постоянно растет, разработчики Tencent решили предоставить владельцам таких устройств уникальные игровые возможности. Всего через два года после выпуска игра Legend of Xuan Yuan уже стала весьма популярной. В силу широкого распространения ультрабуков и трансформеров было решено добавить в игру поддержку сенсорного управления и акселерометров. Трехмерные массовые многопользовательские сетевые ролевые игры (MMORPG) очень популярны в Китае, но до Legend of Xuan Yuan ни в одной из них не была реализована поддержка сенсорного управления. Компания Tencent получила возможность первой внедрить новую технологию, но при этом возник и риск: окажется ли новинка успешной? В этом примере описывается, каким образом разработчики Tencent при поддержке инженеров Intel изменили игру так, чтобы повысить ее удобство на трансформерах и ультрабуках под управлением Windows* 8.

В Legend of Xuan Yuan используется два разных пользовательских интерфейса для режимов планшета и ноутбука. На трансформерах игра определяет, в каком из этих режимов устройство работает в данный момент. В режиме ноутбука игра использует клавиатуру и мышь. В режиме планшета игра переключается на сенсорный интерфейс. Разработчики Tencent стремились добиться плавного перехода между традиционным режимом ноутбука и сенсорным управлением в игре. Игрок не испытывает неудобства, поскольку интерфейс автоматически переключается между режимами. В этом примере мы рассмотрим обнаружение режима работы трансформера и переключение интерфейса в соответствии с текущим режимом.

Преобразование существующего пользовательского интерфейса в сенсорный может быть непростой задачей. Это особенно трудно для игр со сложным интерфейсом, где используются щелчки левой и правой кнопками мыши, а также множество командных клавиш. Не существует единственно верного подхода для адаптации таких интерфейсов. Реализация плавного и точного сенсорного управления требует немалого внимания. Поскольку игра уже достаточно популярна, нужно делать как можно меньше изменений, чтобы не вызывать отторжения у существующих игроков. Мы рассмотрим устройство интерфейса.

Поскольку трансформеры оборудованы акселерометрами, разработчики Tencent также добавили поддержку особо мощной атаки против врагов, если встряхнуть устройство при игре.

Изменение режима игры в соответствии с режимом трансформера

Игра Legend of Xuan Yuan содержит два интерфейса и динамически переключается между ними в зависимости от режима работы трансформера. Когда трансформер работает в режиме ноутбука, игра Legend of Xuan Yuan ведет себя совершенно обычным образом, для ее управления используется клавиатура и мышь. В режиме планшета применяется сенсорное управление. Как это работает?

Вот как мы это сделали: определение состояния трансформера и переключение режима интерфейса

Игра Legend of Xuan Yuan ожидает сообщение WM_SETTINGCHANGE. Это сообщение оповещает приложения об изменениях состояния системы. При изменении состояния трансформера поступает сообщение WM_SETTINGCHANGE с LPARAM, указывающим на строку со значением «ConvertibleSlateMode». Вызов GetSystemMetrics (SM_CONVERTIBLESLATEMODE) возвращает текущее состояние.

В планшетном режиме игры на экран накладывается интерфейс с сенсорными кнопками для различных действий. В режиме ноутбука этот интерфейс скрывается.

В игре Legend of Xuan Yuan используется следующий код обнаружения:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  case WM_SETTINGCHANGE:
    if (lParam != NULL && wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *)lParam) == 0)
    {
      BOOL bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
      if (bSlateMode == True) //Slate mode, display the Touch overlay UI
        …
      else //Laptop mode, hide the touch overlay UI
        …
    }

Рисунок 1. Код для обнаружения изменения состояния системы и для проверки режима системы.

Дополнительные сведения см. в примере кода с поддержкой трансформеров.

Чтобы такой подход работал, он должен поддерживаться изготовителем системы; должен быть установлен соответствующий драйвер. В некоторых системах драйвер не всегда работает правильно, поэтому мы добавили возможность переключения интерфейса вручную. Далее описывается, как работает интерфейс.

Теперь ваша очередь: определите, в каком режиме используется устройство: ноутбука или планшета

Как определить состояние устройства в игре и как изменить интерфейс? Для наибольшего удобства на трансформерах ваша игра должна быть «двуличной»: она должна динамически переключать интерфейс в зависимости от состояния устройства.

Прежде всего, спланируйте интерфейс для режима ноутбука и режима планшета. Подумайте о том, как устройство будут держать в руках или как оно будет стоять на столе. Выберите наиболее удобный для игроков способ взаимодействия с интерфейсом. При проектировании сенсорного интерфейса оставьте на экране больше места для сенсорных элементов управления, чем обычно требуется для кнопок, нажимаемых мышью. В противном случае игрокам будет непросто нажимать нужные элементы управления.

Кроме того, сенсорное взаимодействие зачастую медленнее, чем управление с помощью клавиатуры и мыши, не забывайте об этом. Игровым меню также нужен и интерфейс для клавиатуры с мышью, и сенсорный интерфейс.

Неплохо бы при запуске игры проверять состояние устройства с помощью GetSystemMetrics и соответствующим образом выбирать интерфейс. Помните, что не все системы правильно передают сведения о своем состоянии и не всегда уведомляют вашу игру об изменениях состояния, поэтому выберите начальный интерфейс игры по умолчанию на случай, если текущее состояние устройства не удастся определить.

Следите за сообщением WM_SETTING CHANGE после запуска игры. Когда такое сообщение появится, проверьте его содержимое: LPARAM должен указывать на строку со значением «ConvertibleSlateMode». Это значение указывает, что игра должна вызвать GetSystemMetrics(SM_CONVERTlBLESLATEMODE) и проверить, следует ли сменить интерфейс.

Обнаружение может не всегда действовать, поскольку не все системы могут правильно сообщать об изменении состояния. Пожалуй, если обнаружение не дает достоверный результат, по умолчанию игра должна использовать режим ноутбука. И в любом случае должен быть способ вручную переключить интерфейс между режимом мыши и клавиатуры и режимом планшета.

Полный пример, обнаруживающий изменение состояния системы и меняющий интерфейс, см. в образце с поддержкой трансформеров. Более сложный код с обнаружением пристыковки клавиатуры, изменения ориентации экрана и т. д. см. в примере с обнаружением состояния.

Выбор типа сенсорных сообщений

Перед добавлением поддержки сенсорного управления в существующее приложение необходимо выбрать, какой тип сообщений Window вы собираетесь поддерживать. Выберите один из трех наборов сообщений Window: WM_POINTER, WM_GESTURE или WM_TOUCH. Давайте посмотрим, каким образом мы делали этот выбор для игры Legend of Xuan, чтобы помочь вам принять верное решение.

Как мы это сделали: сравнение типов сенсорных сообщений

Поддержка сенсорного управления — основная «изюминка» новой версии игры Legend of Xuan Yuan. Когда игроки используют сенсорный экран, они видят новый интерфейс с набором сенсорных элементов управления.

WM_POINTER — простейший с точки зрения написания кода тип сообщений, он поддерживает широкий набор жестов. Но работает WM_POINTER только в Windows 8 и более поздних версиях. Разработчикам Tencent требовалось поддерживать огромную базу существующих пользователей, применяющих Windows 7, поэтому от WM_POINTER сразу же отказались.

Перед обсуждением остальных типов сообщений давайте рассмотрим основные элементы интерфейса игры Legend of Xuan Yuan. Сенсорный интерфейс игры использует экранные кнопки в качестве элементов управления. Эти элементы управления можно использовать и для движения, и для действий. Элементы управления движением и действиями находятся на противоположных сторонах экрана, чтобы можно было использовать для управления обе руки. Элементы управления расположены в нижней части экрана. Кроме того, в верхней части экрана находится значок, раскрывающий каскадное меню для более сложных элементов интерфейса. Устройство интерфейса мы обсудим позже, но уже понятно, как именно элементы интерфейса должны работать.


Рисунок 2: Экранный сенсорный интерфейс в правом и левом нижних углах.

Игра должна распознавать одновременное касание в разных местах экрана. Поскольку несколько касаний должны работать одновременно, такое управление называется мультисенсорным.

Теперь, когда мы изучили основные компоненты мультисенсорного интерфейса, можно сравнить оставшиеся типы сенсорных сообщений: WM_GESTURE и WM_TOUCH. Проще всего создавать код для WM_GESTURE — здесь поддерживаются типовые жесты, такие как масштабирование двумя пальцами и боковая прокрутка. Сообщения этого типа скрывают некоторые детали сенсорного взаимодействия и передают коду вашей игры полный жест после его завершения. События простых касаний по-прежнему отправляются в игру как сообщения мыши. Это означает, что типовой сенсорный интерфейс можно реализовать с помощью сообщений мыши для событий простых касаний и с помощью WM_GESTURE для сложных жестов.

WM_GESTURE поддерживает только жесты, включающие один набор связанных точек касания. Из-за этого затрудняется поддержка жестов мультисенсорных интерфейсов, где игрок касается экрана в нескольких местах. WM_GESTURE плохо подходит для этой игры.

WM_TOUCH — это сообщение сенсорного управления самого низкого уровня. Оно предоставляет полный доступ к всем событиям касания (например, «палец коснулся экрана»). Для WM_TOUCH вам потребуется проделать больше работы по сравнению с другими типами сообщений, поскольку вы должны написать код для всех высокоуровневых сенсорных событий и жестов, составив этот код из низкоуровневых сенсорных событий. Несмотря на необходимую дополнительную работу, сообщения WM_TOUCH стали очевидным выбором для игры Legend of Xuan Yuan. Сообщения WM_TOUCH предоставляют полный контроль над всем сенсорным управлением, включая мультисенсорный ввод.

При физическом касании экрана система отправляет игре сообщения WM_TOUCH. Одновременно игра получает сообщение о щелчке мыши. Благодаря этому приложения без полной сенсорной поддержки могут работать с сенсорным управлением. Эти два сообщения разных типов описывают одно и то же физическое событие. Это может усложнить код обработки сообщений. В игре Legend of Xuan Yuan во всех возможных случаях используются сообщения щелчка мыши, а дублирующиеся сообщения удаляются.

Ваша очередь: выбор нужного типа сенсорного сообщения для вашей игры

WM_POINTER — отличный вариант, если ваша игра предназначена только для Windows 8. Если же нужна обратная совместимость, используйте сообщения WM_GESTURE и WM_TOUCH.

При сравнении типов сообщений учитывайте устройство интерфейса вашей игры. Если в нем широко используются жесты, а вы можете без труда написать обработчики щелчков мышью для событий одиночного касания, не являющихся жестами, то, пожалуй, для вашей игры лучше подойдет WM_GESTURE. В противном случае используйте WM_TOUCH. В большинстве игр с полнофункциональным интерфейсом используются именно сообщения WM_TOUCH, особенно при наличии множества элементов управления, которых игроки касаются одновременно.

Рассматривая сенсорные сообщения, не забывайте и о системе меню. Не забудьте удалить лишние сообщения, поступающие при щелчках мыши.

Дополнительные сведения об этих трех типах сообщений см. в этой статье. Дополнительные сведения о выборе между типами сообщений WM_TOUCH и WM_GESTURE с учетом обратной совместимости см. в статье https://software.intel.com/en-us/articles/touch-samples.

Адаптация интерфейса к сенсорному управлению

Адаптация существующего интерфейса игры к сенсорному управлению может быть непростой задачей, причем не существует единственно верного подхода к решению этой задачи.

Как мы это сделали: новый сенсорный интерфейс

Интерфейс с клавиатурой и мышью общеизвестен и привычен. В нем для движения игрового персонажа используются клавиши W, A, S, D. Настраиваемые кнопки действий в нижней части экрана и клавиши с 1 по 9 соответствуют напиткам, навыкам нападения и дополнительным элементам интерфейса. Эти элементы пользовательского интерфейса включают инвентарь, дерево навыков, задачи и карту. По щелчку правой кнопкой мыши персонаж берет оружие, надевает доспехи или открывает сундук с сокровищами.

Сенсорный экран доступен постоянно, но сенсорный интерфейс по умолчанию скрыт при использовании мыши и клавиатуры. В этом режиме на экране отображается сенсорная кнопка.


Рисунок 3. При нажатии на эту сенсорную кнопку в этом режиме открывается сенсорный интерфейс.

Если игрок переводит систему в режим планшета или касается этой кнопки, на экране появляется полный сенсорный интерфейс.

Как мы это сделали: элементы сенсорного пользовательского интерфейса

В режиме планшета игрок обычно держит устройство обеими руками. В интерфейсе для управления используются большие пальцы обеих рук, чтобы свести к минимуму изменения хвата устройства. Перемещения и действия атаки сгруппированы для удобного доступа большими пальцами левой и правой рук игрока

Сначала мы придумали элемент управления в виде колеса для перемещения игрового персонажа. Кольцо накладывается на левую часть экрана. Схожий принцип используется на игровых контроллерах; привычное расположение делает управление более удобным и интуитивным. Большой палец левой руки игрока обычно постоянно касается экрана. Когда игрок перемещает палец по экрану, персонаж движется в ту сторону, куда переместился палец.

Обычная игровая панель действий находится в нижней части экрана, но ей неудобно пользоваться большими пальцами. Мы добавили группу из 4 крупных кнопок действий в правом углу, где на эти кнопки будет удобно нажимать большим пальцем правой руки. Пользователь может настроить эти кнопки для наиболее часто используемых действий, перетащив на них навыки нападения или напитки.

Перед нападением игрок должен навести прицел на противника. В традиционном интерфейсе с клавиатурой и мышью щелчок левой кнопкой используется для нацеливания на одного противника, а клавиша TAB — для перенацеливания на следующего противника, находящегося в пределах радиуса атаки. В сенсорном режиме есть большая кнопка, чтобы нацелиться на самого близкого противника. Игрок также может коснуться противника, чтобы напрямую нацелиться на него, но это используется редко, поскольку при этом нарушается хват устройства игроком.

В интерфейсе для мыши и клавиатуры щелчок правой кнопкой мыши используется, чтобы открыть сундук с сокровищами, взять оружие, надеть броню или выпить напиток. Касание с удержанием является наилучшей заменой щелчку правой кнопкой мыши в сенсорном интерфейсе.

При использовании клавиатуры и мыши на экране есть маленький значок, чтобы открыть каскадные окна. При сенсорном управлении это неудобно, поскольку значки слишком мелкие. Сенсорный интерфейс включает экранный значок для раскрытия остальных элементов интерфейса с помощью каскадного набора значков. Эти значки открывают более сложные компоненты интерфейса, такие как инвентарь, дерево навыков, задачи и пр. Также предусмотрена кнопка для переключения интерфейса между традиционным (клавиатура и мышь) и сенсорным. За счет этого игрок может без труда переключаться между двумя интерфейсами.


Рисунок 4. Полный сенсорный интерфейс с колесом перемещения, кнопками действий и цели, а также каскадными значками.

Вот полный сенсорный интерфейс с открытыми каскадными значками.

Как мы это сделали: обработка сообщений сенсорного интерфейса

Как происходит обработка сообщений? По-разному для разных компонентов интерфейса. Используются сообщения WM_TOUCH и сообщения мыши. Действия, прицеливание и каскадные кнопки интерфейса используют сообщения щелчков мыши. Колесо перемещения и основная часть игрового экрана используют сообщения WM_TOUCH.

Игровой процесс обычно включает постоянное касание колеса для перемещения, повторяющееся использование кнопок выбора противника и навыков атаки. Это означает, что необходима поддержка мультисенсорного ввода. К счастью, WM_TOUCH хорошо поддерживает мультисенсорное управление.

При появлении сообщения WM_TOUCH игра сохраняет определенный контекст. Код сравнивает это касание с другими недавними сообщениями WM_TOUCH, проверяет, насколько долго удерживалось текущее сочетание касаний и определяет расположение касания.

Если область сообщения WM_TOUCH приходилась на колесо перемещения или была рядом с ним, код проверяет место касания относительно центра колеса и относительно предыдущего касания. Если касание было рядом с предыдущим, причем текущий жест был начат на колесе, то игра передвигает персонажа в нужном направлении. При разработке потребовалась достаточно точная настройка для определения различий между длительным непрерывным касанием колеса перемещения и другими касаниями остальной части экрана.

Если сообщение WM_TOUCH находится на экране далеко от других элементов управления, то, вероятно, это часть жеста, такого как масштабирование или прокрутка, либо часть касания с удержанием. Сообщения WM_TOUCH сравниваются с прежними, чтобы определить нужное действие. Если оно достаточно близко к предыдущему и удерживается свыше 0,2 секунд, оно рассматривается как касание и удержание. В противном случае это жест, и экран настраивается соответствующим образом.

Система автоматически формирует сообщения мыши для всех сенсорных сообщений. Каждое сообщение мыши содержит дополнительную информацию с указанием источника этого сообщения. Вызов GetMessageExtralnfo определяет различие.

#define MOUSEEVENTF_FROMTOUCH 0xFF515700

if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) {
  // Click was generated by wisptis / Windows Touch
}else{
  // Click was generated by the mouse.
}

Рисунок 5. Проверка, поступают ли от сенсорного экрана сообщения мыши.

Если сенсорный экран создал событие мыши, а игра уже обработала физическое касание с помощью WM_TOUCH, игра удаляет сообщение мыши.

Если же сенсорное сообщение приходится на один из прочих элементов управления, то оно не обрабатывается, а вместо него используется сообщение мыши.

Когда все элементы интерфейса будут на месте, игра получит удобное сенсорное управление.

В этой статье приводится еще один пример добавления сложного сенсорного интерфейса в игре Wargame: European Escalation: https://software.intel.com/en-us/articles/wargame-european-escalation-performance-and-touch-case-study

Ваша очередь: построение вашего сенсорного пользовательского интерфейса

Перед тем, как создать сенсорный пользовательский интерфейс для вашей игры, продумайте все возможные действия игрока. Затем подумайте, как реализовать эти действия с помощью сенсорного экрана (или других датчиков, например, акселерометра). Обращайте особое внимание на различия между касаниями и щелчками, непрерывными действиями (нажатие и удержание) и жестами, такими как перетаскивание.

Решите, каким образом игрок будет выполнять все эти действия с помощью пользовательского интерфейса. Продумайте, где должны находиться видимые элементы управления. Любые экранные элементы управления и каскадные меню должны быть достаточно крупными, чтобы ими было удобно управлять кончиками пальцев. Подумайте, как игрок будет держать устройство в руках, и учитывайте это при проектировании интерфейса для удобного касания.

Теперь, когда интерфейс спланирован, используйте самые простые сообщения. Определяйте, когда касание попадает в каждый элемент управления. Спланируйте, какие типы сообщений использовать для этих элементов управления (мышь или сенсорные) и убирайте дублирующиеся сообщения.

Для сенсорных сообщений нужно сохранять контекст. Расположение, элемент управления и время будут полезны при составлении жестов из мультисенсорных сообщений. Подумайте о фрагментах игры, где требуется постоянный сенсорный контакт. Тщательно тестируйте это при разработке, чтобы убедиться в удобстве игры при использовании типовых расхождений в жестах. Проверяйте различные направления жестов, расположения касаний, близость к предыдущим касаниям и длительность касаний.

Запускайте интерфейс в режиме, который соответствует текущему состоянию устройства. Переключайте интерфейс между клавиатурой/мышью и сенсорным режимом при каждом изменении состояния устройства. Не забудьте предоставить игроку возможность переключения режима интерфейса вручную на случай, если система не предоставляет нужных уведомлений.

Дополнительные советы по проектированию сенсорных интерфейсов см. в руководстве разработчика сенсорных приложений для ультрабуков и планшетов под управлением Windows..

Датчики

Ультрабуки и трансформеры оборудованы датчиками, такими как гироскоп, акселерометр, GPS и пр. С помощью этих датчиков можно расширить игровые возможности.

Как мы это сделали: встряхните устройство

В игре Legend of Xuan Yuan используется акселерометр, чтобы определить, когда пользователь встряхивает устройство. Персонаж накапливает энергию в ходе игры, затем расходует ее в ходе супер-атаки. Игрок может встряхнуть устройство, чтобы запустить супер-атаку: при этом все ближайшие противники подвергаются атаке в течение 10—20 секун.

Мы протестировали различные виды встряхивания, чтобы измерить типовые значения акселерометра


Рисунок 6. Четыре встряхивания с отображением интенсивности и длительности в трех измерениях.

Любое ускорение свыше 1,6 по одной оси является встряхиванием. Мы также могли использовать сумму абсолютных значений ускорения по каждой оси.

Поскольку это события реального мира, такие данные будут иметь много помех и будут всякий раз различаться. Значения включают и краткое, и длительное встряхивание. В большинстве тестовых случаев на одно встряхивание приходилось одно пиковое значение, но в одном случае встряхивание включало несколько пиковых значений. В этой игре используется встряхивание в любом направлении с ускорением свыше 1,6 по любой оси. Несколько встряхиваний в течение 1,5 секунд считаются одним.

При наличии в игре такого кода любое встряхивание устройства приведет к срабатыванию действия супер-атаки.

Ваша очередь: использование датчиков устройства

Ультрабуки и трансформеры содержат различные датчики. Подумайте, как можно использовать каждый из них в игре.

Какие бы датчики вы ни использовали, откалибруйте их, чтобы узнать, как они реагируют на реальные условия. Учтите различные типовые условия, с которыми могут столкнуться игроки.

Заключение

Мы показали, как адаптировать существующую игру для обнаружения состояния трансформера (ноутбук или планшет). Также мы продемонстрировали, как интерфейс может поддерживать сенсорное управление, и как переключаться между интерфейсами в зависимости от режима работы трансформера. Вместе с акселерометром, запускающим в игре уникальное действие, пользователь получает исключительное удобство в игре.

Компания Tencent пошла на риск, реализовав поддержку сенсорного управления в первой китайской MMORPG-игре. И этот риск оправдал себя. Игра Legend of Xuan Yuan великолепно работает на ноутбуках, планшетах и трансформерах. Надеемся, что и вашу игру ждет не меньший успех!

Авторы

Мак Хан (Mack Han) — инженер по разработке клиентского игрового программного обеспечения в компании Tencent, обладающий 10-летним опытом разработки игр. Он создавал игры для консолей, ПК и мобильных телефонов. Много лет он работал в области крупных трехмерных MMORPG, его области специализации — отрисовка трехмерных изображений и оптимизация.

Кейдж Лю (Cage Lu) — инженер по разработке приложений в корпорации Intel. Он уже несколько лет работает с крупными разработчиками игр в Китае, помогая им оптимизировать производительность игровых клиентов и улучшить пользовательские интерфейсы на платформах Intel.

Пол Линдберг (Paul Lindberg) — старший инженер по программному обеспечению в отделе Developer Relations корпорации Intel. Он помогает разработчикам игр во всем мире создавать великолепные игры и другие приложения, демонстрирующие непревзойденные результаты на платформах Intel.

Справочные материалы

Определение режимов планшета и ноутбука, а также ориентации экрана на трансформерах: http://software.intel.com/en-us/articles/detecting-slateclamshell-mode-screen-orientation-in-convertible-pc

Дополнительные сведения об адаптации для трансформеров:
http://software.intel.com/en-us/articles/how-to-write-a-2 in 1aware-application

Сравнение типов сенсорных сообщений в Windows 8:
http://software.intel.com/en-us/articles/comparing-touch-coding-techniques-windows-8-desktop-touch-sample

<Пример с реализацией сенсорного управления в игре Wargame: European Escalation:
http://software.intel.com/en-us/articles/wargame-european-escalation-performance-and-touch-case-study

Руководство по сенсорному управлению для разработчиков:
http://software.intel.com/en-us/articles/ultrabook-device-and-tablet-windows-touch-developer-guide

Более сложный пример внедрения:
http://software.intel.com/en-us/articles/hot-shots-warps-conventional-touch-gaming

Лицензия

Пример исходного кода распространяется на условиях соглашения Intel Sample Source License Agreement.  Фрагменты этого документа распространяется на условиях ограниченной публичной лицензии корпорации Майкрософт.

 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.

 

Intel, the Intel logo, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

 

Использование OpenCL™ API Debugger

$
0
0

Скачать PDF

1. Введение

OpenCL™ API Debugger — это подключаемый модуль для Microsoft Visual Studio*, позволяющий отлаживать приложения OpenCL, отслеживая среду OpenCL. API Debugger — это новый компонент пакета Compute Code Builder в составе решений Intel® Integrated Native Developer Experience (Intel® INDE) и бета-версии Intel® SDK for OpenCL™ Applications 2014.

API Debugger дает разработчикам возможность просматривать список всех вызовов API OpenCL в своих приложениях; можно просматривать параметры функций, возвращаемые значения и время выполнения. Этот подключаемый модуль также позволяет просматривать различные объекты OpenCL, существующие в памяти при выполнении приложения. Дополнительные сведения о подключаемом модуле API Debugger и его возможностях см. в Руководстве пользователя бета-версии Intel® SDK для OpenCL™ Applications 2014..

В этом руководстве мы демонстрируем одну из областей применения API Debugger: отладку и обнаружение причин сбоя приложений при наличии только исходного кода ядра и двоичного файла приложения (без исходного кода со стороны хоста). Полезнейшая особенность API Debugger — способность показывать исходный код ядра, даже если оно встроено в отлаживаемое приложение. В последнем случае можно выявить источник ошибки ядра, но исправить его в отсутствие полного исходного кода приложения нельзя.

В целях демонстрации мы внесем ошибку в ядро фильтра sobel из раздела Работа с JumpStart  и покажем, как выявить эту ошибку, не имея доступа к исходному коду хоста.

2. Включение Api Debugger в Visual Studio*

Прежде всего нужно включить API Debugger в Visual Studio. Для этого щелкните Tools: Code: Builder – Optionsв Visual Studio или нажмите сочетание клавиш Ctrl+1чтобы открыть диалоговое окно конфигурации отладчика, как показано ниже.

Убедитесь, что флажок Enable OpenCL API Debuggerустановлен, затем нажмите кнопку «ОК». После включения этого подключаемого модуля можно приступить к отладке приложения.

3. Запуск приложения

Как было сказано выше, мы внесли ошибку в приложение sobel, изменив типы аргументов ядра для ширины и высоты, как показано ниже.


kernel void
sobel(__global uchar4* src, __global uchar4* dst, ushort width, ushort height)
{

При попытке запуска приложения с этим новым ядром происходит сбой приложения в момент задания аргументов ядра. При отсутствии подробной обработки ошибок такие проблемы очень сложно обнаружить без полного исходного кода. Посмотрим, как можно выполнить отладку в этом случае.

Поскольку у нас в наличии только двоичный файл приложения и ядро OpenCL, нужно каким-то образом запустить приложение для его отладки в Visual Studio. Запустите командную строку Visual Studio из меню «Пуск» или добавьте %VSINSTALLDIR%\Common7\IDE\ (где %VSINSTALLDIR% — папка, в которую установлена среда Visual Studio) в переменную среды PATH и запустите командную строку. Запустите приложение из командной строки следующим образом:


devenv <приложение>

where <приложение>полный или относительный путь к отлаживаемому приложению, например, sobel.exe.

При этом приложение должно запуститься в Visual Studio для отладки. Убедитесь, что компонент API Debugger включен, как было показано в предыдущем разделе. Запустите отладку, нажав клавишу F5. Приложение запустится, но не сможет выполняться без выполнения ядра OpenCL.

4. Представление проблем и представление трассировки

Откройте представление проблем Tools: Code: Builder: OpenCL Debugger: Problems View. В окне Problems Viewперечисляются все предупреждения и ошибки, возникшие при запуске приложения OpenCL. Наибольший интерес представляют именно ошибки (хотя стоит обращать внимание и на предупреждения). Вы увидите две ошибки, вызванные вызовом clSetKernelArg(), как показано ниже.

Но верхнее представление дает только половину информации: мы всего лишь узнаем о сбое вызова с CL_INVALID_ARG_SIZE. Теперь щелкните правой кнопкой мыши одну из ошибок и выберите Show in Trace View.

При этом появится Trace Viewс трассировкой API OpenCL.

В окне трассировки выберите Functions with arguments names and valuesв списке API Display Mode как показано ниже.

Это подробный режим отображения, в котором вы видите дополнительные сведения об API, включая количество аргументов и их размер.

Если рассмотреть ошибочные вызовы и возвращаемое значение clSetKernelArg(), становится очевидно, что при задании аргументов ядра 2 и 3 возникает какая-то проблема. Снова рассмотрим сигнатуру ядра.


kernel void
sobel(__global uchar4* src, __global uchar4* dst, ushort width, ushort height)
{



В данных представления трассировкивидно, что код задает аргументы ядра размером 4 (поскольку arg_size = 0x4 для обоих вызовов с ошибками), тогда как ядро OpenCL принимает тип данных ushort размером 2. Теперь мы знаем, что нужно исправить либо код системы, либо ядро, чтобы типы данных совпадали.

4.1 Просмотр встроенного исходного кода ядра

Как было упомянуто выше, API Debugger может отображать исходный код ядра, даже если он встроен в двоичный файл. Как и ранее, включите API Debugger и запустите приложение в Visual Studio. После перехода в отладчик откройте представление дерева объектов (Tools→Code Builder — OpenCL Debugger→Objects Tree View) и найдите узел собранной программы (например, «Program [1] (Built)»). Затем щелкните узел программы правой кнопкой мыши и выберите «Open Source Code in a new tab» для просмотра исходного кода ядра.

Обратите внимание, что показанный выше двоичный файл был собран без отладочной информации. Можно изучить исходный код ядра даже в случае, когда двоичный файл собран в режиме выпуска.

5. Заключение

В этом руководстве показано, каким образом API Debuggerпомогает выявлять причины определенных ошибок в приложениях OpenCL, особенно при недоступности исходного кода. Разумеется, API Debugger обладает гораздо более широкой функциональностью и расширяет возможности отладки Visual Studio, предоставляя средства отладки приложений OpenCL непосредственно в этой среде разработки.

 

 

Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

OpenCL and the OpenCL logo are trademarks of Apple Inc and are used by permission by Khronos.

События наблюдения за производительностью внеядерных компонентов платформы Merrifield

$
0
0

Использование событий наблюдения за производительностью внеядерных компонентов платформы Merrifield

В этой статье рассматриваются события наблюдения за производительностью платформы «система на кристалле» Merrifield. Введение в наблюдение за производительностью внеядерных компонентов платформ «система на кристалле» см. в статье: Руководство по наблюдению за производительностью внеядерных компонентов платформы «система на кристалле» Silvermont

Введение в платформу Merrifield с архитектурой «система на кристалле»

Ниже на блок-схеме показано типовое устройство Merrifield. Зеленые стрелки, соединяющие каждый блок, представляют собой интерфейсы; можно отслеживать запросы в интерфейсах для вычисления пропускной способности. Серыми стрелками в южном кластере показаны интерфейсы, для которых не поддерживается отслеживание производительности внеядерных компонентов. Как видно на схеме ниже, анализ будет касаться только северного кластера.

Доступные группы

В следующей таблице описаны доступные группы для Merrifield. Имя группы означает заранее заданный набор событий, которые будут программироваться программными средствами мониторинга. В столбце событий указывается, сколько событий содержится в группе. В столбце «Тактовые импульсы» указывается, включает ли группа отсчеты источника тактовых импульсов SoC.

Таблица групп событий внеядерных компонентов платформы Merrifield

Имя группы

События

Тактовые импульсы

Описание

UNC_SOC_Memory_DDR_BW

5

Да

Подсчитывает количество запросов чтения и записи памяти в канал памяти 0 и 1. Для определения пропускной способности памяти нужно умножить количество событий на 32 байта.

UNC_SOC_DDR_Self_Refresh

5

Да

Подсчитывает количество циклов, в течение которых каналы памяти 0 и 1 находятся в состоянии самообновления.

UNC_SOC_All_Reqs

6

Да

Подсчитывает количество запросов на каждый агент памяти. С помощью счетчиков можно определять ресурсоемкие агенты или оценивать пропускную способность для агента, умножив количество запросов на 64 байта.

UNC_SOC_Module0_BW

7

Да

Подсчитывает количество событий пропускной способности для модуля Silvermont 0. Для определения пропускной способности между модулем Silvermont 0 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).

UNC_SOC_Module0_Snoops

3

Да

Подсчитывает количество запросов и ответов отслеживания для модуля Silvermont 0.

UNC_SOC_Graphics_BW

7

Да

Подсчитывает количество событий пропускной способности для графического контроллера. Для определения пропускной способности между графическим контроллером и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).

UNC_SOC_Display_BW

7

Да

Подсчитывает количество событий пропускной способности для контроллера экрана. Для определения пропускной способности между контроллером экрана и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).

UNC_SOC_Imaging_BW

7

Да

Подсчитывает количество событий пропускной способности для контроллера изображений. Для определения пропускной способности между контроллером изображений и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).

UNC_SOC_LowSpeedPF_BW

7

Да

Подсчитывает события пропускной способности для структуры низкоскоростной периферии. Для определения совокупной пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).

 

UNC_SOC_Memory_DDR_BW

Группа UNC_VISA_Memory_DDR_BW предоставляет счетчики для вычисления пропускной способности всей памяти с точки зрения контроллера памяти «системы на кристалле». С помощью событий можно разбить на части пропускную способность каждого канала. Эти события не предоставляют информации о том, какой агент потребляет больше памяти, но это наиболее точный способ определения фактической используемой пропускной способности памяти.

TКоличество каналов памяти на платформе Merrifield зависит от ее выпуска: может быть либо один, либо два канала. Если существует только один канал, все счетчики, связанные со вторым каналом, будут выдавать нулевые значения. Дополнительные сведения об архитектуре каналов памяти: http://en.wikipedia.org/wiki/Multi-channel_memory_architecture.

На приведенном ниже рисунке показан отслеживаемый поток трафика для этой группы.

В приведенной ниже таблице перечислены события, содержащиеся в группе UNC_VISA_Memory_DDR_BW.

Имя

Счетчик

Описание

DDR_Chan0-Read32B

0

Подсчитывает количество запросов чтения, обращенных к каналу памяти 0.

DDR_Chan0-Write32B

1

Подсчитывает количество запросов записи, обращенных к каналу памяти 0.

DDR_Chan1-Read32B

2

Подсчитывает количество запросов чтения, обращенных к каналу памяти 1.

DDR_Chan1-Write32B

3

Подсчитывает количество запросов записи, обращенных к каналу памяти 1.

Clock_Counter

4

Тактовый счетчик «системы на кристалле»

Анализ результатов

Пропускную способность в МБ/с можно вычислить для всех перечисленных выше событий следующим образом:

Формула метрики событий: количество событий / длительность выборки в секунду * 32 байта / 1000000 байт = МБ/с.

События можно суммировать для получения нужных метрик, например:

  • суммарная пропускная способность памяти = сумма всех событий, МБ/с
  • суммарная пропускная способность чтения = сумма всех событий чтения, МБ/с
  • пропускная способность канала 0 = сумма событий канала 0, МБ/с

Известное поведение

  1. Если платформа Merrifield не имеет двух каналов, показатели счетчика второго канала будут нулевыми.

UNC_SOC_DDR_Self_Refresh

Группа UNC_VISA_DDR_Self_Refresh содержит счетчики для аппаратных событий самообновления памяти. Самообновление представляет собой состояние пониженного потребления электроэнергии, его можно использовать для оптимизации электропитания «системы на кристалле» и приложений.

В приведенной ниже таблице перечислены события, содержащиеся в группе UNC_VISA_DDR_Self_Refresh.

Имя

Счетчик

Описание

DDR_Chan0_Deep_Self_Refresh

0

Подсчитывает количество циклов, в течение которых канал памяти 0 находится в состоянии глубокого самообновления.

DDR_Chan0_Shallow_Self_Refresh

1

Подсчитывает количество циклов, течение которых канал памяти 0 находится в состоянии мелкого самообновления.

DDR_Chan1_Deep_Self_Refresh

2

Подсчитывает количество циклов, в течение которых канал памяти 1 находится в состоянии глубокого самообновления.

DDR_Chan1_Shallow_Self_Refresh

3

Подсчитывает количество циклов, в течение которых канал памяти 1 находится в состоянии мелкого самообновления.

Clock_Counter

4

Тактовый счетчик «системы на кристалле»

Анализ результатов

Формула метрики событий: (количество событий * 100) / (интервал времени * базовая частота DRAM) = резидентность самообновления DDR

Известное поведение

  1. Если платформа Merrifield не имеет двух каналов, показатели счетчика второго канала будут нулевыми.
  2. Счетчики 0, 1, 2, 3 могут работать с исходной тактовой частотой, отличной от частоты счетчика 4.

UNC_SOC_All_Reqs

События счетчиков запросов на каждый агент, содержащиеся в группе UNC_VISA_All_Reqs, измеряют общее количество запросов на доступные агенты «системы на кристалле» в ходе однократной единовременной выборки. Этот показатель учитывает одновременно все агенты, поэтому это важная метрика для изучения всей нестатической, то есть пиковой нагрузки. В отличие от других событий пропускной способности, учет которых происходит по одному или по два одновременно, эта метрика получает данные от всех агентов одновременно.

Пропускную способность на каждого агента можно вычислить, умножив количество запросов для каждого агента на 64 байта, а общая пропускная способность равна сумме значений пропускной способности всех агентов. Важно понимать, что конечный результат имеет приблизительный характер и основывается на предположении, что размер каждого запроса составляет 64 байта. Результат вычисления превысит факти-ческий для транзакций с 32-байтовыми и частичными запросами. Другой недостаток состоит в том, что невозможно отделить данные чтения от данных записи для каждого агента.

Для точного измерения пропускной способности с разделением по чтению и записи следует использовать метрику пропускной способности по агентам для одного или двух агентов одновременно.

Имя

Счетчик

Описание

Mod0_Reqs

0

Подсчитывает количество запросов от модуля Silvermont 0.

Disp_Reqs

1

Подсчитывает количество запросов от контроллера экрана.

GFX_Reqs

2

Подсчитывает количество запросов от графического контроллера.

Imaging_Reqs

3

Подсчитывает количество запросов от контроллера изображений.

LowSpeedPF_Reqs

4

Подсчитывает совокупное количество запросов от структуры низкоскоростной периферии.

Clock_Counter

5

Тактовый счетчик «системы на кристалле»

 

Анализ результатов

Формула метрики событий:

  • количество событий / длительность выборки в секундах * 64 байта / 1000000 байт = оцениваемая пропускная способность агента, МБ/с
  • сумма всех счетчиков событий / длительность выборки в секундах * 64 байта / 1000000 байт = оцениваемая пропускная способность памяти DDR, МБ/с

Известное поведение

  1. Важно помнить, что эти события подсчитывают транзакции с любыми размерами запросов; умножение их на 64 байта для вычисления метрики в МБ/с является огрублением, результат такого вычисления может превышать фактическую пропускную способность каналов памяти.

UNC_SOC_Module0_BW

Группа UNC_VISA_Module0_BW предоставляет счетчики для вычисления пропускной способности модуля 0 процессора с точки зрения системного агента. События можно разделить по типам запросов.

На приведенном ниже рисунке показан отслеживаемый поток трафика для этой группы.

Имя

Счетчик

Описание

Mod0_ReadPartial

0

Подсчитывает все транзакции чтения модуля 0 для запросов любого размера данных. Этот счетчик событий включает частичные, 32-байтовые и 64-байтовые транзакции.

Mod0_Read32B

1

Подсчитывает количество запросов чтения размером 32 байта от модуля 0 Silvermont.

Mod0_Read64B

2

Подсчитывает количество запросов чтения размером 64 байта от модуля 0 Silvermont.

Mod0_WritePartial

3

Подсчитывает все транзакции записи модуля 0 для запросов любого размера данных. Этот счетчик событий включает частичные, 32-байтовые и 64-байтовые транзакции.

Mod0_Write32B

4

Подсчитывает количество запросов записи размером 32 байта от модуля 0 Silvermont.

Mod0_Write64B

5

Подсчитывает количество запросов записи размером 64 байта от модуля 0 Silvermont.

Clock_Counter

6

Тактовый счетчик «системы на кристалле»

 

Анализ результатов

Пропускную способность чтения и записи можно вычислить для 32- и 64-байтовых событий, но вычисление частичных событий затруднено, поскольку у частичных запросов неизвестен объем полезной нагрузки. Также следует понимать, что частичные события для этой группы представляют собой сумму 64-байтовых, 32-байтовых и частичных запросов. Это частичное событие также можно рассматривать как сумму всех запросов чтения или записи.

Формула метрики событий:

  • частичные запросы - 32-байтовые запросы - 64-байтовые запросы = фактическое количество частичных запросов
  • (счетчик Mod0_Read32B * 32 байта / длительность выборки в секундах) + (счетчик Mod0_Read64B * 64 байта / длительность выборки в секундах) = чтение, МБ/с
  • (счетчик Mod0_Write32B * 32 байта / длительность выборки в секундах) + (счетчик Mod0_Write64B * 64 байта / длительность выборки в секундах) = запись МБ/с

Известное поведение

  1. Счетчик частичных событий модулей 0 и 1 включает 32-байтовые, 64-байтовые и частичные запросы. Его можно считать суммарным счетчиком запросов.

UNC_SOC_Module0_Snoops

UNC_VISA_Module0_Snoops подсчитывает количество запросов отслеживания и отчетов отслеживания для модуля Silvermont 0 с точки зрения системного агента. Данные этих счетчиков можно использовать для подтверждения показателей других счетчиков трафика и для выявления взаимосвязей в счетчиках событий отслеживания ядер. В отличие от событий отслеживания, связанных с ядрами, счетчики отслеживания внеядерных компонентов не могут различать показатели для ядер внутри модуля; они считают общее значение для целого модуля, а не для каждого ядра.

Имя

Событие

Описание

Mod0_Snoop_Replies

0

Подсчитывает количество ответов отслеживания, полученных от модуля 0.

Mod0_Snoop_Reqs

1

Подсчитывает количество запросов отслеживания, отправленных в модуль 0.

Clock_Counter

2

Тактовый счетчик «системы на кристалле»

Анализ результатов

Анализ результатов отслеживания зависит от модели использования.

Известное поведение

  1. Показатели счетчиков отслеживания подсчитываются для всего процессорного модуля без возможности разделения по каждому ядру.

UNC_SOC_Graphics_BW

Группа UNC_VISA_Graphics_BW предоставляет счетчики для вычисления пропускной способности графического контроллера с точки зрения системного агента. События можно разделить по типам запросов.

На приведенном ниже рисунке показан поток трафика, отслеживаемый этой группой.

Имя

Счетчик

Описание

GFX_ReadPartial

0

Подсчитывает все транзакции чтения графического контроллера с запросами с частичным размером данных.

GFX_Read32B

1

Подсчитывает количество запросов чтения памяти размером 32 байта от графического контроллера.

GFX_Read64B

2

Подсчитывает количество запросов чтения памяти размером 64 байта от графического контроллера.

GFX_WritePartial

3

Подсчитывает все транзакции записи графического контроллера с запросами с частичным размером данных.

GFX_Write32B

4

Подсчитывает количество запросов записи в память размером 32 байта от графического контроллера.

GFX_Write64B

5

Подсчитывает количество запросов записи в память размером 64 байта от графического контроллера.

Clock_Counter

6

Тактовый счетчик «системы на кристалле»

Анализ результатов

Пропускную способность чтения и записи можно вычислить для 32- и 64-байтовых событий, но вычисление частичных событий затруднено, поскольку у частичных запросов неизвестен объем полезной нагрузки.

Формула метрики событий:

  • (счетчик GFX_Read32B * 32 байта / длительность выборки в секундах) + (счетчик GFX_Read64B * 64 байта / длительность выборки в секундах) = чтение, МБ/с
  • (счетчик GFX_Write32B * 32 байта / длительность выборки в секундах) + (счетчик GFX_Write64B * 64 байта / длительность выборки в секундах) = запись МБ/с

Известное поведение

  1. Вычисление пропускной способности графики затруднено, поскольку графическая подсистема Merrifield в большинстве случаев использует частичную запись с неизвестным размером полезной нагрузки.

UNC_SOC_Display_BW

Группа UNC_VISA_Display_BW содержит события для определения пропускной способности контроллера дисплея и идентична группе UNC_VISA_Graphics_BW по конфигурации счетчиков событий и по метрике анализа. Имена событий изменены с GFX на Disp.

UNC_SOC_Imaging_BW

Группа UNC_VISA_Imaging_BW содержит события для определения пропускной способности контроллера изображений (сигнального процессора изображений) и идентична группе UNC_VISA_Graphics_BW по конфигурации счетчиков событий и по метрике анализа. Имена событий изменены с GFX на Imaging.

UNC_SOC_LowSpeedPF_BW

Группа UNC_VISA_LowSpeedPF_BW содержит события для определения пропускной способности структуры низкоскоростной периферии и представляет совокупную пропускную способность для всех подключаемых компонентов южного кластера: USB3, USB2, EMMC, сетевых адаптеров, шифрования и звукового адаптера. Эта группа идентична группе UNC_VISA_Graphics_BW по конфигурации счетчиков событий и по метрикам анализа. Имена событий изменены с GFX на LowSpeedPF.

Разработка трехмерных игр для Windows* 8 с помощью C++ и Microsoft DirectX*

$
0
0

Скачать PDF

Автор: Бруно Соннино (Bruno Sonnino)

Разработка игр — постоянно актуальная тема: всем нравится играть в игры, их охотно покупают, поэтому их выгодно продавать. Но при разработке хороших игр следует обращать немало внимания на производительность. Никому не понравится игра, «тормозящая» или работающая рывками даже на не самых мощных устройствах.

Для разработки игр можно применять различные языки и платформы, но если в игре для Windows* нужно добиться производительности, рецепт однозначен: Microsoft DirectX* и C++. Эти технологии обеспечивают доступ к оборудованию на самом низком уровне, благодаря чему можно использовать все возможности «железа» и добиться исключительной производительности.

Я решил разработать именно такую игру, хотя главным образом я занимаюсь разработкой на C#. В прошлом я довольно много работал с C++, но теперь этот язык для меня уже не столь прост. Кроме того, DirectX для меня является новинкой, поэтому эту статью можно считать точкой зрения новичка на разработку игр. Прошу опытных разработчиков простить меня за возможные ошибки.

В этой статье я покажу, как разработать игру в футбол с пробитием пенальти по воротам. Игра бьет по мячу, а пользователь управляет вратарем, который должен поймать мяч. Начинать будем не с нуля. Мы будем использовать пакет Microsoft Visual Studio* 3D Starter Kit — это естественный начальный ресурс для всех желающих разрабатывать игры для Windows 8.1.

Microsoft Visual Studio* 3D Starter Kit

После загрузки пакета Starter Kit, можно распаковать его в папку и открыть файл StarterKit.sln. В этом решении есть уже готовый проект C++ для Windows 8.1. При его запуске появится изображение, похожее на рис. 1.


Рисунок 1.Начальное состояние Microsoft Visual Studio* 3D Starter Kit.

Эта программа в составе Starter Kit демонстрирует несколько полезных элементов:

  • Анимировано пять объектов: четыре фигуры вращаются вокруг чайника, а чайник, в свою очередь, «танцует».
  • Каждый предмет сделан из отдельного материала; некоторые имеют сплошной цвет, а поверхность куба представляет собой растровый рисунок.
  • Источник света находится в верхнем левом углу сцены.
  • В правом нижнем углу экрана расположен счетчик кадровой скорости (количество кадров в секунду).
  • Сверху находится индикатор очков.
  • Если щелкнуть какой-либо предмет, он выделяется и увеличивается количество очков.
  • Если щелкнуть экран игры правой кнопкой мыши или провести по экрану от нижнего края к середине, появятся две кнопки для последовательного переключения цвета чайника.

Эти функции можно использовать для создания любых игр, но сначала рассмотрим файлы в составе пакета.

Начнем с файла App.xaml и его аналогов cpp/h. При запуске приложения App.xaml запускается DirectXPage. В DirectXPage.xaml находится элемент SwapChainPanel и панель приложения. Элемент SwapChainPanel служит поверхностью для размещения графики DirectX на странице XAML. Здесь можно добавлять объекты XAML, которые будут отображаться в сцене Microsoft Direct3D* — это удобно для добавления кнопок, подписей и других объектов XAML в игру DirectX без необходимости создания собственных элементов управления с нуля. Пакет Starter Kit также включает элемент StackPanel, который мы будем использовать для подсчета очков.

В Directxpage.xaml.cpp происходит инициализация переменных, подключение обработчиков событий для изменения размера и ориентации, обработчиков событий щелчков мышью и нажатия кнопок на панели приложения. Кроме того, в этом файле содержится и цикл отрисовки. Все объекты XAML обрабатываются как любые другие программы для Windows 8. Файл также обрабатывает событие Tapped, проверяя, приходится ли касание (или щелчок мышью) на объект. Если да, то событие увеличивает счет для этого объекта.

Необходимо сообщить программе, что SwapChainPanel должен отрисовывать содержимое DirectX. Для этого, согласно документации, нужно «вызвать экземпляр SwapChainPanel для IInspectable или IUnknown, затем вызвать Querylnterface для получения ссылки на интерфейс ISwapchainPanelNative (это собственная реализация интерфейса, дополняющая SwapChainPanel и поддерживающая обмен информацией). Затем следует вызвать ISwapchainPanelNative::SetSwapChain для этой ссылки, чтобы связать реализованную цепочку с экземпляром SwapChainPanel». Это осущест¬вляется в методе CreateWindowSizeDependentResources в файле DeviceResources.cpp.

Основной цикл игры находится в файле StarterKitMain.cpp, где отрисовывается страница и счетчик количества кадров в секунду.

Game.cpp содержит игровой цикл и проверку нажатий. В этом файле в методе Update вычисляется анимация, а в методе Render происходит отрисовка всех объектов. Счетчик кадровой скорости отрисовывается в SampleFpsTextRenderer.cpp.

Объекты игры находятся в папке Assets. Teapot.fbx — это чайник, а файл GameLevel.fbx содержит четыре фигуры, которые вращаются вокруг танцующего чайника.

Теперь, ознакомившись с образцом приложения в пакете Starter Kit, можно перейти к созданию собственной игры.

Добавление ресурсов в игру

Мы разрабатываем игру в футбол, поэтому самым первым нашим ресурсом должен быть футбольный мяч, который мы добавим в Gamelevel.fbx. Сначала нужно удалить из этого файла четыре фигуры, выделив каждую из них и нажав кнопку Delete. В обозревателе решений удалите и файл CubeUVImage.png, поскольку он нам не нужен: это текстура для куба, который мы только что удалили.

Теперь добавляем сферу в модель. Откройте инструменты (если их не видно, щелкните View > Toolbox) и дважды щелкните сферу, чтобы добавить ее в модель. Если мяч кажется слишком маленьким, можно увеличить масштаб, нажав вторую кнопку на панели инструментов в верхней части окна редактора, нажав клавишу Z на клавиатуре, с помощью мыши (нажмите и перетащите к середине экрана, чтобы увеличить изображение) или с помощью клавиш со стрелками вверх и вниз. Также для управления масштабированием можно использовать колесико мыши при нажатой клавише Ctrl. Результат должен быть примерно таким, как на рис. 2.


Рисунок 2. Редактор моделей с фигурой сферы.

Пока это просто ровная белая сфера, подсвеченная определенным образом. Ей нужна текстура футбольного мяча. Сначала я попытался использовать в качестве текстуры сетку с шестиугольными ячейками, как показано на рис. 3.


Рисунок 3.Текстура мяча в виде шестиугольной сетки: первая попытка.

Чтобы наложить текстуру на сферу, выберите ее, затем в окне свойств назначьте файл .png свойству Texture1. Идея вроде была неплохая, но результат не особенно удался, как видно на рис. 4.


Рисунок 4.Сфера с наложенной текстурой.

Шестиугольники растянуты из-за проекции точек текстуры на сферу. Нам требуется растянутая текстура, такая как на рис. 5.


Рисунок 5. Текстура футбольного мяча, приспособленная к сфере.

При наложении этой текстуры сфера уже больше похожа на футбольный мяч. Чтобы изображение было более реалистичным, нужно настроить некоторые свойства. Для этого нужно выбрать мяч и изменить эффект Phong в окне свойств. Модель освещения Phong включает направленное и рассеянное освещение и моделирует отражающие свойства объекта. Это шейдер, входящий в состав Visual Studio, его можно перетащить из набора инструментов. Для получения дополнительных сведений о шейдерах и об их создании с помощью конструктора шейдеров Visual Studio щелкните ссылку «Дополнительные сведения». Установите для свойств Red, Green, и Blue в разделе MaterialSpecular значение 0.2, а для свойства MaterialSpecularPower — значение 16. Теперь наш футбольный мяч выглядит лучше (рис. 6).


Рисунок 6. Готовый футбольный мяч.

Если вы не хотите создавать собственные модели в Visual Studio, можно найти готовые модели в Интернете. Visual Studio поддерживает любые модели в формате FBX, DAE и OBJ: достаточно добавить их в состав ресурсов решения. Например, можно использовать файл .obj, подобный показанному на рис. 7 (бесплатная модель с сайта http://www.turbosquid.com).


Рисунок 7. Трехмерная OBJ-модель мяча.

Анимация модели

Модель готова, теперь пора ее анимировать. Но сначала нужно убрать чайник, поскольку он нам не понадобится. В папке Assets удалите файл teapot.fbx. Теперь удалите его загрузку и анимацию. В файле Game.cpp загрузка моделей происходит асинхронно в CreateDeviceDependentResources:


// Load the scene objects.
auto loadMeshTask = Mesh::LoadFromFileAsync(
	m_graphics,
	L"gamelevel.cmo",
	L"",
	L"",
	m_meshModels)
	.then([this]()
{
	// Load the teapot from a separate file and add it to the vector of meshes.
	return Mesh::LoadFromFileAsync(

Нужно изменить модель и удалить продолжение задачи, чтобы загружался только мяч:


void Game::CreateDeviceDependentResources()
{
	m_graphics.Initialize(m_deviceResources->GetD3DDevice(), m_deviceResources->GetD3DDeviceContext(), m_deviceResources->GetDeviceFeatureLevel());

	// Set DirectX to not cull any triangles so the entire mesh will always be shown.
	CD3D11_RASTERIZER_DESC d3dRas(D3D11_DEFAULT);
	d3dRas.CullMode = D3D11_CULL_NONE;
	d3dRas.MultisampleEnable = true;
	d3dRas.AntialiasedLineEnable = true;

	ComPtr<ID3D11RasterizerState> p3d3RasState;
	m_deviceResources->GetD3DDevice()->CreateRasterizerState(&d3dRas, &p3d3RasState);
	m_deviceResources->GetD3DDeviceContext()->RSSetState(p3d3RasState.Get());

	// Load the scene objects.
	auto loadMeshTask = Mesh::LoadFromFileAsync(
		m_graphics,
		L"gamelevel.cmo",
		L"",
		L"",
		m_meshModels);


	(loadMeshTask).then([this]()
	{
		// Scene is ready to be rendered.
		m_loadingComplete = true;
	});
}



Методу ReleaseDeviceDependentResources нужно лишь очистить сетки:


void Game::ReleaseDeviceDependentResources()
{
	for (Mesh* m : m_meshModels)
	{
		delete m;
	}
	m_meshModels.clear();

	m_loadingComplete = false;
}



Теперь нужно изменить метод Update, чтобы вращался только мяч:


void Game::Update(DX::StepTimer const& timer)
{
	// Rotate scene.
	m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
}

Для управления скоростью вращения используется множитель (0.5f). Чтобы мяч вращался быстрее, нужно просто увеличить этот множитель. За каждую секунду мяч будет поворачиваться на угол 0,5/(2 * Пи) радиан. Метод Render отрисовывает мяч с нужным углом вращения:


void Game::Render()
{
	// Loading is asynchronous. Only draw geometry after it's loaded.
	if (!m_loadingComplete)
	{
		return;
	}

	auto context = m_deviceResources->GetD3DDeviceContext();

	// Set render targets to the screen.
	auto rtv = m_deviceResources->GetBackBufferRenderTargetView();
	auto dsv = m_deviceResources->GetDepthStencilView();
	ID3D11RenderTargetView *const targets[1] = { rtv };
	context->OMSetRenderTargets(1, targets, dsv);

	// Draw our scene models.
	XMMATRIX rotation = XMMatrixRotationY(m_rotation);
	for (UINT i = 0; i < m_meshModels.size(); i++)
	{
		XMMATRIX modelTransform = rotation;

		String^ meshName = ref new String(m_meshModels[i]->Name());

		m_graphics.UpdateMiscConstants(m_miscConstants);

		m_meshModels[i]->Render(m_graphics, modelTransform);
	}
}

ToggleHitEffect здесь не будет работать: свечение мяча не изменится при его нажатии:


void Game::ToggleHitEffect(String^ object)
{

}



Нам не нужно, чтобы изменялась подсветка мяча, но нужно получать данные о его касании. Для этого используем измененный метод onHitobject:


String^ Game::OnHitObject(int x, int y)
{
	String^ result = nullptr;

	XMFLOAT3 point;
	XMFLOAT3 dir;
	m_graphics.GetCamera().GetWorldLine(x, y, &point, &dir);

	XMFLOAT4X4 world;
	XMMATRIX worldMat = XMMatrixRotationY(m_rotation);
	XMStoreFloat4x4(&world, worldMat);

	float closestT = FLT_MAX;
	for (Mesh* m : m_meshModels)
	{
		XMFLOAT4X4 meshTransform = world;

		auto name = ref new String(m->Name());

		float t = 0;
		bool hit = HitTestingHelpers::LineHitTest(*m, &point, &dir, &meshTransform, &t);
		if (hit && t < closestT)
		{
			result = name;
		}
	}

	return result;
}



Если сейчас запустить проект, вы увидите, что мяч вращается вокруг своей оси Y. Теперь приведем мяч в движение.

Движение мяча

Чтобы мяч двигался, нужно перемещать его, например, вверх и вниз. Сначала нужно объявить переменную для текущего положения мяча в Game.h:


class Game
{
public:
	// snip
private:
       // snip
       float m_translation;



Затем в методе Update нужно вычислить текущее положение:


void Game::Update(DX::StepTimer const& timer)
{
	// Rotate scene.
	m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
	const float maxHeight = 7.0f;
	auto totalTime = (float) fmod(timer.GetTotalSeconds(), 2.0f);
	m_translation = totalTime > 1.0f ?
		maxHeight - (maxHeight * (totalTime - 1.0f)) : maxHeight *totalTime;
}

Теперь мяч будет подниматься и опускаться каждые 2 секунды. В течение первой секунды мяч будет подниматься, в течение следующей секунды — опускаться. Метод Render вычисляет получившуюся матрицу и отрисовывает мяч в новом положении:


void Game::Render()
{
	// snip

	// Draw our scene models.
	XMMATRIX rotation = XMMatrixRotationY(m_rotation);
	rotation *= XMMatrixTranslation(0, m_translation, 0);



Если сейчас запустить проект, вы увидите, что мяч движется вверх и вниз с постоянной скоростью. Теперь нужно придать мячу физические свойства.

Добавление физики мяча.

Чтобы придать мячу физические эффекты, нужно сымитировать воздействие на него силы, представляющей гравитацию. Если вы помните школьный курс физики, то знаете, что ускоренное движение тела описывается следующими уравнениями:

s = s0 + v0t + 1/2at2

v = v0 + at

Где s — положение тела в момент t, s0 — начальное положение, v0 — начальная скорость, a — ускорение. Для движения по вертикали a — ускорение свободного падения (-10 м/с2), а s0 = 0 (сначала мяч находится на земле, то есть на нулевой высоте). Уравнения превращаются в следующие:

s = v0t -5t2

v = v0 -10t

Мы хотим достигнуть максимальной высоты за 1 секунду. На максимальной высоте скорость равна 0. Поэтому второе уравнение позволяет найти начальную скорость:

0 = v0– 10 * 1 => v0 = 10 m/s

Это дает нам перемещение мяча:

s = 10t – 5t2

Нужно изменить метод Update, чтобы использовать это уравнение:


void Game::Update(DX::StepTimer const& timer)
{
	// Rotate scene.
	m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
	auto totalTime = (float) fmod(timer.GetTotalSeconds(), 2.0f);
	m_translation = 10*totalTime - 5 *totalTime*totalTime;
}

Теперь, когда мяч реалистично движется вверх и вниз, пора добавить футбольное поле.

Добавление футбольного поля

Чтобы добавить футбольное поле, нужно создать новую сцену. В папке Assets щелкните правой кнопкой мыши, чтобы добавить новую трехмерную сцену, и назовите ее field.fbx. Из набора инструментов добавьте плоскость и выберите ее, измените ее размер по оси X на 107, а по оси Z на 60. Задайте для свойства этой плоскости Texture1 изображение футбольного поля. Теперь можно использовать средство масштабирования (или нажимать клавишу Z) для уменьшения изображения.

Затем нужно загрузить модель в CreateDeviceDependentResources в Game.cpp:


void Game::CreateDeviceDependentResources()
{
	// snip

	// Load the scene objects.
	auto loadMeshTask = Mesh::LoadFromFileAsync(
		m_graphics,
		L"gamelevel.cmo",
		L"",
		L"",
		m_meshModels)
		.then([this]()
	{
		return Mesh::LoadFromFileAsync(
			m_graphics,
			L"field.cmo",
			L"",
			L"",
			m_meshModels,
			false  // Do not clear the vector of meshes
			);
	});

	(loadMeshTask).then([this]()
	{
		// Scene is ready to be rendered.
		m_loadingComplete = true;
	});
}



При запуске программы вы увидите, что поле прыгает вместе с мячом. Чтобы поле перестало двигаться, нужно изменить метод Render:


// Renders one frame using the Starter Kit helpers.
void Game::Render()
{
	// snip

	for (UINT i = 0; i < m_meshModels.size(); i++)
	{
		XMMATRIX modelTransform = rotation;

		String^ meshName = ref new String(m_meshModels[i]->Name());

		m_graphics.UpdateMiscConstants(m_miscConstants);

		if (String::CompareOrdinal(meshName, L"Sphere_Node") == 0)
			m_meshModels[i]->Render(m_graphics, modelTransform);
		else
			m_meshModels[i]->Render(m_graphics, XMMatrixIdentity());
	}
}

При этом изменении преобразование применяется только к мячу. Поле отрисовывается без преобразования. Если запустить код сейчас, вы увидите, что мяч отскакивает от поля, но «проваливается» в него в нижней части. Для исправления этой ошибки нужно перенести поле на -0,5 по оси Y. Выберите поле и измените его перенос по оси Y на -0,5. Теперь при запуске приложения мяч будет отскакивать от поля, как на рис. 8.


Рисунок 8.Мяч отскакивает от поля.

Задание положения камеры и мяча

Мяч расположен в центре поля, но нам он там не нужен. В этой игре мяч должен находиться на 11-метровой отметке. Если посмотреть на редактор сцены на рис. 9, видно, что следует переместить мяч по оси X, изменив перемещение мяча в методе Render в Game.cpp:


rotation *= XMMatrixTranslation(63.0, m_translation, 0);



Мяч перемещается на 63 единицы по оси X, то есть устанавливается на 11-метровую отметку.


Figure 9.Field with Axis – X (red) and Z (blue)

После этого изменения вы перестанете видеть мяч, поскольку он вне поля зрения камеры: камера установлена в центре поля и направлена на середину. Нужно изменить положение камеры, чтобы она была направлена на линию ворот. Это нужно сделать в CreateWindowSizeDependentResources в файле Game.cpp:


m_graphics.GetCamera().SetViewport((UINT) outputSize.Width, (UINT) outputSize.Height);
m_graphics.GetCamera().SetPosition(XMFLOAT3(25.0f, 10.0f, 0.0f));
m_graphics.GetCamera().SetLookAt(XMFLOAT3(100.0f, 0.0f, 0.0f));
float aspectRatio = outputSize.Width / outputSize.Height;
float fovAngleY = 30.0f * XM_PI / 180.0f;

if (aspectRatio < 1.0f)
{
	// Portrait or snap view
	m_graphics.GetCamera().SetUpVector(XMFLOAT3(1.0f, 0.0f, 0.0f));
	fovAngleY = 120.0f * XM_PI / 180.0f;
}
else
{
	// Landscape view.
	m_graphics.GetCamera().SetUpVector(XMFLOAT3(0.0f, 1.0f, 0.0f));
}
m_graphics.GetCamera().SetProjection(fovAngleY, aspectRatio, 1.0f, 100.0f);

Теперь камера находится между отметкой середины поля и 11-метровой отметкой и направлена в сторону линии ворот. Новое представление показано на рис. 10.


Рисунок 10. Измененное положение мяча и новое положение камеры.

Теперь нужно добавить ворота.

Добавление штанги ворот

Чтобы добавить на поле ворота, понадобится новая трехмерная сцена с воротами. Можно создать собственную модель или использовать готовую. Эту модель следует добавить в папку Assets, чтобы ее можно было скомпилировать и использовать.

Эту модель нужно загрузить в методе CreateDeviceDependentResources в файле Game.cpp:


auto loadMeshTask = Mesh::LoadFromFileAsync(
	m_graphics,
	L"gamelevel.cmo",
	L"",
	L"",
	m_meshModels)
	.then([this]()
{
	return Mesh::LoadFromFileAsync(
		m_graphics,
		L"field.cmo",
		L"",
		L"",
		m_meshModels,
		false  // Do not clear the vector of meshes
		);
}).then([this]()
{
	return Mesh::LoadFromFileAsync(
		m_graphics,
		L"soccer_goal.cmo",
		L"",
		L"",
		m_meshModels,
		false  // Do not clear the vector of meshes
		);
});

После загрузки задайте положение и отрисуйте в методе Render в Game.cpp:


auto goalTransform = XMMatrixScaling(2.0f, 2.0f, 2.0f) * XMMatrixRotationY(-XM_PIDIV2)* XMMatrixTranslation(85.5f, -0.5, 0);

for (UINT i = 0; i < m_meshModels.size(); i++)
{
	XMMATRIX modelTransform = rotation;

	String^ meshName = ref new String(m_meshModels[i]->Name());

	m_graphics.UpdateMiscConstants(m_miscConstants);

	if (String::CompareOrdinal(meshName, L"Sphere_Node") == 0)
		m_meshModels[i]->Render(m_graphics, modelTransform);
	else if (String::CompareOrdinal(meshName, L"Plane_Node") == 0)
		m_meshModels[i]->Render(m_graphics, XMMatrixIdentity());
	else
		m_meshModels[i]->Render(m_graphics, goalTransform);
}

Это изменение применяет преобразование к воротам и отрисовывает их. Это преобразование является сочетанием трех преобразований: масштабированием (увеличение исходного размера в 2 раза), поворотом на 90 градусов и перемещением на 85,5 единиц по оси X и на -0,5 единиц по оси Y из-за глубины поля. После этого ворота устанавливаются лицом к полю на линии ворот, как показано на рис. 11. Обратите внимание, что важен порядок преобразований: если применить вращение после перемещения, то ворота будут отрисованы совсем в другом месте, и вы их не увидите.


Рисунок 11. Поле с установленными воротами.

Удар по мячу

Все элементы установлены на свои места, но мяч все еще подпрыгивает. Пора по нему ударить. Для этого нужно снова применить физические навыки. Удар по мячу выглядит примерно так, как показано на рис. 12.


Рисунок 12. Схема удара по мячу.

Удар по мячу осуществляется с начальной скоростью v0 под углом α (если не помните школьные уроки физики, поиграйте немного в Angry Birds, чтобы увидеть этот принцип в действии). Движение мяча можно разложить на два разных движения: по горизонтали — это движение с постоянной скоростью (исходим из того, что отсутствует сопротивление воздуха и воздействие ветра), а также вертикальное движение — такое же, как мы использовали раньше. Уравнение движения по горизонтали:

sX = s0 + v0*cos(α)*t

Уравнение движения по вертикали:

sY = s0 + v0*sin(α)*t – ½*g*t2

Таким образом, у нас два перемещения: одно по оси X, другое по оси Y. Если удар нанесен под углом 45 градусов, то cos(α) = sin(α) = sqrt(2)/2, поэтому v0*cos(α) = v0*sin(a)*t. Нужно, чтобы мяч попал в ворота, поэтому дальность удара должна превышать 86 единиц (расстояние до линии ворот равно 85,5). Нужно, чтобы полет мяча занимал 2 секунды. При подстановке этих значений в первое уравнение получим:

86 = 63 + v0 * cos(α) * 2 ≥ v0 * cos(α) = 23/2 = 11.5

Если заменить значения в уравнении, то уравнение перемещения по оси Y будет таким:

sY = 0 + 11.5 * t – 5 * t2

. . . and for the x-axis:

sX = 63 + 11.5 * t

Уравнение для оси Y дает нам время, когда мяч снова ударится о землю. Для этого нужно решить квадратное уравнение (да, я понимаю, что вы надеялись навсегда распрощаться с ними после школьного курса алгебры, но тем не менее):

(−b ± sqrt(b2− 4*a*c))/2*a ≥ (−11.5 ± sqrt(11.52– 4 * −5 * 0)/2 * −5 ≥ 0 or 23/10 ≥ 2.3s

Этими уравнениями можно заменить перемещение для мяча. Сначала в Game.h создайте переменные для сохранения перемещения по трем осям:


float m_translationX, m_translationY, m_translationZ;



Затем в методе Update в Game.cpp добавьте уравнения:


void Game::Update(DX::StepTimer const& timer)
{
	// Rotate scene.
	m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
	auto totalTime = (float) fmod(timer.GetTotalSeconds(), 2.3f);
	m_translationX = 63.0 + 11.5 * totalTime;
	m_translationY = 11.5 * totalTime - 5 * totalTime*totalTime;
}

Метод Render использует эти новые перемещения:


rotation *= XMMatrixTranslation(m_translationX, m_translationY, 0);



Если запустить программу сейчас, вы увидите, как мяч влетает в середину ворот. Если нужно, чтобы мяч двигался в других направлениях, нужно добавить горизон-тальный угол удара. Для этого мы используем перемещение по оси Z.

На рис. 13 видно, что расстояние от 11-метровой отметки до ворот составляет 22,5 единицы, а расстояние между штангами ворот — 14 единиц. Это дает нам угол α = atan(7/22.5), то есть 17 градусов. Можно вычислить и перемещение по оси Z, но можно сделать и проще: мяч должен переместиться до линии в тот же момент, когда он достигнет штанги. Это означает, что мяч должен переместиться на 7/22,5 единицы по оси Z и на 1 единицу по оси X. Уравнение для оси Z будет таким:

sz = 11.5 * t/3.2 ≥ sz = 3.6 * t


Рисунок 13. Схема расстояния до ворот.

Это перемещение до штанги ворот. У любого перемещения с меньшей скоростью угол будет меньше. Чтобы мяч достиг ворот, скорость должна составлять от -3,6 (левая штанга) до 3,6 (правая штанга). Если учесть, что мяч должен полностью попасть в ворота, максимальное расстояние составляет 6/22,5, а скорость — от 3 до -3. Имея эти цифры, можно задать угол удара в методе Update:


void Game::Update(DX::StepTimer const& timer)
{
	// Rotate scene.
	m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
	auto totalTime = (float) fmod(timer.GetTotalSeconds(), 2.3f);
	m_translationX = 63.0 + 11.5 * totalTime;
	m_translationY = 11.5 * totalTime - 5 * totalTime*totalTime;
	m_translationZ = 3 * totalTime;
}

Перемещение по оси Z будет использовано в методе Render:


rotation *= XMMatrixTranslation(m_translationX, m_translationY, m_translationZ);
       ….



Результат должен быть примерно таким, как на рис. 14.


Рисунок 14. Удар под углом.

Добавление вратаря

Движение мяча уже готово, ворота на месте, теперь нужно добавить вратаря, который будет ловить мяч. В роли вратаря у нас будет искаженный куб. В папке Assets добавьте новый элемент (новую трехмерную сцену) и назовите его goalkeeper.fbx.

Добавьте куб из набора инструментов и выберите его. Задайте масштаб: 0,3 по оси X, 1,9 по оси Y и 1 по оси Z. Для свойства MaterialAmbient установите значение 1 для красного цвета и значение 0 для синего и зеленого цвета, чтобы сделать объект красным. Измените значение свойства Red в разделе MaterialSpecular на 1 и значение свойства MaterialSpecularPower на 0,2.

Загрузите новый ресурс в методе CreateDeviceDependentResources:


auto loadMeshTask = Mesh::LoadFromFileAsync(
	m_graphics,
	L"gamelevel.cmo",
	L"",
	L"",
	m_meshModels)
	.then([this]()
{
	return Mesh::LoadFromFileAsync(
		m_graphics,
		L"field.cmo",
		L"",
		L"",
		m_meshModels,
		false  // Do not clear the vector of meshes
		);
}).then([this]()
{
	return Mesh::LoadFromFileAsync(
		m_graphics,
		L"soccer_goal.cmo",
		L"",
		L"",
		m_meshModels,
		false  // Do not clear the vector of meshes
		);
}).then([this]()
{
	return Mesh::LoadFromFileAsync(
		m_graphics,
		L"goalkeeper.cmo",
		L"",
		L"",
		m_meshModels,
		false  // Do not clear the vector of meshes
		);
});

Теперь нужно расположить вратаря в середине ворот и отрисовать его. Это нужно сделать в методе Render в Game.cpp:


void Game::Render()
{
	// snip

	auto goalTransform = XMMatrixScaling(2.0f, 2.0f, 2.0f) * XMMatrixRotationY(-XM_PIDIV2)* XMMatrixTranslation(85.5f, -0.5f, 0);
	auto goalkeeperTransform = XMMatrixTranslation(85.65f, 1.4f, 0);

	for (UINT i = 0; i < m_meshModels.size(); i++)
	{
		XMMATRIX modelTransform = rotation;

		String^ meshName = ref new String(m_meshModels[i]->Name());

		m_graphics.UpdateMiscConstants(m_miscConstants);

		if (String::CompareOrdinal(meshName, L"Sphere_Node") == 0)
			m_meshModels[i]->Render(m_graphics, modelTransform);
		else if (String::CompareOrdinal(meshName, L"Plane_Node") == 0)
			m_meshModels[i]->Render(m_graphics, XMMatrixIdentity());
		else if (String::CompareOrdinal(meshName, L"Cube_Node") == 0)
			m_meshModels[i]->Render(m_graphics, goalkeeperTransform);
		else
			m_meshModels[i]->Render(m_graphics, goalTransform);
	}
}

Этот код размещает вратаря в середине ворот, как показано на рис. 15 (обратите внимание, что положение камеры на снимке экрана отличается).


Рисунок 15. Вратарь в середине ворот.

Теперь нужно сделать так, чтобы вратарь мог перемещаться влево и вправо, чтобы ловить мяч. Для управления движением вратаря пользователь будет нажимать на клавиши со стрелками влево и вправо.

Движение вратаря ограничено штангами ворот, расположенными на расстоянии +7 и -7 единиц по оси Z. Ширина вратаря составляет 1 единицу в каждую сторону, поэтому он может перемещаться на 6 единиц влево или вправо.

Нажатие клавиши перехватывается на странице XAML (Directxpage.xaml) и перена-правляется в класс Game. Добавляем обработчик событий KeyDown в Directxpage.xaml:

<Page
    x:Class="StarterKit.DirectXPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:StarterKit"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" KeyDown="OnKeyDown">

Обработчик событий в DirectXPage.xaml.cpp:


void DirectXPage::OnKeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
	m_main->OnKeyDown(e->Key);
}

m_main является экземпляром класса StarterKitMain, который отрисовывает сцены игры и счетчик кадровой скорости. Нужно объявить публичный метод в StarterKitMain.h:


class StarterKitMain : public DX::IDeviceNotify
{
public:
	StarterKitMain(const std::shared_ptr<DX::DeviceResources>& deviceResources);
	~StarterKitMain();

	// Public methods passed straight to the Game renderer.
	Platform::String^ OnHitObject(int x, int y) {
            return m_sceneRenderer->OnHitObject(x, y); }
	void OnKeyDown(Windows::System::VirtualKey key) {
            m_sceneRenderer->OnKeyDown(key); }….



Этот метод перенаправляет клавишу методу OnKeyDown в классе Game. Теперь нужно объявить метод OnKeyDown в файле Game.h:


class Game
{
public:
	Game(const std::shared_ptr<DX::DeviceResources>& deviceResources);
	void CreateDeviceDependentResources();
	void CreateWindowSizeDependentResources();
	void ReleaseDeviceDependentResources();
	void Update(DX::StepTimer const& timer);
	void Render();
	void OnKeyDown(Windows::System::VirtualKey key);….



Этот метод обрабатывает нажатие клавиш и перемещает вратаря в соответствующую сторону. Перед созданием этого метода нужно объявить частное поле в файле Game.h для сохранения положения вратаря:


class Game
{
       // snip

private:
	// snip

	float m_goalkeeperPosition;



Изначально вратарь занимает положение 0. Это значение будет увеличиваться или уменьшаться при нажатии пользователем клавиши со стрелкой. Если положение больше 6 или меньше -6, положение вратаря не изменяется. Это нужно сделать в методе OnKeyDown в Game.cpp:


void Game::OnKeyDown(Windows::System::VirtualKey key)
{
	const float MaxGoalkeeperPosition = 6.0;
	const float MinGoalkeeperPosition = -6.0;
	if (key == Windows::System::VirtualKey::Right)
		m_goalkeeperPosition = m_goalkeeperPosition >= MaxGoalkeeperPosition ?
	m_goalkeeperPosition : m_goalkeeperPosition + 0.1f;
	else if (key == Windows::System::VirtualKey::Left)
		m_goalkeeperPosition = m_goalkeeperPosition <= MinGoalkeeperPosition ?
	m_goalkeeperPosition : m_goalkeeperPosition - 0.1f;
}

Новое положение вратаря используется в методе Render файла Game.cpp, где вычисляется перемещение вратаря:


auto goalkeeperTransform = XMMatrixTranslation(85.65f, 1.40f, m_goalkeeperPosition);



Применив эти изменения, можно запустить игру: вы увидите, что вратарь движется вправо или влево при нажатии соответствующих клавиш со стрелками (см. рис. 16).


Рисунок 16. Игра с вратарем в нужном положении.

До сих пор мяч двигался постоянно, но это нам не нужно. Мяч должен начинать движение непосредственно после удара и останавливаться при достижении ворот. Вратарь также не должен двигаться до удара по мячу.

Необходимо объявить частное поле m_isAnimating в файле Game.h, чтобы игра «знала», когда мяч движется:


class Game
{
public:
	// snip

private:
	// snip
	bool m_isAnimating;



Эта переменная используется в методах Update и Render в Game.cpp, поэтому мяч перемещается, только когда m_isAnimating имеет значение true:


void Game::Update(DX::StepTimer const& timer)
{
	if (m_isAnimating)
	{
		m_rotation = static_cast<float>(timer.GetTotalSeconds()) * 0.5f;
		auto totalTime = (float) fmod(timer.GetTotalSeconds(), 2.3f);
		m_translationX = 63.0f + 11.5f * totalTime;
		m_translationY = 11.5f * totalTime - 5.0f * totalTime*totalTime;
		m_translationZ = 3.0f * totalTime;
	}
}

void Game::Render()
{
	// snip

	XMMATRIX modelTransform;
	if (m_isAnimating)
	{
		modelTransform = XMMatrixRotationY(m_rotation);
		modelTransform *= XMMatrixTranslation(m_translationX,
                  m_translationY, m_translationZ);
	}
	else
		modelTransform = XMMatrixTranslation(63.0f, 0.0f, 0.0f);
       ….



Переменная modelTransform перемещается из цикла к началу. Нажатие клавиш со стрелками следует обрабатывать в методе OnKeyDown, только когда m_isAnimating имеет значение true:


void Game::OnKeyDown(Windows::System::VirtualKey key)
{
	const float MaxGoalkeeperPosition = 6.0f;

	if (m_isAnimating)
	{
		auto goalKeeperVelocity = key == Windows::System::VirtualKey::Right ?
			0.1f : -0.1f;

		m_goalkeeperPosition = fabs(m_goalkeeperPosition) >= MaxGoalkeeperPosition ?
		m_goalkeeperPosition :
							 m_goalkeeperPosition + goalKeeperVelocity;
	}
}

Теперь нужно ударить по мячу. Это происходит, когда пользователь нажимает пробел. Объявите новое частное поле m_isKick в файле Game.h:


class Game
{
public:
	// snip

private:
	// snip
	bool m_isKick;



Установите для этого поля значение true в методе OnKeyDown в Game.cpp:


void Game::OnKeyDown(Windows::System::VirtualKey key)
{
	const float MaxGoalkeeperPosition = 6.0f;

	if (m_isAnimating)
	{
		auto goalKeeperVelocity = key == Windows::System::VirtualKey::Right ?
			0.1f : -0.1f;

		m_goalkeeperPosition = fabs(m_goalkeeperPosition) >= MaxGoalkeeperPosition ?
		m_goalkeeperPosition :
							 m_goalkeeperPosition + goalKeeperVelocity;
	}
	else if (key == Windows::System::VirtualKey::Space)
		m_isKick = true;
}

Когда m_isKick имеет значение true, в методе Update запускается анимация:


void Game::Update(DX::StepTimer const& timer)
{
	if (m_isKick)
	{
		m_startTime = static_cast<float>(timer.GetTotalSeconds());
		m_isAnimating = true;
		m_isKick = false;
	}
	if (m_isAnimating)
	{
		auto totalTime = static_cast<float>(timer.GetTotalSeconds()) - m_startTime;
		m_rotation = totalTime * 0.5f;
		m_translationX = 63.0f + 11.5f * totalTime;
		m_translationY = 11.5f * totalTime - 5.0f * totalTime*totalTime;
		m_translationZ = 3.0f * totalTime;
		if (totalTime > 2.3f)
			ResetGame();
	}
}

Начальное время удара хранится в переменной m_startTime (объявленной как приватное поле в файле Game.h), которая используется для вычисления времени удара. Если оно превышает 2,3 секунды, игра сбрасывается (за это время мяч уже должен был достигнуть ворот). Метод ResetGame объявляется как частный в Game.h:


void Game::ResetGame()
{
	m_isAnimating = false;
	m_goalkeeperPosition = 0;
}



Этот метод устанавливает для m_isAnimating значение false и сбрасывает положение вратаря. Положение мяча изменять не нужно: мяч будет отрисован на 11-метровой отметке, если m_isAnimating имеет значение false. Также нужно изменить угол удара. Этот код направляет удар вблизи правой штанги:


m_translationZ = 3.0f * totalTime;



Нужно изменить этот подход, чтобы удары были случайными и пользователь не знал, куда будет направлен следующий удар. Необходимо объявить приватное поле m_ballAngle в файле Game.h и инициализировать его при ударе по мячу в методе Update:


void Game::Update(DX::StepTimer const& timer)
{
	if (m_isKick)
	{
		m_startTime = static_cast<float>(timer.GetTotalSeconds());
		m_isAnimating = true;
		m_isKick = false;
		m_ballAngle = (static_cast <float> (rand()) /
			static_cast <float> (RAND_MAX) -0.5f) * 6.0f;
	}
…



Rand()/RAND_MAX дает результат от 0 до 1. Нужно вычесть из результата 0,5, чтобы получить число от -0,5 до 0,5, а затем умножить на 6, чтобы получить итоговый угол до -3 до 3. Чтобы в каждой игре использовать разные последовательности, нужно инициализировать генератор, вызвав srand в методе CreateDeviceDependentResources:


void Game::CreateDeviceDependentResources()
{
	srand(static_cast <unsigned int> (time(0)));
…



Чтобы вызвать функцию времени, нужно включить . Чтобы использовать новый угол для мяча, нужно применить m_ballAngle в методе Update:


m_translationZ = m_ballAngle * totalTime;



Теперь почти весь код готов, но нужно понять, поймал ли вратарь мяч, или же пользователь забил гол. Это можно определить простым способом: проверить, пересекается ли прямоугольник мяча с прямоугольником вратаря в момент достижения мячом линии ворот. Разумеется, для определения забитых голов можно использовать и более сложные методики, но для нашего случая описанного способа вполне достаточно. Все вычисления осуществляются в методе Update:


void Game::Update(DX::StepTimer const& timer)
{
	if (m_isKick)
	{
		m_startTime = static_cast<float>(timer.GetTotalSeconds());
		m_isAnimating = true;
		m_isKick = false;
		m_isGoal = m_isCaught = false;
		m_ballAngle = (static_cast <float> (rand()) /
			static_cast <float> (RAND_MAX) -0.5f) * 6.0f;
	}
	if (m_isAnimating)
	{
		auto totalTime = static_cast<float>(timer.GetTotalSeconds()) - m_startTime;
		m_rotation = totalTime * 0.5f;
		if (!m_isCaught)
		{
			// ball traveling
			m_translationX = 63.0f + 11.5f * totalTime;
			m_translationY = 11.5f * totalTime - 5.0f * totalTime*totalTime;
			m_translationZ = m_ballAngle * totalTime;
		}
		else
		{
			// if ball is caught, position it in the center of the goalkeeper
			m_translationX = 83.35f;
			m_translationY = 1.8f;
			m_translationZ = m_goalkeeperPosition;
		}
		if (!m_isGoal && !m_isCaught && m_translationX >= 85.5f)
		{
			// ball passed the goal line - goal or caught
			auto ballMin = m_translationZ - 0.5f + 7.0f;
			auto ballMax = m_translationZ + 0.5f + 7.0f;
			auto goalkeeperMin = m_goalkeeperPosition - 1.0f + 7.0f;
			auto goalkeeperMax = m_goalkeeperPosition + 1.0f + 7.0f;
			m_isGoal = (goalkeeperMax < ballMin || goalkeeperMin > ballMax);
			m_isCaught = !m_isGoal;
		}

		if (totalTime > 2.3f)
			ResetGame();
	}
}

Объявляем два частных поля в файле Game.h: m_isGoal и m_IsCaught. Эти поля говорят нам о том, что произошло: пользователь забил гол или вратарь поймал мяч. Если оба поля имеют значение false, мяч еще летит. Когда мяч достигает вратаря, программа вычисляет границы мяча и вратаря и определяет, налагаются ли границы мяча на границы вратаря. Если посмотрите в код, то увидите, что я добавил 7.0 f к каждой границе. Я сделал это, поскольку границы могут быть положительными или отрицательными, а это усложнит вычисление наложения. Добавив 7.0 f, я добился того, что все значения стали положительными, чтобы упростить вычисление. Если мяч пойман, его положение устанавливается по центру вратаря. m_isGoal и m_IsCaught сбрасываются при ударе. Теперь добавим в игру счет.

Добавление счета

В игре DirectX можно отрисовывать счет с помощью Direct2D, но поскольку мы разрабатываем игру для Windows 8, то можно использовать и XAML. Можно подключать элементы XAML в игре и создавать связи между элементами XAML и игровой логикой. Это удобный способ отображения информации и взаимодействия с пользователем, поскольку не придется иметь дело с положениями элементов, отрисовщиками и циклами обновления.

В состав Starter Kit входит табло результатов XAML (то самое, которое используется для подсчета нажатий на элементы в сцене с чайником). Нужно просто изменить его, чтобы на нем отображался футбольный счет. Сначала нужно изменить DirectXPage.xaml, чтобы изменить табло счета:

<SwapChainPanel x:Name="swapChainPanel" Tapped="OnTapped"><Border VerticalAlignment="Top" HorizontalAlignment="Center" Padding="10" Background="Black"
          Opacity="0.7"><StackPanel Orientation="Horizontal"><TextBlock x:Name="ScoreUser" Text="0" Style="{StaticResource HudCounter}"/><TextBlock Text="x" Style="{StaticResource HudCounter}"/><TextBlock x:Name="ScoreMachine" Text="0" Style="{StaticResource HudCounter}"/></StackPanel></Border></SwapChainPanel>

Пока мы здесь, можно изменить нижнюю панель приложения, поскольку в этой игре она нам не понадобится. Мы удалили все счетчики нажатий, поэтому теперь нужно удалить код, ссылающийся на них в обработчике OnTapped в файле DirectXPage.xaml.cpp:


void DirectXPage::OnTapped(Object^ sender, TappedRoutedEventArgs^ e)
{

}



Также можно удалить OnPreviousColorPressed, OnNextcolorPressed и ChangeObjectColor из cpp- и h-страниц, поскольку они использовались в удаленных кнопках панели приложения.

Для обновления счета в игре должен быть какой-либо способ обмена информацией между классом Game и страницей XAML. Игровой счет обновляется в классе Game, тогда как счет отображается на странице XAML. Это можно сделать, создав событие в классе Game, но у этого подхода есть недостаток. При добавлении события в класс Game возникает ошибка компиляции: «объявление события WinRT должно быть включено в класс WinRT». Причина заключается в том, что Game не является классом WinRT(ref). Чтобы использовать класс WinRT, нужно определить это событие как публичный класс ref и запечатать его:


public ref class Game sealed



Для этого можно было бы изменить класс, но мы пойдем другим путем: создадим новый класс — в данном случае класс WinRT — и будем использовать его для обмена информацией между классом Game и страницей XAML. Создайте новый класс и назовите его ViewModel:


#pragma once
ref class ViewModel sealed
{
public:
	ViewModel();
};



В файле ViewModel.h добавляем событие и свойства, необходимые для обновления результатов:


#pragma once
namespace StarterKit
{
	ref class ViewModel sealed
	{
	private:
		int m_scoreUser;
		int m_scoreMachine;
	public:
		ViewModel();
		event Windows::Foundation::TypedEventHandler<Object^, Platform::String^>^ PropertyChanged;

		property int ScoreUser
		{
			int get()
			{
				return m_scoreUser;
			}

			void set(int value)
			{
				if (m_scoreUser != value)
				{
					m_scoreUser = value;
					PropertyChanged(this, L"ScoreUser");
				}
			}
		};

		property int ScoreMachine
		{
			int get()
			{
				return m_scoreMachine;
			}

			void set(int value)
			{
				if (m_scoreMachine != value)
				{
					m_scoreMachine = value;
					PropertyChanged(this, L"ScoreMachine");
				}
			}
		};
	};

}



Объявите частное поле типа ViewModel в Game.h (нужно включить ViewModel.h в Game.h). Также нужно объявить публичный метод получения для этого поля:


class Game
{
public:
       // snip
       StarterKit::ViewModel^ GetViewModel();
private:
	StarterKit::ViewModel^ m_viewModel;



Это поле инициализируется в конструкторе Game.cpp:


Game::Game(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
m_loadingComplete(false),
m_deviceResources(deviceResources)
{
	CreateDeviceDependentResources();
	CreateWindowSizeDependentResources();
	m_viewModel = ref new ViewModel();
}

Код метода получения:


StarterKit::ViewModel^ Game::GetViewModel()
{
	return m_viewModel;
}



Когда текущий удар завершается, переменные обновляются в ResetGame в файле Game.cpp:


void Game::ResetGame()
{
	if (m_isCaught)
		m_viewModel->ScoreUser++;
	if (m_isGoal)
		m_viewModel->ScoreMachine++;
	m_isAnimating = false;
	m_goalkeeperPosition = 0;
}

При изменении одного из этих двух свойств возникает событие PropertyChanged, которое можно обработать на странице XAML. Здесь есть одна недоработка: у страницы XAML нет прямого доступа к классу Game (это не ref-класс), но вместо этого осуществляется вызов StarterKitMain. Нужно создать метод получения для ViewModel в StarterKitMain.h:


class StarterKitMain : public DX::IDeviceNotify
{
public:
	// snip
	StarterKit::ViewModel^ GetViewModel() { return m_sceneRenderer->GetViewModel(); }

При наличии этой инфраструктуры можно обрабатывать событие PropertyChanged для ViewModel в конструкторе DirectXPage.xaml.cpp:


DirectXPage::DirectXPage():
	m_windowVisible(true),
	m_hitCountCube(0),
	m_hitCountCylinder(0),
	m_hitCountCone(0),
	m_hitCountSphere(0),
	m_hitCountTeapot(0),
	m_colorIndex(0)
{
	// snip

	m_main = std::unique_ptr<StarterKitMain>(new StarterKitMain(m_deviceResources));
	m_main->GetViewModel()->PropertyChanged += ref new
           TypedEventHandler<Object^, String^>(this, &DirectXPage::OnPropertyChanged);
	m_main->StartRenderLoop();
}

Этот обработчик обновляет счет (его также нужно объявить в DirectXPage.xaml.cpp.h):


void StarterKit::DirectXPage::OnPropertyChanged(Platform::Object ^sender, Platform::String ^propertyName)
{

		if (propertyName == "ScoreUser")
		{
			auto scoreUser = m_main->GetViewModel()->ScoreUser;
			Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, scoreUser]()
			{
				ScoreUser->Text = scoreUser.ToString();
			}));
		}
		if (propertyName == "ScoreMachine")
		{
			auto scoreMachine= m_main->GetViewModel()->ScoreMachine;
			Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler([this, scoreMachine]()
			{
				ScoreMachine->Text = scoreMachine.ToString();
			}));
		}

}



Теперь счет обновляется каждый раз, когда пользователь забивает гол и когда вратарь ловит мяч (рис. 17):


Рисунок 17. Игра с обновлением счета.

Использование сенсорного управления и датчиков в игре

Игра уже вполне работоспособна, но почему бы ее не улучшить? Новые Ultrabook™ оборудованы датчиками и сенсорными экранами, с помощью которых можно расширить возможности игры. Вместо использования клавиатуры для ударов по мячу и перемещения вратаря пользователь может ударить по мячу, коснувшись экрана, и перемещать вратаря, наклоняя экран вправо или влево.

Чтобы ударять по мячу касанием экрана, используйте событие OnTapped в DirectXPage.cpp:


void DirectXPage::OnTapped(Object^ sender, TappedRoutedEventArgs^ e)
{
	m_main->OnKeyDown(VirtualKey::Space);
}

Этот код вызывает метод OnKeyDown, передавая в качестве параметра клавишу пробела — такой же код, как если бы пользователь нажал клавишу пробела. Если хотите, можно усовершенствовать этот код: получать положение касания и запускать удар по мячу только в том случае, если касание приходится на мяч. Пусть это будет вашим заданием на дом. В качестве начальной точки Starter Kit содержит код, чтобы обнаруживать касание пользователем объекта в сцене.

Теперь нужно сделать, чтобы вратарь перемещался, когда пользователь наклоняет экран. Для того нужно использовать измеритель угла наклона, определяющий все движения экрана. Этот датчик возвращает три значения: показатели поворота вокруг поперечной оси (X), продольной оси (Y) и вертикальной оси (Z). Для этой игры нужно считывать только поворот вокруг продольной оси.

Чтобы использовать этот датчик, нужно получить его экземпляр, для чего применяется метод GetDefault. Затем нужно задать интервал считывания, как в этом коде в void Game::CreateDeviceDependentResources в файле Game.cpp:


void Game::CreateDeviceDependentResources()
{
	m_inclinometer = Windows::Devices::Sensors::Inclinometer::GetDefault();
	if (m_inclinometer != nullptr)
	{
		// Establish the report interval for all scenarios
		uint32 minReportInterval = m_inclinometer->MinimumReportInterval;
		uint32 reportInterval = minReportInterval > 16 ? minReportInterval : 16;
		m_inclinometer->ReportInterval = reportInterval;
	}
...

m_inclinometer — частное поле, объявляемое в Game.h. В методе Update изменяем положение вратаря:


void Game::Update(DX::StepTimer const& timer)
{
	// snip
		SetGoalkeeperPosition();
		if (totalTime > 2.3f)
			ResetGame();
	}
}

SetGoalkeeperPosition изменяет положение вратаря в зависимости от значения, которое выдает датчик угла наклона:


void StarterKit::Game::SetGoalkeeperPosition()
{

	if (m_isAnimating && m_inclinometer != nullptr)
	{
		Windows::Devices::Sensors::InclinometerReading^ reading =
                    m_inclinometer->GetCurrentReading();
		auto goalkeeperVelocity = reading->RollDegrees / 100.0f;
		if (goalkeeperVelocity > 0.3f)
			goalkeeperVelocity = 0.3f;
		if (goalkeeperVelocity < -0.3f)
			goalkeeperVelocity = -0.3f;
		m_goalkeeperPosition = fabs(m_goalkeeperPosition) >= 6.0f ?
                 m_goalkeeperPosition : m_goalkeeperPosition + goalkeeperVelocity;
	}
}

После этого изменения можно будет двигать вратаря, наклоняя экран. Теперь игра готова.

Оценка производительности

Игра хорошо работает в системе разработки, но нужно попробовать ее и на менее мощном устройстве. Одно дело — разрабатывать игру на полноценном настольном компьютере с современным графическим процессором и 60 кадрами в секунду. Совсем другое дело — запускать игру на устройстве с процессором Intel® Atom™ и встроенным графическим адаптером.

Ваша игра должна показать хорошую производительность на обоих устройствах. Для измерения производительности можно использовать средства, входящие в состав Visual Studio или пакета Intel® Graphics Performance Analyzers (Intel® GPA), содержащего анализаторы производительности графической подсистемы, помогающие выявлять узкие места и повышать производительность игр. В Intel GPA можно получить наглядный анализ производительности игры и добиться повышения кадровой скорости.

Заключение

Итак, дело сделано. От танцующего чайника мы пришли к игре на DirectX с сенсорным управлением и управлением с помощью клавиатуры. Языки программирования становятся все более похожими, поэтому использование C++/DX не вызвало особых затруднений у разработчика, привыкшего пользоваться C#.

Основное затруднение состоит в освоении трехмерных моделей, в их движении и расположении привычным образом. Для этого потребовалось применить знания физики, геометрии, тригонометрии и математики.

Как бы то ни было, можно заключить, что разработка игры не является непосильной задачей. При наличии терпения и нужных инструментов можно создать великолепные игры с превосходной производительностью.

Благодарности

Большое спасибо Роберто Соннино (Roberto Sonnino) за его советы и техническое рецензирование этой статьи.

Изображения

Дополнительные сведения

Об авторе

Бруно Соннино — сотрудник корпорации Майкрософт уровня Most Valuable Professional (MVP), работает в Бразилии. Он выполняет обязанности разработчика и консультанта, а также является автором пяти книг про Delphi, опубликованных на португальском языке издательством Pearson Education Brazil, и ряда статей для бразильских и американских журналов и веб-сайтов.

 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.

 

Intel, the Intel logo, Intel Atom, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
*Other names and brands may be claimed as the property of others.
Copyright © 2014. Intel Corporation. All rights reserved.


События наблюдения за производительностью внеядерных компонентов платформы Rangeley

$
0
0

Использование событий наблюдения за производительностью внеядерных компонентов платформы Rangeley

В этой статье рассматриваются события наблюдения за производительностью платформы «система на кристалле» Rangeley. Введение в наблюдение за производительностью внеядерных компонентов платформ «система на кристалле» см. в статье:

Введение в платформу Rangeley с архитектурой «система на кристалле»

Ниже на блок-схеме показано типовое устройство Rangeley. Зеленые стрелки, соединяющие каждый блок, представляют собой интерфейсы; можно отслеживать запросы в интерфейсах для вычисления пропускной способности. Серыми стрелками в южном кластере показаны интерфейсы, для которых не поддерживается отслеживание производительности внеядерных компонентов. Как видно на схеме ниже, анализ будет касаться только северного кластера.

Доступные группы

В следующей таблице описаны доступные группы для Rangeley. Имя группы означает заранее заданный набор событий, которые будут программироваться программными средствами мониторинга. В столбце событий указывается, сколько событий содержится в группе. В столбце «Тактовые импульсы» указывается, включает ли группа счетчик из источника тактовых импульсов кристалла.

Таблица групп событий внеядерных компонентов платформы Rangeley

Имя группыСобытияТактовые импульсыОписание
UNC_SOC_Memory_DDR_BW8НетПодсчитывает количество запросов размером 32 и 64 байта к памяти для каналов памяти 0 и 1. Для определения пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Memory_DDR0_BW5ДаПодсчитывает количество запросов размером 32 и 64 байта к памяти для канала памяти 0. Для определения пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Memory_DDR1_BW5ДаПодсчитывает количество запросов размером 32 байта и 64 байта к памяти для канала памяти 1. Для определения пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_DDR_Self_Refresh3ДаПодсчитывает количество циклов, в течение которых каналы памяти 0 и 1 находятся в состоянии самообновления.
UNC_SOC_All_Reqs7ДаПодсчитывает количество запросов на каждый агент памяти. С помощью счетчиков можно определять ресурсоемкие агенты или оценивать пропускную способность для агента, умножив количество запросов на 64 байта.
UNC_SOC_Module0_BW7ДаПодсчитывает количество событий пропускной способности для модуля Silvermont 0. Для определения пропускной способности между модулем Silvermont 0 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module1_BW7ДаПодсчитывает количество событий пропускной способности для модуля Silvermont 1. Для определения пропускной способности между модулем Silvermont 1 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module2_BW7ДаПодсчитывает количество событий пропускной способности для модуля Silvermont 2. Для определения пропускной способности между модулем Silvermont 2 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module3_BW7ДаПодсчитывает количество событий пропускной способности для модуля Silvermont 3. Для определения пропускной способности между модулем Silvermont 3 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module0_1_BW8НетПодсчитывает количество событий пропускной способности для модулей Silvermont 0 и 1. Для определения пропускной способности между модулями Silvermont 0, 1 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module2_3_BW8НетПодсчитывает количество событий пропускной способности для модулей Silvermont 2 и 3. Для определения пропускной способности между модулями Silvermont 2, 3 и памятью нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_Module0_1_Snoops5ДаПодсчитывает количество запросов и ответов отслеживания для модулей Silvermont 0 и 1.
UNC_SOC_Module2_3_Snoops5ДаПодсчитывает количество запросов и ответов отслеживания для модулей Silvermont 2 и 3.
UNC_SOC_Module0_1_2_3_Snoops8НетПодсчитывает количество запросов и ответов отслеживания для модулей Silvermont 0, 1, 2 и 3.
UNC_SOC_LowSpeedPF_BW7ДаПодсчитывает совокупную пропускную способность событий для структуры низкоскоростной периферии. Для определения совокупной пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).
UNC_SOC_HighSpeedPF_BW  

Подсчитывает совокупную пропускную способность событий для структуры высокоскоростной периферии. Для определения совокупной пропускной способности памяти нужно умножить количество событий на размер запроса (32 или 64 байта).

UNC_SOC_Memory_DDR_BW

Группа UNC_VISA_Memory_DDR_BW предоставляет счетчики для вычисления пропускной способности всей памяти с точки зрения контроллера памяти «системы на кристалле». События можно разделить на запросы по каждому каналу, включая запросы размером 32 и 64 байта. Эти события не предоставляют информации о том, какой агент потребляет больше памяти, но это наиболее точный способ определения фактической используемой пропускной способности памяти.

Количество каналов памяти на платформе Rangeley зависит от конкретной модели: может быть либо один, либо два канала. Если существует только один канал, все счетчики, связанные со вторым каналом, будут выдавать нулевые значения. Дополнительные сведения об архитектуре каналов памяти: http://en.wikipedia.org/wiki/Multi-channel_memory_architecture.

Группы UNC_VISA_MEMORY_DDR0_BW и UNC_VISA_MEMORY_DDR1_BW являются подмножествами этой группы, они собирают данные только для каналов памяти 0 и 1.

На приведенном ниже рисунке показан отслеживаемый поток трафика для этой группы.

В приведенной ниже таблице перечислены события, содержащиеся в группе UNC_VISA_Memory_BW.

UNC_SOC_Memory_DDR_BW
ИмяСчетчикОписание
DDR_Chan0_Read32B0Подсчитывает количество запросов чтения размером 32 байта к каналу памяти 0.
DDR_Chan0_Read64B1Подсчитывает количество запросов чтения размером 64 байта к каналу памяти 0.
DDR_Chan0_Write32B2Подсчитывает количество запросов записи размером 32 байта к каналу памяти 0.
DDR_Chan0_Write64B3Подсчитывает количество запросов записи размером 64 байта к каналу памяти 0.
DDR_Chan1_Read32B4Подсчитывает количество запросов чтения размером 32 байта к каналу памяти 1.
DDR_Chan1_Read64B5Подсчитывает количество запросов чтения размером 64 байта к каналу памяти 1.
DDR_Chan1_Write32B6Подсчитывает количество запросов записи размером 32 байта к каналу памяти 1.
DDR_Chan1_Write64B7Подсчитывает количество запросов записи размером 64 байта к каналу памяти 1.

Анализ результатов

Пропускную способность в МБ/с можно вычислить для перечисленных выше 64-байтовых событий следующим образом:

Формула метрики событий: количество_событий/отрезок_в_секундах*64 байт/1000000 байт = МБ/с

Для 32-байтовых событий замените 64 байта на 32:

Формула метрики событий: количество_событий/отрезок_в_секундах*32 байт/1000000 байт = МБ/с

События можно суммировать для получения нужных метрик, например:

  • суммарная пропускная способность памяти = сумма всех событий, МБ/с
  • суммарная пропускная способность чтения = сумма всех событий чтения, МБ/с
  • пропускная способность канала 0 = сумма событий канала 0, МБ/с

Известное поведение

  1. Если платформа не имеет двух каналов, показатели счетчика второго канала будут нулевыми.

UNC_SOC_DDR_Self_Refresh

Группа UNC_VISA_DDR_Self_Refresh содержит счетчики для аппаратных событий самообновления памяти. Самообновление представляет состояние пониженного потребления электроэнергии, его можно использовать для оптимизации электропитания «системы на кристалле» и приложений.

В приведенной ниже таблице перечислены события, содержащиеся в группе UNC_VISA_DDR_Self_Refresh.

ИмяСчетчикОписание
DDR_Chan0_Self_Refresh0Подсчитывает количество циклов, в течение которых канал памяти 0 находится в состоянии самообновления.
DDR_Chan1_Self_Refresh1Подсчитывает количество циклов, в течение которых канал памяти 1 находится в состоянии самообновления.
Clock_Counter2Тактовый счетчик «системы на кристалле».

Анализ результатов

Формула метрики событий: (количество_событий/(базовая_частота_SoC /базовая_частота_DDR))*100 = резидентность самообновления DDR

Известное поведение

  1. Если платформа не имеет двух каналов, показатели счетчика второго канала будут нулевыми
  2. Счетчики 0,1 могут быть запущены на другой исходной частоте, нежели счетчик 2

UNC_SOC_All_Reqs

События счетчиков запросов на каждый агент, содержащиеся в группе UNC_VISA_All_Reqs, измеряют общее количество запросов на доступные агенты «системы на кристалле» в ходе однократной единовременной выборки. Этот показатель учитывает одновременно все агенты, поэтому это важная метрика для изучения всей нестатической, то есть пиковой нагрузки. В отличие от других событий пропускной способности, учет которых происходит по одному или по два одновременно, эта метрика получает данные от всех агентов одновременно.

Пропускную способность на каждого агента можно вычислить, умножив количество запросов для каждого агента на 64 байта, а общая пропускная способность равна сумме значений пропускной способности всех агентов. Важно понимать, что конечный результат имеет приблизительный характер и основывается на предположении, что размер каждого запроса составляет 64 байта. Результат вычисления превысит фактический для транзакций с 32-байтовыми и частичными запросами. Другой недостаток состоит в том, что невозможно отделить данные чтения от данных записи для каждого агента.

Для точного измерения пропускной способности с разделением по чтению и записи следует использовать метрику пропускной способности по агентам для одного или двух агентов одновременно.

ИмяСчетчикОписание
Mod0_Reqs0Подсчитывает количество запросов от модуля Silvermont 0.
Mod1_Reqs1Подсчитывает количество запросов от модуля Silvermont 1.
Mod2_Reqs2Подсчитывает количество запросов от модуля Silvermont 2.
Mod3_Reqs3Подсчитывает количество запросов от модуля Silvermont 3.
HighSpeedPF_Reqs4Подсчитывает совокупное количество запросов от структуры высокоскоростной периферии.
LowSpeedPF_Reqs5Подсчитывает совокупное количество запросов от структуры низкоскоростной периферии.
Clock_Counter6Тактовый счетчик «системы на кристалле».

Анализ результатов

Формула метрики событий:

  • количество_событий/отрезок_в_секундах *64 байт/1000000 байт = оцениваемая пропускная способность агента, МБ/с
  • суммарное_количество_событий/отрезок_в_секундах *64 байта/1000000 байт = оцениваемая пропускная способность памяти DDR, МБ/с

 

Известное поведение

  1. Важно помнить, что эти события подсчитывают транзакции с любыми размерами запросов; умножение их на 64 байта для вычисления метрики в МБ/с является огрублением, результат такого вычисления может превышать фактическую пропускную способность каналов памяти.

UNC_SOC_Module0_BW

Группа UNC_VISA_Module0_BW предоставляет счетчики для вычисления пропускной способности модуля 0 процессора с точки зрения системного агента. События можно разделить по типам запросов.

На приведенном ниже рисунке показан отслеживаемый поток трафика для этой группы.

ИмяСчетчикОписание
Mod0_ReadPartial0Подсчитывает все транзакции чтения модуля 0 для запросов любого размера данных. Этот счетчик событий включает частичные, 32-байтовые и 64-байтовые транзакции.
Mod0_Read32B1Подсчитывает количество запросов чтения размером 32 байта от модуля 0 Silvermont.
Mod0_Read64B2Подсчитывает количество запросов чтения размером 64 байта от модуля 0 Silvermont.
Mod0_WritePartial3Подсчитывает все транзакции записи модуля 0 для запросов любого размера данных. Этот счетчик событий включает частичные, 32-байтовые и 64-байтовые транзакции.
Mod0_Write32B4Подсчитывает количество запросов записи размером 32 байта от модуля 0 Silvermont.
 Mod0_Write64B5Подсчитывает количество запросов записи размером 64 байта от модуля 0 Silvermont.
Clock_Counter6Тактовый счетчик «системы на кристалле».

Анализ результатов

Пропускную способность чтения и записи можно вычислить для 32- и 64-байтовых событий, но вычисление событий затруднено, поскольку у них неизвестен объем полезной нагрузки. Также следует понимать, что частичные события для этой группы представляют собой сумму 64-байтовых, 32-байтовых и частичных запросов. Это частичное событие также можно рассматривать как сумму всех запросов чтения или записи.

Формула метрики событий:

  • частичные_запросы - 32_байтные_запросы - 64_байтные_запросы = фактическое количество частичных запросов
  • (Mod0_Read32B_количество * 32_байта / отрезок_в_секундах) + (Mod0_Read64B_количество * 64_байта / отрезок_в_секундах) = чтение, МБ/с
  • (Mod0_Write32B_количество * 32_байта / отрезок_в_секундах) + (Mod0_Write64B_количество * 64_байта / отрезок_в_секундах) = запись, МБ/с

Известное поведение

  1. Счетчик частичных событий модулей 0, 1, 2 и 3 включает 32-байтовые, 64-байтовые и частичные запросы. Его можно считать суммарным счетчиком запросов.

UNC_SOC_ModuleX_BW,

Группы UNC_VISA_Module1_BW, UNC_VISA_Module2_BW и UNC_VISA_Module3_BW идентичны группе UNC_VISA_Module0_BW с тем лишь исключением, что они подсчитывают события в соответствующих модулях процессора (модули 1, 2 и 3).

UNC_SOC_Module0_1_BW

Ресурсов счетчиков недостаточно для измерения пропускной способности всех модулей процессора одновременно, но группы UNC_VISA_Module0_1_BW и UNC_VISA_Module2_3_BW предоставляют счетчики для одновременного вычисления пропускной способности двух модулей процессора. Частичные события опущены, чтобы добиться параллельного измерения.

На приведенном ниже рисунке показан отслеживаемый поток трафика для UNC_VISA_Module0_1_BW.

ИмяСчетчикОписание
Mod0_Read32B0Подсчитывает количество запросов чтения размером 32 байта от модуля 0 Silvermont.
Mod0_Read64B1Подсчитывает количество запросов чтения размером 64 байта от модуля 0 Silvermont.
Mod0_Write32B2Подсчитывает количество запросов записи размером 32 байта от модуля 0 Silvermont.
Mod0_Write64B3Подсчитывает количество запросов записи размером 64 байта от модуля 0 Silvermont.
Mod1_Read32B4Подсчитывает количество запросов чтения размером 32 байта от модуля 1 Silvermont.
Mod1_Read64B5Подсчитывает количество запросов чтения размером 64 байта от модуля 1 Silvermont.
Mod1_Write32B6Подсчитывает количество запросов записи размером 32 байта от модуля 1 Silvermont.
Mod1_Write64B7Подсчитывает количество запросов записи размером 64 байта от модуля 1 Silvermont.

UNC_SOC_Module0_1_Snoops

UNC_VISA_Module0_1_Snoops подсчитывает количество запросов отслеживания и отчетов отслеживания для модулей Silvermont 0 и 1 с точки зрения системного агента. Данные этих счетчиков можно использовать для подтверждения показателей других счетчиков трафика и для выявления взаимосвязей в счетчиках событий отслеживания ядер. В отличие от событий отслеживания, связанных с ядрами, счетчики отслеживания внеядерных компонентов не могут различать показатели для ядер внутри модуля; они считают общее значение для целого модуля, а не для каждого ядра.

ИмяСобытиеОписание
Mod0_Snoop_Replies0Подсчитывает количество ответов отслеживания, полученных от модуля 0.
Mod0_Snoop_Reqs1Подсчитывает количество запросов отслеживания, отправленных в модуль 0.
Mod1_Snoop_Replies2Подсчитывает количество ответов отслеживания, полученных от модуля 1.
Mod1_Snoop_Reqs3Подсчитывает количество запросов отслеживания, отправленных в модуль 1.
Clock_Counter4

Тактовый счетчик «системы на кристалле».

UNC_VISA_Module2_3_Snoops идентичен счетчику UNC_VISA_Module0_1, но подсчи-тывает количество запросов и ответов отслеживания для модулей процессора 2 и 3. UNC_VISA_Module0_1_2_3_Snoops собирает данные отслеживания одновременно для всех четырех модулей процессора, но не включает тактовый счетчик «системы на кристалле».

Анализ результатов

Анализ результатов отслеживания зависит от модели использования.

Известное поведение

  1. Показатели счетчиков отслеживания подсчитываются для всего процессорного модуля без возможности разделения по каждому ядру.

UNC_SOC_LowSpeedPF_BW

Группа UNC_VISA_LowSpeedPF_BW содержит события для определения пропускной способности структуры низкоскоростной периферии и представляет совокупную пропускную способность для всех подключаемых компонентов южного кластера: USB, SATA и Ethernet.

ИмяСчетчикОписание
LowSpeedPF_ReadPartial0Подсчитывает все транзакции чтения структуры низкоскоростной периферии с запросами с частичным размером данных.
LowSpeedPF_Read32B1Подсчитывает количество запросов чтения размером 32 байта в структуре низкоскоростной периферии.
LowSpeedPF_Read64B2Подсчитывает количество запросов чтения размером 64 байта в структуре низкоскоростной периферии.
LowSpeedPF_WritePartial3Подсчитывает все транзакции записи структуры низкоскоростной периферии с запросами с частичным размером данных.
LowSpeedPF_Write32B4Подсчитывает количество запросов записи размером 32 байта в структуре низкоскоростной периферии.
LowSpeedPF_Write64B5Подсчитывает количество запросов записи размером 64 байта в структуре низкоскоростной периферии.
Clock_Counter6Тактовый счетчик «системы на кристалле».

Анализ результатов

Пропускную способность чтения и записи можно вычислить для 32- и 64-байтовых событий, но вычисление частичных событий затруднено, поскольку у частичных запросов неизвестен объем полезной нагрузки.

Формула метрики событий:

  • (LowspeedPF_Read32B_количество * 32_байта / отрезок_в_секундах) + (LowspeedPF_Read64B_количество * 64_байтов / отрезок_в_секундах) = чтение, МБ/с
  • (LowspeedPF_Read32B_количество * 32_байта / отрезок_в_секундах) + (LowspeedPF_Read64B_количество * 64_байта / отрезок_в_секундах) = запись, МБ/с

Известное поведение

  1. Нет.

UNC_SOC_HighSpeedPF_BW

Группа UNC_VISA_HighSpeedPF_BW содержит события для определения пропускной способности структуры высокоскоростной периферии и представляет совокупную пропускную способность для всех подключаемых высокоскоростных компонентов. Эта группа идентична группе UNC_VISA_LowSpeed_BW по конфигурации счетчиков событий и по метрикам анализа. Имена событий изменены с LowSpeedPF на HighSpeedPF.

 

 

Руководство по установке бета-версии Intel® Integrated Native Developer Experience (Intel® INDE)

$
0
0

Юридическое уведомление

Содержание

1 Общие сведения  

2 Установка Intel® INDE

      2.1 Требования к системе

      2.2 Шаг 1: установка центра Intel INDE

      2.3 Шаг 2: установка среды

      2.4 Шаг 3: установка компонентов Intel INDE

3 Использование бета-версии Intel INDE

      3.1 Тестирование приложений

4 Удаление бета-версии Intel INDE

5 Устранение неполадок при установке

1   Общие сведения

Intel® Integrated Native Developer Experience (Intel® INDE) — это межплатформенный пакет разработки, содержащий ряд компонентов, средств и библиотек Intel, позволяющих разработчикам создавать собственные приложения для Android-устройств с процессорами Intel® и задействовать определенные возможности в устройствах с процессорами ARM*. В этой статье описываются действия по поиску и установке компонентов INDE.

2    Установка Intel® INDE

Выполните следующие действия для установки Intel INDE:

Для выполнения шагов 1 и 2 может потребоваться от 15 до 45 минут (в зависимости от скорости подключения к Интернету). Длительность третьего шага зависит от набора устанавливаемых компонентов.

Можно открыть центр Intel INDE в любое время для получения уведомлений об обновлении компонентов.  

2.1    Требования к системе

Требования к системе для установки Intel INDE:

  • 64-разрядная операционная система Microsoft* Windows* 7, Windows 8 или Windows 8.1
  • 4 GB RAM
  • 6 GB свободного места на жестком диске

2.2    Шаг 1: установка центра Intel INDE

Чтобы установить центр Intel INDE, управляющий дальнейшими действиями по установке, выполните следующие действия:

  1. Перейдите по адресу http://software.intel.com/en-us/intel-inde для загрузки этого продукта.
  2. Зарегистрируйте учетную запись Intel® Developer Zoneчтобы продолжить установку.
  3. После завершения регистрации вы получите электронное письмо с информацией о лицензировании.
  4. В полученном электронном письме щелкните ссылку Intel® Software Development Products Registration Center.Сохраните это электронное письмо для дальнейшего использования.
  5. В папке с загруженными файлами дважды щелкните IntelHubSetup.exe, чтобы запустить программу установки.
  6. По завершении программы установки запустите продукт. На экране появится список всех компонентов Intel INDE:

2.3    Шаг 2: установка среды

Перед установкой всех прочих компонентов Intel INDE необходимо установить компоненты среды.

Среда включает следующие компоненты:

Кроме того, при установке среды реализуется интеграция в следующие среды разработки

  • Microsoft Visual Studio*
    •   Условия: Visual Studio 2012 или более поздней версии (выпуск Pro или Ultimate)
    •   Дополнительно:  подключаемые модули vs-android. Для этих подключаемых модулей требуется JDK 8)
  • Eclipse* (в составе пакета Android* ADT, устанавливаемого с платформой Intel INDE)
  • Android Studio* (в составе платформы Intel INDE)

Для установки среды выполните следующие действия:

  1. Нажмите кнопку Установить в поле Environment Setup в окне центра Intel INDE. Появится мастер установки
  2. В окне Suite выберите один из трех вариантов IDE и нажмите кнопку Далее. В окне Options отображаются средства, выбранные по умолчанию.
  3. Снимите выбор с уже установленных компонентов. Если выбран компонент Intel HAXM, вы увидите, что уже задано рекомендуемое ограничение ОЗУ. Это ограничение можно изменить при необходимости. Нажмите кнопку Далее.
  4. Примите условия лицензионных соглашений и нажмите кнопку Далее.
  5. В окне Destination можно принять место установки по умолчанию или указать другую папку для установки средств Android.
  6. Если пакет Java JDK уже установлен, примите отображаемую папку установки по умолчанию. Если пакет JDK не установлен, его можно установить из JDK 8и указать новую папку.
  7. Нажмите кнопку Далее, чтобы отобразить окно готовности к установке, в котором будут перечислены выбранные для установки компоненты. Можно вернуться назад и изменить набор устанавливаемых компонентов.
  8. Нажмите кнопку Далее, чтобы начать установку выбранных компонентов.
  9. Появится страница завершения установки с уведомлением о том, что установка среды успешно завершена.

В центре Intel INDE в разделе Environment Setup появится значение Установлено:

Перейдите в папку ..\INDE\Framework\*, чтобы найти средства Android.

2.4    Шаг 3: установка компонентов Intel INDE

После установки центра Intel INDE и среды можно установить все остальные компоненты Intel INDE.

Для каждого компонента, который нужно установить, нажмите кнопку Загрузить, чтобы загрузить и установить этот компонент.

3   Использование бета-версии Intel INDE

Вот некоторые задачи, которые можно выполнять с помощью Intel INDE.

Цель/задачаИспользуйте этот компонент INDEЦелевая система
Создание собственного приложения Android для целевых систем с процессорами IntelКомпилятор Intel® для AndroidУстройства с процессорами Intel под управлением Android
Создание приложений для работы с видео и звукомIntel® INDE Media Pack для AndroidУстройства с процессорами Intel или ARM под управлением Android
Разработка приложений Android с высоким уровнем параллельности на базе задачIntel® Threading Building BlocksУстройства с процессорами Intel или ARM под управлением Android, а также клиентские устройства под управлением Microsoft Windows
Создание приложений с программируемой графикой для запуска на различных вычислительных устройствах, на основе стандарта параллельного программирования OpenCL*Compute Code BuilderУстройства с процессорами Intel или ARM под управлением Android, а также клиентские устройства под управлением Microsoft Windows
Трассировка выполнения кода в реальном времени, анализ использования ЦП/ГП и данных задач, а также запись данных кадров, анализ и отладкаСредства Intel® Graphic Performance AnalyzerУстройства с процессорами Intel со следующими операционными системами: Microsoft Windows или Android

3.1    Тестирование приложений

Тестировать приложения можно следующими способами:

  1. Программная эмуляция (эмуляторы доступны в Android SDK)
  2. Программная эмуляция с аппаратным ускорением. При установке среды можно установить компонент Intel® Hardware Accelerated Execution Manager (Intel® HAXM), представляющий собой гипервизор для ускорения эмуляции приложений Android на компьютере (для его использования необходимо, чтобы в BIOS была включена технология виртуализации Intel®¹).
  3. Непосредственное тестирование на устройстве с Android*, подключенном к компьютеру через USB, с помощью ADB.

4   Удаление бета-версии Intel INDE

Чтобы удалить бета-версию Intel INDE, выполните следующие действия:

  1. Найдите значок бета-версии Intel® Integrated Native Developer Experience на панели управления и щелкните его правой кнопкой мыши, чтобы удалить центр Intel INDE. При этом компоненты Intel INDE не будут удалены.
  2. Найдите значок Environment Setup на панели управления и щелкните его правой кнопкой мыши, чтобы удалить. При этом будут удалены компонент Intel HAXM и прочие средства Android, которые были установлены при установке среды Intel INDE.
  3. Найдите какой-либо компонент Intel INDE на панели управления и щелкните его правой кнопкой мыши, чтобы удалить. Повторите эти действия для всех компонентов Intel INDE. 
     

5   Устранение неполадок при установке

В следующей таблице описаны некоторые возможные проблемы при установке и способы решения этих проблем.

Проблема

Причина и возможное решение

При удалении Intel INDE не происходит удаление средств Android*, которые были установлены в Intel INDE.

После удаления центра Intel INDE нужно открыть панель управления и удалить каждый компонент по отдельности.

После удаления среды из панели управления для нее в центре Intel INDE по прежнему указано значение «Установлено».

Удалите записи в реестре по следующему адресу: HKEY_LOCAL_MACHINE\SOFTWARE\ Intel\INDE\Framework. При этом сама программа не будет удалена с жесткого диска. Ее необходимо удалить вручную из папки ..\INDE\Framework\*.

Не удается найти значок Environment Setup на панели управления.

После установки Intel INDE отображается пустой белый экран.

  1. Завершите работу Intel INDE (закройте графический пользовательский интерфейс и службы в области уведомлений).
  2. Откройте диспетчер задач, чтобы проверить, не осталось ли запущенных процессов, например, indehub.exe..
  3. Удалите папку inde из папки C:\Users\\AppData\Local\Temp (введите %Temp% в поле поиска в меню Пуск, а при получении сообщения об ошибке «Файл используется» выполните действия, указанные в п. 2).
  4. С помощью меню Пуск перезапустите Intel INDE.
  5. Если снова появится белый экран, подождите 10—15 секунд, на экране должно появиться изображение. Также экран может мигать — это автоматическое обновление.

 

 

Методология создания игр для трансформеров

$
0
0

Download PDF

Введение

Ноутбуки и планшеты чрезвычайно популярны в разных группах пользователей с разными демографическими характеристиками, поскольку эти устройства предоставляют пользователям специализированные возможности. Трансформеры возникли на стыке этих двух типоразмеров устройств и стали единой универсальной платформой, сочетающей удобства обоих режимов использования.

В этой статье мы рассматриваем важность разработки игр для трансформеров и улучшения пользовательского интерфейса:

  • определение изменения режима ввода (сенсорный экран или клавиатура и мышь);
  • предсказание режима (планшетный режим или режим ноутбука);
  • отображение соответствующего пользовательского интерфейса

Типоразмеры устройств и их использование

Традиционные ноутбуки представляют собой мобильные персональные компьютеры с раскры¬вающимся наподобие морской ракушки корпусом. На таких устройствах можно выполнять практически все задачи, выполняемые на настольных ПК, но, по сравнению с настольными компьютерами, ноутбуки гораздо более компактны и мобильны. С появлением ультрабуков ноутбуки стали легче и тоньше, они получили возможность дольше работать от аккумуляторов при возросшей производительности и функциональности. Для многих пользователей ноутбуки стали предпочитаемыми компьютерными устройствами: на ноутбуке пользователь может делать все то же самое, что и на настольном ПК, с дополнительными удобствами, какими является мобильность и гибкость.

В них используется сенсорный ввод на основе распознавания рукописного ввода или экранной сенсорной клавиатуры (впрочем, можно подключить и обычную внешнюю клавиатуру). Планшеты исключительно компактны и легки, их очень удобно носить с собой. Тем не менее по вычислительной мощности планшеты существенно уступают ноутбукам; функциональность планшетов как вычислительных устройств в значительной мере ограниченна. Планшеты прекрасно подходят для обычных пользователей Интернета, которые, главным образом, читают новости и просматривают популярные веб-сайты, играют в несложные игры или же смотрят телепередачи и кинофильмы в поездках. Кроме того, планшетами довольно часто пользуются представители творческих профессий, такие как дизайнеры и создатели музыки. [1]

Проблема двух устройств

Одна из проблем использования двух устройств (ноутбука для создания содержимого и планшета для потребления содержимого) состоит в сложности создания общего контента для устройств с разными операционными системами и форматами содержимого. Трансформеры успешно решают эту проблему, обеспечивая удобства обоих типов устройств в одном устройстве с одной ОС.


Рисунок 1. Evolution of Computing Devices

Типы устройств-трансформеров

Существует несколько типов трансформеров. У некоторых из них экран вращается на шарнире, у других складывается на 180°, а у некоторых полностью отстыковывается. Во всех случаях есть одна важная общая черта — возможность быстро и без нарушения работы перейти из режима ноутбука в режим планшета и обратно. Итак, вот эти два режима: планшет (физическая клавиатура в этом режиме отсутствует или не используется, а основным средством ввода является сенсорный экран) и ноутбук (основные средства ввода — клавиатура, мышь, сенсорная панель).


Рисунок 2.Некоторые типы трансформеров, доступных на рынке в настоящее время.

Любое программное обеспечение, работающее на этих устройствах, должно быть способно определить типоразмер устройства и изменить пользовательский интерфейс в зависимости от состояния устройства. Например, если программа определяет, что используется сенсорный ввод, она должна автоматически предоставлять возможность использования экранной клавиатуры.

Адаптация трансформеров для игр

Все игры можно разделить на две категории: (1) традиционные игры для ПК, для управления которыми используется мышь, клавиатура или игровые контроллеры; (2) игры для мобильных устройств с сенсорным управлением. Поскольку на трансформерах можно запускать и те, и другие игры, важно понять, как игра будет адаптироваться при изменении пользователем режима работы устройства. Это может произойти в любой момент, даже в процессе игры.

Особенности трансформеров как игровой платформы

Сенсорный режим

Сенсорное управление — новый режим, к которому нужно адаптировать традиционные игры. Сенсорное управление доступно и в режиме планшета, и в режиме ноутбука, но наличие сенсорного интерфейса не всегда означает, что необходимо менять средства управления игрой. Сенсорное управление можно использовать для расширения игровых возможностей, поскольку такой способ управления в ряде случаев является более интуитивным. Тем не менее, при добавлении поддержки сенсорного управления следует помнить о некоторых особенностях.

Устройство пользовательского интерфейса

Любой сенсорный пользовательский интерфейс должен соответствовать правилам проектирования игр для планшетов. Например, важно, чтобы сенсорные кнопки были достаточно крупными и имели промежутки между собой в соответствии со средним размером пальца взрослого человека. Кроме того, важно, чтобы кнопки и формы немедленно реагировали на пользовательский ввод. Помните, что, когда устройство находится в режиме планшета, весьма высока вероятность, что пользователь держит устройство двумя руками. Если спроектировать элементы управления так, чтобы они находились рядом с местами, за которые обычно пользователи держат устройство, игра будет удобной в использовании: пользователю не потребуется удерживать устройство одной рукой, чтобы другой нажать на кнопку в середине экрана. [2]


Рисунок 3. См. http://msdn.microsoft.com/en-us/library/windows/apps/hh465415.aspx

Гладкое изменение пользовательского интерфейса

Разница между традиционным планшетом или ноутбуком и трансформером состоит в том, что пользователь может по своему желанию переключаться между двумя режимами. Когда изменение форм-фактора происходит во время игры, важно его обнаружить и предоставить новый интерфейс, адаптированный для нового режима.

Например, в игре Defense Grid: The Awakening такой переход реализован очень удобно. [3]Когда игра обнаруживает сенсорный ввод, она отображает планшетный интерфейс. Пользовательский интерфейс содержит расположенный у правого края экрана столбец, в котором удобно выбирать кнопки, находящуюся рядом кнопку настроек и игрового меню, а также кнопку быстрой прокрутки в левом нижнем углу экрана. Элементы пользовательского интерфейса расположены рядом с местами, за которые пользователь держит планшет, как показано выше. Когда игра обнаруживает ввод с клавиатуры, мыши или сенсорной панели, элементы сенсорного интерфейса исчезают, отображается указатель мыши. Благодаря этому переключение между состояниями происходит очень естественным и ненавязчивым образом.

Рисунок 4.Элементы планшетного пользовательского интерфейса при обнаружении сенсорного ввода.Рисунок 5.При вводе с клавиатуры или мыши элементы сенсорного интерфейса исчезают, появляется указатель мыши.

На некоторых устройствах можно опрашивать систему через функциональность API Windows* и определять состояние устройства (ноутбук или планшет). Но это решение реализовано не на всех платформах, его наличие на старых трансформерах не гарантируется.

Кроме того, могут возникнуть ситуации (хотя и не так часто), когда нам нужно изменить интерфейс, не дожидаясь действий пользователя. Если пользователь складывает ноутбук и переключается в планшетный режим, имеет смысл отобразить планшетный интерфейс, не требуя, чтобы пользователь прикоснулся к экрану. Это важно в играх, где случайное касание может повлиять на игровой процесс. Этот фактор можно устранить, введя «особое условие» для первого касания после использования клавиатуры и мыши (можно ввести условие, при котором это касание не будет считаться указанием на изменение режима управления игрой), но желание автоматически переключать режим игры вполне закономерно.

GetSystemMetrics - это API Windows для опроса состояния устройства. [4]Соответствующие метрики - SM_CONVERTIBLESLATEMODEи SM_SYSTEMDOCKED. Опрос SM_CONVERTIBLESLATEMODEпозволяет определить режим работы устройства (режим планшета или режим ноутбука). [5]


	bool bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);


Фрагмент кода 1: НЕ ИСПОЛЬЗОВАТЬ! Этот API может возвращать неверное состояние в некоторых системах. См. ниже.

При изменении этой метрики системы она отправляет сообщение WM_SETTINGCHANGEсо значением “ConvertibleSlateMode” в разделе LPARAM.


case WM_SETTINGCHANGE:
	if(wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) lParam) == 0)
NotifySlateModeChange();
	break;
Фрагмент кода 2: Используйте этот механизм. В данном случае сообщение отправляется только при фактическом изменении режима.

Помните, что в некоторых системах эта функциональность может быть недоступна. Не существует простого способа определения этой функциональности API приложением. Это означает, что вызов GetSystemMetrics()может вернуть неверное состояние. На старых устройствах вызов может вернуть значение 0, указывающее на режим планшета, тогда как на самом деле устройство при этом будет работать в режиме ноутбука.

Сообщение WM_SETTINGCHANGEсо значением LPARAMConvertibleSlateMode или SystemDockMode будет разослано, только если эта функция поддерживается. Если игра обнаруживает эти сообщения, она может правильно предоставить пользователю нужный интерфейс. Поскольку эта функция поддерживается не во всех случаях, важно переключать интерфейс на основе изменения пользовательского ввода (сенсорный ввод или ввод с клавиатуры).

Экранная клавиатура

В некоторых случаях физическая клавиатура может быть недоступна. Если в игре требуется ввод текста, важно реализовать поддержку экранной клавиатуры.

Если игра запускается в окне, то пользователь может вручную вызвать экранную клавиатуру на панели задач, но такой подход нельзя назвать интуитивным; кроме того, этот подход непригоден для полноэкранных игр. Для игры можно написать собственную клавиатуру. Это может быть непросто, но зато пользователь получает наибольшее удобство.

Рисунок 6.Экранная клавиатура с фиксированным размером и расположением.Рисунок 7.Экранная клавиатура, размер и расположение которой можно изменять .

В следующем примере кода показано, как вызвать экранную клавиатуру Windows в игре DirectX: https://software.intel.com/en-us/blogs/2013/06/11/touch-keyboard-access-for-windows-8-desktop-apps [6]Для этого подхода требуется, чтобы игра была запущена в режиме развернутого на весь экран окна без рамки. Множество игр для настольных ПК создаются для монопольного полноэкранного режима. Это затрудняет использование встроенных клавиатур: либо вызванная клавиатура останется скрытой, либо она появится на экране, но заставит выйти игру из полноэкранного режима. Переход в полноэкранный монопольный режим и из этого режима связан с получением и высвобождением значительного объема ресурсов, а также с проблемой изменения размера окон. Как правило, это серьезные затруднения, совершенно излишние для обработки клавиатурного ввода. В решении, показанном в этом примере, игра запускается не в монопольном полноэкранном режиме, а в развернутом на весь экран окне без рамки. Преимущество такого подхода состоит в том, что появляющаяся на экране клавиатура никак не мешает игре: просто экран игры сдвигается на один уровень вниз в наборе z-уровней глубины. Игра продолжает выполняться в фоновом режиме, чтобы обрабатывать ввод с клавиатуры, и автоматически снова получает фокус после закрытия клавиатуры.

Автоматический поворот/блокировка ориентации

Все трансформеры оборудованы различными датчиками. Это позволяет воспользоваться функцией автоматического поворота. В планшетном режиме устройство может использоваться в книжной или в альбомной ориентации. Если включен автоматический поворот, игра на основе DirectX потеряет свое устройство D3D, ей потребуется заново создать новое устройство с новым разрешением изображения (с учетом изменения ориентации). Например, разрешение экрана может измениться с 1600x900 на 900x1600. Для полноэкранных игр это нежелательно. В приложениях для современного интерфейса Windows эту проблему несложно устранить: достаточно указать параметры ориентации в манифесте приложения. Для игр с классическим интерфейсом можно получить эту функциональность путем прямого отслеживания и вызова экспортированной функции в user32.dll. Эту функцию можно будет использовать для отключения автоматического поворота в настройках ориентации игры. [7]


typedef enum ORIENTATION_PREFERENCE
{
    ORIENTATION_PREFERENCE_NONE              = 0x0,
    ORIENTATION_PREFERENCE_LANDSCAPE         = 0x1,
    ORIENTATION_PREFERENCE_PORTRAIT          = 0x2,
    ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
    ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED  = 0x8
} ORIENTATION_PREFERENCE;

typedef BOOL (WINAPI *pSDARP)(ORIENTATION_PREFERENCE orientation);

pSDARP pARP;

pARP = (pSDARP) GetProcAddress( GetModuleHandle(TEXT("user32.dll")),"SetDisplayAutoRotationPreferences" );

if( pARP )
{
    pARP( (ORIENTATION_PREFERENCE)(ORIENTATION_PREFERENCE_LANDSCAPE |
ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED) );
}



Фрагмент кода 3. Фрагмент кода с отключением автоматического поворота и выбором только альбомной ориентации.

Сенсорные жесты

Сенсорные жесты делают игровой процесс более интуитивным. В зависимости от типа игры сенсорное управление может быть более интуитивным, чем управление с помощью клавиатуры и мыши. Например, в игре жанра «стратегия в реальном времени» (RTS) сенсорное управление дает пользователю возможность обводить игровые единицы на экране, чтобы выбирать их. После этого можно скомандовать этим единицам перейти в нужное место, коснувшись мини-карты или изменив масштаб основной карты и выбрав место, которое до этого находилось за границей экрана. Кроме того, в играх RTS пользователь может выбрать игровые единицы и прочертить по экрану определенный маршрут для патрулирования. Такие команды трудно представить себе наглядно и непросто реализовать в традиционных системах ввода, но в сенсорном режиме все значительно проще.


Рисунок 8.В игре Civilization V были добавлены сенсорные элементы для удобного сенсорного управления игрой.

Мультисенсорный ввод позволяет добавить множество команд в простой интерфейс. Например, в игре Civilization V используются следующие сенсорные элементы управления[8]:

  • Сведение и разведение пальцев — приближение и удаление камеры
  • Перетаскивание — отображение информации об игровой единице или об участке земли, над которым проходит палец
  • Прокрутка двумя пальцами — перемещение камеры выше или ниже, левее или правее
  • Касание — выбор игровой единицы
  • Двойное касание — команда на перемещение выбранной игровой единицы
  • Касание двумя пальцами — выход из текущей команды без отдачи приказа
  • Касание тремя пальцами — закрытие открытых меню или открытие игрового меню

Поскольку сенсорное управление доступно и в режиме ноутбука, эти новые жесты дополняют традиционные интерфейсы и повышают удобство пользователей.

Выбор сенсорных API

В классических приложениях для Microsoft Windows 8 поддержку сенсорного ввода и жестов можно реализовать тремя способами: с помощью сообщений WM_POINTER, WM_GESTUREили WM_TOUCH messages. [9]

  • WM_POINTER— самый простой для написания код, поддерживается самый широкий набор жестов, но поддерживается только операционная система Windows 8 и более поздние версии.
  • Для WM_GESTUREнесложно писать код; поддерживается обратная совместимость с Windows 7, но накладывается ряд ограничений.
  • WM_TOUCHтоже обратно совместим с Windows 7, но требует создания наибольшего объема кода, поскольку требуется написать собственные алгоритмы распознавания жестов и манипуляций на основе низкоуровневых сенсорных событий.

В зависимости от нужного уровня абстракции, если вы предпочитаете полный контроль, то можете выбрать WM_TOUCH, а не WM_POINTERили WM_GESTURE, хотя при этом придется создать гораздо больше кода. WM_GESTUREможет быть оптимальным, если вам удастся уложиться в ограничения этого метода.



Рисунок 9. Сравнение сенсорных API Windows.

 

Вот ссылка на пример кода, где показана интеграция сенсорного управления в приложении с помощью API WM_GESTUREи WM_TOUCH: https://software.intel.com/en-us/vcsource/samples/windows-7-touch [10]

Упаковка в Unity 3D

Некоторые версии движка Unity 3D не обрабатывают сообщения касания в приложениях, работающих под управлением Windows 7 и классического интерфейса Windows 8. Движок Unity сам по себе не занимается обработкой сообщений касания, но можно зарегистрировать окно Unity для касаний с помощью подключаемого модуля. Проблема в том, чтобы создать подключаемый модуль, использующий разные API Windows для перехвата сообщений касания, отправляемых в приложения. После регистрации окна подключаемый модуль предоставляет доступ к сообщениям касания в сценарии приложения Unity. Образец кода этого подключаемого модуля см. здесь: https://software.intel.com/en-us/articles/adding-multi-touch-support-to-unity-games-on-microsoft-windows-7-and-windows-8-desktop [11]

Сравнение задержек устройств ввода


Рисунок 10.Описание полного набора программных и аппаратных компонентов, влияющих на задержки реагирования при сенсорном управлении.

В зависимости от устройства длительность задержки может составлять 50—100 мс, но этот показатель постоянно улучшается [12].Под задержкой подразумевается время между распознаванием ввода (путем касания) и отображением на экране соответствующего эффекта. Она не сильно отличается от задержки при традиционном вводе с помощью мыши или сенсорной панели. Аппаратная задержка обычной мыши составляет около 8 мс, но к этому нужно добавить задержку программных компонентов.

Если в игре важна быстрая и точная реакция, то сенсорное управление для такой игры непригодно. Тем не менее, сенсорное управление можно использовать, чтобы дополнить обычные элементы управления.

Режим вспомогательного приложения

Даже если игра требует скорости и точности в управлении, а потому непригодна для адаптации к полностью сенсорному управлению на планшете, даже в такой игре могут быть элементы, удобные в сенсорном режиме. Например, игра может включать планирование и настройку персонажей, просмотр и публикацию сохраненных результатов и повторов, просмотр и социальное взаимодействие с друзьями, также играющими в эту игру, упорядочение инвентаря, сортировку заданий и т. п. Такие элементы будут прекрасно работать на планшетах с сенсорным управлением.

Выделение этих элементов игры и добавление вспомогательного приложения для планшетного режима сделает игру более удобной для пользователей.

Другие важные факторы

Учебные материалы или справочное окно в игре должны работать в правильном режиме (сенсорный/клавиатура/контроллер) в зависимости от текущего режима устройства. Если возможно, лучше отображать информацию и о сенсорном режиме, и о режиме клавиатуры и мыши, чтобы пользователь мог переходить из одного режима в другой, не открывая справку для изучения элементов управления.

Добавление уникальных достижений, доступных только в сенсорном режиме, расширит игровые возможности и будет способствовать тому, что традиционные игроки будут охотнее осваивать новые сенсорные возможности.

Об авторе

Дорайсами Ганешкумар (Doraisamy Ganeshkumar) — старший инженер по программному обеспечению в отделе Intel Developer Relations. Он помогает разработчикам игр для ПК оптимизировать свои игры для продукции Intel. В нерабочее время ему нравится кататься на велосипеде, гулять, заниматься столярным ремеслом и сооружать различные технические приспособления.

Справочные материалы

[1]Ноутбуки и планшеты: достоинства и недостатки: http://www.lenovo.com/us/en/faqs/laptop-vs-tablet/

[2]Сенсорное взаимодействие в Windows: http://msdn.microsoft.com/en-us/library/windows/apps/hh465415.aspx

[3]Создание высококачественного сенсорного интерфейса для игры Defense Grid: The Awakening: https://software.intel.com/en-us/articles/creating-a-first-class-touch-interface-for-defense-grid-the-awakening

[4]Библиотека API Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx

[5]Обнаружение режимов планшета и ноутбука, а также ориентации экрана на трансформерах: https://software.intel.com/en-us/articles/detecting-slateclamshell-mode-screen-orientation-in-convertible-pc

[6]Использование сенсорной клавиатуры в классических приложениях для Windows* 8: https://software.intel.com/en-us/blogs/2013/06/11/touch-keyboard-access-for-windows-8-desktop-apps

[7]Обработка функции автоматического поворота Windows 8 в приложениях: https://software.intel.com/en-us/blogs/2013/01/10/handling-windows-8-auto-rotate-feature-in-your-application

[8]Новая платформа для гиганта игровой отрасли: компания Firaxis выходит на мобильный рынок, оптимизируя игру Civilization V* для ультрабуков с сенсорным экраном: http://www.intel.com/content/www/us/en/gaming/firaxis-civ-v.html

[9]Сравнение методик написания кода для обработки сенсорного ввода — образец классического приложения для Windows 8: https://software.intel.com/en-us/articles/comparing-touch-coding-techniques-windows-8-desktop-touch-sample

[10]Сенсорный ввод в классических приложениях для Windows: https://software.intel.com/en-us/vcsource/samples/windows-7-touch

[11]Добавление поддержки мультисенсорного ввода в игры Unity* для Microsoft Windows* 7 и классического интерфейса Windows* 8: https://software.intel.com/en-us/articles/adding-multi-touch-support-to-unity-games-on-microsoft-windows-7-and-windows-8-desktop

[12]Измерение реакции на сенсорный ввод, анализ и оптимизация для приложений Windows*: https://software.intel.com/en-us/articles/touch-response-measurement-analysis-and-optimization-for-windows-applications

Оптимизация игр для Ultrabook™

$
0
0

Download as PDF

Автор: Ли Бэмбер (Lee Bamber)

1. Введение

Недавно я занимался подготовкой игрового движка, над которым я работал для конференции Games Developer Conference. Учитывая значимость этого мероприятия, было важно, чтобы игра достаточно быстро работала на трех устройствах, которые были у меня под рукой: от современного Ultrabook™до системы на два поколения старше.

В этой статье вы узнаете, как увеличить скорость трехмерной игры, и поймете, на что нужно обращать внимание при переносе своих приложений на Ultrabook. Будь вы опытным разработчиком игр, или же программирование для вас просто хобби — в любом случае вы наверняка понимаете важность высокой производительности. Игра, идущая плавно и с высокой кадровой скоростью, будет восприниматься как намного более качественная и профессиональная, нежели игра, спотыкающаяся на несчастных пяти кадрах в секунду. Никакая сколь угодно захватывающая графика не скроет тот факт, что игра просто тормозит, дергается на экране (из-за постоянного рассогласования с вертикальной разверткой монитора), а о сколько-нибудь приемлемой реализации физики и говорить нечего. В этом примере с настоящим игровым проектом я постараюсь рассказать о возможных проблемах при переносе игры на разные платформы и способах решения таких проблем.


Рисунок 1. Если у вашей игры красивые снимки экрана, это поможет поднять продажи, но за низкую кадровую скорость расплачиваться придется уже вам!

В этой статье описывается несколько распространенных причин потери производительности. Разработчикам игр предлагается полезная информация по переносу высококачественных трехмерных игр высшего уровня на Ultrabook с нужным уровнем производительности. Для работы таких игр с комфортной скоростью зачастую требуется мощный дискретный видеоадаптер, а нагрузка на GPU весьма высока. Здесь может пригодиться понимание архитектурных различий между выделенными и интегрированными GPU, но лучший способ повышения производитель¬ности графической подсистемы — анализ конвейера обработки графики для выявления узких мест с дальнейшей оптимизацией этих областей без снижения качества изображения.

Требуется базовое понимание вызовов графических API в целом, знание компонентов, образую¬щих типичные трехмерные игры, а также некоторое знание или опыт использования Ultrabook.

2. Почему важна производительность?

Число игроков на рынке приложений и игр постоянно растет, поэтому уникальные полезные особенности ваших продуктов становятся все более важными для коммерческого успеха, а хорошая производительность сейчас рассматривается не как некий желаемый результат, а как строго необходимый атрибут любой программы или игры. Современные пользователи даже не будут считать вашу игру законченной, если она не будет работать достаточно гладко и комфортно на их устройстве, и не будут возвращаться к игре, если с самого начала о ней сложится отрицательное впечатление.

Это обстоятельство крайне важно. Если же учесть еще и быстрый рост рынка мобильных телефонов, планшетов и ноутбуков, окажется, что производительность имеет первостепенное значение. Вы можете удовольствоваться адаптацией игры к Ultrabook, учитывая высокую вычислительную мощность этих устройств по сравнению с остальными, но пользователи всегда будут требовать высших стандартов и ожидать максимального удобства.


Рисунок 2. Ultrabook раскрывает немалую мощь в умелых руках.

С точки зрения выработки полезных навыков все, что вы сейчас можете сделать для оптимиза¬ции и улучшения кода игры, вы сможете применять и во всех дальнейших проектах, повысив свою квалификацию разработчика.

3. Зачем оптимизировать?

Многие разработчики используют для создания и тестирования трехмерных игр настольные ПК. Из-за наличия выделенного графического адаптера иногда возникает ощущение безграничности вычислительных ресурсов, а это приводит к появлению в коде игр таких алгоритмов и шейдеров, которые работают на самом пределе возможностей GPU. Если же запустить такую игру на менее мощной платформе, она может работать гораздо медленнее. Ultrabook — это исключительно мощные мобильные устройства, но по «грубой силе» обработки графики они все же немало уступают мощным современным графическим процессорам. Кроме того, Ultrabook предназначены для мобильного использования, поэтому может оказаться, что в процессе игры Ultrabook будет работать от аккумулятора: конвейер отрисовки должен быть очень эффективным, чтобы избежать быстрого израсходования всей электроэнергии. Все эти факты необходимо учитывать при создании игровой графики.


Рисунок 3. Варианты использования успешного приложения.

При разработке приложений программисты обычно двигаются «сверху вниз»: сначала создают приложение, а потом стараются адаптировать его для как можно большего количества устройств в рамках отведенного на разработку времени.

Простейший подход — разрабатывать игру на Ultrabook, а затем переносить ее на настольный компьютер с выделенным графическим адаптером: при этом для переноса игры не требуется практически никаких действий. Тем не менее, вашими конкурентами могут стать игры, для которых планка качества установлена гораздо выше. Преимущество у такого подхода только одно: вы с самого начала учитываете время работы системы от аккумулятора и с большей вероятностью разработаете игру, которая будет снижать потребление ресурсов в определенные моменты, например во время заставок или на экранах настроек. Более распространенный подход — разработка на настольном ПК с последующей оптимизацией для Ultrabook: в этом случае, как правило, достигается более высокое качество, поскольку изначально концепция разработки нацелена именно на это.

4. С настольного компьютера на Ultrabook: пример битвы за производительность.

Мой рассказ начинается за много недель до крупного мероприятия — конференции GDC. Моя игра работает на достаточно современном графическом адаптере стоимостью около двухсот долларов с интерфейсом PCI Express* 3.0. При наивысшем качестве графики моя игра выдавала порядка 60 кадров в секунду. Это был вовсе не сверхмощный игровой компьютер, но я мог запускать любые трехмерные игры с самым высоким качеством графики без сколько-нибудь ощутимых проблем с производительностью. В моем распоряжении было шесть ядер, 6 гигабайт системной памяти и массив крайне быстрых твердотельных дисков. Я знал, что на конфе¬ренции в моем распоряжении не будет настольных компьютеров, и не собирался везти с собой через полмира здоровенный стационарный компьютер. Следующим по мощности устройством был мой Ultrabook, который вполне годился для поездки: именно его я и решил взять с собой.


Рисунок 4. GDC 2014 — одна из крупнейших конференций разработчиков.

Мой Ultrabook оснащен процессором Intel® Core™ 4-го поколения с графикой Intel® HD Graphics 4000™: это мое любимое устройство, когда я не на работе. Результаты первого теста оказались, прямо скажем, катастрофическими: кадровая скорость упала настолько, что вообще вся затея начала казаться мне чересчур смелой. Используемая сборка трехмерного игрового движка широко использовала шейдеры и отрисовку множества объектов одновременно. Игра просто глотала циклы CPU, как конфетки, стараясь дотянуться до всех доступных ресурсов. Разумеется, с таким подходом моей игре было крайне далеко до экономных и дружественных приложений, подходящих мобильным устройствам.

Несмотря на очевидную наглость моего плана, я все же знал, что современные Ultrabook — это вполне мощные игровые системы, при правильном подходе они не отстают от настольных компьютеров по производительности, существенно опережая их в удобстве. Кроме того, мне приходилось играть во множество игр на Ultrabook, поэтому я знал, что моя задача вполне выполнима: я решил добиться от игры 60 кадров в секунду.

Написанием кодов я занимаюсь очень давно: я научился программировать задолго до появле-ния анализаторов производительности и графических отладчиков, поэтому основной способ обнаружения узких мест состоял в том, чтобы удалять огромные фрагменты движка до тех пор, пока производительность не повысилась бы. Затем, возвращая по очереди важные фрагменты кода обратно в игру, я мог определить, какие части движка работали медленнее всего. После определения узких мест (а просто взять и удалить их было невозможно) начинался осторожный процесс снижения ресурсоемкости компонентов. Примеры такого подхода: исключение обычного расчета карты в шейдерах для пикселей за пределом определенного расстояния от игрока; пропуск вызовов обновления искусственного интеллекта в каждом втором цикле, чтобы снизить издержки на эти процессы. Это незначительные улучшения, но в сумме они дают весомый эффект, и уже довольно скоро игровой движок стал работать намного быстрее практически без потерь в качестве изображения.

Программистам, для которых отладка производительности является относительно новой областью, я искренне рекомендую не прибегать к такому способу обнаружения узких мест. Можно исполь¬зовать множество инструментов, помогающих выявлять проблемы производитель¬ности вашего приложения, причем эти средства не только выявляют узкие места, но и указывают на природу проблемы. Один из таких бесплатных инструментов — пакет Intel® Graphics Performance Analyzers. Это решение профилирует ваше приложения в ходе его работы и предоставляет снимок всей деятельности программы: что именно она делает и сколько времени это занимает. При демонстрации игры на конференции я обнаружил несколько проблем, которые я впослед¬ствии исправил, чтобы повысить производительность и плавность игры.


Рисунок 5. До и после: снимки экрана игры до и после оптимизации.

Как видно на рисунке 5, мне удалось повысить скорость с 20 до 62 кадров в секунду при крайне незначительных различиях в качестве графики. На снимке экрана «после» удалено мощное динамическое освещение вокруг игрока, а также применен менее агрессивный шейдер фрагментов.

«Голодные» шейдеры

Мы быстро определили, что наибольшее снижение производительности было на этапе отрисовки графики.


Рисунок 6. Панель метрики производительности из начальной версии с низкой кадровой скоростью.

Как видно на рисунке 6, горизонтальная строка, отмеченная как «Отрисовка», потребляла большую часть доступных циклов. При более подробном анализе выяснилось, что крайне много ресурсов расходовалось на отрисовку объектов на экране. После этого стало понятно, что сцена, состоящая из сотен тысяч полигонов (причем для каждого используется ресурсо-емкий шейдер фрагментов), резко снижает производительность. Но насколько именно? Добавив к шейдерам параметры MEDIUM и LOWEST, а также несколько ограничив «аппетит» отрисовки пикселей, нам удалось добиться шестикратного повышения производительности.

Чтобы определить, как на самом деле работают параметры LOWEST и MEDIUM, сначала нужно было определить «наименьший общий знаменатель» для компонентов игры. Определив, какие компоненты для игры совершенно необходимы, и убрав все остальное, я создал в шейдере новый параметр LOWEST. Были удалены почти все элементы: все тени, обычные карты, динамическое освещение, перекрытие текстур, зеркальное отображение и т. п. Поскольку я «обрубил все под корень», можно было запустить игру и понять, какой производительности можно добиться на Ultrabook в наилучшем для этого шейдера случае. Сравнив снимки экрана с параметром HIGHEST и с параметром LOWEST, я обнаружил самый важный отсутствующий компонент, который вызвал бы отрицательную реакцию пользователей при снижении качества графики. Шейдер содержал тени и перекрытия текстур. При отсутствии каждого из этих элементов качество изображения резко снижалось. Вернуть перекрытие текстур можно было без особых затрат. Чтобы протестировать, насколько больше ресурсов будет потреблять игра, я просто вернул код шейдера для этого элемента и снова запустил игру. С тенями все было гораздо сложнее: это касалось и их создания в другой части игрового движка, и их использования в самом шейдере. Учитывая важность этого аспекта для сохранения высокого качества изображения, я потратил достаточное количество времени на изучение различных подходов и наконец, обнаружил достаточно быстрое решение, которое я описываю ниже.

Создать параметр MEDIUM для шейдера было довольно просто: нужно было написать шейдер, промежуточный по качеству между самым высоким и самым низким качеством графики, но всегда склоняясь в пользу производительности. Цель этого параметра — достижение всех преимуществ по скорости, присущих параметру LOWEST, но с добавлением наименее ресурсоемких эффектов, таких как фонарик игрока, динамическое освещение и чуть более высокое качество теней.

Если бы я просто снизил качество всех графических элементов до минимума в режиме LOWEST, мне бы за один прием удалось добиться наибольшей производительности, но игроки относятся к плохой графике столь же отрицательно, как к плохой производительности. Я постарался сохранить 90 % качества изображения на самых высоких настройках и выделить элементы, которые можно было бы исключить или ограничить. Так мне удалось добиться значительного повышения скорости с минимальными потерями качества. С 5 кадров в секунду мне удалось перешагнуть за 40 — неплохое достижение.

Чтобы узнать, почему ваша игра для настольного ПК так медленно работает на Ultrabook, я настоятельно рекомендую разложить по полочкам весь ваш конвейер отрисовки графики и постараться понять, на что тратится время. Для этого можно использовать мой «хирурги-ческий» метод и удалять целые уровни функциональности до тех пор, пока не повысится скорость, или же применить более современный подход и задействовать средства анализа производительности. Какой бы метод вы ни выбрали, после обнаружения проблемы следующая задача — придумать такое решение, при котором возрастает скорость работы, но не снижается качество изображения.

Вот некоторые методики, которые я применил для устранения обнаруженных узких мест производительности.

Тени без затрат

Чтобы решить упомянутую выше проблему с тенями, мне пришлось найти альтернативные решения методики так называемых «каскадных карт теней». Я не стану подробно описывать эту методику, но дополнительные сведения о ней вы найдете здесь: http://msdn.microsoft.com/en-gb/library/windows/desktop/ee416307(v=vs.85).aspx. Работает она примерно так: в поле зрения камеры игрока немедленно рисуются четыре цели отрисовки с тенями всех объектов, каждая с разным уровнем детализации.


Рисунок 7. Каскадные карты теней — представление отладчика игрового движка.

Затем шейдер получает инструкции изменить цвет того или иного пикселя на экране на основании того, попадает ли этот пиксель в область предварительно вычисленной тени. Проблема в том, что это очень ресурсоемкий эффект шейдера, потребляющий много видеопамяти. Ниже приведен код шейдера фрагментов. Обратите внимание, что несколько раз используется ветвление IF, а производительность некоторых графических процессоров ощутимо падает для каждой новой ветви IF. В крайних случаях некоторые системы вычисляют все изменения каждого выходного пикселя, то есть ветвление кода не дает вообще никаких преимуществ.

fPercentLit = 0.0f;
if ( iCurrentCascadeIndex==0 )
{
fPercentLit += vShadowTexCoord.z > tex2D(DepthMap1,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
}
else
{
	if ( iCurrentCascadeIndex==1 )
	{
		fPercentLit += vShadowTexCoord.z > tex2D(DepthMap2,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
	}
	else
	{
		if ( iCurrentCascadeIndex==2 )
		{
			fPercentLit += vShadowTexCoord.z > tex2D(DepthMap3,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
		}
		else
		{
			if ( iCurrentCascadeIndex==3 && vShadowTexCoord.z<1.0 )
			{
				fPercentLit += vShadowTexCoord.z > tex2D(DepthMap4,float2(vShadowTexCoord.x,vShadowTexCoord.y)).x ? 1.0f : 0.0f;
			}
		}
	}
}

Необходимо снизить нагрузку на видеопамять и зависимость от ветвей IF. Решение (одно из возможных) — создать единую очень большую текстуру теней и поместить в эту цель отрисовки результаты самого низкого уровня детализации.

Я написал новую, менее ресурсоемкую методику, которая просто считывала данные из этой большой текстуры без всяких ветвлений. Особенности такого подхода выходят за рамки этой статьи, но общий смысл в том, что сначала нужно выявить причину снижения производительности, а затем придумать такое решение, которое работало бы быстрее, но давало бы изображение такого же качества.

Поддержание качества изображения

При оптимизации игрового движка необходимо следить за сохранением качества изображения на всех этапах разработки игры. Нетрудно просто вырезать все красивые, но ресурсоемкие эффекты ради прироста производительности, но лучше рассматривать каждую проблему как возможность повышения производительности с сохранением требуемого качества картинки. При этом вы не только добьетесь желаемых результатов, но и игра будет еще лучше работать на мощных компьютерах, что дает вам возможность добавлять новые компоненты и элементы при дальнейшем развитии игры.


Рисунок 8. Сравнение игровой сцены при чрезмерном снижении качества изображения.

Разрабатывая игру на настольном ПК, вы наверняка захотите использовать сложные шейдеры фрагментов для создания разнообразных эффектов поверхностей. Если просто удалить их из игры, изображение ухудшится настолько, что станет совсем не похоже на исходное. Для сохранения целостности игры важно поддерживать однородный визуальный стиль для всех методик работы шейдеров. Новые пользователи могут сначала впечатлиться великолепным снимком экрана в интернет-обзоре игры, но будут разочарованы, когда запустят вашу игру и увидят на экране что-то совсем иное.

Во всех возможных случаях старайтесь применять методики, воспроизводящие эффекты ресурсоемких шейдеров с меньшими затратами. Например, можно использовать заранее наложенные текстуры или применять ресурсоемкие пиксельные эффекты только в самой близкой к игроку области.

Уделяйте больше внимания своим близким.

Звучит как хороший жизненный совет, но это еще и неплохая стратегия для оптимизации шейдеров на Ultrabook. Одной инструкции ветвления IF достаточно, чтобы определить, насколько близко к игроку находится вычисляемый пиксель. Если близко, то можно, как и ранее, использовать ресурсоемкий эффект пиксельного шейдера, но если далеко, можно использовать намного менее затратную имитацию или заранее просчитанные эффекты.


Рисунок 9. Эффект смешения в действии: обратите внимание на эффекты карты нормалей вблизи.

Вместе с описанной выше методикой также можно использовать смешение, а если добавить одну дополнительную ветвь IF, можно проверять, на каком расстоянии между двумя точками удаления от игрока находится каждый пиксель. Вблизи игрока (ближе первой точки) можно использовать ресурсоемкие эффекты, а за пределами второй точки можно применять эффекты попроще. Между первой и второй точками следует вычислять смешанный эффект, промежуточный между первым и вторым подходами. Важно, чтобы расстояние между этими двумя точками было сравнительно небольшим, чтобы избежать удвоенного расхода вычислительных ресурсов. Расстояние смешения должно быть настолько большим, чтобы переход остался не замеченным игроком. В приведенном ниже фрагменте кода каждый пиксель обрабатывается в зависимости от его расстояния от камеры обзора: если расстояние составляет от 400 до 600 единиц, вычисляются обе ветви кода.

float4 lighting = float4(0,0,0,0);
float4 viewspacePos = mul(IN.WPos, View);
if ( viewspacePos.z < 600.0f )
{
	// work out surface normal per pixel
	lighting = lit(pow(0.5*(dot(Ln,Nb))+0.5,2),dot(Hn,Nb),24);
}
if ( viewspacePos.z > 400.0f )
{
	// cheapest directional lighting
	lighting = lerp ( lighting, cheaplighting, min((viewspacePos.z-400.0f)/200.0f,1.0f) );
}

Результат получается на удивление хороший, а переход очень плавный и совершенно незаметный при отрисовке. При этом в 90 % сцены теперь используется весьма экономный с точки зрения нагрузки эффект, поэтому скорость игры значительно повышается.

Обработка на лету и предварительная обработка

На оптимизацию игры было затрачено немало времени и усилий, но все равно скорость пока еще отставала от заветных 60 кадров в секунду. Баланс между качеством изображения и возможным повышением производительности был достигнут, но другие части игрового движка, помимо системы шейдеров, образовывали немалый объем вычислительных издержек и снижали скорость игры.

В игровом движке была внутренняя система оценки производительности, которая грубо измеряла каждый крупный сегмент всего конвейера отрисовки. В дополнение к графике, движок также измеряет ресурсы, затрачиваемые на вычисление искусственного интеллекта, физики, оружия, отладки, объемного света и т. п. Один из счетчиков следил за отрисовкой травы в реальном времени: такая методика использовалась в игре для формирования иллюзии бесконечного травяного поля. Снизив ресурсоемкость обработки графики, мы обнаружили, что относительная ресурсоемкость процесса отрисовки травы резко возросла и стала следующей по величине во всем конвейере. При оптимизации нужно всегда следить за такими пиками, а если обнаружится, что они используют слишком много игровых циклов, нужно повнимательнее их изучить. Следует знать, какой уровень потребления ресурсов для того или иного компонента графики является разумным, а какой — явно чрезмерным. В данном случае трава явно не должна была расходовать свыше 10 % всех циклов, особенно с учетом крайнего их дефицита. На настольном ПК это было не столь заметно, но на Ultrabook это существенно повлияло на скорость. Помимо роста потребления ресурсов было замечено, что при игре, всякий раз, когда перед игроком происходила отрисовка новой травы, кадровая скорость резко падала, поскольку пиковая нагрузка мешала обычному плавному выполнению игры.


Рисунок 10. Зеленая, зеленая трава: отрисовка травы в реальном времени может оказаться чрезвычайно ресурсоемкой.

Решение состояло в том, чтобы перенести всю систему отрисовки травы на этап предвари-тельной обработки, происходящий еще до запуска самой игры. Вместо формирования травы «на лету» ее просто переместили перед игроком, причем на глаз практически никакой разницы не было заметно. Теперь ничего не требовалось создавать на лету: траву нужно было всего лишь передвигать. Мой Ultrabook вздохнул с облегчением, поскольку удалось высвободить очень много драгоценных циклов CPU для всего остального игрового движка. Я, в свою очередь, тоже вздохнул с облегчением, поскольку удалось достичь волшебных 60 кадров в секунду, игра пошла с нужной скоростью.

Загадочное дело таинственной неравномерности

Добившись идеальной скорости игры и проехав через полмира, чтобы представить игру и ее движок на конференции, я обнаружил, что на демонстрационных устройствах игра работает неравно¬мерно: то и дело происходят рывки, игра словно спотыкается. На настольных компьютерах этих рывков не было, как не было их и на Ultrabook, который я использовал для тестирования. Рывки возникали только на этих устройствах, причем, что интересно, они были мощнее, чем те устройства, на которых я вполне успешно тестировал игру.

После длительных обсуждений и изучения эту проблему удалось связать с так называемым «разрешением внутреннего таймера». Коротко говоря, во всех играх, скорость действия в которых не зависит от компьютера (то есть, к примеру, персонажу игры нужно одинаковое количество времени, чтобы пробежать из точки А в точку Б вне зависимости от того, на каком компьютере запущена игра), так вот, во всех таких играх требуется доступ к команде GetTime(). Существует несколько команд этого семейства, но самой популярной является команда timeGetTime(), возвращающая количество миллисекунд с момента включения компьютера. При этом предполагается, что результат дается с разрешением в 1 миллисекунду, и действи¬тельно, на многих настольных компьютерах время передается именно с такой точностью. Оказывается, на Ultrabook и других мобильных устройствах, где во главу угла ставится экономия электроэнергии, это разрешение не фиксировано, оно может составлять не 1 миллисекунду, а 10—15. Если вы используете этот таймер для управления физикой в игре, как это было в нашем игровом движке, игра начнет «дергаться» и «спотыкаться» совершенно произвольным образом, поскольку вызовы обновления физики будут хаотично перепрыгивать с одного полученного времени к другому.

Причина перехода от разрешения в 1 мс к 10—15 мс в том, что некоторые системы могут сократить потребление электроэнергии, снизив частоту работы процессора, а из-за этого и частота тактовых импульсов может непредсказуемо измениться. Для этой проблемы существует несколько решений. Мы рекомендуем использовать команду QueryPerformanceTimer(), гарантирующую точность возвращаемого значения времени за счет второй команды, возвращающей частоту работы таймера.

5. Подсказки и советы

Что нужно сделать

  • Дополняйте шейдеры добавочными технологиями, а не заменяйте их при оптимизации для Ultrabook. Ваша игра должна работать и на настольных компьютерах, и на Ultrabook; процесс распространения игры намного проще, если вся игра упакована в один двоичный файл. Шейдеры DirectX* и OpenGL* позволяют создавать разные технологии в рамках одного шейдера. Поскольку ваша игра содержит все необходимое, код игры может определять, на какой платформе игра запущена в данный момент, и выбирать оптимальную процедуру отрисовки, которая на этой платформе даст наибольшую скорость и наивысшее возможное качество.
  • Предложите пользователям экран настроек, где можно выбрать нужный уровень производительности и качества. В подавляющем большинстве случаев компьютерные игроки рассчитывают на наличие таких настроек. Всегда хорошо определять и заранее устанавливать настройки, оптимальные для данной конкретной системы, но у пользователя должна быть возможность изменять эти настройки; кроме того, выбранные вами настройки по умолчанию должны всегда быть работоспособными в системе пользователя.

Чего не стоит делать

  • Не исходите из того, что ваша игра обязана работать со скоростью 60 кадров в секунду. На большинстве современных устройств можно настроить интервал обновления экрана, чтобы пропускать один или даже три сигнала вертикальной развертки: при этом сохранится нужная плавность игры, но при скорости в 30 кадров в секунду. Разумеется, все будет не настолько чудесно, как при 60 кадрах в секунду, но если правильно отрегули¬ровать синхронизацию, игра все же будет восприниматься очень хорошо.
  • При разработке игры не следует недооценивать ресурсоемкость шейдеров фрагментов, особенно если предполагается использовать не самое мощное графическое оборудование. Если скорость игры недопустимо низка, откажитесь от использования шейдеров или ограничьте их использование, действуя методом исключения.
  • Не следует заранее выбирать разрешение экрана вместо пользователя: выбранное вами разрешение может не поддерживаться экраном устройства. Используйте API Windows* API для опроса устройства и получения совместимого разрешения по умолчанию.
  • • Не полагайтесь на то, что timeGetTime() возвращает время с интервалами в 1 милли-секунду. На Ultrabook при включенных технологиях экономии электроэнергии интервалы могут составлять 10—15 мс!

6. Краткие советы по работе с Ultrabook

Дальнейший текст может показаться цитированием очевидного, но тем не менее: предлагаю краткое и полезное руководство по тестированию, запуску и демонстрации ваших игр и трехмерных приложений на Ultrabook.

Экономия электроэнергии

При демонстрации для большой аудитории, если вы хотите показать свою игру в лучшем виде, обязательно подключите Ultrabook к электросети. Не работайте от аккумулятора: для экономии электроэнергии система будет ограничивать производительность оборудования, тогда как вам требуется полная мощность.


Рисунок 11. Управление электропитанием на Ultrabook.

На всякий случай найдите «Управление электропитанием» на панели управления и убедитесь, что при питании компьютера от сети все меры экономии электроэнергии отключены, а все возможные параметры установлены на максимум.

Графика

На панели управления есть еще один раздел, где вы можете управлять ускорением графичес-кого адаптера устройства. Вы найдете параметры, отвечающие за работу GPU и драйвера в режиме экономии электроэнергии. Нужно выбрать режим наибольшей производительности (или эквивалентный ему), чтобы гарантировать наиболее быструю работу графического процессора.


Рисунок 12. :Параметры ускорения обработки графики на Ultrabook™

Необходимость таких действий может вызвать недоумение, но помните, что во главу угла при разработке Ultrabook ставится экономия электроэнергии везде и всегда, где это возможно, что позволяет таким устройствам подолгу работать без подзарядки. Самый простой и действен¬ный способ достижения максимальной производительности Ultrabook — включить его в розетку и выставить все настройки на максимум.

Фоновые задачи

Опытные разработчики, да и опытные пользователи согласятся с этим простым, но эффектив-ным советом: нужно посмотреть, какие фоновые задачи запускаются на Ultrabook при загрузке Windows. Предполагалось, что фоновые программы будут полезными, и при этом не будут потреблять слишком много ресурсов, но когда их много, они имеют нехорошую тенденцию довольно серьезно загружать CPU.

Сколь бы важными ни были эти задачи, когда вы демонстрируете, насколько быстро ваша трехмерная игра может работать на Ultrabook, разумно отключить вообще все задачи, которые не нужны непосредственно для этой цели. За фоновые задачи не беспокойтесь, при следующей загрузке Ultrabook они снова появятся, но зато сейчас в течение всего оставшегося сеанса Windows все ресурсы устройства будут предоставлены одному-единственному приложению — вашему!

7. Выводы

Тема оптимизации игр весьма обширна. Разработчики должны рассматривать оптимизацию как неотъемлемую часть своей повседневной работы. Цель в том, чтобы вашу игру можно было запускать на как можно более широком наборе оборудования. Для достижения этой цели потребуется весь ваш опыт, все знания и умения. Применяя такие средства Intel®, как VTune™ Analyzer и Intel Graphics Performance Analyzers, можно ускорить решение этой задачи. Статьи, подобные этой, подскажут возможные решения, но в конечном итоге все зависит от вашей сообразительности. Как можно добиться этого же результата другим способом? Можно ли сделать это быстрее? Можно ли сделать это умнее? Вот с таких вопросов следует начинать, и чем чаще вы станете их задавать, тем эффективнее сможете оптимизировать свои игры и приложения. Как я предположил в начале этой статьи, вы не только станете выпускать более качественный код, но и расширите свои позиции на стремительно растущем рынке!

Другие материалы по теме

Codemasters GRID 2* on 4th Generation Intel® Core™ Processors - Game development case study
Not built in a day - lessons learned on Total War: ROME II
Developer's Guide for Intel® Processor Graphics for 4th Generation Intel® Core™ Processors
PERCEPTUAL COMPUTING: Augmenting the FPS Experience

Об авторе

Во время, свободное от написания статей, Ли Бэмбер руководит британской компанией The Game Creators (http://www.thegamecreators.com)), которая специализируется на разработке и распространении средств создания компьютерных игр. Эта компания ведет свою историю с 1999 года. Среди плодов работы этой компании вместе с окружающим ее разработчиком игр — множество популярных брендов, в том числе Dark Basic, FPS Creator, а также App Game Kit (AGK). Ли также ведет хронику своей повседневной работы разработчика вместе со снимками экрана и видеороликами: http://fpscreloaded.blogspot.co.uk




 

Intel®Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed.  Join our communities for the Internet of Things, Android*, Intel® RealSense™ Technology and Windows* to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathons, contests, roadshows, and local events.

Any software source code reprinted in this document is furnished under a software license and may only be used or copied in accordance with the terms of that license.
Intel, the Intel logo, Ultrabook, and VTune are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

Неоднородные рабочие группы OpenCL™ 2.0

$
0
0

Download PDF
Download Zipfile

Содержание

Содержание
Введение
Неоднородные рабочие группы
Обзор учебной программы
Требования для учебной программы
Запуск учебной программы
Справочные материалы

Введение

Модель выполнения OpenCL™ включает понятие рабочих групп, которые являются группами отдельных рабочих элементов в NDRange. Рабочие элементы в составе одной и той же рабочей группы могут вместе использовать локальную память, проводить синхронизацию с помощью барьера группы и взаимодействовать с помощью таких групповых функций, как async_work_group_copy. Если приложение использует OpenCL 1.x, то размеры NDRange должны нацело (без остатка) делиться на размеры рабочих групп. Если вызов clEnqueueNDRangeKernelвключает параметры global_sizeи local_sizeкоторые не делятся нацело, вызов возвратит код ошибки CL_INVALID_WORK_GROUP_SIZE. Если же вызов clEnqueueNDRangeKernelуказывает значение NULL для параметра local_size, разрешая выполняемому модулю выбрать размер рабочей группы, то выполняемому модулю потребуется выбрать размер, на который можно нацело разделить глобальные размеры NDRange.

Необходимость выбора такого размера рабочих групп, чтобы на него нацело делился размер NDRange, может вызвать затруднение у разработчиков. Рассмотрим простой алгоритм размытия изображения 3х3 (алгоритм входит в учебный код). В этом алгоритме каждый выходной пиксель вычисляется как среднее значение для значений входных пикселей в соседней области размером 3х3. Такие алгоритмы применяются во множестве приложений для обработки изображений, работающих с соседними группами пикселей, для таких операций, как свертывание, стирание, размытие и фильтрация по среднему. В алгоритмах такого типа можно использовать разные способы для обработки выходных пикселей, расположенных на рамке изображения. Эти пиксели зависят от пикселей вне границ входного изображения. Эта проблема показана на приведенном ниже рисунке.

Можно обрабатывать пиксели границы различными способами, например принять постоянное значение границы или повторно использовать соседние пиксели границы. Но для этого требуется применять попиксельную обработку внутри ядра, что вызовет излишнюю нагрузку. В некоторых приложениях входные значения рамок не имеют значения, их можно пропустить. В этом случае размер NDRange совпадает с размером выходного изображения за вычетом области рамки. При этом зачастую получается размер NDRange, который трудно нацело разделить. Например, для применения фильтра 3x3 к изображению 1920x1080 требуется рамка толщиной в один пиксель с каждой стороны. Проще всего это сделать с помощью ядра 1918х1078. Но ни 1918, ни 1078 не делятся нацело на значения, дающие рабочие группы оптимального размера.

В этом примере используется размытие 3х3, но эта проблема существует и для других алгоритмов.

Неоднородные рабочие группы

В OpenCL 2.0 появилась новая возможность, в которой устранены проблемы, описанные в предыдущем разделе. Речь идет о так называемых неоднородных рабочих группах: выполняемый модуль OpenCL 2.0 может разделить NDRange на рабочие группы неоднородного размера по любому измерению. Если разработчик укажет размер рабочей группы, на который размер NDRange не делится нацело, выполняемый модуль разделит NDRange таким образом, чтобы создать как можно больше рабочих групп с указанным размером, а остальные рабочие группы будут иметь другой размер. Например, для NDRange размером 1918x1078 рабочих элементов при размере рабочей группы 16x16 элементов среда выполнения OpenCL 2.0 разделит NDRange, как показано на приведенном ниже рисунке.

Благодаря этому OpenCL может использовать рабочие группы любого размера для любого размера NDRange, когда разработчик передает значение NULL параметра local_sizeв clEnqueueNDRangeKernel. В целом использование значения NULL в параметре local_sizeостается предпочитаемым методом выполнения ядер, если логика вашего приложения не требует какого-либо определенного размера рабочей группы.

Внутри кода ядра встроенная функция get_local_size()возвращает фактический размер рабочей группы, из которой она была вызвана. Если ядру требуется точный размер, указанный для параметра local_sizeв clEnqueueNDRangeKernel, то встроенная функция get_enqueued_local_size() возвращает эти значения.

Чтобы включить использование неоднородных рабочих групп, необходимо скомпилировать ядро с флагом “-cl-std=CL2.0”, включающим эту и другие возможности OpenCL 2.0. Без использования этого флага компилятор будет использовать версию OpenCL 1.2, даже если устройство поддерживает OpenCL 2.0. Кроме того, неоднородные рабочие группы можно отключить для ядер, скомпилированных для флага “-cl-std=CL2.0” с помощью флага “-cl-uniform-work-group-size”. Это может быть полезно для устаревшего кода ядра до полного перехода на OpenCL 2.0.

Функция неоднородных рабочих групп в OpenCL 2.0 повышает простоту использования OpenCL и может повысить производительность некоторых ядер. Разработчики больше не добавляют код системы и ядра для работы с размерами NDRange, которые не делятся нацело. Код, созданный для использования этой возможности, может эффективно использовать SIMD и выравнивание доступа к памяти: такие преимущества обеспечиваются правильным выбором размера рабочих групп.

Обзор учебной программы

TВ коде учебной программы реализован алгоритм размытия 3х3, описанный выше. Самая интересная часть кода находится в файле main.cpp. Код в этом файле действует следующим образом:

  1. Загрузка входного растрового файла.
  2. Сборка ядра OpenCL C с помощью параметров OpenCL 1.2.
    // Get the box blur kernel compiled using OpenCL 1.2 (which is the
    // default compilation, even on an OpenCL 2.0 device).  This allows
    // the code to show the pre-OpenCL 2.0 behavior.
    cl::Kernel kernel_1_2 = GetKernel(device, context);
  3. Сборка ядра OpenCL C с помощью параметров OpenCL 2.0 (обратите внимание на передачу параметров сборки с флагом OpenCL 2.0).
    // Get the box blur kernel compiled using OpenCL 2.0.  OpenCL 2.0
    // is required in order to use the non-uniform work-groups feature.
    kernel_2_0 = GetKernel(device, context, "-cl-std=CL2.0");
  4. Задание глобального размера, который используется для всех разновидностей запущенных ядер.
    // Set the size of the global NDRange, to be used in all NDRange cases.
    // Since this is a box blur, we use a global size that is two elements
    // smaller in each dimension.  This creates a range which often doesn't
    // divide nicely by local work sizes we might commonly pick for running
    // kernels.
    cl::NDRange global_size = cl::NDRange(input.get_width() - 2,
                                          input.get_height() - 2);
  5. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 1.2, параметр local_sizeимеет значение NULL.
    // Blur the image with a NULL local range using the OpenCL 1.2 compiled
    // kernel.
    cout << "Compiled with OpenCL 1.2 and using a NULL local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_1_2, global_size,
                           cl::NullRange, input, true);
  6. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 1.2, при значении параметра local_size 16x16.
    // Blur the image with an even local range using the OpenCL 1.2
    // compiled kernel.  This won't work, even if we are running on an
    // OpenCL 2.0 implementation.  The kernel has to be explicitly compiled
    // with OpenCL 2.0 compilation enabled in the compiler switches.
    try
    {
        cout << "Compiled with OpenCL 1.2 and using an even local size:"<< endl << endl;
        output = RunBlurKernel(context, queue, kernel_1_2,
                               global_size, cl::NDRange(16, 16), input,
                               true);
        cout << endl;
        output.Write(output_files[1]);
    }
    catch (...)
    {
        cout << "Trying to launch a non-uniform workgroup with a kernel ""compiled using"<< endl <<"OpenCL 1.2 failed (as expected.)"<< endl << endl;
    }
  7. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 2.0, при значении параметра local_size NULL.
    // Blur the image with a NULL local range using the OpenCL 2.0
    // compiled kernel.
    cout << "Compiled with OpenCL 2.0 and using a NULL local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_2_0, global_size,
                           cl::NullRange, input, true);
  8. Размытие изображения с помощью версии ядра, скомпилированной для OpenCL 2.0, при значении параметра local_size 16x16.
    // Blur the image with an even local range using the OpenCL 2.0
    // compiled kernel.  This will only work on an OpenCL 2.0 device
    // and compiler.
    cout << "Compiled with OpenCL 2.0 and using an even local size:"<< endl << endl;
    output = RunBlurKernel(context, queue, kernel_2_0,
                           global_size, cl::NDRange(16, 16), input,
                           true);
  9. Запись выходных файлов, созданных в пп. 2—5.

Для каждого варианта в пп. 5—8 результаты вызова get_local_size () и get_get_enqueued_local_size () в каждом из четырех углов NDRange отображаются на экране. Таким образом, мы видим, как происходит разделение NDRange на рабочие группы.

Для предоставленного входного изображения шаг 6 не будет выполнен, поскольку NDRange невозможно разделить без остатка на рабочие группы 16х16. Кроме того, шаги 7 и 8 не будут выполнены для реализаций OpenCL, не поддерживающих OpenCL 2.0.

Ядро, реализующее алгоритм размытия, хранится в BoxBlur.cl. Оно содержит очень простую реализацию, но не является наиболее эффективным способом применения размытия.

Требования для учебной программы

Для сборки и запуска этой учебной программы нужен ПК, соответствующий следующим требованиям:

  • Процессор серии Intel® Core™ с кодовым названием Broadwell
  • Microsoft Windows* 8 или 8.1
  • Intel® SDK для приложений OpenCL™ версии 2014 R2 или более поздней
  • Microsoft Visual Studio* 2012 или более поздней версии

Запуск учебной программы

Учебная программа представляет собой консольное приложение, которое прочитывает входное растровое изображение и записывает выходные растровые изображения для каждой разновидности NDRange, описанной в приведенном выше разделе (кроме шага 3, поскольку в этом случае возникает ошибка). Эта учебная программа поддерживает несколько параметров командной строки:

ПараметрОписание
-h, -?Отображение текста справки и выход.
-i <входной префикс>Префикс (имя файла) входного растрового изображения. Полное имя файла будет выглядеть так: <входной префикс>.bmp. Этот файл должен быть 24-битным растровым изображением.
-o <выходной префикс>Префикс выходного растрового изображения. Имена создаваемых файлов будут выглядеть так: <выходной префикс>_N.bmp, где N — число от 0 до 3..

 

После запуска учебной программы для предоставленного рисунка результат будет таким:

Input file: input.bmp
Output files: output_0.bmp, output_1.bmp, output_2.bmp, output_3.bmp

Device: Intel(R) HD Graphics 5500
Vendor: Intel(R) Corporation

Compiled with OpenCL 1.2 and using a NULL local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        (  1, 239)                  undefined
   Top right       (637,   0)        (  1, 239)                  undefined
 Bottom left       (  0, 477)        (  1, 239)                  undefined
Bottom right       (637, 477)        (  1, 239)                  undefined


Compiled with OpenCL 1.2 and using an even local size:

Trying to launch a non-uniform workgroup with a kernel compiled using
OpenCL 1.2 failed (as expected.)

Compiled with OpenCL 2.0 and using a NULL local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        (  1, 239)                 (  1, 239)
   Top right       (637,   0)        (  1, 239)                 (  1, 239)
 Bottom left       (  0, 477)        (  1, 239)                 (  1, 239)
Bottom right       (637, 477)        (  1, 239)                 (  1, 239)


Compiled with OpenCL 2.0 and using an even local size:

   Work Item  get_global_id()  get_local_size()  get_enqueued_local_size()
---------------------------------------------------------------------------
    Top left       (  0,   0)        ( 16,  16)                 ( 16,  16)
   Top right       (637,   0)        ( 14,  16)                 ( 16,  16)
 Bottom left       (  0, 477)        ( 16,  14)                 ( 16,  16)
Bottom right       (637, 477)        ( 14,  14)                 ( 16,  16)


Done!

Входное изображение имеет размер 640x480, поэтому размер NDRange в каждом случае составит 638x478. Приведенный выше результат показывает, что запуск ядра OpenCL 1.2 со значением NULL параметра local_sizeвынуждает использовать нечетные размеры для каждой рабочей группы (1, 239). Размеры рабочих групп, не являющиеся степенями двойки, могут работать очень медленно в некоторых ядрах. Конвейеры SIMD могут простаивать, синхронный доступ к памяти может нарушиться.

Запуск ядра OpenCL 1.2 с указанным размером рабочей группы (16x16) выдает ошибку, поскольку ни 648, ни 478 не делятся нацело на 16.

Запуск ядра OpenCL 2.0 со значением NULL параметра local_sizeпозволяет выполняемому модулю OpenCL разделить NDRange на рабочие группы любого размера. Выше показан результат: видно, что выполняемый модуль продолжает использовать однородный размер рабочих групп точно так же, как для ядра OpenCL 1.

Запуск ядра OpenCL 2.0 с заданным размером рабочей группы (16x16) приведет к тому, что размер NDRange будет разделен на неоднородные рабочие группы. Мы видим, что левая верхняя рабочая группа имеет размер 16х16, правая верхняя — 14х16, левая нижняя — 16х14 и правая нижняя — 14х14. Поскольку в большинстве случаев размер рабочей группы составляет 16х16, это ядро будет очень эффективно использовать конвейеры SIMD и доступ к памяти будет очень быстрым.

Справочные материалы

  1. Intel® SDK для приложений OpenCL™ — руководство по оптимизации
  2. Спецификация API Khronos OpenCL 2.0
  3. Спецификация Khronos OpenCL 2.0 для языка C

Использование функций рабочих групп в OpenCL™ 2.0

$
0
0

Download PDF      Download Code

Для новичков в области программирования на OpenCL раздел в спецификации OpenCL 2.0, касающийся этой темы, может показаться слишком академичным и малопонятным. Коротко говоря, функции рабочих групп включают три классических алгоритма уровня рабочих групп (value broadcast, reduce и scan), а также две встроенные функции, проверяющие логический результат операции, проведенной для всей рабочей группы. Алгоритмы reduce и scan поддерживают операции add, min и max.

Описание функций рабочих групп

Для новичков в области программирования на OpenCL раздел в спецификации OpenCL 2.0, касающийся этой темы, может показаться слишком академичным и малопонятным. Коротко говоря, функции рабочих групп включают три классических алгоритма уровня рабочих групп (value broadcast, reduce и scan), а также две встроенные функции, проверяющие логический результат операции, проведенной для всей рабочей группы. Алгоритмы reduce и scan поддерживают операции add, min и max.

Функциональность встроенных функций рабочих групп очевидна из названий:

  • work_group_broadcast() распространяет значение выбранного рабочего элемента на все элементы рабочей группы
  • work_group_reduce()вычисляет значения sum, minили maxдля всех элементов рабочей группы, а затем распространяет полученное значение на все элементы рабочей группы
  • work_group_scan()  вычисляет значения sum, minили maxдля всех предшествующих рабочих элементов (с возможным включением текущих)
  • work_group_all()возвращает логическое И для одинакового логического выражения, вычисленного для каждого рабочего элемента
  • work_group_any()действует аналогично work_group_all(), но использует логическое ИЛИ

Важное ограничение, касающееся перечисленных встроенных функций: они действуют только для скалярных типов данных (например, популярные типы int4 и float4 не поддерживаются). Кроме того, не поддерживаются 8-разрядные типы данных, такие как char или uchar.

Полное описание см. в главе 6.13.15 спецификации OpenCL 2.0 C.

Функции рабочих групп, что следует из их названия, всегда работают параллельно для целой рабочей группы. Из этого проистекает неявное следствие: любой вызов функции рабочей группы действует в качестве барьера.

Использование функций рабочих групп связано с двумя основными идеями. Во-первых, функции рабочих групп удобны. Гораздо проще использовать одну встроенную функцию вместо написания достаточно крупного фрагмента кода, который бы потребовался для реализации такой же функциональности в OpenCL 1.2. Во-вторых, функции рабочих групп эффективнее с точки зрения производительности, поскольку они используют оптимизацию под оборудование.

Пример

Для примера рассмотрим следующую задачу (которая может являться частью какого-либо алгоритма): вычисление сумм префиксов для подчиненных массивов равного размера какого-либо более крупного массива. Итак, нам нужно вычислить сумму префикса для каждого элемента каждого подчиненного массива и сохранить ее в целевой области памяти с той же разметкой. Исходная и целевая компоновки данных показаны на следующей схеме:

Простое ядро OpenCL для выполнения этой задачи может выглядеть так:

  • каждый массив (строка на иллюстрации) будет обрабатываться одной рабочей группой
  • для каждого рабочего элемента сканирование выполняется с помощью простого цикла for()для предшествующих элементов, затем добавляется совокупное значение префикса, а затем результат сохраняется в месте назначения
  • если размер рабочей группы меньше входного массива, то исходный и конечный индексы сдвигаются на размер рабочей группы, совокупный префикс обновляется и этот процесс повторяется до конца исходной строки

Соответствующий код показан ниже:

__kernel void Calc_wg_offsets_naive(

__kernel void Calc_wg_offsets_naive(
                            __global const uint* gHistArray,
                            __global uint* gPrefixsumArray,
                            uint bin_size
                            )
{
    uint lid = get_local_id(0);
    uint binId = get_group_id(0);

    //calculate source/destination offset for workgroup
    uint group_offset = binId * bin_size;
    local uint maxval;

    //initialize cumulative prefix
    if( lid == 0 )  maxval = 0;
    barrier(CLK_LOCAL_MEM_FENCE);

    do
    {
        //perform a scan for every workitem
        uint prefix_sum=0;
        for(int i=0; i<lid; i++)
            prefix_sum += gHistArray[group_offset + i];

        //store result
        gPrefixsumArray[group_offset + lid] = prefix_sum + maxval;
        prefix_sum += gHistArray[group_offset + lid];

        //update group offset and cumulative prefix
        if( lid == get_local_size(0)-1 )  maxval += prefix_sum;
        barrier(CLK_LOCAL_MEM_FENCE);

        group_offset += get_local_size(0);
    }
    while(group_offset < (binId+1) * bin_size);
}

Такой примитивный подход крайне неэффективен в большинстве случаев (кроме очень маленьких рабочих групп). Очевидно, что внутренний цикл for()выполняет слишком много избыточных операций загрузки и сложения; эту процедуру явно можно оптимизировать. Причем с увеличением размера рабочей группы возрастает и избыточность. Для более эффективного использования аппаратных ресурсов Intel HD Graphics требуется более эффективный алгоритм, например Blelloch. Мы не будем подробно его рассматривать: он замечательно описан в классической статье GPU Gems - http://http.developer.nvidia.com/GPUGems3/gpugems3_ch39.html.

Код OpenCL 1.2 с параллельным сканированием будет выглядеть так:

#define WARP_SHIFT 4
#define GRP_SHIFT 8
#define BANK_OFFSET(n)     ((n) >> WARP_SHIFT + (n) >> GRP_SHIFT)

__kernel void Calc_wg_offsets_Blelloch(__global const uint* gHistArray,
                              __global uint* gPrefixsumArray,
                              uint bin_size
                              ,__local uint* temp
                            )
{
    int lid = get_local_id(0);
    uint binId = get_group_id(0);
    int n = get_local_size(0) * 2;

    uint group_offset = binId * bin_size;
    uint maxval = 0;
    do
    {
        // calculate array indices and offsets to avoid SLM bank conflicts
        int ai = lid;
        int bi = lid + (n>>1);
        int bankOffsetA = BANK_OFFSET(ai);
        int bankOffsetB = BANK_OFFSET(bi);

        // load input into local memory
        temp[ai + bankOffsetA] = gHistArray[group_offset + ai];
        temp[bi + bankOffsetB] = gHistArray[group_offset + bi];

        // parallel prefix sum up sweep phase
        int offset = 1;
        for (int d = n>>1; d > 0; d >>= 1)
        {
            barrier(CLK_LOCAL_MEM_FENCE);
            if (lid < d)
            {
                int ai = offset * (2*lid + 1)-1;
                int bi = offset * (2*lid + 2)-1;
                ai += BANK_OFFSET(ai);
                bi += BANK_OFFSET(bi);
                temp[bi] += temp[ai];
            }
            offset <<= 1;
        }

        // clear the last element
        if (lid == 0)
        {
            temp[n - 1 + BANK_OFFSET(n - 1)] = 0;
        }

        // down sweep phase
        for (int d = 1; d < n; d <<= 1)
        {
            offset >>= 1;
            barrier(CLK_LOCAL_MEM_FENCE);

            if (lid < d)
            {
                int ai = offset * (2*lid + 1)-1;
                int bi = offset * (2*lid + 2)-1;
                ai += BANK_OFFSET(ai);
                bi += BANK_OFFSET(bi);

                uint t = temp[ai];
                temp[ai] = temp[bi];
                temp[bi] += t;
            }
        }
        barrier(CLK_LOCAL_MEM_FENCE);

        //output scan result to global memory
        gPrefixsumArray[group_offset + ai] = temp[ai + bankOffsetA] + maxval;
        gPrefixsumArray[group_offset + bi] = temp[bi + bankOffsetB] + maxval;

        //update cumulative prefix sum and shift offset for next iteration
        maxval += temp[n - 1 + BANK_OFFSET(n - 1)] + gHistArray[group_offset + n - 1];
        group_offset += n;
    }
    while(group_offset < (binId+1) * bin_size);
}

Как правило, такой код работает эффективнее и образует не столь высокую нагрузку на аппаратные ресурсы, но с некоторыми оговорками.

В этом коде появляются издержки на перемещение данных между локальной и глобальной памятью, а также некоторые запреты. Для достижения действительно высокой эффективности алгоритму требуется достаточно большой размер рабочей группы. При небольших рабочих группах (<16) производительность вряд ли окажется выше, чем у простого цикла.

Кроме того, обратите внимание на усложнение кода и дополнительную логику, предназначенную для исключения конфликтов в общей локальной памяти (например, макрос BANK_OFFSET).

Использование рабочих групп позволяет обойти все упомянутые проблемы. Соответствующий вариант оптимизированного кода OpenCL приведен ниже:

__kernel void Calc_wg_offsets_wgf(
                            __global const uint* gHistArray,
                            __global uint* gPrefixsumArray,
                            uint bin_size
                            )
{
    uint lid = get_local_id(0);
    uint binId = get_group_id(0);

    uint group_offset = binId * bin_size;
    uint maxval = 0;

    do
    {
        uint binValue = gHistArray[group_offset + lid];
        uint prefix_sum = work_group_scan_exclusive_add( binValue );
        gPrefixsumArray[group_offset + lid] = prefix_sum + maxval;

        maxval += work_group_broadcast( prefix_sum + binValue, get_local_size(0)-1 );

        group_offset += get_local_size(0);
    }
    while(group_offset < (binId+1) * bin_size);
}

Результаты производительности обоих оптимизированных алгоритмов измерены для достаточно большого объема входных данных (каждая рабочая группа сканирует 65 536 элементов, что, в зависимости от локального размера, соответствует 8192 … 2048 итерациям внешнего цикла).

Как и ожидалось, простой цикл работает гораздо медленнее при увеличении локального размера, а производительность обоих оптимизированных вариантов возрастает.

Если задать оптимальный размер рабочей группы для заданного алгоритма, то сравнение ядер будет таким:

Обратите внимание, что применение work_group_scan_exclusive_add() значительно повышает производительность рабочей группы любого размера и одновременно упрощает код.

Заключение

Добавление функций рабочих групп — важное усовершенствование в OpenCL 2.0, значительно упрощающее работу разработчиков, применяющих OpenCL. Правильное использование этой новой функции поможет снизить трудоемкость разработки сложных и высокопроизводительных приложений OpenCL.

Разработка увлекательных приложений для нового поколения компьютеров-моноблоков

$
0
0

By Raghvendra Maloo

Введение

Компьютеры-моноблоки уже много лет используются и дома, и в офисах: они обладают неплохой вычислительной мощностью и большим экраном, но при этом не занимают много места. С появлением операционной системы Microsoft Windows* 8 моноблоки, помимо традиционных клавиатур и мышей, получили и современные возможности сенсорного управления. А сейчас появились устройства нового типа, в которых эти возможности расширены, — портативные моноблоки (pAIO).

Портативные моноблоки — это мощные компьютерные системы с большими экранами, способные работать в горизонтальном положении. Встроенные аккумуляторы обеспе-чивают ограниченную мобильность таких систем. Благодаря этим возможностям открываются новые сценарии использования. Можно разрабатывать приложения и игры, обладающие новыми функциями:

  • Пользовательские интерфейсы с мультисенсорным вводом для одновременной работы нескольких пользователей
  • Многорежимное взаимодействие на основе голосового управления и использо-вания камеры для распознавания жестов
  • Многоцелевое использование устройств, например использование смартфонов в качестве игровых контроллеров
  • Использование Intel® Wireless Display (WiDi) для вывода изображения игры или приложения на ТВ высокой четкости
  • Технология Intel Rapid Start для быстрого возобновления работы системы

Возможность работы в горизонтальном положении не только дает новые возможности, но и создает новые проблемы разработчикам, которым следует по-новому подходить к проектированию приложений, чтобы воспользоваться всеми преимуществами моноблоков. В этой статье приводятся рекомендации для разработчиков программного обеспечения по созданию приложений с сенсорным управлением и удобным пользовательским интерфейсом для портативных моноблоков на базе процессоров Intel.

Правило № 1. Изучите возможности платформы портативных моноблоков

Портативные моноблоки дают разработчикам приложений беспрецедентные возможности благодаря большим сенсорным экранам, возможности работы в горизонтальном положении и высокой вычислительной мощности, достаточной для ресурсоемких многопользовательских мультисенсорных приложений 

Переносные моноблоки во многом схожи с обычными моноблоками. Системы на базе процессоров Intel обладают рядом важных характеристик, расширяющих возможности разработчиков и конечных пользователей. Переносные моноблоки поддерживают стационарную и адаптивную установку. Механизм наклона экрана поддерживает возможность установки в вертикальном, наклонном и горизонтальном положении. Размер экрана составляет от 18,4 до 27 дюймов (см. рис. 1). Моноблоки оборудуются сенсорными экранами, поддерживающими не менее 10 одновременных точек касания. Встроенные аккумуляторы обеспечивают ограниченную мобильность таких систем. Возможность работы в горизонтальном положении открывает пути для разработки принципиально новых программ, в полной мере использующих все преимущества мультисенсорных многопользовательских программ на больших экранах.

Рисунок 1.Среды разработки приложений для Windows 8.

Семейство процессоров Intel® Core™ обеспечивает высокую производительность и возможность использования великолепных визуальных эффектов, необходимых для полнофункционального применения многопользовательских мультисенсорных приложений на моноблоках в различных категориях: в играх, обучении, развлече¬ниях, здравоохранении, — для создания содержимого и просто для получения информации. Разработчики приложений могут в полной мере положиться на мощь процессоров Intel Core: приложения будут работать быстро и плавно (см. таблицу 1).

Новые современные технологии также раскрывают возможности переносных моноблоков. С появлением новых процессоров Intel Core 4-го поколения переносные моноблоки смогли воспользоваться новыми технологиями этой платформы, включая технологии Intel Rapid Start, Intel Smart Connect и не только их. Технология Intel Rapid Start позволяет быстро возобновлять работу из состояния глубокого сна (примерно за 6 секунд). Основные преимущества:

  • Меньше ожидание: быстрое возобновление, быстрее, чем обычный запуск или возобновление после гибернации.
  • Более эффективное включение и выключение системы: мгновенное включение и готовность к работе, быстрая и мощная альтернатива полному запуску системы и завершению работы.
  • Сохранение пользовательского контекста: как при использовании режимов сна или ожидания, пользователь может вернуться к прежней работе, возобновить просмотр сайтов в Интернете, запустить приостановленные фильмы и пр.

Технология Intel Smart Connect поддерживает более полезное состояние сна: система периодически пробуждается, чтобы обновить данные всех открытых приложений. После обновления содержимого система вновь возвращается в состояние сна.

Компонент3rdПроцессоры Intel® Core™ третьего поколения4thПроцессоры Intel® Core™ четвертого поколенияПреимущества

Процессор

  • Технология Intel® Turbo Boost
  • Технология Intel® Hyper-Threading
  • Технология Intel Turbo Boost 2.0
  • Intel Advanced Vector Extensions 2.0 (Intel AVX2)
  • Повышение производительности при многопоточных и однопо­точных нагрузках.
  • Повышение производительности при распознавании лиц, профессиональной обработке изображений и высокопроизво­дительных вычислениях.

USB

USB 3.0 (5 Gbps)

USB 3.0 (5 Gbps)

Скорость более чем в 10 раз выше по сравнению с USB 2.0

Мультимедиа и изображение

  • Intel® Quick Sync Video
  • Технология Intel® Clear Video HD
  • Intru™ 3D
  • Графический процессор Intel® HD 2500/4000 
  • Intel® Wireless Display 3.x
  • Технология Intel Rapid Start 
  • Технология Intel Smart Connect 
  • Intel Quick Sync Video
  • Технология Intel Clear Video HD 
  • Intru 3D
  • Графический процессор Intel HD 4600/Iris 
  • Intel Wireless Display 3.x
  • Быстрое возобновление работы.
  • Приложения для электронной почты, социальных сетей и другие приложения, постоянно получающие доступ в Интернет, регулярно обновляются.
  • Ускорение перекодирования видео3.
  • Просмотр изображений и видео высокой четкости с эталонным качеством: резкость изображения, плавность воспроизведения, яркие цвета4.
  • Поддержка воспроизведения трехмерных изображений на ПК6.
  • Мощный встроенный графический процессор4.
  • Потоковая передача содержимого непосредственно на телевизоры высокой четкости с большим экраном5.

Таблица 1.Сравнение процессоров.

Правило № 2. Тщательно продумывайте стратегию разработки программного обеспечения

Windows 8 поддерживает две разные среды разработки, каждая из которых обладает определенным набором средств разработки, набором компонентов и возможностей, определенным уровнем совместимости с прежними версиями Windows и определенной моделью распространения и продаж.

Приложения для Windows 8 можно создавать с помощью различных языков программирования и инструментов. Можно создавать компоненты на одном языке и использовать их в приложении, написанном на другом языке программирования. Тем не менее на самом раннем этапе разработки нужно принять решение и выбрать тип разрабатываемого приложения; это может быть приложение для Магазина Windows либо приложение рабочего стола Windows (см. рис. 2).

Приложения рабочего стола работают в классическом режиме Windows 8. Этот режим похож на традиционную среду Windows, но интерфейс различается. В классическом режиме поддерживается и сенсорное управление, и датчики. Кроме того, некоторые драйверы оборудования и некоторые возможности устройств, например Intel® Wireless Display (Intel® WiDi) и OpenGL*, в настоящее время доступны только для приложений рабочего стола.

Приложения для Магазина Windows используют новые API WinRT и разрабатываются в среде Visual Studio* 2012 на языках C++, C# или с помощью веб-технологий, таких как HTML5, JavaScript* и CSS3.

Рисунок 2.Среды разработки приложений для Windows* 8

Разработчикам следует помнить, что некоторые возможности и технологии устройств еще не освоены для среды нового интерфейса Windows. Выбор одного из двух направлений (приложение рабочего стола или приложение для Магазина Windows) определяет, какие среды разработки, аппаратные возможности будут доступны для вас, какова будет обратная совместимость с более ранними версиями Windows, а также в конечном итоге каким способом можно будет продавать и распространять ваше приложение (см. таблицу 2).

Распространять и продавать приложения для Магазина Windows можно только через Магазин Windows. В Магазине Windows приложения становятся доступными для миллионов покупателей во всем мире. Разработчики приложений рабочего стола обладают более гибкими возможностями в отношении продажи и распространения своих приложений. Помимо традиционных каналов распространения и продажи некоторые разработчики смогут размещать свои приложения рабочего стола в каталоге Магазина Windows (со ссылкой на веб-сайт для покупки).

Компонент/набор инструментовПриложения рабочего столадля Windows* 8Приложения для Магазина Windows

Intel® WiDi

Да (могут потребоваться плагины для браузера).

Нет

Programmable GFX – OpenGL*

Да 

Нет

Programmable GFX – OpenCL

Да 

Нет

Programmable GFX – OCL*, CM*

Да 

Нет

Intel® Graphics Performance Analyzers (Intel® GPA)

Полная функциональность, исключая следующее: IE10, анализ приложений WinRT и DX10 в Frame Analyzer (с драйвером 15.28 и новым OpenCL SDK)

Нет (WinRT не поддерживает оснастки)

Intel® Performance Bottleneck Analyzer (Intel® PBA aka xIF)

Поддерживается анализ десктопных приложений. Средство просмотра работает в декстопномрежиме..

Ограниченный набор функций работает с WinRT.

Dev Environments (VS*, Eclipse*)

Да 

Частично

Intel AppUp® center

Да 

Нет

Windows Store

Нет (некоторые приложения рабочего стола могут быть указаны в Магазине Windows со ссылкой на веб-сайт для приобретения)

Да

Compatible with previous versions of Windows

Да

Нет

Таблица 2. Функциональная совместимость приложений для Магазина Windows* и приложений рабочего стола.

Правило № 3. Реализация сенсорного управления крайне важна для создания привлекательных приложений для портативных моноблоков

В Windows 8 предусмотрены гибкие возможности и для приложений для Магазина Windows, и для приложений рабочего стола

Сенсорное управление — это интуитивный, привлекательный и естественный способ взаимодействия пользователей с приложением. Пользовательский мультисенсорный интерфейс многопользовательских приложений на переносных моноблоках на базе процессоров Intel Core опирается на современную модель использования сенсорного управления как неотъемлемую часть общей архитектуры решения. К счастью, корпорация Майкрософт предоставила сенсорные API для поддержки и классических приложений, и приложений для Магазина Windows.  

Приложения для Windows Store

В Windows поддерживается два набора API для создания приложений для Магазина Windows: среда выполнения Windows (WinRT) и библиотека Windows для JavaScript (WinJS).

Среда исполнения Windows.Эти API JavaScript, C#, Visual Basic* и C++ предоставляют доступ ко всем основным функциям платформы.

  • События указателя используются для получения базовых данных (расположение и тип устройства), расширенных данных (давление и геометрия контактной области) и для поддержки более сложного взаимодействия.
  • События жестов используются для обработки статических однопальцевых жестов, таких как касание и касание с удержанием (двойное касание и касание для вызова контекстного меню, аналогичное щелчку правой кнопкой мыши, являются производными от этих простых жестов).
  • События манипуляции используются для динамических мультисенсорных жестов, таких как сведение и разведение пальцев, а также для взаимодействия с использованием данных инерции и скорости, таких как прокрутка, масштабирование и поворот.

Библиотека Windows для JavaScript. WinJS предоставляет библиотеку API JavaScriptс элементами управления, стилями CSS и вспомогательными функциями для написания кода. Пространство имен WinJS покрывает функци­ональность, близкую к пространствам имен Windows.UI.XAML в среде WinRT.

Приложения рабочего стола для Windows 8

Приложения рабочего стола работают в классическом режиме Windows 8. В приложениях рабочего стола для Microsoft Windows 8 можно реализовать поддержку сенсорного ввода и жестов тремя способами:

  • WM_POINTER — самый простой с точки зрения написания кода и поддерживает самый широкий набор жестов, но работает только под управлением Windows 8. Сообщения WM_POINTER используются для получения сенсорного ввода сообщения, а для распознавания жестов и манипуляций — функции контекста взаимодействия.
  • Для WM_GESTURE также несложно писать код; в этом случае поддерживается обратная совместимость с Windows 7, но накладывается больше всего ограничений.
  • WM_TOUCH предоставляет полное решение для поддержки сенсорного управления в Windows 7 с обратной совместимостью. Оно уведомляет приложение о каждом событии касания, а ваш код должен собирать эти события и распознавать соответствующие жесты.

Существует довольно распространенное заблуждение: якобы невозможно разрабатывать приложения, работающие с сенсорным вводом и датчиками, для классического режима Windows 8. Это неверно. Кроме того, некоторые драйверы оборудования и некоторые возможности устройств, например WiDi и OpenGL*, в настоящее время доступны только для приложений рабочего стола.

Многорежимное взаимодействие

В приложениях рабочего стола для Windows 8, включая и игры, можно применить многорежимное взаимодействие, основанное на применении голосового управления и распознавания жестов камерой. Разработчики могут рассмотреть возможность использования Intel® RealSense SDK для поддержки многорежимного взаимодействия на переносных моноблоках. Кроме того, разработчики могут использовать Intel® Common Connectivity Framework (Intel® CCF) для поддержки сценариев с одновременным использованием нескольких устройств: дополнительные устройства, например смартфоны, можно использовать в качестве контроллеров для игр, запущенных на моноблоке.

Программные платформы и тестирование

Разработчики игр для классического интерфейса Windows 8 получают в свое распоряжение широкий набор существующих программных платформ и средств тестирования. Эти средства помогают ускорить цикл разработки, оптимизировать производительность и отладить сенсорные интерфейсы приложений для моноблоков (см. таблицу 3).

СредствоПреимущества

Microsoft XNA

Средства и библиотеки для обеспечения переносимости платформы позволяют разработчикам сосредоточиться на содержимом и пользовательском интерфейсе.

Adobe Flash*, AIR, Gaming SDK

Платформа для поддержки пользовательского интерфейса, эффектов мультимедиа и веб-приложений.

OpenGL and DirectX*

Доступ к возможностям графического оборудования для оптимизации работы приложений с интенсивной графической нагрузкой.

Windows* Presentation Foundation (WPF)

Мощная платформа графического пользовательского интерфейса с более высоким уровнем абстракции, по сравнению с DirectX с элементами, которые можно связывать и которыми можно управлять на основе событий.

HTML5

Язык разметки для веб-приложений с широкими графическими возможностями и мультимедиа. Исключительно хорошо подходит для разработки интернет-игр.

GPUView

Поддерживает отладку проблем, связанных с перегрузкой GPU.

Intel® Power Gadgets

Измеряет потребление электроэнергии процессором в конкретных сценариях.

Visual Studio* 2012 Profiler

Отслеживает и составляет профили наиболее ресурсоемких стеков вызовов для выявления узких мест производительности.

FRAPS

Измерение кадровой скорости (количество кадров в секунду) для плавного отображения графики.

Таблица 3.Программные платформы и средства тестирования приложений рабочего стола для Windows* 8

Правило № 4. Поставьте себя на место пользователя

Проектирование многопользовательских мультисенсорных приложений для больших горизонтальных экранов требует другого мышления, это уже не экран телефона!

Сообщество разработчиков уже довольно давно занимается созданием игр и приложений для сенсорных устройств, таких как телефоны и планшеты, но с появлением портативных моноблоков многие ограничения, обусловленные небольшими размерами экранов, устранены, а разработчики получили свободу в реализации более интересных и привлекательных функций.

Для создания продуманного дизайна нужно полностью понимать, как именно пользователи в большинстве случаев взаимодействуют с приложением. В зависимости от приложения в одной игре может быть до четырех игроков, поэтому важно понимать возможности многопользовательского управления. Кроме того, расположение элементов управления на экране должно отражать предполагаемые способы использования устройства (см. таблицу 4).

ИспользованиеКоличество пользователейСоображения по выбору модели управленияПример приложения

Многопользовательская игра с индивидуальными средствами управления

  • 2 игрока с противоположных сторон.
  • 4 игрока по углам

Требуется настраивать ориентацию в соответствии с расположением игроков. Наилучшее расположение: по краям экрана

Игра в футбол: элементы управления находятся у противоположных краев экрана

Многопользовательская игра с общими средствами управления

Несколько игроков находятся вокруг экрана без определенного порядка

Общие элементы управления в удобных для доступа местах

Традиционные семейные настольные игры с общими средствами управления (цифровые игральные кости, штрафные карточки и т. п.) в середине игрового поля (экрана)

Многопользовательские приложения для совместной работы

Поддержка нескольких пользователей, совместно использующих один экран

Общие графические элементы управления для удобного восприятия

Планировщик ландшафтов

Таблица 4.Примеры использования в многопользовательских играх

Расположение пользователя

Новые многопользовательские приложения связаны с возможностью исполь­зования моноблоков в горизонтальном положении, когда экран является, по сути, поверхностью стола. Разработчикам необходимо проводить более подробный анализ взаимодействия пользователей с приложением и друг с другом. Крайне важно поставить себя на место пользователя:

  • На раннем этапе проектирования нужно четко определить количество и тип пользователей. Потребуется ли каждому пользователю отдельный набор элементов управления (как в большинстве игр) или будет достаточно одного набора элементов управления?
  • Наиболее удобные цели касания должны быть у краев экрана.
  • У нескольких игроков в любой момент времени может быть несколько точек фокуса

Огромное значение имеют пользовательские средства управления

Устройство пользовательского интерфейса может повлиять на удобство сенсорного управления вашим приложением. Чтобы оптимизировать приложение для сенсорного управления, соблюдайте следующие правила:

  • Учитывая крупный размер экранов моноблоков, можно использовать более крупные значки и изображения, чтобы свести к минимуму масштабирование.
  • Каждый пользователь должен быть уверен в том, какие элементы управления ему доступны. Для указания можно использовать расположение, цвет или форму. Инструкции на основе изображений обычно проще понимать с различных углов обзора.
  • Для сенсорного управления требуются более крупные элементы интерфейса: это обеспечит точность. При этом руки не должны заслонять другие важные сведения на экране. Впрочем, на больших экранах реализовать удобный сенсорный ввод проще, чем на планшетах.
  • Убедитесь, что элементы интерфейса всегда видны: помните, что руки пользователей могут заслонять другие элементы управления или информацию на экране.

Приложения должны быть увлекательными и интересными

Использование горизонтальных моноблоков с большими экранами в качестве поверхностей столов предоставляет новые возможности для привлечения пользователей с помощью наглядных и интуитивных сенсорных взаимодействий. Приложение должно быть «живым», оно должно заинтересовать пользователей, поощрять его использование и изучение. Следующие советы помогут сделать приложение более естественным и увлекательным:

  • Всегда предоставляйте непосредственную прямую визуальную обратную связь для касаний. Например, можно с помощью подсветки или подсказок выделять текущую цель касания, чтобы предотвратить случайное касание других объектов.
  • Настройте физику для наиболее реалистичного ощущения. Используйте физические эффекты, такие как ускорение и инерция, для придания естественного ощущения взаимодействиям, например прокрутке.
  • Подумайте о дальнейшем расширении функциональности с помощью многорежимного взаимодействия на основе управления голосом и жестами

Заключение

Переносные моноблоки открывают новые возможности для разработчиков приложений благодаря большим сенсорным экранам, горизонтальному рабочему положению и определенной мобильности. Эти новые решения на основе процессоров Intel Core способны обеспечить великолепное графическое качество игр и приложений в сочетании с непревзойденной плавностью работы. Тем не менее для проектирования новых приложений требуется совершенно иной взгляд на концепцию их применения и четкое понимание возможных вариантов и путей разработки. Корпорация Intel поможет выбрать правильный путь, предоставив обширную библиотеку ресурсов, касающихся принципов разработки, интеграции сенсорного управления и возможностей платформы. Дополнительные сведения см. по ссылкам ниже.

About the Author

Raghvendra Maloo is a Senior System Software Engineer in the PCCG Innovation Development Vehicle (IDV) team. He is a Microsoft Windows Expert and currently working on Touch and Stylus software stack of IDV Reference Systems. Raghvendra’ s focus areas includes Multi User Multi Touch experience on the All-in-One Form Factor Systems. Before joining Intel, Raghvendra worked for Microsoft as a Software Design Engineer for its Office Mobile Products. Raghvendra owns multiple patents and publications in the field of Touch Sensors, New User Experiences and Parallel Computing. Raghvendra was also a speaker in Intel Developer Forum 2013 presenting Software Development Opportunities for All-in-One Systems

Проектирование и разработка:

  1. Проектирование для ультрабуков и сенсорных настольных приложений:
    http://software.intel.com/en-us/articles/designing-for-ultrabook-devices-and-touch-enabled-desktop-applications
  2. Разработка с использованием API классического интерфейса:
    http://software.intel.com/en-us/articles/developing-with-desktop-natural-user-interface-api-s-for-developers
  3. Средства разработки приложений рабочего стола для Windows:
    http://software.intel.com/en-us/articles/designer-tools-for-windows-desktop-applications
  4. Преобразование приложений для ультрабуков — сенсорные интерфейсы:
    http://software.intel.com/en-us/blogs/2012/08/09/re-imagining-apps-for-ultrabook-part-1-touch-interfaces/
  5. Принципы проектирования сенсорных интерфейсов — позы и целевые объекты касания:
    http://software.intel.com/en-us/blogs/2012/08/29/touch-design-principles-part-2-postures-and-touch-targets
  6. Поддержка сенсорного управления в приложениях для Windows* 8 на языке C#:
    http://software.intel.com/en-us/articles/enabling-touch-in-windows-8-metro-style-apps-with-c
  7. Сенсорное управление. Создание современных приложений для ультрабуков:
    http://software.intel.com/en-us/articles/the-human-touch-building-ultrabook-applications-in-a-post-pc-age
  8. Обработка сенсорного ввода в приложениях для Windows* 8:
    http://software.intel.com/en-us/articles/handling-touch-input-in-windows-8-applications
  9. Кнопки интерфейса с поддержкой сенсорного управления:
    http://software.intel.com/en-us/articles/touch-friendly-control-buttons-bubbles-2
  10. Образцы реагирования на касания:
    http://software.intel.com/en-us/articles/touch-reactive-sample-bubbles
  11. Центр разработчиков Windows 8.1:
    http://msdn.microsoft.com/en-us/windows/apps/br229516
  12. Руководство пользователя по технологии Intel Rapid Start:
    http://download.intel.com/support/motherboards/desktop/sb/rapid_start_technology_user_guide.pdf 
  13. Технология Intel® Smart Connect:
    http://www.intel.com/content/www/us/en/architecture-and-technology/smart-connect-technology.html

Образцы кода:

  1. Сравнение методик написания кода для обработки сенсорного ввода — образец приложения рабочего стола для Windows 8:
    http://software.intel.com/en-us/articles/comparing-touch-coding-techniques-windows-8-desktop-touch-sample
  2. Образцы сенсорных приложений:
    http://software.intel.com/en-us/articles/touch-samples
  3. Разработка приложений для ультрабуков под управлением Windows* 8 — приложения для обработки фото с сенсорным управлением и датчиками:
    http://software.intel.com/en-us/articles/photo-application-for-ultrabook-and-windows-8-desktop-applications-development-with-touch-and-sensors
  4. Образец приложения рабочего стола Windows с управлением при помощи сенсорного ввода и камеры:
    http://software.intel.com/en-us/articles/windows-desktop-touch-camera-sample-whitepaper

 

© Intel Corporation, 2013.  Все права защищены.

Intel, эмблема Intel, AppUp, Core, InTru и Ultrabook являются товарными знаками корпорации Intel в США и в других странах.

* Прочие наименования и товарные знаки могут быть собственностью третьих лиц.

 OpenCL и эмблема OpenCL являются товарными знаками Apple Inc. и используются с разрешения Khronos.

1 (Технология Intel® Turbo Boost) Требуется система, поддерживающая технологию Intel® Turbo Boost. Технологии Intel Turbo Boost и Intel Turbo Boost 2.0 доступны только на некоторых процессорах Intel®. Обратитесь к изготовителю устройства. Производительность может различаться в зависимости от оборудования, программ и конфигурации системы. Дополнительные сведения см. по адресу www.intel.com/go/turbo.

2 (Гиперпоточность) Требуется система с поддержкой технологии гиперпоточности Intel®; обратитесь к изготовителю компьютера. Производительность может различаться в зависимости от использованного оборудования и программ. Доступно не на всех процессорах Intel®. Дополнительные сведения, в том числе и сведения о том, какие процессоры поддерживают технологию гиперпоточности Intel, см. по адресу http://www.intel.com/go/ht.

3 (Quick Sync Video — 3-летний базовый показатель) Перекодирование видео с помощью CyberLink* MediaEspresso 6 для отображения видеофайла в формате MPG2 длительностью 4 минуты, объемом 449 МБ, с разрешением 1920 x 1080i и скоростью потока 18 884 Кбит/с для воспроизведения на Apple iPod* с разрешением 640 x 360, кодек H.264, формат файла MP4. Ускорение в 4 раза на процессорах Intel® Core™ третьего поколения i5-3450 (настольный ПК) и Intel® Core™ i5-3320M (ноутбук) по сравнению с процессорами Intel® Core™ (настольный ПК), Intel® Core™2 Duo E8400 (настольный ПК) и P8600 (ноутбук).

4 (Встроенная графика) Встроенные компоненты обработки графики доступны не на всех ПК. Может требоваться оптимизированное программное обеспечение. Обратитесь к изготовителю системы. Подробные сведения см. по адресу http://www.intel.com/go/biv.

5 (Intel® Wireless Display) Требуется ПК, планшет или смартфон, поддерживающий Intel® Wireless Display, а также совместимый адаптер и телевизор. Воспроизведение видео высокой четкости в формате 1080p и Blu-ray* или другого защищенного содержимого поддерживается некоторыми процессорами Intel®со встроенной графикой. Обратитесь к изготовителю ПК. Дополнительные сведения см. по адресу www.intel.com/go/widi.

6 Для просмотра стереоскопических трехмерных материалов требуются трехмерные очки и монитор, поддерживающий трехмерное изображение.  При просмотре трехмерных материалов может существовать физический риск для здоровья.


Описание ультрабуков-трансформеров и рекомендации по разработке приложений, учитывающих режим работы трансформера

$
0
0

Download as PDF

Введение

Ультрабуки-трансформеры — это ПК, которые можно переключать между режимом ноутбука (для работы) и режимом планшета (для потребительских целей). В этой статье вы узнаете об аппаратных возможностях трансформеров, о возможностях трансформеров под управлением Windows* 8/8.1 для потребительских и профессиональных задач, а также получите рекомендации по разработке приложений для наибольшего удобства пользователей в каждом режиме.

Содержание

  • Разработка приложений для рабочего стола Windows 8/8.1.
  • Классификация трансформеров (какие устройства являются трансформерами, а какие нет).
  • Модели использования трансформеров.
  • Приложения с поддержкой режимов работы трансформеров.
  • Рекомендации по разработке приложений для ультрабуков.
  • Оценка готовности приложений к работе на трансформерах

Что такое ультрабук-трансформер?

Ультрабук-трансформер — это устройство, которое можно использовать как ноутбук и как планшет. По вычислительной мощности и производительности он не отличается от обычных ноутбуков, что позволяет выполнять всю работу и все задачи по созданию данных без ограничений. Большинство трансформеров также поддерживают сенсорный ввод, оборудованы датчиком и пером. Когда пользователи находятся в поездках и используют устройство соответственно (например, смотрят фильм, играют в игры, проверяют почту или читают книги), они могут переключить трансформер в режим планшета, который не только более удобен, но и устраняет необходимость иметь несколько гаджетов. Длительное время работы трансформеров от аккумулятора дополняет их преимущества.

У настоящих трансформеров клавиатура всегда входит в конструкцию, а в планшетном режиме она либо складывается, либо отсоединяется. Устройства, для которых можно отдельно приобрести клавиатуру, не являются трансформерами. Дополнительные характеристики трансформеров — мощная полнофункциональная операционная система, такая как Windows 8/8.1, и экран размером 10 дюймов или больше.

В следующей таблице перечислены некоторые доступные в данный момент конфигурации трансформеров.

Таблица 1:Доступные варианты конфигурации трансформеров

Типоразмер

Режим планшета

Режим ноутбука

Изображение

Папка

181⁰-360⁰

0⁰-180⁰

Экран на горизонтальной оси

Экран направлен наружу

 

 

Экран направлен в сторону клавиатуры

Слайдер

Экран закрывает какую-либо часть клавиатуры

 

 

Экран не закрывает клавиатуру

Экран на шарнире

Положение закрытой крышки, экран направлен вверх, ИЛИ горизонтальное положение, экран направлен вверх.

Все прочие положения

Отсоединяемый экран

Экран отсоединен от клавиатуры, ИЛИ клавиатура подсоединена, экран не направлен в сторону клавиатуры  

 

Клавиатура подсоединена, экран направлен в сторону клавиатуры

Два экрана

Положение закрытой крышки, экран направлен вверх, ИЛИ горизонтальное положение, крышка или экран направлены вверх

Экран направлен в сторону клавиатуры

Что не является ультрабуком-трансформером?

Наличие отсоединяемого экрана и клавиатуры не означает, что устройство является трансформером. Ниже перечислены устройства, не включенные в классификацию трансформеров.

  • Ноутбуки с сенсорным экраном. Сенсорное управление — новая функция на многих ноутбуках, но их нельзя считать трансформерами, потому что они не переключаются из режима ноутбука в режим планшета; многие из таких устройств имеют слишком большой вес и не обладают различными возможностями планшетов.
  • Планшеты под управлением Android*/iOS*/Win RT. К таким устройствам можно подключать приобретаемую отдельно клавиатуру, но такие устройства не поддерживают многозадачность, запуск различных приложений и не имеют совместимости с периферийными устройствами, а потому не могут считаться трансформерами.
  • Моноблоки AIO. Это современные устройства, часто используемые для игр, но они не обладают возможностями ноутбука и планшета, встроенными в одно устройство.
  • Фаблеты. Устройства этого типа являются промежуточными между телефонами и планшетами, но не обладают такой же вычислительной мощностью, графическими возможностями и способностью долго работать от аккумулятора, как трансформеры, а потому не могут быть считаться таковыми.

Примеры моделей использования

Теперь, когда вы понимаете характеристики трансформеров, рассмотрим поддерживаемые модели их использования. Трансформеры изменяют парадигму приложений для ПК. В мире, где традиционно разрабатывается два типа приложений — для работы и для потребления данных, — трансформеры предоставляют гибкую платформу, позволяющую разработать одно универсальное приложение. В приведенных ниже примерах показаны возможности использования трансформеров конечными потребителями и пользователями в организациях.

Использование потребителем

  • Многозадачность или использование одного приложения. Режим ноутбука поддерживает многозадачность и запуск множества приложений одновременно, что менее вероятно в режиме планшета. Обратите внимание, что это различие касается использования устройств в классическом режиме Windows 8. Приложения с современным интерфейсом Windows должны следовать требованиям Windows 8 в отношении «песочницы».
  • Игры. Интерактивные игры, поддерживающие клавиатуру и джойстик, в режиме ноутбука и сенсорные элементы управления в режиме планшета (пример: GestureWorks* GamePlay)
  • Создание данных или потребление данных. Реализация функций создания и потребления данных в одном и том же приложении требует пересмотреть структуру этого приложения.

TВ таблице 2 перечислены некоторые виды использования обоих режимов и показаны различия и требования для разработки приложений для ультрабуков:

Таблица 2: Сравнение режима ноутбука и режима планшета для потребительского использования

Режим ноутбука

Режим планшета

Просмотр и редактирование видео и звука (пример: семейство Magix Video*/Movie Edit* www.magix.com)

 

Воспроизведение видео и звука

Расширенное редактирование с использованием клавиатуры и мыши (пример: приложение Krita Gemini; www.kogmbh.com/download.html)

 

Рисование с помощью сенсорного ввода или пера

Приобретение товаров

 

Просмотр товаров

Ввод текста электронного письма

 

Просмотр электронной почты

Использование рабочих приложений для создания документов и электронных таблиц

 

Просмотр документов и электронных таблиц

Добавление комментариев и публикация ответов на сайтах социальных сетей

Просмотр новостей на сайтах социальных сетей

Создание документов с помощью клавиатуры и мыши

Чтение документов (сенсорное управление используется для навигации, перо — для заметок)

 

 

Профессиональное использование

Во множестве организаций распространена практика, когда для выполнения разных задач применяется несколько устройств. Например, сотрудник отдела продаж может использовать ноутбук для подробного анализа данных, но носит с собой планшет, чтобы делать заметки при посещении клиентов. Благодаря трансформерам отпадает необходимость иметь несколько устройств. В приведенной ниже таблице показаны примеры профессионального использования трансформеров.

Таблица 3:Сравнение режима ноутбука и режима планшета для профессионального использования

Категория

Режим ноутбука

Режим планшета

Образование

Запись заметок в классе, создание исследовательских материалов, написание статей, создание презентаций, копирование и вставка данных из нескольких источников

 

Потребление данных, например чтение книг и просмотр лекций с одновременным вводом заметок с помощью пера

Здравоохранение

Ввод примечаний к диаграммам с помощью клавиатуры и мыши

Ввод примечаний к диаграммам с помощью пера.

Поиск диагноза пациента с помощью сенсорного экрана и пера

 

Розничная торговля

Размещение заказов, подробный анализ продаж или складских запасов

Поиск по складским запасам для покупателей, помощь в обнаружении товаров, полные транзакции покупок в демонстрационном зале для снижения времени ожидания покупателей

 

 

Приложения с поддержкой трансформеров

Ниже приводятся примеры возможностей приложений для трансформеров:

  • Преобразуемый пользовательский интерфейс. Приложения, у которых интерфейс гладко переключается между режимами, удобны для пользователей. Приложение с традиционным интерфейсом в режиме ноутбука, но с оптимизированным для сенсорного управления интерфейсом в режиме планшета будет очень удобно. Переключение интерфейса может происходить автоматически или вручную, что поясняется в разделе рекомендаций ниже.
  • Приложения с дополнительными сенсорными элементами управления. Такой подход годится для игровых приложений, разработанных для Windows* 7 и предусматривающих управление с помощью клавиатуры или джойстика. При разработке приложений для Windows 8, в которой сенсорное управление является основным, наличие сенсорных элементов управления может оказаться удобным в обоих режимах.

Рекомендации по разработке приложений для ультрабуков

Если у вас есть существующие приложения для Windows 7 или Windows* XP, имеет смысл учесть следующие рекомендации по разработке, чтобы обеспечить гладкий переход при создании приложений для ультрабуков и трансформеров.

  • Если приложение предусматривает ввод данных, реализуйте в приложении поддержку программной клавиатуры, чтобы поддержать удобство работы пользователей в режиме планшета, когда физическая клавиатура недоступна.
  • Оптимизируйте существующие приложения для Windows 7 и Windows XP к сенсорному управлению для поддержания удобства работы пользователей на трансформерах с Windows 8.
  • Используйте руководство по сенсорному управлению для разработчиков: http://software.intel.com/en-us/touch-and-sensors
  • Оптимизируйте ваше приложение к использованию его на экранах различных размеров, разрешения и ориентации, учитывая фактические размеры и разрешения экранов, доступных на рынке ультрабуков. Кроме того, в режиме ноутбука, как правило, используется альбомная ориентация, но в режиме планшета ориентация во многом зависит от приложения. Убедитесь, что разметка вашего приложения и используемые элементы управления автоматически масштабируются для разных разрешений и ориентаций.
  • Узнайте о масштабировании для разных размеров экрана: http://blogs.msdn.com/b/b8/archive/2012/03/21/scaling-to-different-screens.aspx
  • Узнайте о разработке приложений для высоких значений DPI для Windows* 8: http://software.intel.com/en-us/articles/developing-for-high-dpi-applications-for-windows-8
  • Узнайте о поддержке нескольких разрешений: http://msdn.microsoft.com/en-us/library/windows/apps/dn263244.aspx

Оценка готовности приложений к работе на трансформерах

Способ переключения каждого приложения из режима ноутбука в режим планшета зависит от этого приложения. Тем не менее все приложения для трансформеров должны: 1) обнаруживать изменения состояния и 2) содержать функциональность для поддержки изменений состояния. Опираясь на модели использования и требования поддержки трансформеров, перечисленные в предыдущем режиме, можно привести рекомендации, которые следует учесть при разработке приложений для трансформеров.

  • Определение изменения состояния. В таблице 1 перечислены некоторые трансформеры и показано изменение их аппаратного режима. Тем не менее определение изменения режима приложением в некоторой степени зависит от BIOS и микропрограммы и поддерживается не всеми доступными на рынке устройствами. При подготовке приложения к поддержке трансформеров мы рекомендуем понять, как использовать API Windows 8 для определения смены режимов. Дополнительные сведения об обнаружении этого изменения см. в следующей статье:
    • Определение переключения из режима ноутбука в режим планшета: http://software.intel.com/en-us/articles/detecting-slateclamshell-mode-screen-orientation-in-convertible-pc
    • Как написать приложение, поддерживающее трансформеры: http://software.intel.com/en-us/articles/how-to-write-a-2-in-1aware-application

      Примечание. Не все устройства, доступные на рынке в настоящее время, автоматически определяют изменение состояния. Автоматическое определение изменения состояния зависит от компонентов, упомянутых в приведенных выше справочных статьях. Дополнительные сведения по этой теме будут опубликованы в ближайшее время. В то же время разработчикам рекомендуется рассмотреть перечисленные ниже варианты: некоторые из них можно использовать без зависимости.
  • Разработайте разные интерфейсы для режима ноутбука и режима планшета. Способы взаимодействия пользователей с трансформерами в режиме ноутбука и в режиме планшета существенно различаются. В режиме ноутбука в качестве основных методов ввода используют мышь и клавиатуру, а в режиме планшета предпочитают сенсорный экран и перо. Для повышения удобства пользователей имеет смысл разрабатывать отдельные интерфейсы для режима ноутбука и для режима планшета.
  • Напишите код для определения изменений состояния вручную. Поскольку автоматическое определение смены состояния устройства может быть недоступно, для начала неплохо написать ручной переключатель в приложении. В этом случае при появлении поддержки автоматического определения состояния будет проще доработать приложение.
  • PСнабжайте игры дополнительным сенсорным интерфейсом для удобства пользователя. Для игр на ПК наложение сенсорного интерфейса следует считать эффективным способом преобразования приложения для трансформеров.
  • Оптимизируйте приложения для обработки разных типов ввода. . Сенсорное управление/клавиатуру и мышь следует считать эффективными взаимозаменяемыми механизмами на случай, если один или несколько других методов ввода будут недоступны. Например, не все трансформеры поддерживают перо. Если ваше приложение использует перо, добавьте резервные механизмы, чтобы приложение работало на устройствах, не поддерживающих перо.

Заключение

Ультрабуки уже стали частью массового рынка, тогда как трансформеры представляют собой растущий сегмент рынка. Разработчикам приложений следует рассматривать возможности, предлагаемые этими устройствами для разработки приложений, использовать предоставленные в этой статье рекомендации и подготавливать свои приложения для таких устройств, снижая объем усилий и времени, затрачиваемых на выпуск приложений для конечных пользователей.

Об авторе

Мегана Рао (Meghana Rao) работает техническим маркетинговым инженером в подразделении Intel Software and Services. Она помогает разработчикам понимать возможности платформ Intel и писать приложения, удобные для пользователей.

 

Intel, the Intel logo, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

Преобразование пользовательского интерфейса: проектирование интерфейса будущего (1 из 5) Технология Intel® RealSense™ для разработчиков игр

$
0
0

Download PDF

Способы нашего взаимодействия с играми (и способы взаимодействия игр с нами) постоянно изменяются по мере появления новых технологий и новых возможностей. В отрасли компьютерных игр всегда быстро применяли потенциал новых интерактивных технологий. Развитие новых видов интерфейсов идет постоянно, и разработчики игр готовятся осваивать новые интересные идеи и технологии. Одна из таких перспективных технологий — Intel® RealSense™, сочетающая трехмерную камеру и усовершенствованное распознавание речи. С помощью Intel® RealSense™ SDK (бета-версия) разработчики только начинают изучать потенциал этой технологии для создания увлекательных игр, намного опережающих классические аппаратные контроллеры по возможностям интерактивности.

Эта статья (первая в серии из пяти статей о компьютерных системах с использованием перцептивных вычислений и о технологии Intel RealSense) содержит рассказ наших разработчиков, благодаря которым эта технология и увидела свет.

Изменение облика воображаемого мира

«Управление с помощью жестов интересно нам для создания ощущения преобразования и возможности использовать тактильные взаимодействия между вами и экраном компьютера», — говорит Робин Ханике из компании Funomena, описывая готовящуюся к выпуску игру на основе технологии Intel RealSense.

Funomena

Будучи убежденным сторонником положительного влияния игр, Ханике приняла участие в основании компании Funomena в 2013 году. Одна из целей этой компании состоит в изучении пределов эмоционального взаимодействия между игроками и технологиями. «В нашей игре персонаж идет по пути преобразования индивидуальности. На концепцию игры серьезно повлияло искусство оригами. Нам нравится, что камера может обнаруживать мельчайшее изменение положения рук игрока». Высокая точность отслеживания жестов расширяет возможности ввода. Технология Intel RealSense дает играм возможность очень точно реагировать на то, как именно игроки будут двигаться перед камерой. «Мы можем использовать эту информацию, чтобы игроки могли обращаться с объек­тами в реальном времени».

Эта игра пока не представлена для открытого ознакомления, но известно, она опирается на высокую точность камеры Intel® RealSense™ 3D для распознавания жестов; игроки будут напрямую взаимо­дей­ствовать с игровым миром, по-новому изучать загадки и головоломки в игре. «Нас всегда интересовала возможность расширить границы того, что может выразить игра. Мы создаем то, что бросает вызов вашим ощущениям, но при этом активно принимаем вашу реакцию как игрока. Вам понадобится в буквальном смысле собственными руками раскрывать загадки этого мира одну за другой и изменять каждый уровень в соответствии с вашим пониманием того, как должен выглядеть результат», — заявила Ханике.

Основы движения

Израильская компания Side-Kick Games уже несколько лет работает с контроллерами на основе распознавания движений, включая двухмерные веб-камеры (с помощью промежуточных систем PointGrab*, XTR* и EyeSight*), Kinect* и PrimeSense*. Благодаря накопленным знаниям внедрение технологии Intel RealSense оказалось весьма несложным процессом.

«Мы построили в наших играх уровень для контроллера движений, поэтому у нас много интерфейсов для обработки сигналов от промежуточных систем и стандартный интерфейс для управления движениями, — поясняет Таль Равив, операционный директор компании. — С помощью этой инфраструктуры и нашего опыта в области управления движением переход на технологию Intel RealSense с управления движением всем телом как на большом, так и на маленьком расстоянии прошел довольно гладко. Интерфейс технологии Intel RealSense очень прост и обладает отличными возможностями для отслеживания. По сравнению с другими технологиями пришлось преодолевать намного меньше затруднений».

В перспективной игре Warrior Wave компании Side-Kick игроки используют движения рук, чтобы укрыть солдат и защитить их от противника. Разработчики использовали разные функции технологии Intel RealSense в соответствии с игровым контекстом. «Мы используем два типа элементов управления. Первая часть — «силуэт». Это часть SDK, которая позволяет игре «видеть» руку, но не «знает», как она устроена (ладонь, пальцы). Отслеживаемая часть SDK — «скелет», она дает информацию о структуре руки (расположение каждого кончика пальца и середины ладони), — продолжает Равив. — Базовая механика игры работает с «силуэтом», но другие компоненты, такие как меню, работают со «скелетом».

Warrior Wave

Компания Side-Kick Games также заботится о том, чтобы технология Intel RealSense применялась в подходящем для нее контексте. Другие технологии используются в игре Warrior Waveвместе с ней для достижения оптимального удобства. «Игроки используют сенсорный экран для переходов по меню и включения различных функций, поскольку этот метод наиболее интуитивен. Управление движением применяется в игре для достижения более глубокого погружения в ее атмосферу, поскольку игрок не привязан к традиционной клавиатуре и мыши, — поясняет Равив. — Такое сочетание оптимально для игроков. В будущем сочетание голосового управления и управления движением будет играть более важную роль в пользовательском интерфейсе, но основное преимущество управления движением сейчас раскрывается в самой игре».

Выполнение приказов

Команда разработчиков Iridium Studios использует и управление движениями, и распознавание речи Intel RealSense для создания более реалистичного интерфейса для создаваемой игры There Came an Echo. в жанре стратегии реального времени. «В прошлом, управляя в стратегии в реальном времени небольшой группой боевых единиц, обычно мы использовали мышь, — говорит Джейсон Вишнов, основатель компании Iridium. — Но в реальном мире мы же не рисуем в воздухе воображаемый прямоугольник вокруг группы людей, чтобы заставить их идти. С людьми нужно общаться, а для этого мы используем жесты и голос».

В игре There Came an Echoголосовые команды крайне важны для реалистичного игрового процесса с высокой степенью вовлечения. Использование точных голосовых команд создает весьма интересный игровой процесс, более похожий на реальную жизнь. Впрочем, для Джейсона не менее важны и преимущества распознавания речи для игрового сюжета. «Мы потратили немало времени и сил на создание сценария и формирование персонажей, подобных обычным людям, каждый с настоящей мотивацией, настоящим страхом и изъянами характера. Распознавание речи помогает игроку лучше понять игровых персонажей, их характеры и роли в сценарии», — говорит Вишнов.

There Camean Echo

Возможности распознавания движений камерой Intel RealSense 3D сами по себе позволяют отдавать неголосовые команды в обстановке тактического боя, имитируемого в игре. «Некоторые жесты руками, используемые в войсках, можно связать напрямую с игровыми командами, и это очень интересно. Например, можно отдать команду впередили цель, сжав кулак, можно управлять движением солдат, поднимая руку - это очень здорово», — говорит Вишнов.

Впрочем, помимо точности самой технологии, ее удобство во многом зависит от контекста, в котором находится игрок. «Если просто взять и применить в игре набор жестов (не потому что это там нужно, а просто потому что у вас есть такая возможность), то игроки будут путаться, теряться и утрачивать ощущение связи с игрой, — говорит Вишнов. — Очень важно добиться того, чтобы жесты были правильными и естественными».

Измерение пульса

Одним из проектов, способных служить примером детализации и точности трехмерной камеры Intel RealSense, является приключенческая игра Nevermind с расширенной биологической обратной связью. В этой игре, которая будет выпущена компанией Flying Mollusk, игрок действует в качестве оператора «нейрозонда», способного путешествовать по разуму жертв психологических травм, решать головоломки и преодолевать защитные механизмы мозга, чтобы восстанавливать психическое здоровье пострадавших. Игра определяет стрессовое состояние игрока с помощью технологии биологической обратной связи. При обнаружении стресса среда динамически реагирует на страх игрока; по мере усиления беспокойства уровни стресса становятся все более сложными. Напротив, если игрок расслабляется, игра Nevermindприобретает более мягкий характер. За счет этого игра Nevermindпомогает игрокам внимательнее отслеживать свое стрессовое состояние и справляться с ним как в игре, так и в реальном мире.

Nevermind

«Меня всегда интересовали возможности биологической обратной связи в играх», — говорит Эрин Рейнольдс, творческий директор компании Flying Mollusk. Она с 2009 года изучает вопросы применения биологической обратной связи для построения более тесной взаимосвязи между игроком и игрой. Существовали разные варианты биологической обратной связи, но ни один из них не был достаточно пригоден для большинства потребителей. Технология Intel RealSense меняет такое положение.

«Камера Intel RealSense 3D может измерять пульс, а мы с этой помощью определяем стресс и страх игрока. На этом построена вся игра Nevermind , — говорит Эрин. — До этого игрокам в Nevermindприходилось надевать под одежду нагрудный ремень с датчиком пульса. А теперь, благодаря камере, они могут просто сесть за компьютер и играть. Так гораздо удобнее и интуитивнее».

Способность камеры Intel RealSense 3D измерить пульс, просто «глядя» на голову человека, открывает целый мир возможностей, поражающих воображение Эрин Рейнольдс. «Это означает, что разработчики могут сделать биологическую обратную связь важной частью своей продукции, будь то игры, медицинские системы или приложения для связи, — говорит она. — Все это чрезвычайно увлекательные возможности».

«Еще одна функция биологической обратной связи камеры — определение эмоций. Эта возможность очень нравится разработчикам, у нее огромный потенциал, чтобы изменить подход к тому, как мы будем играть в игры в будущем», — добавляет Чак Мак-Фадден, продукт-менеджер Intel, отвечающий за технологию Intel RealSense.

Новый уровень

Использование технологии Intel RealSense зависит от определенных нужд игры по созданию требуемых ощущений у игроков. Об этом свидетельствуют разные подходы этих разработчиков. Другие возможные области использования технологии Intel RealSense только открываются. «Мы проводим «хакатоны» и игровые конференции с использованием наших технологий, мы путешествуем по всему миру и общаемся с разработчиками игр, — говорит Мак-Фадден. — Мы даем разработчикам код и камеру Intel RealSense 3D и даем им полную свободу для творчества».

Корпорация Intel также проводит конкурс Intel® RealSense™ App challenge 2014 (по словам Мак-Фаддена, с миллионными призами), целью которого является поощрение изобретатели самых удачных, необычных и творческих идей использования новой технологии. «В числе предложенных были и такие идеи, которые лично я и представить бы себе не мог, например новый способ играть на музыкальных инструментах, — говорит Мак-Фадден. — Очень интересно наблюдать, как технология Intel RealSense выходит на новый уровень».

«Как разработчики, мы больше не загнаны в жесткие рамки соглашений тридцатилетней давности о том, как должен быть устроен интерфейс, — говорит Рейнольдс, подчеркивая преимущества технологии Intel RealSense. — Мы получили возможность увидеть нужды современного общества и изменить способ взаимодействия с компьютерами».

«Не знаю, сколько людей уже пользуются преимуществами этой новой технологии, — говорит Ханике о новых возможностях организации пользовательского интерфейса с помощью новой технологии Intel RealSense. — Мы на рубеже. Мы можем определять, какими будут эти интерфейсы, каким будет будущее. Мы можем задать контекст, создать эмоциональную связь с пользователями и вывести их из привычной зоны комфорта, — заключает Ханике. — Мы заставляем их привыкнуть к будущему».

Ресурсы и дополнительные сведения

Изучить технологию Intel® RealSense™, узнать о бета-версии Intel® RealSense™ SDK для Windows и заказать набор разработчика можно здесь.

Прочтите мнение о том, почему технология Intel RealSenseтак важна

Парить в воздухе без контроллера можно тут

Ваш проект готов к демонстрации? Станьте участником программы Intel® Software Innovator. Эта программа поддерживает разработчиков передовых проектов, дает возможность выступить с рассказом о своем проекте и устроить демонстрацию

Приступите к работе в центре ресурсов для разработчиков

 

Использование сенсорных жестов для управления параметрами физики в Unity* 3D с TouchScript

$
0
0

Download PDF

Автор: Линн Томпсон

При разработке игр и программ моделирования может понадобиться предоставить пользователям возможность управления ресурсами, которые используются в моделировании физики. Из этой статьи вы узнаете, как разрабатывать сцены Unity* 3D с настроенными сенсорными жестами для изменения физических характеристик используемых ресурсов, включая расположение, размер, массу и скорость. Эти изменения можно использовать для улучшения пользовательского интерфейса моделирования или для повышения эстетического качества сцены. В данном примере показана среда Unity 3D под управлением Windows* 8 в качестве удобной платформы для управления физическими характеристиками в играх и программах моделирования с помощью сенсорных жестов.

Настройка сцены Unity 3D

Я настроил геометрию этой сцены в Autodesk 3ds Max*. Я применил к поверхности волновой модификатор и модификатор изгиба; с одной стороны поверхности находится зеленая башня. Эту сцену я экспортировал из Autodesk 3ds Max в формате FBX, а затем импортировал в Unity 3D (см. рис. 1). Измененная поверхность с изгибом и волнами влияет на движение других ресурсов, добавляемых на сцену во время выполнения.

 


Примечание. Убедитесь, что геометрические объекты, импортируемые из сторонних приложений, не содержат настолько много фрагментов поверхностей, что движок Unity 3D будет перегружен или просто перестанет работать. В определенных средах разработки может указываться максимальное допустимое количество вершин и треугольников на каждый импортированный ресурс. Ресурсы в этом примере не используют никакие материалы, шейдеры и текстуры, но если такие ресурсы используются, следует учитывать их влияние на производительность целевой платформы разработки.


 


Рисунок 1. Башня с одной стороны поверхности, применены модификаторы изгиба и волн

Кроме того, с геометрией «отображение во время выполнения» импортированы сферы, которые не отображаются во время выполнения. Эти сферы я разместил над волнообразными выступами (см. рис. 2).

Рисунок 2. Поверхность с волнами, сферы не отрисовываются во время выполнения

Я использую расположение этих сфер в качестве места, откуда сферы будут попадать в сцену. Эти сферы я добавил программно, поэтому добавить их физические свойства нужно тоже програм­мно. Я делаю это с помощью следующего кода (обратите внимание, что имена 17 создающихся сфер - TargetSpawn[000 - 016]):


	int spawnPoint = 1;
	string spawnPointString = "";
	Vector3 spawnPosition = new Vector3(0.0f,0.0f,0.0f);
	Quaternion spawnRotation = new Quaternion(0.0f,0.0f,0.0f,0.0f);
	float spawnTime = 0.0f;


	void Update ()
	{



		spawnTime += Time.deltaTime;
		if(spawnTime > 1.0f)
		{
			spawnTime = 0.0f;

			if(spawnPoint == 17){spawnPoint = 1;}

			if(spawnPoint < 10){spawnPointString = "TargetSpawn00" + spawnPoint;}
			else{spawnPointString = "TargetSpawn0" +  spawnPoint;}

			GameObject spawnPointGO = GameObject.Find(spawnPointString);
			spawnPosition = spawnPointGO.transform.position;

			GameObject targetSphere = (GameObject)Instantiate
			 (GameObject.CreatePrimitive (PrimitiveType.Sphere),
			spawnPosition,spawnRotation);

			Color randomColor = new
			 Color(Random.value,Random.value,Random.value,1.0f);
			targetSphere.renderer.material.color = randomColor;


			targetSphere.collider.tag = "targetSphere";

			targetSphere.transform.localScale = new Vector3(10.0f,10.0f,10.0f);
			targetSphere.AddComponent ("Rigidbody");
			targetSphere.AddComponent ("GenericPan");
			targetSphere.AddComponent ("PanGesture");
			Destroy (targetSphere,60.0f);

			spawnPoint += 1;

		}
	}




При реализации приведенного выше сценария волнообразная основа заполняется твердыми физическими сферами, которые исчезают через 60 секунд (обратите внимание на вызов функции Destroy в предпоследней строке сценария). Можно настроить время до разрушения создаваемых сфер (в моем случае оно равно 60 секундам) на основе возможностей целевой платформы и нужных характеристик сцены. Башня в конце сцены настроена так, чтобы стрелять по капсулам, если они оказываются слишком близко. Эта башня не настроена для упреждающего сопровождения сфер и обычно промахивается (см. рис. 3).

Рисунок 3. Башня стреляет капсулами по создающимся твердым сферам

Создающиеся сферы скатываются в глубину платформы, а капсулы, которыми стреляет зеленая башня, отталкивают их к задней стенке. Больше всего на производительность в этой сцене Unity 3D влияет огромное количество выпущенных башней капсул и созданных сфер, одновременно отображающихся в активном представлении.

Прокрутка

IВ предыдущем разделе я программно применил сценарий GenericPan к созданным сферам.
Этот сценарий GenericPan позволяет пользователям передвигать сферу с помощью жеста прокрутки. Хотя сфера перемещается, преобразование ее локального расположения изменяется в функции Update сценария. Объект по-прежнему является частью физического моделирования при жесте прокрутки, он может взаимодействовать с другими объектами сцены. Я также применил жест GenericPan к прямоугольной задней стенке в сцене, чтобы с помощью стенки можно было передвигать сферы внутри выемки платформы. Можно переносить заднюю стенку, чтобы поместить ее перед башней и защитить, таким образом, созданные сферы от попадания выпускаемых башней капсул. Вот полный код сценария:


using TouchScript.Events;
using TouchScript.Gestures;
using UnityEngine;
using System;
using System.Collections;


public class GenericPan : MonoBehaviour
{
	private Vector3 targetPan;
	private Vector3 startPos;
	private float panSpeed;
	private float panFrac;
	private bool panning;


	void Start ()
	{
		startPos = targetPan = transform.localPosition;
		panSpeed = 10.0f;
		panFrac = 10.0f;
		panning = false;
		GetComponent<PanGesture>().StateChanged += onPanStateChanged;

	}

	void Update ()
	{

		if(panning)
		{
			//this.rigidbody.velocity = transform.forward * Vector3.Magnitude (transform.localPosition - targetPan);


			panFrac = panSpeed * Time.deltaTime;
        	transform.localPosition = Vector3.Lerp(transform.localPosition, targetPan, panFrac);
			panning = false;
		}
	}

	private void onPanStateChanged(object sender, GestureStateChangeEventArgs e)
    {
        switch (e.State)
        {
            case Gesture.GestureState.Began:
            case Gesture.GestureState.Changed:
                var target = sender as PanGesture;
                Debug.DrawRay(transform.position, target.WorldTransformPlane.normal);
                Debug.DrawRay(transform.position, target.WorldDeltaPosition.normalized);

                var local = new Vector3(transform.InverseTransformDirection(target.WorldDeltaPosition).x, transform.InverseTransformDirection(target.WorldDeltaPosition).y, transform.InverseTransformDirection(target.WorldDeltaPosition).z);
                targetPan += transform.InverseTransformDirection(transform.TransformDirection(local));
				panning = true;
                //if (transform.InverseTransformDirection(transform.parent.TransformDirection(targetPan - startPos)).y < 0) targetPan = startPos;
                break;
        }

    }

}



Обратите внимание, что в функции onPanStateChangedпеременная Vector3 localиспользует все три оси, тогда как в других моделях пользовательского интерфейса я использовал только оси x- и y-. Можно настроить нужным образом функциональность и других атрибутов, включая скорость прокрутки. При перемещении задней стенки для защиты сфер от выпускаемых башней капсул не так просто правильно разместить эту стенку. Нужно изменить переменную Vector3 localв отдельном сценарии, чтобы задняя стенка защищала сферы от попадания капсул из башни.

Касание

Далее для изменения физических характеристик я настроил жест касания. Я программно добавил этот жест к сферам во время их создания с помощью следующего кода:


targetSphere.AddComponent ("GenericTap");
targetSphere.AddComponent ("TapGesture");

Сценарий GenericTapвыполняет все модификации твердых тел в функции onTapи не использует функцию Update. Функция onTapувеличивает размер сферы в 2 раза при каждом ее касании пользователем. Я добавил это поведение, чтобы отслеживать сферы на сцене и удобнее наблюдать за их поведением. Каждый раз, когда пользователь касается сферы, ее физическая масса увеличивается в 10 раз. Результат виден на рис. 4: попадание выпущенных башней капсул не приводит к перемещению крупной сферы, которой пользователь коснулся 2 или 3 раза, тогда как другие сферы с легкостью перемещаются при попаданиях.


Рисунок 4. Попадание капсул не приводит к перемещению сферы с увеличенными размером и массой

Код сценария GenericTapвыглядит так:


using UnityEngine;
using System.Collections;
using TouchScript.Events;
using TouchScript.Gestures;


public class GenericTap: MonoBehaviour {

	private Vector3 startScale;

	void Start ()
	{

	startScale = transform.localScale;
	if (GetComponent<TapGesture>() != null) GetComponent<TapGesture>().StateChanged += onTap;


	}

	void Update ()
	{

	}

	private void onTap(object sender, GestureStateChangeEventArgs 	gestureStateChangeEventArgs)
    	{
        if (gestureStateChangeEventArgs.State == Gesture.GestureState.Recognized)
		{
            		transform.rigidbody.mass *= 10;
			transform.localScale *= 2.0f;
		}
	}

}



Этот сценарий прост: масса и размер сферы дискретно изменяются при выполнении жеста касания. В более сложной игровой среде жест касания может запускать последовательность событий, где масса и размер будут последовательно увеличиваться за определенное время и в зависимости от других элементов моделируемой сцены. Еще одно возможное улучшение состоит в использовании метода Time.deltaTimeдля настройки последовательности жестов для снижения массы и размера двойными касаниями.

Нажатие и отпускание

Затем я настраиваю жест «нажатие и отпускание», чтобы увеличить скорость движения созданных сфер в зависимости от времени между нажатием и отпусканием. Эта функциональность также добавляется программным образом во время создания:


			targetSphere.AddComponent ("PressGesture");
			targetSphere.AddComponent ("ReleaseGesture");
			targetSphere.AddComponent ("GenericPressRelease");

Я настраиваю сценарий GenericPressReleaseдля переключения двух логических переменных в функциях onPressи onRelease. Первая логическая переменная отслеживает, как изменилась скорость в последнем цикле жеста «нажатие и отпускание», чтобы в текущем цикле применить противоположное изменение. Вторая логическая переменная отслеживает, задействован ли сценарий в цикле жеста «нажатие и отпускание». Если да, то в зависимости от этого увеличивается или уменьшается скорость поступательного движения сферы. Для этого я использую параметр rigidbody.velocityсозданной сферы. Я использую переменную времени, чтобы регулировать величину изменения скорости поступательного движения. Результат таков: скорость движения сферы вперед увеличивается каждый нечетный раз, когда сфера получает жест «нажатие и отпускание», и уменьшается каждый четный раз при получении этого жеста. Код жеста «нажатие и отпускание» таков:


using UnityEngine;
using System.Collections;
using TouchScript.Events;
using TouchScript.Gestures;


public class GenericPressRelease : MonoBehaviour {

	private Vector3 startScale;
	private float velocityMult;
	private bool pressed;
	private bool currentlyIncreasing;
	private float timeSinceChanged;

	void Start ()
	{

	startScale = transform.localScale;
	velocityMult = 10.0f;
	pressed = false;
	currentlyIncreasing = true;
	timeSinceChanged = 0.0f;
	if (GetComponent<PressGesture>() != null) GetComponent<PressGesture>().StateChanged += onPress;
    if (GetComponent<ReleaseGesture>() != null) GetComponent<ReleaseGesture>().StateChanged += onRelease;

	}

	void Update ()
	{
		timeSinceChanged += Time.deltaTime;
		if(timeSinceChanged >= 0.25 && currentlyIncreasing && velocityMult <= 100 && pressed)
		{
			velocityMult += 10.0f;
			rigidbody.velocity = transform.forward * velocityMult;
			timeSinceChanged = 0.0f;
		}
		if(timeSinceChanged >= 0.25 && !currentlyIncreasing && velocityMult >= 0 && pressed)
		{
			velocityMult += -10.0f;
			rigidbody.velocity = transform.forward * velocityMult;
			timeSinceChanged = 0.0f;
		}

	}

	private void onPress(object sender, GestureStateChangeEventArgs gestureStateChangeEventArgs)
    {
        if (gestureStateChangeEventArgs.State == Gesture.GestureState.Recognized)
		{
			pressed = true;
		}
	}
	private void onRelease(object sender, GestureStateChangeEventArgs gestureStateChangeEventArgs)
    {
        if (gestureStateChangeEventArgs.State == Gesture.GestureState.Recognized)
		{
			pressed = false;
			currentlyIncreasing = !currentlyIncreasing;
		}
    }

}



Эта функциональность может быть полезной в играх со стрельбой, где может возрастать скорость снарядов, вследствие чего попадание будет иначе воздействовать на цели. Кроме того, в играх со стрельбой можно настроить эту функцию в качестве защитного механизма: нажатие или отпускание пользователем будет снижать скорость и ослаблять влияние попадания. Эту функцию можно использовать в играх в стиле Тетриса, чтобы при увеличении скорости движения фигур давать пользователю больше очков.

Другие физические свойства

Я использовал жесты, показанные в этой статье, для управления такими характеристиками ресурсов сцены Unity 3D, как расположение, размер, масса и скорость движения. Другие параметры твердых тел, которыми удобно управлять с помощью жестов, — угловая скорость, сопротивление движению и центр масс. Можно связать эти параметры твердых тел, управляемые с помощью жестов, с существующими параметрами, такими как цвет и текстура. Также есть возможность создавать собственные переменные для моделирования физики твердых тел. Пример — переменная hitDamage, которая увеличивается при каждом касании; при обнаружении попадания из объекта вычитается определенное количество «здоровья».

Заключение

IЯ создал и запустил пример физического моделирования с твердыми телами, приведенный в этой статье, с помощью Unity 3D под управлением Windows 8 на ультрабуке. Я настроил наибольшее время жизни выпускаемых башней снарядов и создаваемых сфер для этой платформы. В результате моделирование должным образом реагировало на запрограммированные сенсорные жесты. Время жизни актива — всего один из параметров, которые нужно учитывать при изменении физических характеристик. При этом приложение не должно давать пользователю возможности приведения физического моделирования в состояние, из-за которого снизится производительность и скорость реагирования всего приложения. Для этого проще всего ограничить минимальные и максимальные значения всех изменяемых физических характеристик. Если учитывать вопросы производительности, Windows 8 на ультрабуках является жизнеспособной платформой для разработки моделей Unity 3D с изменением характеристик ресурсов сцены при физическом моделировании.

Другие материалы:

Об авторе

Линн Томпсон — специалист в области ИТ, более 20 лет проработавший в области компьютеризации предпринимательской и производственной сфер. Одной из первых его работ стало использование САПР для создания и редактирования чертежей контрольных приборов для энергосистем. Тогда же он получил степень бакалавра электротехники в Университете Небраски (г. Линкольн). В эпоху бума доткомов Линн занимался системным администри­рованием операционных систем, баз данных и приложений на различных платформах в одном из ИТ-интеграторов. Позже, после «краха доткомов», он участвовал во множестве проектов в роли ИТ-консультанта. Линн работал с компаниями, работающими в сфере легкой промыш­ленности, а также в нефтегазовой и оборонной индустрии. Сейчас он вновь вернулся к своей специальности и работает инженером-энергетиком. Линн получил магистерскую степень инженера со специализацией в области управления техническими системами (также в Университете Небраски).

 

Intel® RealSense™. Работа с потоками необработанных данных

$
0
0

Download PDF

1. Введение

Разработчикам, которые интересуются возможностями, доступными при внедрении управления без помощи контроллеров в своих приложениях, достаточно ознакомиться с Intel RealSense SDK, сопутствующими примерами и ресурсами в Интернете. Если вы «погрузитесь» в это решение, то обнаружите широкий набор функций, позволяющих создавать совершенно новые, великолепные интерфейсы с использованием новых технологий.

В этой статье мы поговорим о потоках различных необработанных данных, о доступе к ним и о способах их использования. За счет прямого доступа к необработанным данным мы не только сможем работать с метаданными, но и получим самый быстрый способ определять, что делает пользователь в реальном мире.

В этой статье в качестве камеры Intel RealSense мы использовали трехмерную камеру Bell Cliff, которая выдает несколько потоков данных — от традиционного цветного изображения RGB до данных о глубине и картинки с инфракрасной камеры. Каждый из этих потоков ведет себя по-своему, но об этом мы подробнее поговорим ниже. Ознакомившись с этой статьей, вы узнаете, какие потоки доступны и когда работать с ними.

Для понимания представленных материалов полезно (но необязательно) знать C++ для ознакомления с примерами кода и иметь общее представление о технологии Intel RealSense (или о ее более ранней версии — Intel® Perceptual Computing SDK).

2. Почему это важно

Если вас интересует только реализация простой системы распознавания жестов или лица, то в модулях алгоритмов Intel RealSense SDK вы найдете все необходимое, а о потоках необработанных данных можно не заботиться. Проблема возникнет, когда вам потребуется функциональность, отсутствующая в модулях алгоритмов в составе SDK. Приложение не будет работать без альтернативного решения.

Итак, первый вопрос: «Что нужно вашему приложению и можно ли выполнить эти требования с помощью модулей алгоритмов Intel RealSense SDK?». Если нужен указатель на экране, отслеживающий перемещение руки, для этого может оказаться достаточно модуля отслеживания руки или пальцев. Чтобы быстро определить, соответствует ли доступная функциональность вашим нуждам, можно использовать примеры в составе SDK. Если таких возможностей недостаточно, то можно приступить к планированию использования потоков необработанных данных.

Например, в настоящее время поддерживается обнаружение двухмерных жестов. Но что, если вам нужно обнаруживать жесты по набору трехмерных рук и определять дополнительную информацию по движению рук пользователя? Что, если нужно записать высокоскоростной поток жестов и сохранить их в виде последовательности, а не в виде снимка? Потребуется обойти систему распознавания пальцев и рук, образующую вычислительную нагрузку, и внедрить методику для динамического кодирования телеметрии в реальном времени. Вообще можно столкнуться с недостаточной функциональностью, может потребоваться более прямое решение для той или иной программной проблемы.

Еще пример: предположим, что вы создаете приложение, которое обнаруживает и распознает язык жестов и преобразует его в текст для передачи в телеконференции. Текущая функциональность Intel RealSense SDK поддерживает отслеживание рук и пальцев (но только в одиночных жестах) и не имеет целенаправленной поддержки распознавания языка жестов. Единственное решение в таких случаях — разработка собственной системы распознавания жестов, которая сможет быстро преобразовывать жесты в последовательность положений пальцев и рук, а с помощью системы шаблонов будет распознавать знаки и восстанавливать текст. Единственный доступный в настоящее время способ достижения этого результата — доступ к потоку необработанных данных с помощью высокоскоростной записи и преобразование значения на лету.

Возможность написания кода для восполнения пробела между существующей и нужной функциональностью крайне важна, и она обеспечивается в Intel RealSense SDK.

Эта технология пока относительно нова, и разработчики еще только изучают ее возможности. Доступ к потокам необработанных данных расширяет возможные действия, а из таких усовершенствований рождаются новые решения.

3. Потоки

Лучший способ узнать о потоках данных — самостоятельно ознакомиться с ними. Для этого нужно запустить пример Raw Streams, находящийся в папке bin установленного экземпляра Intel Realsense SDK.

\Intel\RSSDK\bin\win32\raw_streams.exe

Пример снабжен полным исходным кодом и проектом, который нам очень пригодится. Если запустить исполняемый файл и нажать копку START при запуске приложения, вы получите цветной поток RGB, как показано на рис. 1.

Рисунок 1. Типичный цветной поток RGB

Помахав самому себе ручкой, нажмите кнопку STOP, откройте меню Depth и выберите 640x480x60. Снова нажмите кнопку START.


Рисунок 2. Отфильтрованный поток данных глубины с камеры Intel® RealSense™ 3D.

Как видно на рис. 2, это изображение значительно отличается от цветного потока RGB. Вы видите черно-белое изображение, представляющее расстояние каждого пикселя до камеры. Светлые пиксели ближе, а темные — дальше; черные либо считаются фоном, либо не распознаны достоверно.

Двигаясь перед камерой, вы поймете, что камера может очень быстро принимать решения о действиях пользователя. Например, совершенно ясно, как выделить на сцене руки благодаря толстому черному контуру, отделяющему их от тела и головы, находящихся дальше от камеры.


Рисунок 3. Ночное видение. Камера Intel® RealSense™ 3D выдает поток необработанного видеоизображения, снятого в инфракрасном спектре.

Последний тип потока может быть неизвестен прежним разработчикам Intel Perceptual Computing SDK, но на рис. 3 видно, что в меню IR можно получить с камеры изображение, снятое в инфракрасном диапазоне. Это поток необработанных данных, его скорость чтения намного превышает частоту обновления типовых мониторов.

 

Можно инициализировать все или любые из этих потоков для их одновременного чтения по мере потребностей приложения; для каждого потока можно выбрать требуемое разрешение и частоту обновления. Важно отметить, что итоговая кадровая скорость входящих потоков будет зависеть от доступной пропускной способности. Например, если попытаться инициализировать поток RGB при 60 кадрах в секунду, поток глубины при 120 кадрах в секунду и ИК-поток при 120 кадрах в секунду и передавать все эти потоки с единой синхронизацией, будет доступна лишь наименьшая скорость обновления (60 кадров в секунду), и только если с такой работой справится система.

Образец с необработанными потоками пригоден для начала работы, но не позволяет сочетать потоки, поэтому его следует использовать только для ознакомления с типами, разрешениями и скоростями обновления, доступными для вашей камеры. Помните, что пакет Intel RealSense SDK предназначен для работы с различными типами трехмерных камер, поэтому разрешение образца может быть недоступным на других камерах. Поэтому не следует жестко задавать разрешение в коде приложений.

4. Создание потоков и доступ к данным

Просмотреть полный исходный код примера с необработанными потоками можно, открыв следующий проект в Visual Studio*.

\Intel\RSSDK\sample\raw_streams\raw_streams_vs20XX.sln

В примере содержится простой пользовательский интерфейс и полный набор параметров, поэтому код не очень легко читается. Имеет смысл убирать добавочный код и оставлять только необходимые строки кода, служащие для того, чтобы создавать, обрабатывать и удалять поток, полученный с камеры. Ниже приведен код, представляющий собой «очищенную» версию приведенного выше проекта, но в этом коде сохранены все необходимые компоненты даже для простейших приложений Intel RealSense.

Первые две важные функции — это инициализация камеры Intel RealSense 3D и ее высвобождение по завершении работы программы. Это видно в приведенном ниже коде, а подробные сведения о вызываемых функциях будут приведены ниже.


int RSInit ( void )
{
	InitCommonControls();
	g_session=PXCSession::CreateInstance();
	if (!g_session) return 1;
	g_bConnected = false;
	g_RSThread = CreateThread(0,0,ThreadProc,g_pGlob->hWnd,0,0);
	Sleep(6000);
	if ( g_bConnected==false )
		return 1;
	else
		return 0;
}

void RSClose ( void )
{
	g_bConnected = false;
	WaitForSingleObject(g_RSThread,INFINITE);
}


Здесь мы имеем функции верхнего уровня для любого приложения, предназначенного для необработанных данных: создание экземпляра сеанса и потока для выполнения кода, обрабатывающего поток, затем высвобождение потока с помощью глобального флага g_bConnected. Рекомендуется использовать потоки ЦП при работе с потоками данных, поскольку это даст возможность основному приложению работать с любой требуемой кадровой скоростью, независимо от кадровой скорости камеры. Кроме того, это помогает распределить нагрузку на ЦП среди нескольких ядер, благодаря чему повышается общая производительность приложения.

В приведенном выше коде нас интересует только строка с функцией ThreadProc, которая содержит весь код, отвечающий за управление потоками. Перед переходом к подробностям отметим, что этот исходный код не является исчерпывающим, здесь для улучшения читаемости удалены глобальные объявления и второстепенные разделы. Сведения о глобальных объявлениях см. в первоначальном исходном коде образца проекта raw_streams.


static DWORD WINAPI ThreadProc(LPVOID arg)
{
	CRITICAL_SECTION g_display_cs;
	InitializeCriticalSection(&g_depthdataCS);
	HWND hwndDlg=(HWND)arg;
	PopulateDevices(hwndDlg);
	PXCCapture::DeviceInfo dinfo=GetCheckedDevice(hwndDlg);
	PXCCapture::Device::StreamProfileSet profiles=GetProfileSet(hwndDlg);
	StreamSamples((HWND)arg,&dinfo,&profiles,
		false, false, false,
		g_file
		);

	ReleaseDeviceAndCaptureManager();
	g_session->Release();
	DeleteCriticalSection(&g_depthdataCS);
	return 0;
}

Для работы с потоком данных важно создать «главный раздел» в коде. Если не сделать это в многопоточной среде, то два потока теоретически смогут записывать данные в одну и ту же глобальную переменную одновременно, что нежелательно.

Для тех, кто не знаком с многопоточностью, эта функция вызывается и не завершается, пока для главного потока (создавшего этот поток) для параметра g_bConnected не будет установлено значение false. Главный вызов функции здесь — StreamSamples, а остальной код выше и ниже служит лишь для входа и выхода. Первая интересующая нас функция — PopulateDevices, она практически идентична такой же функции в проекте raw_streams. Она заполняет список g_devices именами всех доступных устройств. Если вы используете камеру Intel RealSense 3D на ультрабуке, то есть вероятность, что у вас будет два устройства (второе — встроенная камера ультрабука). Обратите внимание на следующие строки.


static const int ID_DEVICEX=21000;
static const int NDEVICES_MAX=100;
int c = ID_DEVICEX;
g_session->CreateImpl<PXCCapture>(g_devices[c],&g_capture);
g_device=g_capture->CreateDevice((c-ID_DEVICEX)%NDEVICES_MAX);

Код, константы и глобальные функции скопированы из первоначального кода, их можно еще более сократить. Важнейшие вызовы здесь — Createlmpl и CreateDevice. В результате указатель камеры Intel RealSense 3D теперь хранится в g_device.

При наличии действующего указателя на устройство остальной код инициализации работает без проблем. Функция StreamProfileSet является оболочкой для этого кода.

g_device->QueryDeviceInfo(&dinfo);

Функция StreamProfileSet отвечает за сбор всех типов потоков и разрешений, которые нужно инициализировать, она может быть простой или сложной, исходя из потребностей. В целях совместимости с камерами настоятельно рекомендуется перечислить доступные разрешения и типы в списке вместо жесткого кодирования фиксированных настроек.


PXCCapture::Device::StreamProfileSet GetProfileSet(HWND hwndDlg)
{
	PXCCapture::Device::StreamProfileSet profiles={};
	if (!g_device) return profiles;

	PXCCapture::DeviceInfo dinfo;
	g_device->QueryDeviceInfo(&dinfo);
	for (int s=0, mi=IDXM_DEVICE+1;s<PXCCapture::STREAM_LIMIT;s++)
	{
		PXCCapture::StreamType st=PXCCapture::StreamTypeFromIndex(s);
		if (!(dinfo.streams&st)) continue;

		int id=ID_STREAM1X+s*NPROFILES_MAX;
		int nprofiles=g_device->QueryStreamProfileSetNum(st);
		for (int p=0;p<nprofiles;p++)
		{
			if ( st==PXCCapture::StreamType::STREAM_TYPE_COLOR ) continue;
			if ( st==PXCCapture::StreamType::STREAM_TYPE_IR ) continue;
			if ( st==PXCCapture::StreamType::STREAM_TYPE_DEPTH && p==2 )
						{
				PXCCapture::Device::StreamProfileSet profiles1={};
				g_device->QueryStreamProfileSet(st, p, &profiles1);
				profiles[st]=profiles1[st];
						}
		}
		mi++;
	}

	return profiles;
}


QueryStreamProfileSet возвращает значительный объем кода, в котором нам нужны доступные потоки для одиночного потока глубины и возврат профиля. Можно написать собственные условия для поиска нужных потоков, будь то с определенным разрешением или с определенной кадровой скоростью, если есть условия отката, чтобы приложение могло работать с потоком подходящего формата.

Итоговая функция и центральный блок кода для доступа к данным потока — StreamSamples. Если убрать код безопасности и комментарии, код будет выглядеть так:


void StreamSamples(HWND hwndDlg, PXCCapture::DeviceInfo *dinfo, PXCCapture::Device::StreamProfileSet *profiles, bool synced, bool isRecord, bool isPlayback, pxcCHAR *file)
{
	PXCSenseManager *pp=g_session->CreateSenseManager();
	pp->QueryCaptureManager()->FilterByDeviceInfo(dinfo);
	for (PXCCapture::StreamType st=PXCCapture::STREAM_TYPE_COLOR;st!=PXCCapture::STREAM_TYPE_ANY;st++)
	{
		PXCCapture::Device::StreamProfile &profile=(*profiles)[st];
		if (!profile.imageInfo.format) continue;
		pp->EnableStream(st,profile.imageInfo.width, profile.imageInfo.height, profile.frameRate.max);
	}
	pp->QueryCaptureManager()->FilterByStreamProfiles(profiles);
	MyHandler handler(hwndDlg);
	if (pp->Init(&handler)>=PXC_STATUS_NO_ERROR)
	{
		pp->QueryCaptureManager()->QueryDevice()->SetMirrorMode(PXCCapture::Device::MirrorMode::MIRROR_MODE_DISABLED);
		g_bConnected = true;
		for (int nframes=0;g_bConnected==true;nframes++)
		{
			pxcStatus sts2=pp->AcquireFrame(synced);
			if (sts2<PXC_STATUS_NO_ERROR && sts2!=PXC_STATUS_DEVICE_LOST) break;
			if (sts>=PXC_STATUS_NO_ERROR)
			{
				PXCCapture::Sample *sample = (PXCCapture::Sample*)pp->QuerySample();

				short invalids[1];
				invalids[0] = pp->QueryCaptureManager()->QueryDevice()->QueryDepthSaturationValue();
				invalids[1] = pp->QueryCaptureManager()->QueryDevice()->QueryDepthLowConfidenceValue();

				PXCImage::ImageInfo dinfo=sample->depth->QueryInfo();
				PXCImage::ImageData ddata;
				if (sample->depth->AcquireAccess(	PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_DEPTH,&ddata)>=PXC_STATUS_NO_ERROR)
				{
					EnterCriticalSection(&g_depthdataCS);
					memset ( g_depthdata, 0, sizeof(g_depthdata) );
					short *dpixels=(short*)ddata.planes[0];
					int dpitch = ddata.pitches[0]/sizeof(short);
					for (int y = 0; y < (int)dinfo.height; y++)
					{
						for (int x = 0; x < (int)dinfo.width; x++)
						{
							short d = dpixels[y*dpitch+x];
							if (d == invalids[0] || d == invalids[1]) continue;
							g_depthdata[x][y] = d;
						}
					}
					LeaveCriticalSection(&g_depthdataCS);
					g_bDepthdatafilled = true;
				}
				sample->depth->ReleaseAccess(&ddata);
			}
			pp->ReleaseFrame();
		}
	}
	pp->Close();
	pp->Release();
}

На первый взгляд, здесь многовато кода, но, если разобраться, вы увидите, что это просто несколько вызовов настройки, условный цикл и заключительная чистка перед возвращением к функции ThreadProc, вызвавшей этот код. Основная используемая переменная называется pp, это указатель диспетчера Intel RealSense SDK для наших основных действий. Примечание. Как было сказано выше, для повышения удобочитаемости кода из него удалено отслеживание ошибок, но на практике не следует создавать код, исходящий из того, что все без исключения вызовы Intel RealSense SDK будут успешными.

Первый фрагмент кода, который будет включать интересующие нас потоки, выглядит так:

pp->EnableStream(st,profile.imageInfo.width, profile.imageInfo.height, profile.frameRate.max);

Этот простой запрос включает тип потока с определенным разрешением и кадровой скоростью и отдает камере команду приготовиться к отправке нам этих необработанных данных. Следующая важная строка активирует диспетчер, чтобы он мог начать процесс получения данных:


MyHandler handler(hwndDlg);
if (pp->Init(&handler)>=PXC_STATUS_NO_ERROR

Класс MyHandler определен в исходном проекте raw_streams и происходит от класса PXCSenseManager: Handler. В случае успеха вы узнаете, что камера включена и передает поток данных.

Теперь нужно запустить условный цикл, который будет работать до тех пор, пока какое-либо внешнее воздействие не изменит условие цикла. В этом цикле мы будем получать данные потока последовательно по одному кадру. Для этого используется команда AcquireFrame.


	for (int nframes=0;g_bConnected==true;nframes++)
	{
		pxcStatus sts2=pp->AcquireFrame(synced);

Пока g_bConnected имеет значение true, мы будем делать это как можно быстрее в отдельном потоке, созданном для этой цели. Для получения фактических данных требуется еще несколько строк кода:


	PXCCapture::Sample *sample = (PXCCapture::Sample*)pp->QuerySample();

	short invalids[1];
	invalids[0] = pp->QueryCaptureManager()->QueryDevice()->QueryDepthSaturationValue();
	invalids[1] = pp->QueryCaptureManager()->QueryDevice()->QueryDepthLowConfidenceValue();

	PXCImage::ImageInfo dinfo=sample->depth->QueryInfo();
	PXCImage::ImageData ddata;
	if (sample->depth->AcquireAccess(	PXCImage::ACCESS_READ, PXCImage::PIXEL_FORMAT_DEPTH,&ddata)>=PXC_STATUS_NO_ERROR)

Первая команда получает от диспетчера образец указателя и использует его для получения указателя на фактические данные в памяти с помощью последней команды AcquireAccess. Код выполняет два запроса, чтобы узнать у диспетчера, какие значения соответствуют «насыщенному» пикселю и «недостоверному» пикселю. Оба этих условия могут возникнуть при получении данных глубины с камеры. Их следует игнорировать при интерпретации возвращенных данных. Основной результат этого кода: структура данных ddata теперь заполнена информацией, которая позволит нам получить прямой доступ к данным глубины (в этом примере). Изменив соответствующие параметры, можно получить доступ к данным потоков COLOR и IR, если они включены.

На этом фрагмент кода, относящийся к Intel RealSense SDK, завершен (от первого вызова инициализации до получения указателя на данные потока). Остальной код будет несколько привычнее для разработчиков, обладающих опытом создания программ для обработки изображений.


		EnterCriticalSection(&g_depthdataCS);
		memset ( g_depthdata, 0, sizeof(g_depthdata) );
		short *dpixels=(short*)ddata.planes[0];
		int dpitch = ddata.pitches[0]/sizeof(short);
		for (int y = 0; y < (int)dinfo.height; y++)
		{
			for (int x = 0; x < (int)dinfo.width; x++)
			{
				short d = dpixels[y*dpitch+x];
				if (d == invalids[0] || d == invalids[1]) continue;
				g_depthdata[x][y] = d;
			}
		}
		LeaveCriticalSection(&g_depthdataCS);

Обратите внимание, что важный объект сеанса, созданный ранее, используется для блокировки нашего потока, чтобы никакой другой поток не мог получить доступ к нашим глобальным переменным. Это делается для того, чтобы можно было написать глобальный массив и быть уверенным в том, что на работу не будет влиять код из другой части приложения. Если проследить вложенные циклы, вы увидите, что после блокировки потока мы очищаем глобальный массив g_depthdata и заполняем его значениями из упомянутой выше структуры ddata, которая содержит указатель на данные глубины. Во вложенных циклах мы также сравниваем значение пикселей глубины с двумя недопустимыми значениями, которые мы задали раньше с помощью вызовов QueryDepthSaturationValue и QueryDepthLowConf idenceValue.

После переноса данных в глобальный массив поток ЦП может получить следующий кадр из поточных данных, а главный поток ЦП может приступить к анализу этих данных и к принятию решений. Можно даже создать новый рабочий поток для выполнения этого анализа, что даст возможность приложению работать в трех потоках и эффективнее использовать ресурсы многоядерной архитектуры.

5. Что делать с данными потока

Итак, теперь вы знаете, как получить поток данных с камеры Intel RealSense 3D, и, наверное, интересуетесь, что делать с этими данными. Разумеется, можно просто вывести эти данные на экран и полюбоваться изображением, но вскоре потребуется преобразовать эти данные в полезную информацию и обработать ее в вашем приложении.

Как не существует двух одинаковых снежинок, так и все реализации необработанных потоков данных будут различаться, но все же существует несколько общих подходов, помогающих наладить анализ данных. Чтобы сократить объем нового кода, мы будем использовать приведенный выше код в качестве шаблона для примеров, предлагаемых ниже.

Найти ближайшую точку

Рекомендуется найти ближайшую к камере точку объекта, находящегося перед ней. При этом вы только что передали данные глубины из потока данных в глобальный массив в потоке ЦП. Можно создать вложенный цикл для проверки каждого значения в массиве:


short bestvalue = 0;
int bestx = 0;
int besty = 0;
for ( int y = 0; y < (int)dinfo.height; y++)
{
	for ( int x = 0; x < (int)dinfo.width; x++)
	{
		short thisvalue = g_depthdata[x][y];
		if ( thisvalue > bestvalue )
		{
			bestvalue = thisvalue;
			bestx = x;
			besty = y;
		}
	}
}

Каждый раз при обнаружении более близкого значения оно заменяет текущее наилучшее значение, при этом записываются координаты по осям X и Y. К тому моменту, когда цикл обойдет каждый пиксель в данных глубины, в итоговых переменных BESTX и BESTY будут храниться координаты данных глубины для ближайшей к камере точки.

Игнорировать объекты на заднем плане

Может потребоваться идентифицировать формы объектов переднего плана, но приложение не должно путать их с объектами на заднем плане, например с сидящим пользователем или с проходящими мимо людьми.


short newshape[dinfo.height][dinfo.width];
memcpy(newshape,0,sizeof(newshape));
for ( int y = 0; y < (int)dinfo.height; y++)
{
	for ( int x = 0; x < (int)dinfo.width; x++)
	{
		short thisvalue = g_depthdata[x][y];
		if ( thisvalue>32000 && thisvalue<48000 )
		{
			newshape[x][y] = thisvalue;
		}
	}
}

Если добавить условие при чтении каждого пикселя и передавать только те пиксели, которые находятся в пределах определенного диапазона, то из данных глубины можно извлекать объекты и передавать их во второй массив для дальнейшей обработки.

6. Подсказки и советы

Что следует делать

  • Если вы работаете с примерами впервые и используете ультрабук со встроенной камерой, то приложение может использовать эту встроенную камеру вместо камеры Intel RealSense. Убедитесь, что камера Intel RealSense правильно подключена и что ваше приложение использует устройство Intel® RealSense™ 3D camera. Для получения дополнительных сведений о том, как найти список устройств, см. ссылки на g_devices в этой статье.
  • Всегда старайтесь использовать многопоточные вычисления в приложении Intel RealSense: в этом случае приложение не будет «привязано» к кадровой скорости потока камеры Intel RealSense 3D, а на многоядерных системах будет достигнута более высокая производительность.

Чего не следует делать

  • Не задавайте жестко в коде параметры устройства или профиля при инициализации потоков, поскольку будущие камеры Intel RealSense 3D могут не поддерживать заданные вами параметры. Всегда следует перечислять доступные устройства и профили и использовать условия поиска, чтобы найти нужное.
  • Избегайте ненужной передачи данных во вторичные массивы, поскольку при каждом таком цикле расходуется немало ресурсов ЦП и памяти. Старайтесь, чтобы анализ данных был как можно ближе к первоначальной операции чтения данных..

7. Заключение

Знание того, как получить поток необработанных данных с камеры Intel RealSense 3D, поможет расширить возможности этой технологии и создавать современные решения. Мы уже видели великолепные приложения с управлением без помощи рук, созданные первыми разработчиками в этой области, но это лишь малая часть всех возможностей новых технологий.

Многие пользователи по-прежнему относятся к компьютерам как к устройствам, на которые следует активно воздействовать, чтобы они работали, но теперь компьютеры получили «зрение» и могут наблюдать за всеми нашими движениями. Не подсматривать, прошу заметить, а просто наблюдать, чтобы в нужный момент прийти на помощь. Согласно поговорке в стране слепых одноглазый станет королем. Разве неверно, что мы живем в мире, населенном «слепыми» компьютерами? Представьте, какая произойдет революция, если один из них в не столь отдаленном будущем «прозреет»? Будучи разработчиками, мы являемся архитекторами этой революции, вместе мы можем создать совершенно новую парадигму, в которой компьютеры видят своих операторов и стараются им помогать.

Об авторе

В свободное от написания статей время Ли Бэмбер (Lee Bamber) руководит британской компанией The Game Creators (http://www.thegamecreators.com), которая специализируется на разработке и распространении средств создания компьютерных игр. Эта компания ведет свою историю с 1999 года. Среди плодов работы этой компании вместе с окружающим ее разработчиком игр — множество популярных брендов, в том числе Dark Basic, FPS Creator, а также App Game Kit (AGK).

Ли ведет хронику своей повседневной работы разработчика вместе со снимками экрана и видеороликами: http://fpscreloaded.blogspot.co.uk

Планирование оптимизации с Unity*

$
0
0

By John Wesolowski

Загрузки

How To Plan Optimizations with Unity* [PDF 2.15MB]


Аннотация

Unity содержит ряд настроек и инструментов, позволяющих добиться плавной работы графики в играх. Для этого проекта мы отобрали те из них, с которыми могут возникнуть сложности, и проанализировали их влияние на производительность игр на ГП Intel®.

Мы рассматриваем использование Unity с точки зрения разработчика игр. Мы стремились найти области снижения производительности, а затем определить, как улучшить работу приложений с помощью встроенных в Unity средств. Одно из преимуществ Unity состоит в возможности быстрого создания контента, но для того, чтобы добиться производительности, особенно на мобильных устройствах и планшетах, разработчику потребуется тщательно спланировать использование встроенных механизмов оптимизации производительности. В этой статье новым и существующим пользователям Unity предлагаются советы по повышению производительности при создании уровней и игр, а также описываются новые способы создания содержимого.


Введение

Создавать игры с использованием Unity относительно просто. В Unity имеется магазин, где можно приобретать различные элементы, такие как модели, готовые сценарии, демо или даже полные игры. Для тестирования я работал с существующей игрой, чтобы определить, в каких областях можно добиться повышения производительности, а в каких — нет. Я использовал техническое демо Unity под названием Boot Camp (ее можно бесплатно загрузить в магазине ресурсов), чтобы оценить сложность проблемы.

Для создания игровых параметров и запуска всех сцен я использовал Unity 3.0. Тестирование проводилось на компьютере с процессором Intel® Core 3-го поколения с ГП Intel® HD Graphics 4000. Результаты тестирования неприменимы к мобильным устройствам.

Quality Manager

В Unity доступны дополнительные параметры рендеринга для игр: меню Edit->Project Settings->Quality (рис. 1). Это настраиваемые параметры рендеринга, которые можно настроить индивидуально. В Unity содержится встроенная документация, поясняющая параметры качества и их настройку с помощью API сценариев Unity.

Рисунок 1. Доступ к тегам и слоям осуществляется через меню Edit->Project Settings->Tag inspector

Для изыскания возможностей оптимизации в Unity я решил попробовать изменить настройки качества, чтобы понять, что при этом можно выиграть или потерять, хотя я не тестировал все доступные параметры.

Качество текстур

В Quality Settings Inspector есть раскрывающееся меню, где можно выбрать разрешение рендеринга для текстур. Можно выбрать разрешение 1/8, ¼, ½ или полное разрешение. Для оценки прироста или снижения производительности при разном разрешении текстур я измерил кадровую скорость тестовой сцены при всех доступных в Unity настройках качества по умолчанию (Fastest, Fast, Good и пр.), изменяя только качество текстур перед каждым измерением.

На рис. 2 и 3 показано сравнение между сценами с 1/8 разрешения текстур и с полным разрешением текстур.

Рисунок 2. Сцена Unity* Boot Camp с разрешением 1/8

Рисунок 3. Сцена Unity* Boot Camp с полным разрешением

Мы измерили кадровую скорость (в кадрах в секунду) с помощью Intel® Graphics Performance Analyzers (Intel® GPA) после изменения разрешения текстур. При уровне качества Fantastic (таблица 1) видно, что производительность не слишком заметно изменилась при изменении размера текстур.

Таблица 1. Изменение кадровой скорости при переключении между различным качеством текстур в Unity

На компьютерах с ГП Intel®производительность теоретически не изменяется в зависимости от размера текстур, но следует учитывать и другие факторы, такие как общий объем памяти устройства и использование памяти приложением.

Shadow Distance

Shadow Distance — это параметр, определяющий глубину отбраковки, используемую для теней игровых объектов. Если игровой объект находится в пределах заданного расстояния от камеры, то тени этого объекта отрисовы­ваются, если же объект находится дальше этого расстояния, то тени такого объекта не отображаются (исключаются из отрисовки).

В зависимости от используемых параметров тени могут отрицательно повлиять на производительность, поскольку их расчет и отрисовка являются ресурсоемкими операциями. Тестирование влияния параметра Shadow Distance

  • Создайте тестовую сцену.
  • Задайте для этой сцены параметры качества Unity по умолчанию.
  • Постепенно увеличивайте значение параметра Shadow Distance и измеряйте кадровую скорость с помощью Intel GPA.
  • Выберите другое значение качества по умолчанию в Unity и повторите измерение кадровой скорости.

В этом тесте уровни качества Fastest и Fast не использовались, поскольку в этих режимах тени отключены.


Рисунок 4. Этот параметр доступен в меню Inspector: Edit->Project Settings->Quality

Рисунок 5. Техническое демо Unity* Boot Camp

Таблица 2. Изменение кадровой скорости при изменении значения параметра Shadow Distance в технической демонстрации Unity* Boot Camp

Тени значительно влияют на производительность. Тест показал, что кадровая скорость упала почти вдвое при переключении расстояния с 0 до 50 в режиме Simple. Важно учитывать, действительно ли видны игровые объекты, и убедиться, что ненужные тени не отрисовываются. Глубину отбраковки теней можно настра­ивать с помощью сценариев Unity для различных ситуаций. Мы проверили только воздействие глубины отбраковки теней, но аналогичные изменения производи­тельности могут возникать и при настройке других параметров качества теней.

Слои

Всем игровым объектам в Unity при создании назначается слой. Изначально всем объектам назначается слой по умолчанию, как показано на рис. 6, но можно создать собственные уникальные слои. Это можно сделать двумя способами. Можно просто щелкнуть поле Layer и выбрать Add New Layer. Также можно использовать меню Edit->Project Settings->Tags.

Рисунок 6. Меню Layer в окне Inspector игрового объекта

Рисунок 7. Tag Manager в окне Inspector

В окне Inspector (рис. 7) можно создать новый слой и указать, к какому номеру слоя он должен принадлежать. При использовании обоих методов открывается одно и то же окно Tag Manager. После создания слоя можно назначать этому слою игровые объекты, выбирая нужный слой в окне параметров в окне Inspector игрового объекта в поле Layer. Таким способом можно группировать объекты на одних и тех же слоях, чтобы затем обрабатывать их вместе. Помните о том, что такое слои, и как их создавать и настраивать, когда я буду рассказывать о некоторых других функциях слоев в этой статье.

Расстояния отбраковки слоев

Камера не будет отрисовывать игровые объекты, находящиеся за пределами плоскости отсечения в Unity. С помощью сценариев Unity можно задать для определенных слоев более короткое расстояние до плоскости отсечения.

Рисунок 8. Образец сценария из документации Unity с изменением расстояния отбраковки слоев

Настройка более короткого расстояния отбраковки для игровых объектов требует некоторой работы. Сначала нужно разместить объекты на слое. Затем нужно написать сценарий, чтобы изменить расстояние отбраковки этого конкретного слоя, и назначить сценарий камере. Образец сценария на рис. 8 показывает, как создается массив 32 значений с плавающей запятой, соответствующий 32 доступ­ным слоям, которые можно создать с помощью меню Edit->Project Settings->Tags. Если изменить значение индекса в этом массиве и присвоить его camera.layerCullDistances, то для соответствующего слоя изменится расстояние отбраковки. Если не назначить число индексу, то соответствующий слой будет использовать дальнюю плоскость отсечения камеры.

Для тестирования производительности layerCullDistances я создал три сцены, заполненные объектами низкой, средней и высокой сложности. В этих сценах идентичные игровые объекты собраны вместе и расположены в ряд с постепенным удалением от камеры. Я использовал Intel GPA для измерения кадровой скорости при постепенном увеличении расстояния отбраковки слоя, добавляя по группе объектов при каждом измерении (т. е. одна группа объектов при первом измерении, 6 групп объектов при шестом измерении).

На рисунках 9, 10 и 11 показаны сцены, которые я использовал для тестирования с объектами разных типов.

Сапоги: полигонов — 278, вершин — 218

Рисунок 9. Тестовая сцена с сапогами — объектами с низким числом полигонов и вершин

Динозавры: полигонов — 4398, вершин — 4400

Рисунок 10. Тестовая сцена с динозаврами — объектами со средним числом полигонов и вершин

Самолеты: полигонов — 112 074, вершин — 65 946

Рисунок 11. Тестовая сцена с самолетами — объектами с большим числом полигонов и вершин

В таблицах 3, 4 и 5 показано изменение кадровой скорости во всех тестовых сценах.


Таблица 3. Данные, полученные в сцене с сапогами (рис. 9)

Таблица 4. Данные, полученные в сцене с динозаврами (рис. 10)

Таблица 5. Данные, полученные в сцене с самолетами (рис. 11)

Таблица 6. Данные всех тестовых сцен в режиме Fantastic

Эти данные показывают повышение производительности, которого можно добиться с помощью функции layerCullDistances в Unity

В таблице 6 показано, как производительность изменяется при увеличении количества объектов на экране, особенно если это сложные объекты. С точки зрения разработчика игр, правильное использование layerCullDistances позволяет значительно повысить производительность. Например, для маленьких объектов со сложной моделью, расположенных дальше от камеры, можно настроить отрисовку только при достаточном приближении, когда эти объекты уже можно различить. При планировании и создании уровней разработчику следует учитывать сложность моделей и видимость объектов, расположенных на большом расстоянии от камеры. Заблаговременное планирование позволяет добиться лучших результатов при использовании layerCullDistances.

Камера

Я изучил возможности работы с камерой в Unity и ее настройки. Я попробовал выбрать различные параметры, поработал с другими компонентами и дополнениями.


Рисунок 12. Меню Inspector, открывающееся после выбора камеры

При создании новой сцены по умолчанию появляется только один игровой объект камеры под названием Main Camera. Чтобы добавить еще одну камеру, сначала создайте пустой игровой объект: Game Object->Create Empty. Затем выберите этот пустой объект и добавьте компонент камеры: Components->Rendering->Camera.

Камеры в Unity поддерживают широкие возможности настройки, как показано на рис. 12. Вот какие настройки я рассмотрел: Rendering Path и HDR.

Render Path

С помощью параметра Render Path можно указать в Unity, как обрабатывать рендеринг света и теней в игре. В Unity поддерживаются три типа рендеринга, вот они в порядке от наиболее ресурсоемкого к наименее ресурсоемкому: Deferred (отложенная, только в Unity Pro), Forward (заблаговременная) и Vertex Lit (освещение вертексов). В каждом случае тени и свет обрабатываются немного иначе, и для их обработки требуется разный объем ресурсов ЦП и ГП. Важно понимать, для какой платформы и для какого оборудования ведется разработка, чтобы выбрать соответствующий рендерер. Если выбрать рендерер, который не поддерживается графическим адаптером, Unity автоматически переключится на менее ресурсоемкий способ рендеринга.

Рисунок 13. Окно Player Settings Inspector

Настроить значение Rendering Path можно двумя способами. Первый способ:
Edit->Project Settings->Player (рис. 13). Раскрывающийся список Rendering Path находится на вкладке Others Settings. Второй способ: с помощью окна пользовательского интерфейса Camera Inspector (рис. 14). Если выбрать любой параметр, отличный от Use Player Settings, настройки по умолчанию будут заменены, но только для данной камеры. Поэтому можно использовать разные камеры с различными настройками буфера рендеринга для света и теней.

Рисунок 14. Раскрывающийся список при выборе параметра Rendering Path в окне Camera

Разработчики должны знать, каким образом действуют различные режимы рендеринга освещения, входящие в состав Unity. В разделе справочных материалов в конце этого документа приводятся ссылки на документацию по Unity. Убедитесь, что вы точно знаете целевую аудиторию своей игры и платформу, на которой потенциальные пользователи будут играть в эту игру. Это поможет вам выбрать соответствующий способ рендеринга для данной платформы. Например, если игра содержит несколько источников света и графических эффектов, использующих отложенный рендеринг, то на компьютерах с маломощным графическим адаптером играть в такую игру будет попросту невозможно. Если ваша целевая аудитория включает любителей казуальных игр, устройства которых не обладают высокой вычислительной мощью, то также могут возникнуть проблемы. Разработчики должны знать целевую платформу, для которой предназначена их игра, и соответственным образом выбирать способ рендеринга и обработки освещения в игре.

HDR (High Dynamic Range)

При обычном рендеринге значения красного (R), зеленого (G) и синего (B) цветов каждого пикселя представлены десятичным числом, значение которого составляет от 0 до 1. Если ограничить диапазон значений для этих цветов, освещение будет выглядеть нереалистично. Чтобы добиться более естественного освещения, в Unity можно включить расширенный динамический диапазон (HDR). В этом случае значения R, G и B каждого пикселя могут выходить за пределы обычного диапазона. HDR создает буфер изображения, поддерживающий значения вне диапазона от 0 до 1, и выполняет постобработку графических эффектов, таких как размытие и блики. После вычисления эффектов постобработки значения R, G и B в буфере изображения сбрасываются до значений в пределах диапазона от 0 до 1 технологией построения карт оттенков Unity. Если построение карт оттенков не выполняется при использовании HDR, то пиксели могут оказаться за пределами допустимого диапазона, из-за чего некоторые цвета сцены могут выглядеть неправильно по сравнению с остальными.

При использовании HDR следите за параметрами, влияющими на производительность. При использовании заблаговременного рендеринга сцены HDR будет работать только при наличии графических эффектов. В противном случае включение HDR ни на что не повлияет. При отложенном рендеринге HDR всегда используется.

Если сцена обрабатывается с помощью отложенного рендеринга, а камере присвоены графические эффекты, то следует включить HDR. На рис. 15 сравнивается количество вызовов рендеринга для сцены с эффектами и отложенным рендерингом при включенном и отключенном HDR. Без HDR количество вызовов рендерингазначительно выше, чем при использовании HDR, если сцена содержит эффекты. На рис. 15 количество вызовов рендеринга представлено отдельными синими полосками, а высота каждой полоски соответствует величине нагрузки каждого вызова на ГП.


Рисунок 15. Измерение, проведенное с помощью Intel® Graphics Performance Analyzers, показывает, что при отключенном HDR выполняется свыше 2000 вызовов рендеринга, тогда как при включенном HDR — немногим более 900 вызовов рендеринга.

Ознакомьтесь с документацией Unity по HDR, чтобы понять, как работает эта функциональность. Также нужно знать, в каких случаях следует применять расширенный динамический диапазон, чтобы получить за счет этого прирост производительности, а в каких случаях это не имеет смысла.

Графические эффекты

В Unity Pro содержится ряд графических эффектов, которыеулучшают вид сцены. Чтобы добавить компонент Image Effects после создания проекта, используйте меню Assets->Import Package->Image Effects. После импорта можно добавить эффект к камере двумя способами. Щелкните игровой объект камеры, в окне камеры выберите Add Component, а затем Image Effects. Также можно щелкнуть объект камеры в меню, выбрав Component->Image Effect.

Рассеянное затенение в экранном пространстве — SSAO

 

Рассеянное затенение в экранном пространстве (SSAO) — это графический эффект в составе пакета Image Effect в Unity Pro. На рис. 16 показано различие между включенным и отключенным SSAO. Изображения выглядят схоже, но производительность существенно различается. У сцены без SSAO кадровая скорость составила 32 кадра в секунду, а с SSAO — 24 кадра в секунду, то есть на 25 % ниже.


Рисунок 16. Сравнение одного и того же уровня с отключенным SSAO (сверху) и с включенным SSAO (снизу)

Будьте осторожны при добавлении графических эффектов, поскольку они могут отрицательно повлиять на производительность. При подготовке этого документа мы тестировали только SSAO, но следует ожидать схожих результатов и при использовании других эффектов.

Исключение заслоненных объектов

Исключение заслоненных объектов — это отключение рендеринга не только тех объектов, которые находятся за плоскостью отсечения камеры, но также и объектов, скрытых за другими объектами. Это очень выгодно с точки зрения производительности, поскольку значительно сокращается объем информации, которую следует обработать. Тем не менее, настройка исключения заслоненных объектов происходит не слишком просто. Перед настройкой сцены для исключения заслоненных объектов следует разобраться с используемой терминологией.

Заслоняющий объект — объект, помеченный как заслоняющий, выступает в качестве преграды: все загороженные им объекты, помеченные как заслоняемые, не отрисовываются.

Заслоняемый объект — если пометить объект таким образом, он не будет отрисовываться в Unity, если его загораживает заслоняющий объект.

Например, если пометить все объекты, находящиеся внутри дома, как заслоняемые, то сам дом можно пометить как заслоняющий. Если игровой персонаж будет находиться снаружи этого дома, то все объекты внутри дома, помеченные как заслоняемые, не будут отрисовываться. При этом ускоряется обработка на ЦП и ГП.

Использование и настройка исключения заслоненных объектов задокументированы в Unity. Ссылку на информацию по настройке см. в разделе справочных материалов.

Для демонстрации изменения производительности (в зависимости от исключения заслоненных объектов) я создал сцену, где на переднем плане находится стена, а за ней — объекты со сложными моделями. Я измерил кадровую скорость сцены с исключением заслоненных объектов, а затем без него. На рис. 17 показана сцена с разной кадровой скоростью.


Рисунок 17. На изображении слева исключение заслоненных объектов отключено, отрисовываются все объекты, расположенные за стеной, поэтому кадровая скорость составляет 31 кадр в секунду. На изображении справа исключение заслоненныхобъектов включено, объекты, заслоненные стеной, не отрисовываются, поэтому скорость возросла до 126 кадров в секунду.

Исключение заслоненных объектов должно быть настроено разработчиками вручную. Не следует забывать об исключении заслоненных объектов при проектировании игр, поскольку это снижает требования к оборудованию и позволяет повысить производительность.

Уровень детализации (LOD)

С помощью уровня детализации (LOD) можно присвоить одному игровому объекту несколько моделей разной сложности и переключаться между ними в зависимости от расстояния между объектом и камерой. Это может быть выгодно с точки зрения производительности для сложных игровых объектов, находящихся далеко от камеры. С помощью уровня детализации можно автоматически упрощать модели. Сведения об использовании и настройке уровня детализации см. в документации Unity. Ссылка приведена в разделе справочных материалов.

Для тестирования прироста производительности при изменении уровня детализации я создал сцену с группой домов, которым присвоено 3 разные модели. Расположив камеру в одном и том же месте, я измерил кадровую скорость сцены с домами при использовании самой сложной модели. Затем я изменил расстояние детализации, чтобы задействовать модели с меньшей степенью детализации, и провел измерение еще раз. Я проделал эту процедуру для трех уровней моделей и записал полученные данные в таблице 5.

На рис. 18, 19 и 20 показаны три разных уровня сложности моделей с указанием количества полигонов и вершин в каждой модели.

 

Наилучшее качество — уровень детализации 0

Здание А

Вершин — 7065

Полигонов – 4999

Здание Б

Вершин — 5530

Полигонов – 3694

Рисунок 18. Уровень детализации 0. Это наивысший уровень детализации, на котором используются самые сложные модели

 

Среднее качество — уровень детализации 1

Здание А

Вершин — 6797

Полигонов — 4503

Здание Б

Полигонов — 5476

Вершин — 3690

Рисунок 19. Уровень детализации 1. Этот уровень находится на одну ступень ниже по шкале детализации, на нем используются модели средней сложности

   

Низкое качество — уровень детализации 2

Здание А

Вершин — 474

Полигонов – 308

Здание Б

Полигонов – 450

Вершин — 320

Рисунок 20. Уровень детализации 2. Это последний уровень детализации, здесь используются наименее сложные модели

Переключаясь между разными уровнями детализации, я измерял кадровую скорость для сравнения (таблица 7).

Таблица 7. Сравнение кадровой скорости при разных уровнях детализации

В таблице 7 видно повышение производительности при настройке и использовании разных уровней детализации. Кадровая скорость значительно возрастает при переключении на менее сложные модели. Впрочем, при этом увеличивается объем работы художников, которым придется создавать несколько моделей каждого объекта. Проектировщики игр должны сами принимать решение о том, следует ли затратить дополнительное время на рисование добавочных моделей, чтобы за счет этого добиться повышения производительности.

Пакетная обработка

Избыточное количество вызовов рендеринга может привести к чрезмерной нагрузке на ЦП и снижению производительности. Чем больше на экране объектов, тем больше вызовов рендеринга нужно сделать. В Unity поддерживается так называемая пакетная обработка, позволяющая поместить несколько игровых объектов в один вызов рендеринга. Статическая пакетная обработка предназначена для статических объектов, а динамическая — для движущихся объектов. Динамическая пакетная обработка выполняется автоматически при выполнении всех требований (см. документацию по пакетной обработке), а статическую пакетную обработку требуется задавать вручную.


Существуют определенные требования для совместного рендеринга объектов и для динамической, и для статической пакетной обработки. Все эти требования перечислены в документе по пакетной обработке, ссылка на который приведена в разделе справочных материалов.


Для тестирования прироста производительности при статической пакетной обработке я создал сцену со сложными игровыми объектами в виде самолетов (рис. 21) и измерил кадровую скорость с пакетной обработкой и без нее (таблица 8).

 

Рисунок 21. Статическая пакетная обработка тестовой сцены с очень сложными моделями самолета


Таблица 8. Разница в кадровой скорости и количестве вызовов рендерингапри включенной и отключенной статической пакетной обработке (рис. 21)

В Unity поддерживается два типа пакетной обработки, динамическая и статическая. Для получения наибольшего преимущества от пакетной обработки старайтесь объединить как можно больше объектов в пакет для одного вызова рендеринга. Сведения о том, какие объекты подходят для динамической или статической пакетной обработки, см. в документации Unity.

Заключение

В Unity можно без особого труда начать работу над проектами, но с не меньшей легкостью можно и допустить недостаточную производительность приложений. В Unity поддерживается ряд настроек и инструментов, позволяющих добиться плавной графики в играх, но не все эти средства удобно настраиваются и интуитивно понятны. Кроме того, некоторые настройки в Unity при их включении или неверном использовании могут отрицательно повлиять на производительность игр. При разработке с использованием Unity важно заранее подготовить план, поскольку для некоторых функций, связанных с производительностью, требуется настройка вручную, которая может оказаться значительно труднее, если не запланировать ее заблаговременно (при создании проекта).

Справочные материалы

Документация по параметрам качества:

http://docs.unity3d.com/Documentation/Components/class-QualitySettings.html

API сценариев для параметров качества:
http://docs.unity3d.com/Documentation/ScriptReference/QualitySettings.html

Техническая демонстрация Boot Camp:
http://u3d.as/content/unity-technologies/bootcamp/28W

Документация по уровню детализации:
http://docs.unity3d.com/Documentation/Manual/LevelOfDetail.html

Документация по исключению скрытых частей:
http://docs.unity3d.com/Documentation/Manual/OcclusionCulling.html

Документация по пакетной обработке:
http://docs.unity3d.com/Documentation/Manual/DrawCallBatching.html

Документация по параметру Rendering Path:
http://docs.unity3d.com/Documentation/Manual/RenderingPaths.html

Intel GPA:
http://software.intel.com/en-us/vcsource/tools/intel-gpa

Other Related Content and Resources

Unity MultiTouch Source (finally)
http://software.intel.com/en-us/blogs/2013/05/01/the-unity-multi-touch-source-finally

Implementing Multiple Touch Gestures Using Unity3D With Touchscript
http://software.intel.com/en-us/articles/implementing-multiple-touch-gestures-using-unity-3d-with-touchscript

Multithreading Perceptual Computing Applications in Unity3D
http://software.intel.com/en-us/blogs/2013/07/26/multithreading-perceptual-computing-applications-in-unity3d

Unity3D Touch GUI Widgets
http://software.intel.com/en-us/articles/unity-3d-touch-gui-widgets

Об авторе

Джон Весоловски, стажер

Задачей группы, в которой я работал в Intel, была подготовка наборов микросхем Intel®для перспективных технологий с упором на видеоигры. Мы должны были тестировать самые последние и будущие видеоигры, чтобы обнаруживать возможные ошибки или области для дальнейшего улучшения в архитектуре Intel®и в самих играх.

Вне работы мне всегда нравилось играть в Halo* 2 с друзьями через Интернет, но, поскольку в Майкрософт отключили Xbox LIVE* для игр для первой консоли Xbox*, мы с друзьями играем в Halo 2 по локальной сети, когда собираемся вместе. Еще мне нравится играть в покер и запускать воздушные змеи. Сейчас я учусь в университете штата Калифорния в Монтерей-Бэй, моя специальность — компьютерные науки и информационные технологии.

Примечания

ИНФОРМАЦИЯ В ДАННОМ ДОКУМЕНТЕ ПРИВЕДЕНА ТОЛЬКО В ОТНОШЕНИИ ПРОДУКТОВ INTEL. ДАННЫЙ ДОКУМЕНТ НЕ ПРЕДОСТАВЛЯЕТ ЯВНОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ЛИЦЕНЗИИ, ЛИШЕНИЯ ПРАВА ВОЗРАЖЕНИЯ ИЛИ ИНЫХ ПРАВ НА ИНТЕЛЛЕКТУАЛЬНУЮ СОБСТВЕННОСТЬ. КРОМЕ СЛУЧАЕВ, УКАЗАННЫХ В УСЛОВИЯХ И ПРАВИЛАХ ПРОДАЖИ ТАКИХ ПРОДУКТОВ, INTEL НЕ НЕСЕТ НИКАКОЙ ОТВЕТСТВЕННОСТИ И ОТКАЗЫВАЕТСЯ ОТ ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ В ОТНОШЕНИИ ПРОДАЖИ И/ИЛИ ИСПОЛЬЗОВАНИЯ СВОИХ ПРОДУКТОВ, ВКЛЮЧАЯ ОТВЕТСТВЕННОСТЬ ИЛИ ГАРАНТИИ ОТНОСИТЕЛЬНО ИХ ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ, ОБЕСПЕЧЕНИЯ ПРИБЫЛИ ИЛИ НАРУШЕНИЯ КАКИХ-ЛИБО ПАТЕНТОВ, АВТОРСКИХ ПРАВ ИЛИ ИНЫХ ПРАВ НА ИНТЕЛЛЕКТУАЛЬНУЮ СОБСТВЕННОСТЬ.

КРОМЕ СЛУЧАЕВ, СОГЛАСОВАННЫХ INTEL В ПИСЬМЕННОЙ ФОРМЕ, ПРОДУКТЫ INTEL НЕ ПРЕДНАЗНАЧЕНЫ ДЛЯ ИСПОЛЬЗОВАНИЯ В СИТУАЦИЯХ, КОГДА ИХ НЕИСПРАВНОСТЬ МОЖЕТ ПРИВЕСТИ К ТРАВМАМ ИЛИ ЛЕТАЛЬНОМУ ИСХОДУ.

Корпорация Intel оставляет за собой право вносить изменения в технические характеристики и описания своих продуктов без предварительного уведомления. Проектировщики не должны полагаться на отсутствующие характеристики, а также характеристики с пометками «зарезервировано» или «не определено». Эти характеристики резервируются Intel для будущего использования, поэтому отсутствие конфликтов совместимости для них не гарантируется. Информация в данном документе может быть изменена без предварительного уведомления. Не используйте эту информацию в окончательном варианте дизайна.

Продукты, описанные в данном документе, могут содержать ошибки и неточности, из-за чего реальные характеристики продуктов могут отличаться от приведенных здесь. Уже выявленные ошибки могут быть предоставлены по запросу.

Перед размещением заказа получите последние версии спецификаций в региональном офисе продаж Intel или у местного дистрибьютора.

Копии документов с порядковым номером, ссылки на которые содержатся в этом документе, а также другую литературу Intel можно получить, позвонив по телефону
1-800-548-47-25 либо на сайте http://www.intel.com/design/literature.htm

Программное обеспечение и нагрузки, использованные в тестах производительности, могли быть оптимизированы для достижения высокой производительности на микропроцессорах Intel. Тесты производительности, такие как SYSmark* и MobileMark*, проводятся на определенных компьютерных системах, компонентах, программах, операциях и функциях. Любые изменения любого из этих элементов могут привести к изменению результатов. При выборе приобретаемых продуктов следует обращаться к другой информации и тестам производительности, в том числе к тестам производительности определенного продукта в сочетании с другими продуктами.

Данный документ и описываемое в нем программное обеспечение предоставляются по лицензии и могут использоваться и распространяться только согласно условиям лицензии.

Intel и эмблема Intel являются товарными знаками корпорации Intel в США и в других странах. © Intel Corporation, 2014. Все права защищены.

* Прочие наименования и товарные знаки могут быть собственностью третьих лиц.

Viewing all 156 articles
Browse latest View live