{"id":24171286,"url":"https://github.com/gitfrandu4/vr-fishing","last_synced_at":"2026-05-02T23:36:44.493Z","repository":{"id":271011381,"uuid":"911826864","full_name":"gitfrandu4/vr-fishing","owner":"gitfrandu4","description":"🎣 WebXR fishing simulator using Three.js \u0026 Ammo.js. Features PBR materials, custom shaders, physics-based line simulation, and procedural fish AI. Supports both VR and desktop modes.","archived":false,"fork":false,"pushed_at":"2025-01-09T15:18:22.000Z","size":13596,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-13T00:36:20.187Z","etag":null,"topics":["ammojs","fbx","fbx-loader","javascript","threejs","webxr"],"latest_commit_sha":null,"homepage":"https://gitfrandu4.github.io/vr-fishing/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gitfrandu4.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-04T00:30:05.000Z","updated_at":"2025-01-09T15:18:26.000Z","dependencies_parsed_at":"2025-01-04T19:38:04.443Z","dependency_job_id":null,"html_url":"https://github.com/gitfrandu4/vr-fishing","commit_stats":null,"previous_names":["gitfrandu4/igproject"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Fvr-fishing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Fvr-fishing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Fvr-fishing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitfrandu4%2Fvr-fishing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gitfrandu4","download_url":"https://codeload.github.com/gitfrandu4/vr-fishing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241505668,"owners_count":19973456,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ammojs","fbx","fbx-loader","javascript","threejs","webxr"],"created_at":"2025-01-13T00:36:28.979Z","updated_at":"2025-10-10T14:41:37.218Z","avatar_url":"https://github.com/gitfrandu4.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VR Fishing 🎣\n\n**URL del Proyecto**: [https://gitfrandu4.github.io/vr-fishing/](https://gitfrandu4.github.io/vr-fishing/)\n\n## Introducción y Motivación del Proyecto\n\nVR Fishing nace como un proyecto integrador que combina los tres bloques fundamentales del curso de Informática Gráfica:\n\n### Fundamentos\n\n- Implementación de conceptos básicos de rasterización y transformaciones 3D\n- Uso de primitivas geométricas para construir el entorno\n- Gestión de visibilidad y recorte de objetos\n- Sistema de iluminación básica\n\n### Realismo\n\n- Animación de peces mediante sistemas de partículas y morphing\n- Implementación de shaders personalizados para el agua, el cesped y efectos visuales\n- Sistema avanzado de materiales PBR (Physically Based Rendering)\n- Mapeo de texturas y efectos ambientales\n- Sistema de física para la simulación de la caña y los peces\n\n### Realidad Mixta\n\n- Integración completa con WebXR para experiencia VR\n- Controles adaptados tanto para PC como para dispositivos VR\n- Sistema de interacción natural con los controladores VR\n- Optimizaciones específicas para rendimiento en VR\n\nLa motivación principal ha sido crear una experiencia que demuestre la aplicación práctica de estos tres bloques en un único proyecto cohesivo, permitiendo ver cómo los conceptos fundamentales sirven de base para implementar características realistas que finalmente se integran en un entorno de realidad virtual inmersivo.\n\n---\n\n## Índice\n\n- [VR Fishing 🎣](#vr-fishing-)\n  - [Introducción y Motivación del Proyecto](#introducción-y-motivación-del-proyecto)\n    - [Fundamentos](#fundamentos)\n    - [Realismo](#realismo)\n    - [Realidad Mixta](#realidad-mixta)\n  - [Índice](#índice)\n  - [Descripción General](#descripción-general)\n  - [Aspectos Técnicos](#aspectos-técnicos)\n    - [Sistema de Renderizado y Pipeline Gráfico](#sistema-de-renderizado-y-pipeline-gráfico)\n    - [Sistemas de Iluminación](#sistemas-de-iluminación)\n    - [Materiales y Shaders](#materiales-y-shaders)\n    - [Técnicas de Optimización](#técnicas-de-optimización)\n    - [Sistema de Físicas](#sistema-de-físicas)\n    - [Efectos Visuales Avanzados](#efectos-visuales-avanzados)\n    - [Integración VR](#integración-vr)\n    - [Gestión de Recursos](#gestión-de-recursos)\n    - [Implementación VR/XR](#implementación-vrxr)\n      - [1. Inicialización del Sistema VR](#1-inicialización-del-sistema-vr)\n      - [2. Sistema de Controladores VR](#2-sistema-de-controladores-vr)\n      - [3. Sistema de Interacción con Controladores](#3-sistema-de-interacción-con-controladores)\n      - [4. Sistema de Movimiento en VR](#4-sistema-de-movimiento-en-vr)\n      - [5. Optimizaciones Específicas para VR](#5-optimizaciones-específicas-para-vr)\n      - [6. Retroalimentación Háptica](#6-retroalimentación-háptica)\n  - [Estructura de Archivos y Directorios](#estructura-de-archivos-y-directorios)\n  - [Tecnologías Utilizadas](#tecnologías-utilizadas)\n  - [Principales Módulos](#principales-módulos)\n    - [SceneManager](#scenemanager)\n    - [Environment](#environment)\n    - [FishingRod](#fishingrod)\n    - [FishManager](#fishmanager)\n  - [Funcionamiento General](#funcionamiento-general)\n  - [Controles y Uso](#controles-y-uso)\n  - [Uso de Librerías Externas](#uso-de-librerías-externas)\n    - [Ammo.js](#ammojs)\n    - [three.js](#threejs)\n    - [FBXLoader](#fbxloader)\n    - [Estructura Geométrica de los Modelos FBX](#estructura-geométrica-de-los-modelos-fbx)\n      - [Características Técnicas](#características-técnicas)\n  - [Configuración y Formato de Código](#configuración-y-formato-de-código)\n  - [Pasos para Ejecutar el Proyecto](#pasos-para-ejecutar-el-proyecto)\n  - [Referencias y Bibliografía](#referencias-y-bibliografía)\n\n---\n\n## Descripción General\n\nVR Fishing es un simulador de pesca en Realidad Virtual (VR) desarrollado con **three.js** y **Ammo.js**. El proyecto recrea un lago virtual con peces interactivos, donde el usuario puede lanzar una caña de pescar, capturar peces y acumular puntuación. Está diseñado para funcionar tanto en modo VR como en modo escritorio.\n\n🔗 **Accede al proyecto aquí**: [https://gitfrandu4.github.io/vr-fishing/](https://gitfrandu4.github.io/vr-fishing/)\n\n---\n\n## Aspectos Técnicos\n\n### Sistema de Renderizado y Pipeline Gráfico\n\nEl proyecto utiliza Three.js como motor de renderizado WebGL, implementando un pipeline gráfico completo que incluye:\n\n```javascript\n// Ejemplo de SceneManager.js - Pipeline de renderizado\nexport class SceneManager {\n  constructor() {\n    this.scene = new THREE.Scene();\n    this.camera = new THREE.PerspectiveCamera(\n      70, // FOV\n      window.innerWidth / window.innerHeight, // Aspect Ratio\n      0.1, // Near plane\n      1000000, // Far plane\n    );\n\n    // Configuración avanzada del renderizador\n    this.renderer = new THREE.WebGLRenderer({ antialias: true });\n    this.renderer.setPixelRatio(window.devicePixelRatio);\n    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\n    this.renderer.toneMappingExposure = 0.5;\n    this.renderer.shadowMap.enabled = true;\n  }\n\n  startAnimation(renderCallback) {\n    this.renderer.setAnimationLoop(() =\u003e {\n      if (renderCallback) renderCallback();\n      this.renderer.render(this.scene, this.camera);\n    });\n  }\n}\n```\n\n### Sistemas de Iluminación\n\nSe implementan múltiples tipos de luces para crear una iluminación realista:\n\n```javascript\n// Ejemplo de Environment.js - Sistema de iluminación\ncreateLighting() {\n  // Luz ambiental para iluminación global indirecta\n  const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.4);\n  this.scene.add(hemiLight);\n\n  // Luz ambiental para relleno suave\n  const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);\n  this.scene.add(ambientLight);\n\n  // Luz direccional principal (sol)\n  const directionalLight = new THREE.DirectionalLight(0xffffff, 2);\n  directionalLight.position.set(1, 1, 1);\n  directionalLight.castShadow = true;\n  this.scene.add(directionalLight);\n}\n```\n\n### Materiales y Shaders\n\nEl proyecto implementa diversos tipos de materiales PBR (Physically Based Rendering):\n\n```javascript\n// Ejemplo de FishingRod.js - Materiales PBR\ncreateMaterial(type) {\n  if (!this.textures) {\n    return new THREE.MeshStandardMaterial({\n      color: type === 'wood' ? 0x8b4513 : 0x888888,\n      roughness: type === 'wood' ? 0.9 : 0.4,\n      metalness: type === 'wood' ? 0.1 : 0.8,\n      name: type === 'wood' ? 'WoodMaterial' : 'MetalMaterial'\n    });\n  }\n\n  const textures = type === 'wood' ? {\n    map: this.textures.wood,\n    normalMap: this.textures.woodNormal,\n    roughnessMap: this.textures.woodRoughness,\n    roughness: 0.9,\n    metalness: 0.1\n  } : {\n    map: this.textures.metal,\n    normalMap: this.textures.metalNormal,\n    roughnessMap: this.textures.metalRoughness,\n    roughness: 0.4,\n    metalness: 0.8\n  };\n\n  return new THREE.MeshStandardMaterial(textures);\n}\n\n// Ejemplo de shaders/fishShaders.js - Shaders personalizados\nexport const fishShaders = {\n  vertexShader: `\n    varying vec3 vPosition;\n    varying vec3 vNormal;\n    void main() {\n      vPosition = position;\n      vNormal = normal;\n      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n    }\n  `,\n  fragmentShader: `\n    uniform float time;\n    uniform float waterLevel;\n    uniform vec3 color;\n    varying vec3 vPosition;\n    varying vec3 vNormal;\n\n    void main() {\n      float caustics = sin(vPosition.x * 3.0 + time) *\n                      sin(vPosition.z * 3.0 + time) * 0.8 + 0.2;\n      vec3 viewDirection = normalize(cameraPosition - vPosition);\n      float rimLight = pow(1.0 - max(0.0, dot(viewDirection, vNormal)), 2.0);\n      vec3 finalColor = color * (1.0 + caustics + rimLight);\n      gl_FragColor = vec4(finalColor, 0.95);\n    }\n  `\n};\n```\n\n### Técnicas de Optimización\n\n```javascript\n// Ejemplo de FishManager.js - Instanciación y optimización\nsetupFishInstances(fishModel, config) {\n  for (let i = 0; i \u003c config.count; i++) {\n    const fish = fishModel.clone();\n    // Optimización de geometría\n    fish.traverse(child =\u003e {\n      if (child.isMesh) {\n        child.geometry = child.geometry.clone();\n        child.geometry = new THREE.BufferGeometry().fromGeometry(child.geometry);\n        child.castShadow = true;\n        child.receiveShadow = true;\n      }\n    });\n\n    // Posicionamiento procedural optimizado\n    const x = Math.random() * 8 - 4;\n    const z = Math.random() * 8 - 4;\n    const y = Math.random() * (config.maxDepth - config.minDepth) + config.minDepth;\n    fish.position.set(x, y, z);\n\n    this.scene.add(fish);\n    this.fishes.push(fish);\n  }\n}\n```\n\n### Sistema de Físicas\n\n```javascript\n// Ejemplo de FishingRod.js - Simulación física de la línea\ncreateLine() {\n  const lineGeometry = new THREE.BufferGeometry();\n  const lineMaterial = new THREE.LineBasicMaterial({\n    color: 0xffffff,\n    transparent: true,\n    opacity: 0.6\n  });\n\n  const rodTip = new THREE.Vector3(0, 1.5, 0);\n  const waterPoint = new THREE.Vector3(0, -2, 0);\n  lineGeometry.setFromPoints([rodTip, waterPoint]);\n\n  this.line = new THREE.Line(lineGeometry, lineMaterial);\n\n  // Simulación física de la línea\n  this.updateLinePhysics = (time) =\u003e {\n    const positions = this.line.geometry.attributes.position.array;\n    const tension = this.calculateLineTension();\n    const windEffect = Math.sin(time * 2) * 0.1;\n\n    for (let i = 0; i \u003c positions.length; i += 3) {\n      positions[i + 1] += windEffect * (1 - tension);\n    }\n    this.line.geometry.attributes.position.needsUpdate = true;\n  };\n}\n```\n\n### Efectos Visuales Avanzados\n\n```javascript\n// Ejemplo de Environment.js - Sistema de agua avanzado\ncreateWater() {\n  const waterGeometry = new THREE.CircleGeometry(5, 64);\n  this.water = new Water(waterGeometry, {\n    textureWidth: 512,\n    textureHeight: 512,\n    waterNormals: this.textures.waterNormal,\n    sunDirection: new THREE.Vector3(),\n    sunColor: 0xffffff,\n    waterColor: 0x001e0f,\n    distortionScale: 3.7,\n    fog: this.scene.fog !== undefined\n  });\n\n  this.water.material.onBeforeCompile = (shader) =\u003e {\n    shader.uniforms.time = { value: 0 };\n    shader.vertexShader = shader.vertexShader.replace(\n      '#include \u003ccommon\u003e',\n      `\n      #include \u003ccommon\u003e\n      uniform float time;\n      varying vec3 vPosition;\n      `\n    );\n  };\n}\n\n// Ejemplo de celestials/Sky.js - Sistema atmosférico\nsetupSky() {\n  this.sky = new Sky();\n  this.sky.scale.setScalar(450000);\n\n  const uniforms = this.sky.material.uniforms;\n  uniforms['turbidity'].value = 10;\n  uniforms['rayleigh'].value = 3;\n  uniforms['mieCoefficient'].value = 0.005;\n  uniforms['mieDirectionalG'].value = 0.7;\n}\n```\n\n### Integración VR\n\n```javascript\n// Ejemplo de game.js - Sistema de interacción VR\nsetupVRControllers() {\n  this.controllerR = this.renderer.xr.getController(0);\n\n  // Sistema de raycasting para interacción\n  const geometry = new THREE.BufferGeometry().setFromPoints([\n    new THREE.Vector3(0, 0, 0),\n    new THREE.Vector3(0, 0, -1)\n  ]);\n  const line = new THREE.Line(geometry);\n  line.name = 'line';\n  line.scale.z = 5;\n  this.controllerR.add(line);\n\n  // Eventos de interacción VR\n  this.controllerR.addEventListener('selectstart', () =\u003e {\n    const controllerPos = new THREE.Vector3();\n    this.controllerR.getWorldPosition(controllerPos);\n    if (this.fishingRod.grab(this.controllerR, controllerPos)) {\n      this.isRodGrabbed = true;\n    }\n  });\n}\n```\n\n### Gestión de Recursos\n\n```javascript\n// Ejemplo de FishManager.js - Gestión de recursos y memoria\nasync loadFishType(config) {\n  return new Promise((resolve, reject) =\u003e {\n    this.loader.load(\n      config.modelPath,\n      (fish) =\u003e {\n        fish.scale.setScalar(config.scale);\n        // Optimización de memoria\n        fish.traverse((child) =\u003e {\n          if (child.isMesh) {\n            child.geometry.dispose();\n            child.material.dispose();\n          }\n        });\n        this.setupFishInstances(fish, config);\n        resolve();\n      },\n      (xhr) =\u003e {\n        console.log(`${config.modelPath}: ${(xhr.loaded / xhr.total) * 100}% loaded`);\n      },\n      (error) =\u003e {\n        console.error(`Error loading ${config.modelPath}:`, error);\n        reject(error);\n      }\n    );\n  });\n}\n\ndispose() {\n  // Limpieza de recursos\n  this.fishes.forEach(fish =\u003e {\n    fish.traverse(child =\u003e {\n      if (child.geometry) child.geometry.dispose();\n      if (child.material) {\n        if (Array.isArray(child.material)) {\n          child.material.forEach(material =\u003e material.dispose());\n        } else {\n          child.material.dispose();\n        }\n      }\n    });\n    this.scene.remove(fish);\n  });\n  this.fishes = [];\n}\n```\n\n### Implementación VR/XR\n\nLa implementación de la Realidad Virtual utiliza la API WebXR, que proporciona acceso a dispositivos VR a través del navegador. El sistema se estructura en varias capas:\n\n#### 1. Inicialización del Sistema VR\n\n```javascript\n// Ejemplo de game.js - Inicialización VR\nclass Game {\n  constructor() {\n    this.sceneManager = new SceneManager();\n    this.renderer = this.sceneManager.renderer;\n    this.renderer.xr.enabled = true; // Habilitamos soporte XR\n\n    // Configuración específica para VR\n    this.renderer.xr.setReferenceSpaceType('local-floor');\n    this.renderer.xr.setSession(session);\n\n    // Creamos el botón VR con opciones personalizadas\n    const vrButton = VRButton.createButton(this.renderer, {\n      requiredFeatures: ['local-floor', 'bounded-floor'],\n      optionalFeatures: ['hand-tracking'],\n    });\n  }\n}\n```\n\n#### 2. Sistema de Controladores VR\n\nLos controladores VR se implementan con un sistema completo de seguimiento y eventos:\n\n```javascript\n// Ejemplo de game.js - Sistema de controladores\nsetupVRControllers() {\n  // Configuración de fábrica de modelos de controladores\n  const controllerModelFactory = new XRControllerModelFactory();\n\n  // Controlador derecho\n  this.controllerR = this.renderer.xr.getController(0);\n  const controllerGripR = this.renderer.xr.getControllerGrip(0);\n\n  // Controlador izquierdo\n  this.controllerL = this.renderer.xr.getController(1);\n  const controllerGripL = this.renderer.xr.getControllerGrip(1);\n\n  // Sistema de visualización de rayos para apuntar\n  const geometry = new THREE.BufferGeometry();\n  geometry.setAttribute('position', new THREE.Float32BufferAttribute([0, 0, 0, 0, 0, -1], 3));\n  const material = new THREE.LineBasicMaterial({\n    color: 0xffffff,\n    transparent: true,\n    opacity: 0.5\n  });\n\n  // Añadimos líneas de ayuda visual a los controladores\n  this.controllerR.add(new THREE.Line(geometry, material));\n  this.controllerL.add(new THREE.Line(geometry, material));\n\n  // Cargamos los modelos 3D de los controladores\n  controllerGripR.add(controllerModelFactory.createControllerModel(controllerGripR));\n  controllerGripL.add(controllerModelFactory.createControllerModel(controllerGripL));\n}\n```\n\n#### 3. Sistema de Interacción con Controladores\n\nLa interacción se maneja a través de un sistema de eventos completo:\n\n```javascript\n// Ejemplo de game.js - Sistema de eventos de controladores\nsetupControllerEvents() {\n  // Eventos del controlador derecho (caña de pescar)\n  this.controllerR.addEventListener('selectstart', () =\u003e {\n    // Botón trigger - Agarrar caña\n    const controllerPos = new THREE.Vector3();\n    this.controllerR.getWorldPosition(controllerPos);\n    if (this.fishingRod.grab(this.controllerR, controllerPos)) {\n      this.isRodGrabbed = true;\n      // Retroalimentación háptica\n      if (this.controllerR.gamepad) {\n        this.controllerR.gamepad.vibrationActuator?.playEffect('dual-rumble', {\n          duration: 100,\n          strongMagnitude: 0.5,\n          weakMagnitude: 0.5\n        });\n      }\n    }\n  });\n\n  this.controllerR.addEventListener('squeezestart', () =\u003e {\n    // Botón grip - Lanzar línea\n    if (this.isRodGrabbed \u0026\u0026 !this.isCasting) {\n      this.fishingRod.startCasting();\n      this.isCasting = true;\n    }\n  });\n\n  // Eventos del controlador izquierdo (movimiento)\n  this.controllerL.addEventListener('thumbstickmove', (event) =\u003e {\n    // Joystick - Movimiento del jugador\n    const { x, y } = event.axes;\n    if (Math.abs(x) \u003e 0.1 || Math.abs(y) \u003e 0.1) {\n      this.movePlayer(x, y);\n    }\n  });\n}\n```\n\n#### 4. Sistema de Movimiento en VR\n\nEl movimiento en VR se implementa con varias técnicas para reducir la cinetosis:\n\n```javascript\n// Ejemplo de game.js - Sistema de movimiento VR\nclass Game {\n  movePlayer(x, y) {\n    // Vector de dirección basado en la orientación de la cámara\n    const camera = this.sceneManager.camera;\n    const direction = new THREE.Vector3();\n    camera.getWorldDirection(direction);\n    direction.y = 0;\n    direction.normalize();\n\n    // Vector derecho de la cámara para movimiento lateral\n    const right = new THREE.Vector3();\n    right.crossVectors(camera.up, direction).normalize();\n\n    // Calculamos el movimiento final\n    const moveSpeed = 0.1;\n    const movement = new THREE.Vector3();\n    movement.addScaledVector(direction, -y * moveSpeed); // Adelante/Atrás\n    movement.addScaledVector(right, x * moveSpeed); // Izquierda/Derecha\n\n    // Aplicamos el movimiento con suavizado\n    this.playerPosition.add(movement);\n\n    // Verificamos colisiones con el entorno\n    this.checkEnvironmentCollisions();\n  }\n\n  checkEnvironmentCollisions() {\n    // Raycast para detectar colisiones con el terreno y objetos\n    const raycaster = new THREE.Raycaster(\n      this.playerPosition,\n      new THREE.Vector3(0, -1, 0),\n    );\n    const intersects = raycaster.intersectObjects(this.collisionObjects);\n\n    if (intersects.length \u003e 0) {\n      // Ajustamos la altura del jugador al terreno\n      const groundY = intersects[0].point.y;\n      this.playerPosition.y = groundY + this.playerHeight;\n    }\n  }\n}\n```\n\n#### 5. Optimizaciones Específicas para VR\n\n```javascript\n// Ejemplo de SceneManager.js - Optimizaciones VR\nclass SceneManager {\n  setupVROptimizations() {\n    // Ajuste dinámico de resolución basado en el rendimiento\n    this.renderer.xr.setFramebufferScaleFactor(0.8);\n\n    // Sistema de LOD para VR\n    this.setupLODSystem();\n\n    // Optimización de sombras para VR\n    this.setupVRShadows();\n  }\n\n  setupLODSystem() {\n    const lod = new THREE.LOD();\n\n    // Nivel de detalle alto (cerca)\n    const highDetailGeometry = new THREE.SphereGeometry(1, 32, 32);\n    const highDetailMesh = new THREE.Mesh(highDetailGeometry, this.material);\n    lod.addLevel(highDetailMesh, 0);\n\n    // Nivel de detalle medio\n    const mediumDetailGeometry = new THREE.SphereGeometry(1, 16, 16);\n    const mediumDetailMesh = new THREE.Mesh(\n      mediumDetailGeometry,\n      this.material,\n    );\n    lod.addLevel(mediumDetailMesh, 5);\n\n    // Nivel de detalle bajo (lejos)\n    const lowDetailGeometry = new THREE.SphereGeometry(1, 8, 8);\n    const lowDetailMesh = new THREE.Mesh(lowDetailGeometry, this.material);\n    lod.addLevel(lowDetailMesh, 10);\n  }\n\n  setupVRShadows() {\n    // Configuración optimizada de sombras para VR\n    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n    this.renderer.shadowMap.autoUpdate = false;\n    this.renderer.shadowMap.needsUpdate = true;\n  }\n}\n```\n\n#### 6. Retroalimentación Háptica\n\n```javascript\n// Ejemplo de FishingRod.js - Sistema háptico\nclass FishingRod {\n  provideFishBiteHapticFeedback() {\n    if (this.controller \u0026\u0026 this.controller.gamepad) {\n      // Patrón de vibración para cuando un pez muerde el anzuelo\n      const hapticEffect = {\n        duration: 300,\n        strongMagnitude: 0.7,\n        weakMagnitude: 0.3,\n      };\n\n      // Secuencia de pulsos para simular tirones del pez\n      const pulseCount = 3;\n      let delay = 0;\n\n      for (let i = 0; i \u003c pulseCount; i++) {\n        setTimeout(() =\u003e {\n          this.controller.gamepad.vibrationActuator?.playEffect(\n            'dual-rumble',\n            hapticEffect,\n          );\n        }, delay);\n        delay += 400;\n      }\n    }\n  }\n}\n```\n\n---\n\n## Estructura de Archivos y Directorios\n\n```bash\n.\n├── index.html\n├── script.js\n├── game.js\n├── style.css\n├── lib/\n│   └── ammo.js\n├── modules/\n│   ├── SceneManager.js\n│   ├── Environment.js\n│   ├── FishingRod.js\n│   ├── FishManager.js\n│   ├── celestials/\n│   │   ├── CelestialManager.js\n│   │   ├── Sky.js\n│   │   ├── Sun.js\n│   │   ├── Moon.js\n│   │   └── Stars.js\n│   └── shaders/\n│       ├── skyShaders.js\n│       ├── fishShaders.js\n│       └── sunShaders.js\n├── models/\n│   ├── fish.fbx\n│   └── fishred.fbx\n├── textures/\n│   ├── wood/\n│   ├── metal_mesh/\n│   ├── grass/\n│   ├── rock/\n│   ├── water/\n│   └── solarsystem/\n├── .prettierrc.json\n└── package.json\n```\n\n---\n\n## Tecnologías Utilizadas\n\n- **[three.js](https://threejs.org/)** - Renderizado 3D en WebGL.\n- **[Ammo.js](https://github.com/kripken/ammo.js/)** - Simulación física y colisiones.\n- **WebXR** - APIs para Realidad Virtual y Realidad Aumentada en navegadores.\n- **HTML5/CSS3** - Estructura y estilo del juego.\n- **JavaScript (ES6+)** - Lógica del juego y controladores interactivos.\n\n---\n\n## Principales Módulos\n\n### SceneManager\n\nGestiona la escena 3D principal, incluyendo la configuración de la cámara, el renderizador y el bucle de animación. Implementa el patrón Singleton para mantener una única instancia de la escena.\n\n```javascript\nexport class SceneManager {\n  constructor() {\n    // Configuración básica de Three.js\n    this.scene = new THREE.Scene();\n    this.camera = new THREE.PerspectiveCamera(\n      70, // FOV\n      window.innerWidth / window.innerHeight, // Aspect Ratio\n      0.1, // Near plane\n      1000000, // Far plane\n    );\n\n    // Configuración del renderizador con soporte VR\n    this.renderer = new THREE.WebGLRenderer({ antialias: true });\n    this.renderer.xr.enabled = true;\n    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;\n    this.renderer.shadowMap.enabled = true;\n  }\n\n  startAnimation(renderCallback) {\n    // Bucle de renderizado optimizado para VR\n    this.renderer.setAnimationLoop(() =\u003e {\n      if (renderCallback) renderCallback();\n      this.renderer.render(this.scene, this.camera);\n    });\n  }\n}\n```\n\n### Environment\n\nCrea y gestiona el entorno virtual del lago, implementando técnicas avanzadas de shaders para el agua, terreno y efectos atmosféricos. Utiliza mapas de normales y técnicas de iluminación PBR (Physically Based Rendering).\n\n```javascript\nexport class Environment {\n  constructor(scene) {\n    this.scene = scene;\n    this.water = null;\n    this.celestials = new CelestialManager(scene);\n  }\n\n  createWater() {\n    const waterGeometry = new THREE.CircleGeometry(5, 64);\n    this.water = new Water(waterGeometry, {\n      textureWidth: 512,\n      textureHeight: 512,\n      flowDirection: new THREE.Vector2(1, 1),\n      scale: 7,\n      flowSpeed: 0.25,\n      reflectivity: 0.35,\n      opacity: 0.65,\n    });\n  }\n\n  update(time) {\n    // Actualización de shaders y efectos dinámicos\n    if (this.water?.material?.uniforms) {\n      this.water.material.uniforms.config.value.x = time * 0.5;\n      this.water.material.uniforms.flowDirection.value.set(\n        Math.sin(time * 0.1),\n        Math.cos(time * 0.1),\n      );\n    }\n  }\n}\n```\n\n### FishingRod\n\nImplementa la física e interacción de la caña de pescar utilizando técnicas de cinemática y simulación de cuerdas. Integra controles tanto para VR como para teclado/ratón.\n\n```javascript\nexport class FishingRod {\n  constructor(scene) {\n    this.scene = scene;\n    this.isGrabbed = false;\n    this.isCasting = false;\n    this.castPower = 0;\n  }\n\n  createLine() {\n    // Sistema de física para la línea de pesca\n    const lineGeometry = new THREE.BufferGeometry();\n    const lineMaterial = new THREE.LineBasicMaterial({\n      color: 0xffffff,\n      transparent: true,\n      opacity: 0.6,\n    });\n\n    // Simulación de física de cuerda\n    this.updateLinePhysics = (time) =\u003e {\n      const positions = this.line.geometry.attributes.position.array;\n      const tension = this.calculateLineTension();\n      const windEffect = Math.sin(time * 2) * 0.1;\n\n      // Aplicar física a cada segmento de la línea\n      for (let i = 0; i \u003c positions.length; i += 3) {\n        positions[i + 1] += windEffect * (1 - tension);\n      }\n      this.line.geometry.attributes.position.needsUpdate = true;\n    };\n  }\n}\n```\n\n### FishManager\n\nGestiona el movimiento y comportamiento de los peces. Utiliza shaders personalizados para efectos submarinos.\n\n```javascript\nimport { fishShaders } from './shaders/fishShaders.js';\n\nexport class FishManager {\n  constructor(scene) {\n    this.scene = scene;\n    this.fishes = [];\n  }\n\n  createFishMaterial(color) {\n    // Shader personalizado para efectos submarinos\n    return new THREE.ShaderMaterial({\n      uniforms: {\n        time: { value: 0 },\n        waterLevel: { value: -0.3 },\n        color: { value: new THREE.Color(color) },\n      },\n      vertexShader: fishShaders.vertexShader,\n      fragmentShader: fishShaders.fragmentShader,\n    });\n  }\n\n  update(time) {\n    this.fishes.forEach((fish) =\u003e {\n      if (!fish.userData.isCaught) {\n        // Movimiento procedural de los peces\n        fish.userData.angle += fish.userData.speed;\n        const newX =\n          fish.userData.centerX +\n          Math.cos(fish.userData.angle) * fish.userData.radius;\n        const newZ =\n          fish.userData.centerZ +\n          Math.sin(fish.userData.angle) * fish.userData.radius;\n\n        // Actualizar posición y rotación\n        fish.position.set(newX, fish.userData.baseY, newZ);\n        fish.rotation.y =\n          Math.atan2(newX - fish.position.x, newZ - fish.position.z) +\n          Math.PI / 2;\n      }\n    });\n  }\n}\n\nexport const fishShaders = {\n  vertexShader: `\n    varying vec3 vPosition;\n    varying vec3 vNormal;\n    void main() {\n      vPosition = position;\n      vNormal = normal;\n      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n    }\n  `,\n  fragmentShader: `\n    uniform float time;\n    uniform float waterLevel;\n    uniform vec3 color;\n    \n    varying vec3 vPosition;\n    varying vec3 vNormal;\n    \n    void main() {\n      // Efectos submarinos caustics\n      float caustics = sin(vPosition.x * 3.0 + time) * \n                      sin(vPosition.z * 3.0 + time) * 0.8 + 0.2;\n      \n      // Rim lighting submarino\n      vec3 viewDirection = normalize(cameraPosition - vPosition);\n      float rimLight = pow(1.0 - max(0.0, dot(viewDirection, vNormal)), 2.0);\n      \n      vec3 finalColor = color * (1.0 + caustics + rimLight);\n      gl_FragColor = vec4(finalColor, 0.95);\n    }\n  `,\n};\n```\n\nLos shaders han sido modularizados en archivos separados dentro de la carpeta `shaders/` para mejorar la mantenibilidad y reutilización del código. El shader de los peces implementa:\n\n1. **Vertex Shader**: Prepara las variables necesarias para los cálculos de iluminación y efectos.\n\n   - Pasa la posición y normal del vértice al fragment shader\n   - Calcula la posición final del vértice en el espacio de la pantalla\n\n2. **Fragment Shader**: Implementa efectos visuales submarinos:\n   - Caustics: Simula el efecto de la luz atravesando el agua\n   - Rim lighting: Añade un efecto de borde iluminado para mejor visibilidad\n   - Color dinámico: Modula el color base con los efectos para dar realismo\n\nCada módulo está diseñado siguiendo principios de programación orientada a objetos y patrones de diseño comunes en el desarrollo de aplicaciones 3D. La arquitectura modular permite una fácil extensibilidad y mantenimiento del código, mientras que el uso de shaders personalizados y técnicas avanzadas de renderizado asegura un rendimiento óptimo y efectos visuales de alta calidad.\n\n---\n\n## Funcionamiento General\n\n1. **Inicialización** – Se carga el entorno con `SceneManager` y `Environment`.\n2. **Creación de la caña** – `FishingRod` crea la caña de pescar interactiva.\n3. **Simulación de peces** – `FishManager` posiciona y anima a los peces.\n4. **Interacción del usuario** – Agarrar caña (`E`), lanzar (`ESPACIO`), atrapar (`F`).\n\n---\n\n## Controles y Uso\n\n- **Modo Escritorio**\n\n  - `WASD` / Flechas - Mover cámara.\n  - `E` - Agarrar/Soltar caña.\n  - `ESPACIO` - Lanzar línea.\n  - `F` - Atrapar pez.\n  - `R` - Reiniciar caña.\n  - `Q` - Activar/Desactivar depuración.\n\n- **Modo VR**\n  - **Controlador derecho**:\n    - `Trigger` – Agarrar y lanzar línea.\n    - `Grip` – Recoger línea.\n\n---\n\n## Uso de Librerías Externas\n\n### Ammo.js\n\nSe utiliza para la **simulación física y detección de colisiones**. Lo utilizamos para:\n\n- Calcular interacciones entre la caña, la línea y los peces (por ejemplo, si se desea una física más realista del sedal o colisiones con objetos).\n- Manejar el movimiento y colisiones cuando el pez es arrojado fuera del agua.\n\nEn este proyecto, la configuración de Ammo.js se realiza cargando el script `ammo.js` (versión compilada de Bullet Physics para Web), y luego llamando a:\n\n```js\nAmmo().then(() =\u003e {\n  // Inicializamos nuestra escena o lógicas físicas aquí\n});\n```\n\n### three.js\n\n**three.js** es la librería principal para renderizado 3D. En este proyecto se usa para:\n\n- Crear la escena, cámara y renderizador.\n- Incorporar la compatibilidad con **WebXR** a través de `renderer.xr.enabled = true;` y la clase `VRButton`.\n- Añadir geometrías (Cañas, Peces, Entorno) y materiales basados en shaders personalizables.\n- Manejar luces, sombras y otros efectos de postprocesado (por ejemplo, tono HDR con `ACESFilmicToneMapping`).\n\n### FBXLoader\n\nPermite **cargar modelos** en formato `.fbx` para dar vida a los peces animados:\n\n- Se importa desde el directorio de addons de three.js, por ejemplo:\n\n```js\nimport { FBXLoader } from 'three/addons/loaders/FBXLoader.js';\n```\n\n- Cada modelo se clona y se posiciona en el lago, agregando rotación, escalado y diferentes parámetros de movimiento.\n- Gracias a `FBXLoader`, es posible tener peces con animaciones complejas (si el `.fbx` incluye rigs y animaciones), o simplemente mallas estáticas para un movimiento procedural.\n\n### Estructura Geométrica de los Modelos FBX\n\nLos modelos FBX utilizados en el proyecto representan una estructura de malla poligonal (polygon mesh) optimizada para renderizado en tiempo real. \n\n#### Características Técnicas\n\n1. **Topología Poligonal**:\n\n   - Malla triangulada: Todos los polígonos son triángulos (primitiva básica en WebGL)\n   - Aproximadamente 2,500 triángulos por modelo de pez\n   - Optimización mediante índices compartidos para vértices comunes\n\n2. **Atributos por Vértice**:\n\n   - Posición (vec3): Coordenadas XYZ en el espacio 3D\n   - Normal (vec3): Vector normal para cálculos de iluminación\n   - UV (vec2): Coordenadas de textura para mapeo de materiales\n   - Tangente (vec4): Vectores tangentes para normal mapping\n\n\nEsta estructura geométrica optimizada permite:\n\n- Renderizado eficiente en WebGL\n- Gestión de memoria optimizada\n- Animaciones fluidas en tiempo real\n- Compatibilidad con técnicas de shading avanzadas\n\n---\n\n## Configuración y Formato de Código\n\n**Configuración de Prettier**:\n\n```json\n{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}\n```\n\n---\n\n## Pasos para Ejecutar el Proyecto\n\n1. **Clonar el repositorio**:\n\n```bash\ngit clone https://github.com/gitfrandu4/vr-fishing.git\ncd vr-fishing\n```\n\n2. **Abrir con Visual Studio Code**:\n\n   - Abre la carpeta del proyecto en VS Code\n   - Instala la extensión \"Live Server\" si aún no la tienes\n     - Puedes encontrarla buscando \"Live Server\" en la pestaña de extensiones\n     - O instalarla directamente desde el [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)\n\n3. **Iniciar Live Server**:\n\n   - Haz clic derecho en el archivo `index.html`\n   - Selecciona \"Open with Live Server\"\n   - O haz clic en \"Go Live\" en la barra de estado inferior de VS Code\n\n4. **Acceder al proyecto**:\n\n   - El navegador se abrirá automáticamente en `http://127.0.0.1:5500` (o un puerto similar)\n   - El proyecto se actualizará automáticamente cuando hagas cambios en el código\n\n5. **Entrar en modo VR** (si es compatible):\n   - Usa el botón \"Enter VR\" que aparece en la esquina inferior derecha\n   - Coloca el visor VR y disfruta de la experiencia\n\n**Nota**: Al ser un proyecto HTML/JavaScript estático, no requiere ninguna instalación adicional ni servidor específico. Live Server proporciona una forma cómoda de servir los archivos y ver los cambios en tiempo real durante el desarrollo.\n\n---\n\n## Referencias y Bibliografía\n\n1. **Three.js Documentation**\n\n   - [https://threejs.org/docs/](https://threejs.org/docs/)\n   - Framework base del proyecto\n   - Referencia para implementación de geometrías y materiales\n\n2. **WebXR Device API Specification**\n\n   - [https://www.w3.org/TR/webxr/](https://www.w3.org/TR/webxr/)\n   - Estándar para implementación de VR\n   - Base para el sistema de interacción VR\n\n3. **GLSL Shader Language Specification**\n\n   - [https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf](https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf)\n   - Referencia para desarrollo de shaders personalizados\n\n4. **Bullet Physics Documentation**\n\n   - [https://pybullet.org/wordpress/](https://pybullet.org/wordpress/)\n   - Base de Ammo.js para simulación física\n\n5. **\"Learn OpenGL\"**\n\n   - [https://learnopengl.com/](https://learnopengl.com/)\n   - Referencia para conceptos de renderizado y shaders\n\n6. **\"The Book of Shaders\"**\n   - [https://thebookofshaders.com/](https://thebookofshaders.com/)\n   - Guía para desarrollo de shaders GLSL\n\n---\n\n🎯 **¡Buena pesca!**\n\n---\n\n# Notas\n\n## Rasterización\n\nLa rasterización se refiere al proceso fundamental en gráficos por computadora mediante el cual las primitivas geométricas tridimensionales, como triángulos, se convierten en píxeles en una pantalla bidimensional.\n\nEn VR Fishing, esto implica:\n\n* Transformar objetos 3D (como la caña de pescar, los peces, o el entorno del lago) desde su representación en el espacio tridimensional a coordenadas 2D en la pantalla, aplicando transformaciones de cámara y perspectiva.\n\n* Llenar los píxeles dentro de cada triángulo con información de color, iluminación y textura, calculada según las propiedades definidas por los shaders y los materiales (como el agua o los peces).\n\n* Este proceso es crucial para renderizar la escena de manera eficiente y en tiempo real, especialmente en una experiencia inmersiva como VR, donde el rendimiento es esencial para garantizar una experiencia fluida y cómoda para el usuario.\n\n## Materiales PBR\n\nLos materiales PBR (_Physically Based Rendering_, o Renderizado Basado en Física) son una técnica avanzada para simular cómo interactúa la luz con los materiales de una escena 3D de manera más realista, basándose en las leyes físicas de la óptica. Los materiales PBR logran un equilibrio entre realismo y rendimiento, lo que los hace ideales para aplicaciones en tiempo real como videojuegos, simuladores y proyectos de VR como VR Fishing.\n\nPrincipales Componentes de los Materiales PBR\n\n* **Textura Albedo**: Representa el color base del material, sin efectos de iluminación ni sombras. Es el color \"plano\" de la superficie.\n* **Mapa de Normal**: Define detalles de la superficie como pequeñas irregularidades o texturas (baches, rayas, etc.) simulando geometría adicional sin aumentar el número de polígonos.\n* **Mapa de Rugosidad (_Roughness_)**: Controla cuán suave o rugosa es la superficie del material. Una superficie rugosa (como madera) dispersa la luz de manera difusa, mientras que una superficie lisa (como metal pulido) genera reflejos nítidos.\n* **Mapa Metálico (_Metallic_)**: Determina si un material tiene propiedades metálicas (como oro, acero) o no metálicas (como madera, plástico).\n* **Mapa de Oclusión Ambiental (AO - _Ambient Occlusion_)**: Añade sombras suaves en áreas donde la luz ambiental tiene menos acceso, como esquinas o grietas.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitfrandu4%2Fvr-fishing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgitfrandu4%2Fvr-fishing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitfrandu4%2Fvr-fishing/lists"}