Fixed more UV coordinate issues in the warp shader.

Main issue was a wrong -, replaced with + in the rotation calculation. Plus we shouldn't negate the Y pos, as this may mess up UV calculations done in HLSL.
This commit is contained in:
Kai Blaschke
2023-03-22 17:24:28 +01:00
parent 2707a1d221
commit 75fe0f0ede
14 changed files with 130 additions and 119 deletions

View File

@ -16,7 +16,7 @@ void Filters::Draw()
glEnable(GL_BLEND);
m_presetState.untexturedShader.Bind();
m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped);
glBindVertexArray(m_vaoID);
glVertexAttrib4f(1, 1.0, 1.0, 1.0, 1.0);

View File

@ -139,6 +139,9 @@ void FinalComposite::InitializeMesh(const PresetState& presetState)
return;
}
float const halfTexelWidth = 0.5f / static_cast<float>(presetState.renderContext.viewportSizeX);
float const halfTexelHeight = 0.5f / static_cast<float>(presetState.renderContext.viewportSizeY);
float const dividedByX = 1.0f / static_cast<float>(compositeGridWidth - 2);
float const dividedByY = 1.0f / static_cast<float>(compositeGridHeight - 2);
@ -147,18 +150,19 @@ void FinalComposite::InitializeMesh(const PresetState& presetState)
for (int gridY = 0; gridY < compositeGridHeight; gridY++)
{
int const gridY2 = gridY - gridY / (compositeGridHeight / 2);
float v = gridY2 * dividedByY;
v = SquishToCenter(v, 3.0f);
float sy = -((v) *2 - 1);
float const v = SquishToCenter(gridY2 * dividedByY, 3.0f);
float const sy = -((v - halfTexelHeight) * 2.0f - 1.0f);
for (int gridX = 0; gridX < compositeGridWidth; gridX++)
{
int i2 = gridX - gridX / (compositeGridWidth / 2);
float u = i2 * dividedByX;
u = SquishToCenter(u, 3.0f);
float sx = (u) *2 - 1;
auto& pComp = m_vertices.at(gridX + gridY * compositeGridWidth);
pComp.x = sx;
pComp.y = sy;
int const gridX2 = gridX - gridX / (compositeGridWidth / 2);
float const u = SquishToCenter(gridX2 * dividedByX, 3.0f);
float const sx = (u - halfTexelWidth) * 2.0f - 1.0f;
auto& vertex = m_vertices.at(gridX + gridY * compositeGridWidth);
vertex.x = sx;
vertex.y = sy;
float rad;
float ang;
@ -227,11 +231,11 @@ void FinalComposite::InitializeMesh(const PresetState& presetState)
ang = PI * 0.0f;
}
}
pComp.u = u;
pComp.v = 1.0f - v;
vertex.u = u;
vertex.v = v;
pComp.radius = rad;
pComp.angle = ang;
vertex.radius = rad;
vertex.angle = ang;
}
}
@ -254,8 +258,8 @@ void FinalComposite::InitializeMesh(const PresetState& presetState)
bool const leftHalf = (gridX < compositeGridWidth / 2);
bool const topHalf = (gridY < compositeGridHeight / 2);
bool const center4 = ((gridX == compositeGridWidth / 2 || gridX == compositeGridWidth / 2 - 1) &&
(gridY == compositeGridHeight / 2 || gridY == compositeGridHeight / 2 - 1));
bool const center4 = ((gridX == compositeGridWidth / 2) &&
(gridY == compositeGridHeight / 2));
if ((static_cast<int>(leftHalf) + static_cast<int>(topHalf) + static_cast<int>(center4)) % 2 == 1)
{

View File

@ -81,16 +81,18 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio
{
m_isFirstFrame = true;
}
m_state.mainTexture = m_framebuffer.GetColorAttachmentTexture(m_previousFrameBuffer, 0);
m_framebuffer.MaskDrawBuffer(1, true);
// First evaluate per-frame code
PerFrameUpdate();
m_framebuffer.Bind(m_previousFrameBuffer);
// Motion vector field. Drawn to the previous frame texture before warping it.
// Only do it after drawing one frame after init or resize.
if (!m_isFirstFrame)
{
m_framebuffer.Bind(m_previousFrameBuffer);
m_motionVectors.Draw(m_perFrameContext, m_framebuffer.GetColorAttachmentTexture(m_previousFrameBuffer, 1));
}
@ -103,6 +105,7 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio
// Draw previous frame image warped via per-pixel mesh and warp shader
m_perPixelMesh.Draw(m_state, m_perFrameContext, m_perPixelContext);
m_framebuffer.MaskDrawBuffer(1, true);
// Update blur textures
@ -128,7 +131,7 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio
// Todo: Song title anim would go here
// We no longer need the previous frame image, as the composite shader reads from the current frame image.
// We no longer need the previous frame image, use it to render the final composite.
m_framebuffer.BindRead(m_currentFrameBuffer);
m_framebuffer.BindDraw(m_previousFrameBuffer);
m_state.mainTexture = m_framebuffer.GetColorAttachmentTexture(m_currentFrameBuffer, 0);
@ -140,8 +143,10 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio
// TEST: Copy result to default framebuffer
m_framebuffer.BindRead(m_previousFrameBuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, renderContext.viewportSizeX, renderContext.viewportSizeY,
renderContext.viewportSizeX, renderContext.viewportSizeY,0, 0,
0, 0, renderContext.viewportSizeX, renderContext.viewportSizeY,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Swap framebuffers for the next frame.
@ -211,9 +216,9 @@ void MilkdropPreset::Load(std::istream& stream)
void MilkdropPreset::InitializePreset(PresetFileParser& parsedFile)
{
// Create the offscreen rendering surfaces.
m_framebuffer.CreateColorAttachment(0, 0); // Main image
m_framebuffer.CreateColorAttachment(0, 0); // Main image
m_framebuffer.CreateColorAttachment(0, 1, GL_RG16F, GL_RG, GL_FLOAT); // Motion vector u/v
m_framebuffer.CreateColorAttachment(1, 0); // Main image
m_framebuffer.CreateColorAttachment(1, 0); // Main image
m_framebuffer.CreateColorAttachment(1, 1, GL_RG16F, GL_RG, GL_FLOAT); // Motion vector u/v
// Mask the motion vector buffer by default.

View File

@ -96,11 +96,6 @@ private:
auto ParseFilename(const std::string& filename) -> std::string;
/**
* @brief Draws the composite shader quad to create the final output image.
*/
void ApplyCompositeShader();
std::string m_absoluteFilePath; //!< The absolute file path of the MilkdropPreset
std::string m_absolutePath; //!< The absolute path of the MilkdropPreset

View File

@ -120,7 +120,7 @@ void MilkdropShader::LoadVariables(const PresetState& presetState, const PerFram
m_shader.Bind();
m_shader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
m_shader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped);
m_shader.SetUniformFloat4("rand_frame", {floatRand(),
floatRand(),

View File

@ -86,7 +86,7 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_motionVectorShader.Bind();
m_motionVectorShader.SetUniformMat4x4("vertex_transformation", m_presetState.orthogonalProjection);
m_motionVectorShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
m_motionVectorShader.SetUniformFloat("length_multiplier", static_cast<float>(*presetPerFrameContext.mv_l));
m_motionVectorShader.SetUniformFloat("minimum_length", minimumLength);

View File

@ -33,13 +33,15 @@ void PerPixelMesh::InitVertexAttrib()
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
// Only position & texture coordinates are per-vertex, colors are equal all over the grid (used for decay).
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, x))); // Position, radius & angle
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, zoom))); // zoom, zoom exponent, rotation & warp
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, centerX))); // Center coord
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, distanceX))); // Distance
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, stretchX))); // Stretch
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, x))); // Position, radius & angle
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, radius))); // Position, radius & angle
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, zoom))); // zoom, zoom exponent, rotation & warp
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, centerX))); // Center coord
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, distanceX))); // Distance
glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, stretchX))); // Stretch
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -134,6 +136,9 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState)
return;
}
float aspectX = static_cast<float>(presetState.renderContext.aspectX);
float aspectY = static_cast<float>(presetState.renderContext.aspectY);
// Either viewport size or mesh size changed, reinitialize the vertices.
int vertexIndex{0};
for (int gridY = 0; gridY <= m_gridSizeY; gridY++)
@ -146,16 +151,14 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState)
vertex.y = static_cast<float>(gridY) / static_cast<float>(m_gridSizeY) * 2.0f - 1.0f;
// Milkdrop uses sqrtf, but hypotf is probably safer.
vertex.radius = hypotf(vertex.x * static_cast<float>(presetState.renderContext.aspectX),
vertex.y * static_cast<float>(presetState.renderContext.aspectY));
vertex.radius = hypotf(vertex.x * aspectX, vertex.y * aspectY);
if (gridY == m_gridSizeY / 2 && gridX == m_gridSizeX / 2)
{
vertex.angle = 0.0f;
}
else
{
vertex.angle = atan2f(vertex.y * static_cast<float>(presetState.renderContext.aspectY),
vertex.x * static_cast<float>(presetState.renderContext.aspectX));
vertex.angle = atan2f(vertex.y * aspectY, vertex.x * aspectX);
}
vertexIndex++;
@ -303,7 +306,7 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState,
if (!m_warpShader)
{
m_perPixelMeshShader.Bind();
m_perPixelMeshShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
m_perPixelMeshShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped);
m_perPixelMeshShader.SetUniformInt("texture_sampler", 0);
m_perPixelMeshShader.SetUniformFloat4("aspect", {presetState.renderContext.aspectX,
presetState.renderContext.aspectY,
@ -320,9 +323,9 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState,
m_warpShader->LoadVariables(presetState, perFrameContext);
auto& shader = m_warpShader->Shader();
shader.SetUniformFloat4("aspect", {presetState.renderContext.aspectX,
presetState.renderContext.aspectY,
presetState.renderContext.invAspectX,
presetState.renderContext.invAspectY});
presetState.renderContext.aspectY,
presetState.renderContext.invAspectX,
presetState.renderContext.invAspectY});
shader.SetUniformFloat("warpTime", warpTime);
shader.SetUniformFloat("warpScaleInverse", warpScaleInverse);
shader.SetUniformFloat4("warpFactors", warpFactors);

