Se eliminan efectos con shaders para dejar el ejemplo unicamente de demostracion de interoperabilidad en cuda
This commit is contained in:
parent
7d8368a199
commit
24b29705a7
14 changed files with 31 additions and 339 deletions
BIN
.cache/clangd/index/glwidget.cpp.C8B78D3731FA9869.idx
Normal file
BIN
.cache/clangd/index/glwidget.cpp.C8B78D3731FA9869.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/glwidget.h.1FDF732EFCED4BD8.idx
Normal file
BIN
.cache/clangd/index/glwidget.h.1FDF732EFCED4BD8.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/main.cpp.1EFC64217C8EEBC3.idx
Normal file
BIN
.cache/clangd/index/main.cpp.1EFC64217C8EEBC3.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/mainwindow.cpp.106F8539DEEA62A2.idx
Normal file
BIN
.cache/clangd/index/mainwindow.cpp.106F8539DEEA62A2.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/mainwindow.h.1CF791588B2BEEF8.idx
Normal file
BIN
.cache/clangd/index/mainwindow.h.1CF791588B2BEEF8.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/videodecoder.cpp.B5F31E0C60CEA00D.idx
Normal file
BIN
.cache/clangd/index/videodecoder.cpp.B5F31E0C60CEA00D.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/videodecoder.h.D0CE50575247D653.idx
Normal file
BIN
.cache/clangd/index/videodecoder.h.D0CE50575247D653.idx
Normal file
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.17)
|
||||
project(crt_player_cuda VERSION 1.0.0 LANGUAGES CXX)
|
||||
project(zero_copy_example VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
|
@ -36,10 +36,10 @@ set(HEADERS
|
|||
)
|
||||
|
||||
# Definir ejecutable
|
||||
add_executable(crt_player_cuda ${SOURCES} ${HEADERS})
|
||||
add_executable(zero_copy_example ${SOURCES} ${HEADERS})
|
||||
|
||||
# Enlazar librerías de Qt6, FFmpeg y CUDA
|
||||
target_link_libraries(crt_player_cuda PRIVATE
|
||||
target_link_libraries(zero_copy_example PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
|
|
@ -52,7 +52,7 @@ target_link_libraries(crt_player_cuda PRIVATE
|
|||
${CUDART_LIBRARY}
|
||||
)
|
||||
|
||||
target_include_directories(crt_player_cuda PRIVATE
|
||||
target_include_directories(zero_copy_example PRIVATE
|
||||
${AVCODEC_INCLUDE_DIRS}
|
||||
${AVFORMAT_INCLUDE_DIRS}
|
||||
${AVUTIL_INCLUDE_DIRS}
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -76,23 +76,25 @@ cudaMemcpy2DToArray(arrayUV, 0, 0, (void*)frame->data[1], frame->linesize[1], w,
|
|||
cudaGraphicsUnmapResources(1, &m_cudaResourceY, 0);
|
||||
```
|
||||
|
||||
### Punto 4: Conversión Cromática y Filtros en el Fragment Shader
|
||||
### Punto 4: Conversión Cromática en el Fragment Shader
|
||||
|
||||
Para corregir el origen invertido entre OpenGL y CUDA, las coordenadas del Quad están configuradas con el eje vertical invertido ($V = 1.0 - V$). En el fragment shader [shader.frag](file:///home/sebastian/repos/zero_copy_video_player/shader.frag), leemos ambas texturas en paralelo y realizamos la conversión matemática de NV12 a RGB:
|
||||
|
||||
```glsl
|
||||
float y = texture(u_texY, uv).r;
|
||||
vec2 uvVal = texture(u_texUV, uv).rg;
|
||||
float y = texture(u_texY, v_texCoord).r;
|
||||
vec2 uvVal = texture(u_texUV, v_texCoord).rg;
|
||||
|
||||
// El formato NV12 almacena U y V entrelazados. Restamos 0.5 para centrar la crominancia.
|
||||
float u = uvVal.r - 0.5;
|
||||
float v = uvVal.g - 0.5;
|
||||
|
||||
// Matriz estándar de conversión YUV (NV12) a RGB
|
||||
float r = y + 1.402 * v;
|
||||
float g = y - 0.344136 * u - 0.714136 * v;
|
||||
float b = y + 1.772 * u;
|
||||
vec3 color = vec3(r, g, b);
|
||||
```
|
||||
|
||||
Por último, sobre esta señal de color RGB, se aplican los filtros de curvatura 3D de la lente, líneas de barrido (scanlines), aberración cromática y viñeteado.
|
||||
fragColor = vec4(r, g, b, 1.0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
49
glwidget.cpp
49
glwidget.cpp
|
|
@ -13,13 +13,7 @@ GLWidget::GLWidget(QWidget *parent)
|
|||
, m_cudaResourceUV(nullptr)
|
||||
, m_allocatedWidth(0)
|
||||
, m_allocatedHeight(0)
|
||||
, m_crtEnabled(true)
|
||||
, m_curvature(2.0f)
|
||||
, m_scanlineDensity(400.0f)
|
||||
, m_scanlineOpacity(0.35f)
|
||||
, m_aberration(0.0015f)
|
||||
, m_vignette(0.20f)
|
||||
, m_brightness(1.10f)
|
||||
|
||||
{
|
||||
m_localFrame = av_frame_alloc();
|
||||
}
|
||||
|
|
@ -51,40 +45,7 @@ void GLWidget::onFrameReady() {
|
|||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setCrtEnabled(bool enabled) {
|
||||
m_crtEnabled = enabled;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setCurvature(float value) {
|
||||
m_curvature = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setScanlineDensity(float value) {
|
||||
m_scanlineDensity = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setScanlineOpacity(float value) {
|
||||
m_scanlineOpacity = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setAberration(float value) {
|
||||
m_aberration = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setVignette(float value) {
|
||||
m_vignette = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::setBrightness(float value) {
|
||||
m_brightness = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void GLWidget::clearVideo() {
|
||||
cleanupCudaGL();
|
||||
|
|
@ -227,13 +188,7 @@ void GLWidget::paintGL() {
|
|||
glBindTexture(GL_TEXTURE_2D, m_texUV);
|
||||
m_shaderProgram.setUniformValue("u_texUV", 1);
|
||||
|
||||
m_shaderProgram.setUniformValue("u_crtEnabled", m_crtEnabled);
|
||||
m_shaderProgram.setUniformValue("u_curvature", m_curvature);
|
||||
m_shaderProgram.setUniformValue("u_scanlineDensity", m_scanlineDensity);
|
||||
m_shaderProgram.setUniformValue("u_scanlineOpacity", m_scanlineOpacity);
|
||||
m_shaderProgram.setUniformValue("u_aberration", m_aberration);
|
||||
m_shaderProgram.setUniformValue("u_vignette", m_vignette);
|
||||
m_shaderProgram.setUniformValue("u_brightness", m_brightness);
|
||||
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
int posLocation = m_shaderProgram.attributeLocation("a_position");
|
||||
|
|
|
|||
18
glwidget.h
18
glwidget.h
|
|
@ -23,14 +23,7 @@ public:
|
|||
|
||||
void setVideoDecoder(VideoDecoder *decoder);
|
||||
|
||||
// Ajustes del Shader CRT
|
||||
void setCrtEnabled(bool enabled);
|
||||
void setCurvature(float value);
|
||||
void setScanlineDensity(float value);
|
||||
void setScanlineOpacity(float value);
|
||||
void setAberration(float value);
|
||||
void setVignette(float value);
|
||||
void setBrightness(float value);
|
||||
|
||||
|
||||
void clearVideo();
|
||||
|
||||
|
|
@ -65,14 +58,7 @@ private:
|
|||
int m_allocatedWidth;
|
||||
int m_allocatedHeight;
|
||||
|
||||
// Estado del Shader
|
||||
bool m_crtEnabled;
|
||||
float m_curvature;
|
||||
float m_scanlineDensity;
|
||||
float m_scanlineOpacity;
|
||||
float m_aberration;
|
||||
float m_vignette;
|
||||
float m_brightness;
|
||||
|
||||
};
|
||||
|
||||
#endif // GLWIDGET_H
|
||||
|
|
|
|||
184
mainwindow.cpp
184
mainwindow.cpp
|
|
@ -12,8 +12,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
: QMainWindow(parent)
|
||||
, m_updatingSeek(false)
|
||||
{
|
||||
setWindowTitle("Retro CRT Video Player (C++/Qt6 & Native CUDA Zero-Copy)");
|
||||
resize(1200, 720);
|
||||
setWindowTitle("Zero-Copy CUDA-GL Video Player");
|
||||
resize(960, 600);
|
||||
|
||||
m_glWidget = new GLWidget(this);
|
||||
m_videoDecoder = new VideoDecoder(this);
|
||||
|
|
@ -35,7 +35,6 @@ void MainWindow::setupUI() {
|
|||
this->setStyleSheet(
|
||||
"QMainWindow { background-color: #08080f; }"
|
||||
"QWidget { color: #f0f0f5; font-family: 'Outfit', 'Segoe UI', sans-serif; font-size: 13px; }"
|
||||
"QFrame#sidebar { background-color: #11111d; border-left: 1px solid #22223b; border-radius: 0px; }"
|
||||
"QPushButton { background-color: #ff007f; color: white; border: none; padding: 8px 15px; border-radius: 6px; font-weight: bold; min-width: 60px; }"
|
||||
"QPushButton:hover { background-color: #ff3399; }"
|
||||
"QPushButton:pressed { background-color: #cc0066; }"
|
||||
|
|
@ -45,22 +44,16 @@ void MainWindow::setupUI() {
|
|||
"QSlider::handle:horizontal { background: #ffffff; border: 1px solid #ff007f; width: 14px; height: 14px; margin: -4px 0; border-radius: 7px; }"
|
||||
"QSlider::handle:horizontal:hover { background: #ff007f; }"
|
||||
"QLabel { color: #a0a0c0; }"
|
||||
"QCheckBox { spacing: 8px; }"
|
||||
"QCheckBox::indicator { width: 18px; height: 18px; border: 1px solid #ff007f; border-radius: 4px; background: #1a1a2e; }"
|
||||
"QCheckBox::indicator:checked { background-color: #ff007f; image: url(check.png); /* O usar un color plano */ }"
|
||||
"QGroupBox { font-weight: bold; border: 1px solid #22223b; border-radius: 8px; margin-top: 15px; padding-top: 15px; color: #ff007f; }"
|
||||
);
|
||||
|
||||
QWidget *centralWidget = new QWidget(this);
|
||||
setCentralWidget(centralWidget);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget);
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
|
||||
mainLayout->setContentsMargins(10, 10, 10, 10);
|
||||
mainLayout->setSpacing(10);
|
||||
|
||||
// --- COLUMNA IZQUIERDA: REPRODUCTOR ---
|
||||
QVBoxLayout *playerLayout = new QVBoxLayout();
|
||||
playerLayout->addWidget(m_glWidget, 1);
|
||||
mainLayout->addWidget(m_glWidget, 1);
|
||||
|
||||
// Controles Multimedia
|
||||
QHBoxLayout *controlsLayout = new QHBoxLayout();
|
||||
|
|
@ -90,135 +83,7 @@ void MainWindow::setupUI() {
|
|||
m_timeLabel->setAlignment(Qt::AlignCenter);
|
||||
controlsLayout->addWidget(m_timeLabel);
|
||||
|
||||
playerLayout->addLayout(controlsLayout);
|
||||
mainLayout->addLayout(playerLayout, 3); // 3/4 del ancho de ventana
|
||||
|
||||
// --- COLUMNA DERECHA: SIDEBAR DE AJUSTES ---
|
||||
QFrame *sidebar = new QFrame(this);
|
||||
sidebar->setObjectName("sidebar");
|
||||
sidebar->setFixedWidth(300);
|
||||
|
||||
QVBoxLayout *sidebarLayout = new QVBoxLayout(sidebar);
|
||||
sidebarLayout->setContentsMargins(15, 15, 15, 15);
|
||||
|
||||
QLabel *sidebarTitle = new QLabel("AJUSTES CRT RETRO", this);
|
||||
sidebarTitle->setStyleSheet("font-size: 16px; font-weight: bold; color: #ff007f; margin-bottom: 10px;");
|
||||
sidebarTitle->setAlignment(Qt::AlignCenter);
|
||||
sidebarLayout->addWidget(sidebarTitle);
|
||||
|
||||
QScrollArea *scrollArea = new QScrollArea(this);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setFrameShape(QFrame::NoFrame);
|
||||
|
||||
QWidget *scrollWidget = new QWidget(this);
|
||||
QVBoxLayout *scrollLayout = new QVBoxLayout(scrollWidget);
|
||||
scrollLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Activador General
|
||||
m_crtCheckbox = new QCheckBox("Habilitar Efecto CRT", this);
|
||||
m_crtCheckbox->setChecked(true);
|
||||
m_crtCheckbox->setStyleSheet("font-weight: bold; font-size: 14px; color: #ffffff;");
|
||||
connect(m_crtCheckbox, &QCheckBox::toggled, this, &MainWindow::onCrtToggled);
|
||||
scrollLayout->addWidget(m_crtCheckbox);
|
||||
|
||||
// Grupo de Controles Geométricos
|
||||
QGroupBox *geoGroup = new QGroupBox("Geometría y Lente", this);
|
||||
QVBoxLayout *geoLayout = new QVBoxLayout(geoGroup);
|
||||
|
||||
QLabel *curvLabel = new QLabel("Curvatura de Pantalla:", this);
|
||||
geoLayout->addWidget(curvLabel);
|
||||
QHBoxLayout *curvLayout = new QHBoxLayout();
|
||||
m_curvatureSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_curvatureSlider->setRange(0, 50); // 0.0 a 5.0
|
||||
m_curvatureSlider->setValue(20);
|
||||
connect(m_curvatureSlider, &QSlider::valueChanged, this, &MainWindow::onCurvatureChanged);
|
||||
curvLayout->addWidget(m_curvatureSlider);
|
||||
m_curvatureLabel = new QLabel("2.0", this);
|
||||
m_curvatureLabel->setFixedWidth(30);
|
||||
curvLayout->addWidget(m_curvatureLabel);
|
||||
geoLayout->addLayout(curvLayout);
|
||||
scrollLayout->addWidget(geoGroup);
|
||||
|
||||
// Grupo de Estilo Scanline
|
||||
QGroupBox *scanlineGroup = new QGroupBox("Efecto Scanlines", this);
|
||||
QVBoxLayout *scanlineLayout = new QVBoxLayout(scanlineGroup);
|
||||
|
||||
QLabel *densLabel = new QLabel("Densidad de Líneas:", this);
|
||||
scanlineLayout->addWidget(densLabel);
|
||||
QHBoxLayout *densLayout = new QHBoxLayout();
|
||||
m_scanlineDensitySlider = new QSlider(Qt::Horizontal, this);
|
||||
m_scanlineDensitySlider->setRange(100, 1000);
|
||||
m_scanlineDensitySlider->setValue(400);
|
||||
connect(m_scanlineDensitySlider, &QSlider::valueChanged, this, &MainWindow::onScanlineDensityChanged);
|
||||
densLayout->addWidget(m_scanlineDensitySlider);
|
||||
m_scanlineDensityLabel = new QLabel("400", this);
|
||||
m_scanlineDensityLabel->setFixedWidth(30);
|
||||
densLayout->addWidget(m_scanlineDensityLabel);
|
||||
scanlineLayout->addLayout(densLayout);
|
||||
|
||||
QLabel *opacLabel = new QLabel("Opacidad de Líneas:", this);
|
||||
scanlineLayout->addWidget(opacLabel);
|
||||
QHBoxLayout *opacLayout = new QHBoxLayout();
|
||||
m_scanlineOpacitySlider = new QSlider(Qt::Horizontal, this);
|
||||
m_scanlineOpacitySlider->setRange(0, 100); // 0% a 100%
|
||||
m_scanlineOpacitySlider->setValue(35);
|
||||
connect(m_scanlineOpacitySlider, &QSlider::valueChanged, this, &MainWindow::onScanlineOpacityChanged);
|
||||
opacLayout->addWidget(m_scanlineOpacitySlider);
|
||||
m_scanlineOpacityLabel = new QLabel("0.35", this);
|
||||
m_scanlineOpacityLabel->setFixedWidth(30);
|
||||
opacLayout->addWidget(m_scanlineOpacityLabel);
|
||||
scanlineLayout->addLayout(opacLayout);
|
||||
scrollLayout->addWidget(scanlineGroup);
|
||||
|
||||
// Grupo de Imperfecciones
|
||||
QGroupBox *imperfGroup = new QGroupBox("Óptica y Color", this);
|
||||
QVBoxLayout *imperfLayout = new QVBoxLayout(imperfGroup);
|
||||
|
||||
QLabel *aberrLabel = new QLabel("Aberración Cromática (RGB split):", this);
|
||||
imperfLayout->addWidget(aberrLabel);
|
||||
QHBoxLayout *aberrLayout = new QHBoxLayout();
|
||||
m_aberrationSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_aberrationSlider->setRange(0, 100); // 0.0000 a 0.0100
|
||||
m_aberrationSlider->setValue(15);
|
||||
connect(m_aberrationSlider, &QSlider::valueChanged, this, &MainWindow::onAberrationChanged);
|
||||
aberrLayout->addWidget(m_aberrationSlider);
|
||||
m_aberrationLabel = new QLabel("0.0015", this);
|
||||
m_aberrationLabel->setFixedWidth(45);
|
||||
aberrLayout->addWidget(m_aberrationLabel);
|
||||
imperfLayout->addLayout(aberrLayout);
|
||||
|
||||
QLabel *vigLabel = new QLabel("Viñeteado (Esquinas oscuras):", this);
|
||||
imperfLayout->addWidget(vigLabel);
|
||||
QHBoxLayout *vigLayout = new QHBoxLayout();
|
||||
m_vignetteSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_vignetteSlider->setRange(5, 50); // 0.05 a 0.50
|
||||
m_vignetteSlider->setValue(20);
|
||||
connect(m_vignetteSlider, &QSlider::valueChanged, this, &MainWindow::onVignetteChanged);
|
||||
vigLayout->addWidget(m_vignetteSlider);
|
||||
m_vignetteLabel = new QLabel("0.20", this);
|
||||
m_vignetteLabel->setFixedWidth(30);
|
||||
vigLayout->addWidget(m_vignetteLabel);
|
||||
imperfLayout->addLayout(vigLayout);
|
||||
|
||||
QLabel *brightLabel = new QLabel("Brillo Adicional:", this);
|
||||
imperfLayout->addWidget(brightLabel);
|
||||
QHBoxLayout *brightLayout = new QHBoxLayout();
|
||||
m_brightnessSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_brightnessSlider->setRange(80, 150); // 0.80 a 1.50
|
||||
m_brightnessSlider->setValue(110);
|
||||
connect(m_brightnessSlider, &QSlider::valueChanged, this, &MainWindow::onBrightnessChanged);
|
||||
brightLayout->addWidget(m_brightnessSlider);
|
||||
m_brightnessLabel = new QLabel("1.10", this);
|
||||
m_brightnessLabel->setFixedWidth(30);
|
||||
brightLayout->addWidget(m_brightnessLabel);
|
||||
imperfLayout->addLayout(brightLayout);
|
||||
scrollLayout->addWidget(imperfGroup);
|
||||
|
||||
scrollLayout->addStretch(1);
|
||||
scrollArea->setWidget(scrollWidget);
|
||||
sidebarLayout->addWidget(scrollArea);
|
||||
|
||||
mainLayout->addWidget(sidebar);
|
||||
mainLayout->addLayout(controlsLayout);
|
||||
}
|
||||
|
||||
void MainWindow::openVideoFile() {
|
||||
|
|
@ -289,43 +154,4 @@ void MainWindow::onPlaybackFinished() {
|
|||
m_seekBar->setValue(0);
|
||||
}
|
||||
|
||||
// --- SLOTS DE PARÁMETROS DEL SHADER ---
|
||||
|
||||
void MainWindow::onCrtToggled(bool checked) {
|
||||
m_glWidget->setCrtEnabled(checked);
|
||||
}
|
||||
|
||||
void MainWindow::onCurvatureChanged(int value) {
|
||||
float curvatureVal = value / 10.0f;
|
||||
m_curvatureLabel->setText(QString::number(curvatureVal, 'f', 1));
|
||||
m_glWidget->setCurvature(curvatureVal);
|
||||
}
|
||||
|
||||
void MainWindow::onScanlineDensityChanged(int value) {
|
||||
m_scanlineDensityLabel->setText(QString::number(value));
|
||||
m_glWidget->setScanlineDensity(static_cast<float>(value));
|
||||
}
|
||||
|
||||
void MainWindow::onScanlineOpacityChanged(int value) {
|
||||
float opacityVal = value / 100.0f;
|
||||
m_scanlineOpacityLabel->setText(QString::number(opacityVal, 'f', 2));
|
||||
m_glWidget->setScanlineOpacity(opacityVal);
|
||||
}
|
||||
|
||||
void MainWindow::onAberrationChanged(int value) {
|
||||
float aberrationVal = value / 10000.0f;
|
||||
m_aberrationLabel->setText(QString::number(aberrationVal, 'f', 4));
|
||||
m_glWidget->setAberration(aberrationVal);
|
||||
}
|
||||
|
||||
void MainWindow::onVignetteChanged(int value) {
|
||||
float vignetteVal = value / 100.0f;
|
||||
m_vignetteLabel->setText(QString::number(vignetteVal, 'f', 2));
|
||||
m_glWidget->setVignette(vignetteVal);
|
||||
}
|
||||
|
||||
void MainWindow::onBrightnessChanged(int value) {
|
||||
float brightnessVal = value / 100.0f;
|
||||
m_brightnessLabel->setText(QString::number(brightnessVal, 'f', 2));
|
||||
m_glWidget->setBrightness(brightnessVal);
|
||||
}
|
||||
|
|
|
|||
24
mainwindow.h
24
mainwindow.h
|
|
@ -24,14 +24,7 @@ private slots:
|
|||
void onPositionChanged(qint64 positionMs);
|
||||
void onPlaybackFinished();
|
||||
|
||||
// Slots de actualización de los sliders del Shader
|
||||
void onCrtToggled(bool checked);
|
||||
void onCurvatureChanged(int value);
|
||||
void onScanlineDensityChanged(int value);
|
||||
void onScanlineOpacityChanged(int value);
|
||||
void onAberrationChanged(int value);
|
||||
void onVignetteChanged(int value);
|
||||
void onBrightnessChanged(int value);
|
||||
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
|
@ -46,20 +39,7 @@ private:
|
|||
QSlider *m_seekBar;
|
||||
QLabel *m_timeLabel;
|
||||
|
||||
// Sliders del Shader y sus etiquetas indicadoras
|
||||
QCheckBox *m_crtCheckbox;
|
||||
QSlider *m_curvatureSlider;
|
||||
QLabel *m_curvatureLabel;
|
||||
QSlider *m_scanlineDensitySlider;
|
||||
QLabel *m_scanlineDensityLabel;
|
||||
QSlider *m_scanlineOpacitySlider;
|
||||
QLabel *m_scanlineOpacityLabel;
|
||||
QSlider *m_aberrationSlider;
|
||||
QLabel *m_aberrationLabel;
|
||||
QSlider *m_vignetteSlider;
|
||||
QLabel *m_vignetteLabel;
|
||||
QSlider *m_brightnessSlider;
|
||||
QLabel *m_brightnessLabel;
|
||||
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
71
shader.frag
71
shader.frag
|
|
@ -5,76 +5,19 @@ out vec4 fragColor;
|
|||
|
||||
uniform sampler2D u_texY;
|
||||
uniform sampler2D u_texUV;
|
||||
uniform bool u_crtEnabled;
|
||||
uniform float u_curvature;
|
||||
uniform float u_scanlineDensity;
|
||||
uniform float u_scanlineOpacity;
|
||||
uniform float u_aberration;
|
||||
uniform float u_vignette;
|
||||
uniform float u_brightness;
|
||||
uniform float u_time;
|
||||
|
||||
// Función para distorsión de barril (curvatura CRT)
|
||||
vec2 curve(vec2 uv) {
|
||||
if (u_curvature <= 0.0) return uv;
|
||||
uv = (uv - 0.5) * 2.0;
|
||||
uv.x *= 1.0 + (uv.y * uv.y) * (u_curvature * 0.05);
|
||||
uv.y *= 1.0 + (uv.x * uv.x) * (u_curvature * 0.05);
|
||||
uv = (uv / 2.0) + 0.5;
|
||||
return uv;
|
||||
}
|
||||
void main() {
|
||||
float y = texture(u_texY, v_texCoord).r;
|
||||
vec2 uvVal = texture(u_texUV, v_texCoord).rg;
|
||||
|
||||
// Conversión NV12 (Y + UV entrelazados) a RGB
|
||||
vec3 getNv12Color(vec2 uv) {
|
||||
float y = texture(u_texY, uv).r;
|
||||
vec2 uvVal = texture(u_texUV, uv).rg;
|
||||
// El formato NV12 almacena U y V entrelazados. Restamos 0.5 para centrar la crominancia.
|
||||
float u = uvVal.r - 0.5;
|
||||
float v = uvVal.g - 0.5;
|
||||
|
||||
// Matriz estándar de conversión YUV (NV12) a RGB
|
||||
float r = y + 1.402 * v;
|
||||
float g = y - 0.344136 * u - 0.714136 * v;
|
||||
float b = y + 1.772 * u;
|
||||
return vec3(r, g, b);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_texCoord;
|
||||
|
||||
if (u_crtEnabled) {
|
||||
uv = curve(uv);
|
||||
}
|
||||
|
||||
// Verificar límites para recortar esquinas curvas
|
||||
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 color;
|
||||
if (u_crtEnabled && u_aberration > 0.0) {
|
||||
// Aberración Cromática (RGB split) utilizando muestreos desfasados de NV12
|
||||
float r = getNv12Color(vec2(uv.x - u_aberration, uv.y)).r;
|
||||
float g = getNv12Color(uv).g;
|
||||
float b = getNv12Color(vec2(uv.x + u_aberration, uv.y)).b;
|
||||
color = vec3(r, g, b);
|
||||
} else {
|
||||
color = getNv12Color(uv);
|
||||
}
|
||||
|
||||
// Aplicar Brillo
|
||||
color *= u_brightness;
|
||||
|
||||
if (u_crtEnabled) {
|
||||
// 1. Efecto Scanlines (Líneas de Barrido)
|
||||
float scanline = sin(uv.y * u_scanlineDensity * 3.14159265);
|
||||
scanline = mix(1.0, (scanline + 1.0) * 0.5, u_scanlineOpacity);
|
||||
color *= scanline;
|
||||
|
||||
// 2. Efecto Viñeteado (Esquinas oscuras)
|
||||
float vignette = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);
|
||||
vignette = clamp(pow(16.0 * vignette, u_vignette), 0.0, 1.0);
|
||||
color *= vignette;
|
||||
}
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
|
||||
fragColor = vec4(r, g, b, 1.0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue