LampArray 効果
ゲーム ループ内で ILampArray カラー関数を呼び出して、エフェクトとアニメーションを生成します。 このページでは、いくつかの例を示します。
簡単にするために、これらの例では、可能であれば ILampArray::SetColor を使用して、デバイス上のすべてのランプに色を適用します。 ILampArray::SetColorsForIndices を使用して、個々のランプまたはランプのセットで効果を生成できます。
フェードと点滅
色の RGB 値に時間間隔で増加または減少するパーセンテージを掛けて、ランプをフェード インまたはフェード アウトします。 ランプのフェードインとフェードアウトを繰り返して、点滅、呼吸、または点滅効果を作成します。
次の例では、LampArray のすべてのランプをオンまたはオフに点滅させます。
uint32_t currentFrame = 0;
// The total number of frames in one blink
const float blinkFrameCount = 90;
const float blinkFadeFrameCount = blinkFrameCount / 2;
// The color to fade in and out. In this example we'll use red.
const LampArrayColor mainColor = {0xFF /* r */, 0x0 /* g */, 0x0 /* b */, 0xFF /* a */};
Microsoft::WRL::ComPtr<ILampArray> lampArray;
void BlinkUpdateFrame(ILampArray* lampArrayToUpdate)
{
LampArrayColor currentFrameColor = mainColor;
float colorScale = 1.0;
if (currentFrame < blinkFadeFrameCount)
{
// Fade out to black
colorScale = (blinkFadeFrameCount - currentFrame) / blinkFadeFrameCount;
}
else
{
// Fade in to full color value
colorScale = (currentFrame - blinkFadeFrameCount) / blinkFadeFrameCount;
}
currentFrameColor.r = static_cast<uint8_t>(mainColor.r * colorScale);
currentFrameColor.g = static_cast<uint8_t>(mainColor.g * colorScale);
currentFrameColor.b = static_cast<uint8_t>(mainColor.b * colorScale);
// Apply the color
lampArrayToUpdate->SetColor(currentFrameColor);
// Increment our current frame, accounting for overflow
if (++currentFrame > blinkFrameCount)
{
currentFrame = 0;
}
}
void MainLoop(
_In_ volatile bool& terminateLoop)
{
color.a = 0xFF;
while (!terminateLoop)
{
Sleep(50);
BlinkUpdateFrame(lampArray.Get());
}
}
カラー サイクル
色の赤、緑、青の値を徐々に増やしたり減らしたりして、色のサイクルを作成します。 これにより、RGB スペクトルの広範囲の色がブレンドされます。
次の例では、LampArray で RGB カラー サイクルを実行します。
uint32_t currentFrame = 0;
// The total number of frames in one cycle
const float cycleFrameCount = 180;
// The size of each "ramp" of the cycle (blending from one color to the next)
const float rampIntervalFrameCount = cycleFrameCount / 6;
// The color to set in each frame
LampArrayColor color = {};
Microsoft::WRL::ComPtr<ILampArray> lampArray;
void CycleUpdateFrame(ILampArray* lampArrayToUpdate)
{
// Calculate the color for the current frame.
if (currentFrame < rampIntervalFrameCount)
{
// Red -> yellow: increase g
color.r = 0xFF;
color.g = static_cast<BYTE>(0xFF * (currentFrame / rampIntervalFrameCount));
}
else if (currentFrame < (2 * rampIntervalFrameCount))
{
// Yellow -> green: decrease r
color.r = static_cast<BYTE>(0xFF * (((2 * rampIntervalFrameCount) - currentFrame) / rampIntervalFrameCount));
color.g = 0xFF;
}
else if (currentFrame < (3 * rampIntervalFrameCount))
{
// Green -> cyan: increase b
color.g = 0xFF;
color.b = static_cast<BYTE>(0xFF * ((currentFrame - (2 * rampIntervalFrameCount)) / rampIntervalFrameCount));
}
else if (currentFrame < (4 * rampIntervalFrameCount))
{
// Cyan -> blue: decrease g
color.g = static_cast<BYTE>(0xFF * (((4 * rampIntervalFrameCount) - currentFrame) / rampIntervalFrameCount));
color.b = 0xFF;
}
else if (currentFrame < (5 * rampIntervalFrameCount))
{
// Blue -> magenta: increase r
color.r = static_cast<BYTE>(0xFF * ((currentFrame - (4 * rampIntervalFrameCount)) / rampIntervalFrameCount));
color.b = 0xFF;
}
else
{
// Magenta -> red: decrease b
color.r = 0xFF;
color.b = static_cast<BYTE>(0xFF * ((cycleFrameCount - currentFrame) / rampIntervalFrameCount));
}
// Apply the color
lampArrayToUpdate->SetColor(color);
// Increment our current frame, accounting for overflow
if (++currentFrame > cycleFrameCount)
{
currentFrame = 0;
}
}
void MainLoop(
_In_ volatile bool& terminateLoop)
{
color.a = 0xFF;
while (!terminateLoop)
{
Sleep(50);
CycleUpdateFrame(lampArray.Get());
}
}
位置ベースのエフェクト
波紋や波など、デバイス全体を移動するように見える効果を作成する場合は、ILampInfo::GetPosition と ILampArray::GetBoundingBox を使用します。
次の例では、デバイス全体で左から右に移動するフェード アウト ランプの波を作成します。 「フェードと点滅」セクションのスケーリングの概念が組み込まれていることに注意してください。ただし、ランプごとに適用されます。
Microsoft::WRL::ComPtr<ILampArray> lampArray;
uint32_t currentFrame = 0;
// The total number of frames in one wave
const uint32_t waveFrameCount = 30;
// The number of frames it takes for each Lamp to fade out
const uint32_t fadeDurationInFrames = 10;
// Helper class for per-Lamp effect state information
struct LampContext
{
uint32_t lampIndex;
// How far to the right this Lamp is located compared to the total length of the device.
float xPercentage;
// The number of frames left in this Lamp's fade-out
uint32_t fadeFramesRemaining;
};
std::vector<LampContext> lampContexts;
// The Lamp indices for the device, in sorted order by position from left to right
std::vector<uint32_t> indices;
// The colors to set in each frame
std::vector<LampArrayColor> colors;
// The index in the sorted array representing the peak of the wave
uint32_t lastUpdatedIndex = 0;
// The base color to use in the wave effect
const LampArrayColor mainColor = {0xFF /* r */, 0x0 /* g */, 0x0 /* b */, 0xFF /* a */};
void WaveUpdateFrame(ILampArray* lampArrayToUpdate)
{
float framePercentage = (float)currentFrame / (float)myFrameCount;
const uint32_t lampCount = lampArrayToUpdate->GetLampCount();
for (uint32_t i = 0; i < lampCount; i++)
{
auto& lampContext = lampContexts[i];
// Mark any Lamps for which we should start a new fade-out.
// Use lastUpdatedIndex to track which Lamps we've started in this wave.
if (i >= lastUpdatedIndex && lampContext.xPercentage <= framePercentage)
{
lastUpdatedIndex = i;
// This Lamp should start at full brightness on this frame.
lampContext.fadeFramesRemaining = fadeDurationInFrames + 1;
}
// Process fade-outs for any Lamps that have fade-out frames remaining
if (lampContext.fadeFramesRemaining > 0)
{
lampContext.fadeFramesRemaining--;
// Optimization: use the full strength color for the first fade-out frame (without scaling)
if (lampContext.fadeFramesRemaining == fadeDurationInFrames)
{
colors[i] = mainColor;
}
else
{
// Scale the main color down based on how many fade-out frames are remaining for this Lamp.
float scaleFactor = (float)lampContext.fadeFramesRemaining / (float)fadeDurationInFrames;
auto& lampColor = colors[i];
lampColor.r = static_cast<BYTE>(scaleFactor * mainColor.r);
lampColor.g = static_cast<BYTE>(scaleFactor * mainColor.g);
lampColor.b = static_cast<BYTE>(scaleFactor * mainColor.b);
}
}
}
// Apply the color
lampArrayToUpdate->SetColorsForIndices(lampCount, indices.data(), colors.data());
// Increment our current frame, accounting for overflow
if (++currentFrame > waveFrameCount)
{
currentFrame = 0;
// The peak of the wave also needs to wrap around
lastUpdatedIndex = 0;
}
}
HRESULT MainLoop(
_In_ volatile bool& terminateLoop)
{
color.a = 0xFF;
// Set up contexts
const uint32_t lampCount = lampArray->GetLampCount();
for (uint32_t i = 0; i < lampCount; i++)
{
LampContext context = {};
context.lampIndex = i;
Microsoft::WRL::ComPtr<ILampInfo> lampInfo;
RETURN_IF_FAILED(lampArray->GetLampInfo(i, &lampInfo));
LampArrayPosition lampPosition = {};
lampInfo->GetPosition(&lampPosition);
// Our position values will be relative to the total length of the device.
context.xPercentage = (float)lampPosition.xInMeters / (float)boundingBox.xInMeters;
lampContexts.push_back(context);
}
// Sort the contexts by position from left to right
std::sort(lampContexts.begin(),
lampContexts.end(),
[](LampContext const& a, LampContext const& b)
{
return a.xPercentage < b.xPercentage;
});
// Set up our indices buffer in sorted order
for (uint32_t i = 0; i < lampCount; i++)
{
indices[i] = lampContexts[i].lampIndex;
}
colors.resize(lampCount);
// Animation loop for the sample
while (!terminateLoop)
{
Sleep(33);
WaveUpdateFrame(lampArray.Get());
}
return S_OK;
}