View File

@ -111,15 +111,15 @@ private:
int m_gridSizeX{}; //!< Warp mesh X resolution.
int m_gridSizeY{}; //!< Warp mesh Y resolution.
int m_viewportWidth{}; //!< Last known viewport width.
int m_viewportWidth{}; //!< Last known viewport width.
int m_viewportHeight{}; //!< Last known viewport height.
VertexList m_vertices; //!< The calculated mesh vertices.
std::vector<int> m_listIndices; //!< List of vertex indices to render.
VertexList m_drawVertices; //!< Temp data buffer for the vertices to be drawn.
std::vector<int> m_listIndices; //!< List of vertex indices to render.
VertexList m_drawVertices; //!< Temp data buffer for the vertices to be drawn.
Shader m_perPixelMeshShader; //!< Special shader which calculates the per-pixel UV coordinates.
Shader m_perPixelMeshShader; //!< Special shader which calculates the per-pixel UV coordinates.
std::unique_ptr<MilkdropShader> m_warpShader; //!< The warp shader. Either preset-defined or a default shader.
Sampler m_perPixelSampler{GL_CLAMP_TO_EDGE, GL_LINEAR}; //!< The main texture sampler.
};

View File

@ -7,6 +7,7 @@
#include <random>
const glm::mat4 PresetState::orthogonalProjection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -40.0f, 40.0f);
const glm::mat4 PresetState::orthogonalProjectionFlipped = glm::ortho(-1.0f, 1.0f, 1.0f, -1.0f, -40.0f, 40.0f);
PresetState::PresetState()
: globalMemory(projectm_eval_memory_buffer_create())
@ -81,7 +82,7 @@ void PresetState::Initialize(PresetFileParser& parsedFile)
mvR = parsedFile.GetFloat("mv_r", mvR);
mvG = parsedFile.GetFloat("mv_g", mvG);
mvB = parsedFile.GetFloat("mv_b", mvB);
mvA = parsedFile.GetBool("bMotionVectorsOn", false) ? 0.0 : 1.0; // for backwards compatibility
mvA = parsedFile.GetBool("bMotionVectorsOn", false) ? 1.0 : 0.0; // for backwards compatibility
mvA = parsedFile.GetFloat("mv_a", mvA);
// Motion:
@ -99,6 +100,8 @@ void PresetState::Initialize(PresetFileParser& parsedFile)
warpAnimSpeed = parsedFile.GetFloat("fWarpAnimSpeed", warpAnimSpeed);
warpScale = parsedFile.GetFloat("fWarpScale", warpScale);
zoomExponent = parsedFile.GetFloat("fZoomExponent", zoomExponent);
// Borders:
outerBorderSize = parsedFile.GetFloat("ob_size", outerBorderSize);
outerBorderR = parsedFile.GetFloat("ob_r", outerBorderR);
outerBorderG = parsedFile.GetFloat("ob_g", outerBorderG);

