Implementar zoom por profundidad Z con perspectiva 3D + toggle
NUEVAS CARACTERÍSTICAS: - Zoom por profundidad Z: Escala sprites según distancia (0.5x-1.5x) - Toggle con Numpad / (KP_DIVIDE) para activar/desactivar perspectiva - Fix transición figura→física: Reset automático de depth_scale a 1.0 - Texto informativo: "DEPTH ZOOM ON/OFF" IMPLEMENTACIÓN TÉCNICA: - Ball class: Nueva variable depth_scale_ (0.5-1.5) - Ball class: Getters/setters getDepthScale() / setDepthScale() - Engine::addSpriteToBatch(): Parámetro scale con valor defecto 1.0 - Engine::addSpriteToBatch(): Cálculo de vértices escalados centrados - Engine::updateShape(): Cálculo depth_scale = 0.5 + z_normalized * 1.0 - Engine::render(): Pasa depth_scale al batch en modo SHAPE - Engine::toggleShapeMode(): Reset depth_scale en salida de figura - Engine: Variable depth_zoom_enabled_ (true por defecto) - Batch rendering: Mantiene performance (sin llamadas individuales) EFECTO VISUAL: - Pelotas lejanas (Z-): Pequeñas (50%) y oscuras - Pelotas medias (Z=0): Normales (100%) y brillo medio - Pelotas cercanas (Z+): Grandes (150%) y brillantes - Perspectiva 3D realista combinada con Z-sorting CONTROLES: - Numpad /: Toggle zoom por profundidad (solo en modo SHAPE) - Por defecto: ACTIVADO para máximo realismo 3D README ACTUALIZADO: - Añadida tecla KP_/ a tabla de controles - Actualizada sección "Características Técnicas" - Añadida línea "Zoom por profundidad" en características - Actualizada sección "Uso" con control de perspectiva 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,7 @@ El nombre refleja su proposito: **ViBe** (vibe-coding experimental) + **Physics*
|
|||||||
| `KP_+` | **Aumentar escala de figura (+10%)** |
|
| `KP_+` | **Aumentar escala de figura (+10%)** |
|
||||||
| `KP_-` | **Reducir escala de figura (-10%)** |
|
| `KP_-` | **Reducir escala de figura (-10%)** |
|
||||||
| `KP_*` | **Reset escala de figura a 100%** |
|
| `KP_*` | **Reset escala de figura a 100%** |
|
||||||
|
| `KP_/` | **Toggle zoom por profundidad Z (perspectiva ON/OFF)** |
|
||||||
|
|
||||||
## 📊 Informacion en Pantalla
|
## 📊 Informacion en Pantalla
|
||||||
|
|
||||||
@@ -147,10 +148,11 @@ Cuando se activa el debug display con la tecla `H`:
|
|||||||
|
|
||||||
- **Física de atracción**: Sistema spring-damper (Hooke's Law) para transición suave
|
- **Física de atracción**: Sistema spring-damper (Hooke's Law) para transición suave
|
||||||
- **Profundidad Z simulada**: Color modulado según distancia (oscuro=fondo, brillante=frente)
|
- **Profundidad Z simulada**: Color modulado según distancia (oscuro=fondo, brillante=frente)
|
||||||
|
- **Zoom por profundidad**: Perspectiva 3D con escala variable (50%-150% según Z)
|
||||||
- **Z-sorting**: Painter's Algorithm para oclusión correcta
|
- **Z-sorting**: Painter's Algorithm para oclusión correcta
|
||||||
- **Escala dinámica**: Control manual con Numpad +/- (30% - 300%)
|
- **Escala dinámica**: Control manual con Numpad +/- (30% - 300%)
|
||||||
- **Protección de clipping**: Escala limitada automáticamente según resolución
|
- **Protección de clipping**: Escala limitada automáticamente según resolución
|
||||||
- **Sin sprites adicionales**: Usa `SDL_SetTextureColorMod` para simular profundidad
|
- **Sin sprites adicionales**: Usa `SDL_SetTextureColorMod` y vértices escalados para efectos 3D
|
||||||
|
|
||||||
### Parámetros Físicos (defines.h)
|
### Parámetros Físicos (defines.h)
|
||||||
|
|
||||||
@@ -191,6 +193,7 @@ SHAPE_SCALE_STEP = 0.1f; // Incremento 10%
|
|||||||
|
|
||||||
- **Activación**: Presiona Q/W/E/R/T/Y/U/I para figura específica, o F para toggle
|
- **Activación**: Presiona Q/W/E/R/T/Y/U/I para figura específica, o F para toggle
|
||||||
- **Escala**: Usa Numpad +/- para ajustar tamaño, * para reset
|
- **Escala**: Usa Numpad +/- para ajustar tamaño, * para reset
|
||||||
|
- **Perspectiva**: Numpad / para activar/desactivar zoom por profundidad (ON por defecto)
|
||||||
- **Salir**: G (sin gravedad), cursores (con gravedad), F (toggle), o 1-8 (cambiar escenario)
|
- **Salir**: G (sin gravedad), cursores (con gravedad), F (toggle), o 1-8 (cambiar escenario)
|
||||||
- **Compatible**: Funciona con 1-100,000 pelotas
|
- **Compatible**: Funciona con 1-100,000 pelotas
|
||||||
- **Temas**: Mantiene paleta de colores activa
|
- **Temas**: Mantiene paleta de colores activa
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ Ball::Ball(float x, float vx, float vy, Color color, std::shared_ptr<Texture> te
|
|||||||
target_x_ = pos_.x;
|
target_x_ = pos_.x;
|
||||||
target_y_ = pos_.y;
|
target_y_ = pos_.y;
|
||||||
depth_brightness_ = 1.0f;
|
depth_brightness_ = 1.0f;
|
||||||
|
depth_scale_ = 1.0f;
|
||||||
rotoball_attraction_active_ = false;
|
rotoball_attraction_active_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +298,10 @@ void Ball::setDepthBrightness(float brightness) {
|
|||||||
depth_brightness_ = brightness;
|
depth_brightness_ = brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ball::setDepthScale(float scale) {
|
||||||
|
depth_scale_ = scale;
|
||||||
|
}
|
||||||
|
|
||||||
// Activar/desactivar atracción física hacia esfera RotoBall
|
// Activar/desactivar atracción física hacia esfera RotoBall
|
||||||
void Ball::enableRotoBallAttraction(bool enable) {
|
void Ball::enableRotoBallAttraction(bool enable) {
|
||||||
rotoball_attraction_active_ = enable;
|
rotoball_attraction_active_ = enable;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class Ball {
|
|||||||
float pos_3d_x_, pos_3d_y_, pos_3d_z_; // Posición 3D en la esfera
|
float pos_3d_x_, pos_3d_y_, pos_3d_z_; // Posición 3D en la esfera
|
||||||
float target_x_, target_y_; // Posición destino 2D (proyección)
|
float target_x_, target_y_; // Posición destino 2D (proyección)
|
||||||
float depth_brightness_; // Brillo según profundidad Z (0.0-1.0)
|
float depth_brightness_; // Brillo según profundidad Z (0.0-1.0)
|
||||||
|
float depth_scale_; // Escala según profundidad Z (0.5-1.5)
|
||||||
bool rotoball_attraction_active_; // ¿Está siendo atraída hacia la esfera?
|
bool rotoball_attraction_active_; // ¿Está siendo atraída hacia la esfera?
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -82,6 +83,8 @@ class Ball {
|
|||||||
void setRotoBallScreenPosition(float x, float y); // Establecer posición directa en pantalla
|
void setRotoBallScreenPosition(float x, float y); // Establecer posición directa en pantalla
|
||||||
void setDepthBrightness(float brightness);
|
void setDepthBrightness(float brightness);
|
||||||
float getDepthBrightness() const { return depth_brightness_; }
|
float getDepthBrightness() const { return depth_brightness_; }
|
||||||
|
void setDepthScale(float scale);
|
||||||
|
float getDepthScale() const { return depth_scale_; }
|
||||||
|
|
||||||
// Sistema de atracción física hacia esfera RotoBall
|
// Sistema de atracción física hacia esfera RotoBall
|
||||||
void enableRotoBallAttraction(bool enable);
|
void enableRotoBallAttraction(bool enable);
|
||||||
|
|||||||
@@ -346,6 +346,17 @@ void Engine::handleEvents() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_DIVIDE:
|
||||||
|
if (current_mode_ == SimulationMode::SHAPE) {
|
||||||
|
depth_zoom_enabled_ = !depth_zoom_enabled_;
|
||||||
|
text_ = depth_zoom_enabled_ ? "DEPTH ZOOM ON" : "DEPTH ZOOM OFF";
|
||||||
|
int text_width = static_cast<int>(text_.length() * 8);
|
||||||
|
text_pos_ = (current_screen_width_ - text_width) / 2;
|
||||||
|
text_init_time_ = SDL_GetTicks();
|
||||||
|
show_text_ = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SDLK_1:
|
case SDLK_1:
|
||||||
scenario_ = 0;
|
scenario_ = 0;
|
||||||
initBalls(scenario_);
|
initBalls(scenario_);
|
||||||
@@ -443,6 +454,7 @@ void Engine::render() {
|
|||||||
SDL_FRect pos = balls_[idx]->getPosition();
|
SDL_FRect pos = balls_[idx]->getPosition();
|
||||||
Color color = balls_[idx]->getColor();
|
Color color = balls_[idx]->getColor();
|
||||||
float brightness = balls_[idx]->getDepthBrightness();
|
float brightness = balls_[idx]->getDepthBrightness();
|
||||||
|
float depth_scale = balls_[idx]->getDepthScale();
|
||||||
|
|
||||||
// Mapear brightness de 0-1 a rango MIN-MAX
|
// Mapear brightness de 0-1 a rango MIN-MAX
|
||||||
float brightness_factor = (ROTOBALL_MIN_BRIGHTNESS + brightness *
|
float brightness_factor = (ROTOBALL_MIN_BRIGHTNESS + brightness *
|
||||||
@@ -453,14 +465,14 @@ void Engine::render() {
|
|||||||
int g_mod = static_cast<int>(color.g * brightness_factor);
|
int g_mod = static_cast<int>(color.g * brightness_factor);
|
||||||
int b_mod = static_cast<int>(color.b * brightness_factor);
|
int b_mod = static_cast<int>(color.b * brightness_factor);
|
||||||
|
|
||||||
addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, r_mod, g_mod, b_mod);
|
addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, r_mod, g_mod, b_mod, depth_scale);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// MODO PHYSICS: Renderizar en orden normal del vector
|
// MODO PHYSICS: Renderizar en orden normal del vector (sin escala de profundidad)
|
||||||
for (auto &ball : balls_) {
|
for (auto &ball : balls_) {
|
||||||
SDL_FRect pos = ball->getPosition();
|
SDL_FRect pos = ball->getPosition();
|
||||||
Color color = ball->getColor();
|
Color color = ball->getColor();
|
||||||
addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, color.r, color.g, color.b);
|
addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, color.r, color.g, color.b, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,7 +786,7 @@ void Engine::renderGradientBackground() {
|
|||||||
SDL_RenderGeometry(renderer_, nullptr, bg_vertices, 4, bg_indices, 6);
|
SDL_RenderGeometry(renderer_, nullptr, bg_vertices, 4, bg_indices, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b) {
|
void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale) {
|
||||||
int vertex_index = static_cast<int>(batch_vertices_.size());
|
int vertex_index = static_cast<int>(batch_vertices_.size());
|
||||||
|
|
||||||
// Crear 4 vértices para el quad (2 triángulos)
|
// Crear 4 vértices para el quad (2 triángulos)
|
||||||
@@ -785,23 +797,29 @@ void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g,
|
|||||||
float gf = g / 255.0f;
|
float gf = g / 255.0f;
|
||||||
float bf = b / 255.0f;
|
float bf = b / 255.0f;
|
||||||
|
|
||||||
|
// Aplicar escala al tamaño (centrado en el punto x, y)
|
||||||
|
float scaled_w = w * scale;
|
||||||
|
float scaled_h = h * scale;
|
||||||
|
float offset_x = (w - scaled_w) / 2.0f; // Offset para centrar
|
||||||
|
float offset_y = (h - scaled_h) / 2.0f;
|
||||||
|
|
||||||
// Vértice superior izquierdo
|
// Vértice superior izquierdo
|
||||||
vertices[0].position = {x, y};
|
vertices[0].position = {x + offset_x, y + offset_y};
|
||||||
vertices[0].tex_coord = {0.0f, 0.0f};
|
vertices[0].tex_coord = {0.0f, 0.0f};
|
||||||
vertices[0].color = {rf, gf, bf, 1.0f};
|
vertices[0].color = {rf, gf, bf, 1.0f};
|
||||||
|
|
||||||
// Vértice superior derecho
|
// Vértice superior derecho
|
||||||
vertices[1].position = {x + w, y};
|
vertices[1].position = {x + offset_x + scaled_w, y + offset_y};
|
||||||
vertices[1].tex_coord = {1.0f, 0.0f};
|
vertices[1].tex_coord = {1.0f, 0.0f};
|
||||||
vertices[1].color = {rf, gf, bf, 1.0f};
|
vertices[1].color = {rf, gf, bf, 1.0f};
|
||||||
|
|
||||||
// Vértice inferior derecho
|
// Vértice inferior derecho
|
||||||
vertices[2].position = {x + w, y + h};
|
vertices[2].position = {x + offset_x + scaled_w, y + offset_y + scaled_h};
|
||||||
vertices[2].tex_coord = {1.0f, 1.0f};
|
vertices[2].tex_coord = {1.0f, 1.0f};
|
||||||
vertices[2].color = {rf, gf, bf, 1.0f};
|
vertices[2].color = {rf, gf, bf, 1.0f};
|
||||||
|
|
||||||
// Vértice inferior izquierdo
|
// Vértice inferior izquierdo
|
||||||
vertices[3].position = {x, y + h};
|
vertices[3].position = {x + offset_x, y + offset_y + scaled_h};
|
||||||
vertices[3].tex_coord = {0.0f, 1.0f};
|
vertices[3].tex_coord = {0.0f, 1.0f};
|
||||||
vertices[3].color = {rf, gf, bf, 1.0f};
|
vertices[3].color = {rf, gf, bf, 1.0f};
|
||||||
|
|
||||||
@@ -1010,9 +1028,10 @@ void Engine::toggleShapeMode(bool force_gravity_on_exit) {
|
|||||||
// Volver a modo física normal
|
// Volver a modo física normal
|
||||||
current_mode_ = SimulationMode::PHYSICS;
|
current_mode_ = SimulationMode::PHYSICS;
|
||||||
|
|
||||||
// Desactivar atracción - las pelotas conservan su velocidad tangencial actual
|
// Desactivar atracción y resetear escala de profundidad
|
||||||
for (auto& ball : balls_) {
|
for (auto& ball : balls_) {
|
||||||
ball->enableRotoBallAttraction(false);
|
ball->enableRotoBallAttraction(false);
|
||||||
|
ball->setDepthScale(1.0f); // Reset escala a 100% (evita "pop" visual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activar gravedad al salir (solo si se especifica)
|
// Activar gravedad al salir (solo si se especifica)
|
||||||
@@ -1120,6 +1139,11 @@ void Engine::updateShape() {
|
|||||||
float z_normalized = (z_3d + shape_size) / (2.0f * shape_size);
|
float z_normalized = (z_3d + shape_size) / (2.0f * shape_size);
|
||||||
z_normalized = std::max(0.0f, std::min(1.0f, z_normalized));
|
z_normalized = std::max(0.0f, std::min(1.0f, z_normalized));
|
||||||
balls_[i]->setDepthBrightness(z_normalized);
|
balls_[i]->setDepthBrightness(z_normalized);
|
||||||
|
|
||||||
|
// Calcular escala según profundidad Z (perspectiva) - solo si está activado
|
||||||
|
// 0.0 (fondo) → 0.5x, 0.5 (medio) → 1.0x, 1.0 (frente) → 1.5x
|
||||||
|
float depth_scale = depth_zoom_enabled_ ? (0.5f + z_normalized * 1.0f) : 1.0f;
|
||||||
|
balls_[i]->setDepthScale(depth_scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ private:
|
|||||||
ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F
|
ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F
|
||||||
std::unique_ptr<Shape> active_shape_; // Puntero polimórfico a figura activa
|
std::unique_ptr<Shape> active_shape_; // Puntero polimórfico a figura activa
|
||||||
float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-)
|
float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-)
|
||||||
|
bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado
|
||||||
|
|
||||||
// Batch rendering
|
// Batch rendering
|
||||||
std::vector<SDL_Vertex> batch_vertices_;
|
std::vector<SDL_Vertex> batch_vertices_;
|
||||||
@@ -123,7 +124,7 @@ private:
|
|||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
void renderGradientBackground();
|
void renderGradientBackground();
|
||||||
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b);
|
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);
|
||||||
|
|
||||||
// Sistema de Figuras 3D
|
// Sistema de Figuras 3D
|
||||||
void toggleShapeMode(bool force_gravity_on_exit = true); // Toggle PHYSICS ↔ última figura (tecla F)
|
void toggleShapeMode(bool force_gravity_on_exit = true); // Toggle PHYSICS ↔ última figura (tecla F)
|
||||||
|
|||||||
Reference in New Issue
Block a user