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;
}