View File

@ -110,7 +110,7 @@ public:
BlendableFloat mvR{1.0f};
BlendableFloat mvG{1.0f};
BlendableFloat mvB{1.0f};
BlendableFloat mvA{1.0f};
BlendableFloat mvA{0.0f};
BlendableFloat blur1Min{0.0f};
BlendableFloat blur2Min{0.0f};
BlendableFloat blur3Min{0.0f};
@ -160,4 +160,5 @@ public:
std::map<int, TextureSamplerDescriptor> randomTextureDescriptors; //!< Descriptors for random texture IDs. Should be the same across both warp and comp shaders.
static const glm::mat4 orthogonalProjection; //!< Projection matrix that transforms DirectX screen-space coordinates into the OpenGL coordinate frame.
static const glm::mat4 orthogonalProjectionFlipped; //!< Projection matrix that transforms DirectX screen-space coordinates into the OpenGL coordinate frame.
};

View File

@ -69,7 +69,7 @@ void VideoEcho::Draw()
}
m_presetState.texturedShader.Bind();
m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped);
m_presetState.texturedShader.SetUniformInt("texture_sampler", 0);
auto mainTexture = m_presetState.mainTexture.lock();
@ -122,13 +122,13 @@ void VideoEcho::DrawVideoEcho()
float const tempLow = 0.5f - 0.5f / zoom;
float const temphigh = 0.5f + 0.5f / zoom;
m_vertices[0].u = tempLow;
m_vertices[0].v = temphigh;
m_vertices[0].v = tempLow;
m_vertices[1].u = temphigh;
m_vertices[1].v = temphigh;
m_vertices[1].v = tempLow;
m_vertices[2].u = tempLow;
m_vertices[2].v = tempLow;
m_vertices[2].v = temphigh;
m_vertices[3].u = temphigh;
m_vertices[3].v = tempLow;
m_vertices[3].v = temphigh;
// Flipping
if (pass == 1)
@ -197,13 +197,13 @@ void VideoEcho::DrawVideoEcho()
void VideoEcho::DrawGammaAdjustment()
{
m_vertices[0].u = 0.0f;
m_vertices[0].v = 1.0f;
m_vertices[0].v = 0.0f;
m_vertices[1].u = 1.0f;
m_vertices[1].v = 1.0f;
m_vertices[1].v = 0.0f;
m_vertices[2].u = 0.0f;
m_vertices[2].v = 0.0f;
m_vertices[2].v = 1.0f;
m_vertices[3].u = 1.0f;
m_vertices[3].v = 0.0f;
m_vertices[3].v = 1.0f;
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);

View File

@ -72,10 +72,6 @@ void Waveform::Draw(const PerFrameContext& presetPerFrameContext)
const auto smoothedSamples = SmoothWave(waveVertices, smoothedWave.data());
m_tempAlpha = static_cast<float>(*presetPerFrameContext.wave_a);
if (m_presetState.modWaveAlphaByvolume)
{
ModulateOpacityByVolume(presetPerFrameContext);
}
MaximizeColors(presetPerFrameContext);
// Always draw "thick" dots.
@ -159,8 +155,7 @@ void Waveform::MaximizeColors(const PerFrameContext& presetPerFrameContext)
// the rest accordingly
int texsize = std::max(m_presetState.renderContext.viewportSizeX, m_presetState.renderContext.viewportSizeY);
if (m_mode == Mode::Blob2 || m_mode == Mode::ExplosiveHash)
if (m_mode == Mode::CenteredSpiro || m_mode == Mode::ExplosiveHash)
{
if (texsize <= 256)
{
@ -184,7 +179,7 @@ void Waveform::MaximizeColors(const PerFrameContext& presetPerFrameContext)
m_tempAlpha *= 0.15f;
}
}
else if (m_mode == Mode::Blob3)
else if (m_mode == Mode::CenteredSpiroVolume)
{
if (texsize <= 256)
{
@ -211,6 +206,11 @@ void Waveform::MaximizeColors(const PerFrameContext& presetPerFrameContext)
m_tempAlpha *= std::pow(m_presetState.audioData.treb, 2.0f);
}
if (m_presetState.modWaveAlphaByvolume)
{
ModulateOpacityByVolume(presetPerFrameContext);
}
if (m_tempAlpha < 0.0f)
{
m_tempAlpha = 0.0f;
@ -221,39 +221,32 @@ void Waveform::MaximizeColors(const PerFrameContext& presetPerFrameContext)
m_tempAlpha = 1.0f;
}
float waveR{static_cast<float>(*presetPerFrameContext.wave_r)};
float waveG{static_cast<float>(*presetPerFrameContext.wave_g)};
float waveB{static_cast<float>(*presetPerFrameContext.wave_b)};
if (*presetPerFrameContext.wave_brighten > 0)
{
constexpr float fMaximizeWaveColorAmount = 1.0f;
float cr{static_cast<float>(*presetPerFrameContext.wave_r)};
float cg{static_cast<float>(*presetPerFrameContext.wave_g)};
float cb{static_cast<float>(*presetPerFrameContext.wave_b)};
float max = cr;
if (max < cg)
float max = waveR;
if (max < waveG)
{
max = cg;
max = waveG;
}
if (max < cb)
if (max < waveB)
{
max = cb;
max = waveB;
}
if (max > 0.01f)
{
cr = cr / max * fMaximizeWaveColorAmount + cr * (1.0f - fMaximizeWaveColorAmount);
cg = cg / max * fMaximizeWaveColorAmount + cg * (1.0f - fMaximizeWaveColorAmount);
cb = cb / max * fMaximizeWaveColorAmount + cb * (1.0f - fMaximizeWaveColorAmount);
waveR = waveR / max * fMaximizeWaveColorAmount + waveR * (1.0f - fMaximizeWaveColorAmount);
waveG = waveG / max * fMaximizeWaveColorAmount + waveG * (1.0f - fMaximizeWaveColorAmount);
waveB = waveB / max * fMaximizeWaveColorAmount + waveB * (1.0f - fMaximizeWaveColorAmount);
}
}
glVertexAttrib4f(1, cr, cg, cb, m_tempAlpha);
}
else
{
glVertexAttrib4f(1,
static_cast<float>(*presetPerFrameContext.wave_r),
static_cast<float>(*presetPerFrameContext.wave_g),
static_cast<float>(*presetPerFrameContext.wave_b),
m_tempAlpha);
}
glVertexAttrib4f(1, waveR, waveG, waveB, m_tempAlpha);
}
@ -378,8 +371,8 @@ void Waveform::WaveformMath(const PerFrameContext& presetPerFrameContext)
break;
}
case Mode::Blob2:
case Mode::Blob3: { // Both "centered spiro" waveforms are identical. Only difference is the alpha value.
case Mode::CenteredSpiro:
case Mode::CenteredSpiroVolume: { // Both "centered spiro" waveforms are identical. Only difference is the alpha value.
// Alpha calculation is handled in MaximizeColors().
m_samples = RenderWaveformSamples;

View File

@ -15,8 +15,8 @@ public:
{
Circle = 0, //!< Circular wave.
XYOscillationSpiral, //!< X-Y osc. that goes around in a spiral, in time.
Blob2, //!< Centered spiro (alpha constant). Aimed at not being so sound-responsive, but being very "nebula-like".
Blob3, //!< Centered spiro (alpha tied to volume). Aimed at having a strong audio-visual tie-in.
CenteredSpiro, //!< Centered spiro (alpha constant). Aimed at not being so sound-responsive, but being very "nebula-like".
CenteredSpiroVolume, //!< Centered spiro (alpha tied to volume). Aimed at having a strong audio-visual tie-in.
DerivativeLine, //!< Horizontal "script", left channel.
ExplosiveHash, //!< Weird explosive complex # thingy.
Line, //!< Angle-adjustable left channel, with temporal wave alignment.

View File

@ -51,7 +51,11 @@ void main(){
// Initial texture coordinates, with built-in zoom factor
vec2 uv = vec2(pos.x * aspectX * 0.5 * zoom2Inverse + 0.5,
-pos.y * aspectY * 0.5 * zoom2Inverse + 0.5);
pos.y * aspectY * 0.5 * zoom2Inverse + 0.5);
// original UV coordinates
vec2 uv_original = vec2(pos.x * 0.5 + 0.5 + texelOffset.x,
pos.y * 0.5 + 0.5 + texelOffset.y);
// Stretch on X, Y
uv.x = (uv.x - center.x) / stretch.x + center.x;
@ -70,7 +74,7 @@ void main(){
float cosRotation = cos(rot);
float sinRotation = sin(rot);
uv.x = uv2.x * cosRotation - uv2.y * sinRotation + center.x;
uv.y = uv2.x * sinRotation - uv2.y * cosRotation + center.y;
uv.y = uv2.x * sinRotation + uv2.y * cosRotation + center.y;
// Translation
uv -= distance;
@ -85,7 +89,7 @@ void main(){
frag_COLOR = vec4(decay, decay, decay, 1.0);
frag_TEXCOORD0.xy = uv;
frag_TEXCOORD0.zw = gl_Position.xy;
frag_TEXCOORD1 = vertex_position.zw;
frag_TEXCOORD1 = uv_original;
}
)";
@ -505,9 +509,9 @@ void main() {
)";
const std::string kPresetWarpVertexShaderGlsl330 = R"(
#define pos vertex_position.xy
#define radius vertex_position.z
#define angle vertex_position.w
#define pos vertex_position
#define radius rad_ang.x
#define angle rad_ang.y
#define zoom transforms.x
#define zoomExp transforms.y
#define rot transforms.z
@ -518,11 +522,12 @@ const std::string kPresetWarpVertexShaderGlsl330 = R"(
#define invAspectX aspect.z
#define invAspectY aspect.w
layout(location = 0) in vec4 vertex_position;
layout(location = 1) in vec4 transforms;
layout(location = 2) in vec2 center;
layout(location = 3) in vec2 distance;
layout(location = 4) in vec2 stretch;
layout(location = 0) in vec2 vertex_position;
layout(location = 1) in vec2 rad_ang;
layout(location = 2) in vec4 transforms;
layout(location = 3) in vec2 center;
layout(location = 4) in vec2 distance;
layout(location = 5) in vec2 stretch;
uniform mat4 vertex_transformation;
uniform vec4 aspect;
@ -537,52 +542,54 @@ out vec4 frag_TEXCOORD0;
out vec2 frag_TEXCOORD1;
void main() {
gl_Position = vertex_transformation * vec4(vec2(pos.x, -pos.y), 0.0, 1.0);
gl_Position = vertex_transformation * vec4(pos, 0.0, 1.0);
float zoom2 = pow(zoom, pow(zoomExp, radius * 2.0 - 1.0));
float zoom2Inverse = 1.0 / zoom2;
// Initial texture coordinates, with built-in zoom factor
vec2 uv = vec2(pos.x * aspectX * 0.5 * zoom2Inverse + 0.5,
pos.y * aspectY * 0.5 * zoom2Inverse + 0.5);
float u = pos.x * aspectX * 0.5 * zoom2Inverse + 0.5;
float v = -pos.y * aspectY * 0.5 * zoom2Inverse + 0.5;
// original UV coordinates
vec2 uv_original = vec2(pos.x * 0.5 + 0.5 + texelOffset.x,
-pos.y * 0.5 + 0.5 + texelOffset.y);
// Stretch on X, Y
uv.x = (uv.x - center.x) / stretch.x + center.x;
uv.y = (uv.y - center.y) / stretch.y + center.y;
u = (u - center.x) / stretch.x + center.x;
v = (v - center.y) / stretch.y + center.y;
// Warping
uv.x += warp * 0.0035 * sin(warpTime * 0.333 + warpScaleInverse * (pos.x * warpFactors.x - pos.y * warpFactors.w));
uv.y += warp * 0.0035 * cos(warpTime * 0.375 - warpScaleInverse * (pos.x * warpFactors.z + pos.y * warpFactors.y));
uv.x += warp * 0.0035 * cos(warpTime * 0.753 - warpScaleInverse * (pos.x * warpFactors.y - pos.y * warpFactors.z));
uv.y += warp * 0.0035 * sin(warpTime * 0.825 + warpScaleInverse * (pos.x * warpFactors.x + pos.y * warpFactors.w));
u += warp * 0.0035 * sin(warpTime * 0.333 + warpScaleInverse * (pos.x * warpFactors.x - pos.y * warpFactors.w));
v += warp * 0.0035 * cos(warpTime * 0.375 - warpScaleInverse * (pos.x * warpFactors.z + pos.y * warpFactors.y));
u += warp * 0.0035 * cos(warpTime * 0.753 - warpScaleInverse * (pos.x * warpFactors.y - pos.y * warpFactors.z));
v += warp * 0.0035 * sin(warpTime * 0.825 + warpScaleInverse * (pos.x * warpFactors.x + pos.y * warpFactors.w));
// Rotation
vec2 uv2 = vec2(uv.x - center.x,
uv.y - center.y);
float u2 = u - center.x;
float v2 = v - center.y;
float cosRotation = cos(rot);
float sinRotation = sin(rot);
uv.x = uv2.x * cosRotation - uv2.y * sinRotation + center.x;
uv.y = uv2.x * sinRotation - uv2.y * cosRotation + center.y;
u = u2 * cosRotation - v2 * sinRotation + center.x;
v = u2 * sinRotation + v2 * cosRotation + center.y;
// Translation
uv -= distance;
u -= distance.x;
v -= distance.y;
// Undo aspect ratio fix
uv.x = (uv.x - 0.5) * invAspectX + 0.5;
uv.y = (uv.y - 0.5) * invAspectY + 0.5;
u = (u - 0.5) * invAspectX + 0.5;
v = (v - 0.5) * invAspectY + 0.5;
// Final half-texel translation
uv += texelOffset;
u += texelOffset.x;
v += texelOffset.y;
frag_COLOR = vec4(decay, decay, decay, 1.0);
frag_TEXCOORD0.xy = uv;
frag_TEXCOORD0.xy = vec2(u, v);
frag_TEXCOORD0.zw = uv_original;
frag_TEXCOORD1 = vertex_position.zw;
frag_TEXCOORD1 = rad_ang;
}
)";