High school project, procedural programming, error in the preview of the 3D generation

55 views Asked by At

The problem I have is about the preview of the 3D generation. I want there to be the central preview, which you can move and all that and then on the smaller right there are three canvases that are static and that show different points of view of the generation. One of the problems is that when I start the project for the first time, two objects are generated and if I move it, one goes through another, then I regenerate it and this second creation disappears but the previews (which are below the first generation) They remain like the first generation, that is, they are not updated and remain like the first. I don't think I explained it very well, so I recommend that you run it and see the error yourself.

Keep in mind that we are two students doing a "complex" programming project for ourselves for the first time. Any information would be of great help.

Code Snippet

// perlin.js  & pruebas.js

var perlin = new PerlinNoise(); // Agrega esta línea para crear una instancia de PerlinNoise
var scene, camera, renderer;
var llanuraGroup;
var mouseDown = false;
var mouseX = 0,
  mouseY = 0;
var rotationSpeed = 0.01;

// Perlin Noise

// var PerlinNoise = function() {  // <-- original code
function PerlinNoise() {           // <-- modified for snippet

  this.permutation = [
    151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
    140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
    247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
    57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
    74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
    60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
    65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
    200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3,
    64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85,
    212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170,
    213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172,
    9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112,
    104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179,
    162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199,
    106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236,
    205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61,
    156, 180
  ];
  this.p = [];
  for (var i = 0; i < 256; i++) {
    this.p[256 + i] = this.p[i] = this.permutation[i];
  }
};

PerlinNoise.prototype.dot = function(g, x, y) {
  return g[0] * x + g[1] * y;
};

PerlinNoise.prototype.fade = function(t) {
  return t * t * t * (t * (t * 6 - 15) + 10);
};

PerlinNoise.prototype.lerp = function(t, a, b) {
  return a + t * (b - a);
};

PerlinNoise.prototype.grad = function(hash, x, y) {
  var h = hash & 7;
  var grad = [
    [1, 1],
    [-1, 1],
    [1, -1],
    [-1, -1],
    [1, 0],
    [-1, 0],
    [0, 1],
    [0, -1]
  ];
  return this.dot(grad[h], x, y);
};

PerlinNoise.prototype.noise = function(x, y) {
  var X = Math.floor(x) & 255;
  var Y = Math.floor(y) & 255;
  x -= Math.floor(x);
  y -= Math.floor(y);
  var fadeX = this.fade(x);
  var fadeY = this.fade(y);

  var A = this.p[X] + Y;
  var B = this.p[X + 1] + Y;

  var AA = this.p[A];
  var AB = this.p[A + 1];
  var BA = this.p[B];
  var BB = this.p[B + 1];

  var u = this.lerp(fadeX, this.grad(AA, x, y), this.grad(BA, x - 1, y));
  var v = this.lerp(fadeX, this.grad(AB, x, y - 1), this.grad(BB, x - 1, y - 1));

  return (this.lerp(fadeY, u, v) + 1) / 2;
};

PerlinNoise.prototype.generateNoise = function(width, height, scale) {
  var noiseData = [];
  var maxNoiseHeight = -Infinity;
  var minNoiseHeight = Infinity;

  for (var y = 0; y < height; y++) {
    noiseData[y] = [];
    for (var x = 0; x < width; x++) {
      var noise = this.noise(x / scale, y / scale);
      noiseData[y][x] = noise;
      if (noise > maxNoiseHeight) {
        maxNoiseHeight = noise;
      }
      if (noise < minNoiseHeight) {
        minNoiseHeight = noise;
      }
    }
  }

  // Normalize the noise values to range between 0 and 1
  for (var y = 0; y < height; y++) {
    for (var x = 0; x < width; x++) {
      noiseData[y][x] = (noiseData[y][x] - minNoiseHeight) / (maxNoiseHeight - minNoiseHeight);
    }
  }

  return noiseData;
};

// Inicializar escena
function init() {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.getElementById("canvas-container").appendChild(renderer.domElement);

  // Crear nuevos renderizadores para las vistas adicionales
  renderer2 = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer2.setSize(window.innerWidth / 2, window.innerHeight / 2);
  document.getElementById("canvas-container").appendChild(renderer2.domElement);

  renderer3 = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer3.setSize(window.innerWidth / 2, window.innerHeight / 2);
  document.getElementById("canvas-container").appendChild(renderer3.domElement);

  renderer4 = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer4.setSize(window.innerWidth / 2, window.innerHeight / 2);
  document.getElementById("canvas-container").appendChild(renderer4.domElement);

  document.addEventListener('mousedown', onMouseDown, false);
  document.addEventListener('mouseup', onMouseUp, false);
  document.addEventListener('mousemove', onMouseMove, false);
}


// Función para manejar el evento de click izquierdo del mouse
function onMouseDown(event) {
  if (event.button === 0) {
    mouseDown = true;
    mouseX = event.clientX;
    mouseY = event.clientY;
  }
}

// Función para manejar el evento de soltar el click izquierdo del mouse
function onMouseUp(event) {
  if (event.button === 0) {
    mouseDown = false;
  }
}

// Función para manejar el evento de movimiento del mouse
function onMouseMove(event) {
  if (mouseDown) {
    var deltaX = event.clientX - mouseX;
    var deltaY = event.clientY - mouseY;
    llanuraGroup.rotation.y += deltaX * rotationSpeed;
    llanuraGroup.rotation.x += deltaY * rotationSpeed;
    mouseX = event.clientX;
    mouseY = event.clientY;
  }
}


function generarLlanura() {
  // Obtener preferencias de montaña del usuario
  var mountainInput = document.getElementById("mountainInput").value;
  var preferences = parseMountainPreferences(mountainInput);

  // Limpiar escena
  while (scene.children.length > 0) {
    scene.remove(scene.children[0]);
  }

  // Dividir la llanura en secciones
  var seccionesX = Math.random() * 10; // Número de secciones horizontales
  var seccionesZ = 5; // Número de secciones verticales

  // Generar geometría de la llanura
  var llanuraGeometry = new THREE.PlaneGeometry(100, 100, seccionesX, seccionesZ);
  llanuraGeometry.rotateX(-Math.PI / 2);

  // Material de malla con color basado en la altura
  var colorMaterial = new THREE.MeshBasicMaterial({
    vertexColors: THREE.VertexColors
  });

  // Crear grupo para la llanura
  llanuraGroup = new THREE.Group();

  // Generar montañas en cada sección de la llanura
  for (var i = 0; i <= seccionesX; i++) {
    for (var j = 0; j <= seccionesZ; j++) {
      var seccionGeometry = new THREE.PlaneGeometry(20, 20, 10, 10);
      seccionGeometry.rotateX(-Math.PI / 2);
      seccionGeometry.translate((i - seccionesX / 2) * 20, 0, (j - seccionesZ / 2) * 20);

      // Deformar vértices de forma aleatoria utilizando Perlin Noise
      var vertices = seccionGeometry.attributes.position.array;
      var colors = [];

      for (var k = 0; k < vertices.length; k += 3) {
        var x = vertices[k];
        var y = vertices[k + 1];
        var z = vertices[k + 2];


        var altura = perlin.noise(x / 10, z / 10) * 10; // Ajusta el rango de altura de las montañas aquí


        // Aplicar preferencias de montaña
        if (preferences.size === "pequeñas") {
          altura *= 0.5;
        } else if (preferences.size === "grandes") {
          altura *= 1.5;
        }

        // Calcular color basado en la altura (gradiente de color con rojo oscuro)
        var color = new THREE.Color(0x00FF00); // Color predeterminado (verde)
        var darkColor = new THREE.Color(0xFF0000); // Color oscuro (rojo oscuro)

        var t = (altura + 5) / 10; // Escala de 0 a 1
        color.lerpHSL(darkColor, t); // Interpolación lineal entre verde y rojo oscuro

        vertices[k + 1] = altura;
        colors.push(color.r, color.g, color.b);
      }

      // Aplicar colores a la geometría
      seccionGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

      // Crear malla de la sección
      var seccionMesh = new THREE.Mesh(seccionGeometry, colorMaterial);
      llanuraGroup.add(seccionMesh);
    }
  }

  // Añadir el grupo a la escena
  scene.add(llanuraGroup);
}

// Función para analizar las preferencias de montaña del usuario
function parseMountainPreferences(input) {
  var preferences = {
    size: "normales" // Valor predeterminado
  };

  // Analizar preferencias
  var words = input.toLowerCase().split(" ");
  if (words.includes("pequeñas")) {
    preferences.size = "pequeñas";
  } else if (words.includes("grandes")) {
    preferences.size = "grandes";
  }

  return preferences;
}


// Renderizar
function render() {
  requestAnimationFrame(render);

  // Renderizar la vista principal
  renderer.render(scene, camera);

  // Renderizar vistas adicionales
  renderer2.render(scene, llanuraGroup.userData.camera);
  renderer3.render(scene, llanuraGroup2.userData.camera);
  renderer4.render(scene, llanuraGroup3.userData.camera);
}


// Configurar cámara
function setupCamera() {
  var llanuraBoundingBox = new THREE.Box3().setFromObject(llanuraGroup);
  var llanuraSize = llanuraBoundingBox.getSize(new THREE.Vector3());
  var llanuraCenter = llanuraBoundingBox.getCenter(new THREE.Vector3());

  var distance = Math.max(llanuraSize.x, llanuraSize.y, llanuraSize.z) * 1.5;
  var cameraPosition = llanuraCenter.clone().add(new THREE.Vector3(0, distance, distance));

  camera.position.copy(cameraPosition);
  camera.lookAt(llanuraCenter);

  // Ajustar la cámara para las vistas laterales
  setupCameraForView(llanuraGroup, 50);
}

// Inicializar y renderizar
function setup() {
  init();
  generarLlanura();
  generarOtrasLlanuras();
  setupCamera();
  render();


}

function generarOtrasLlanuras() {
  // Crear nuevas llanuras
  llanuraGroup2 = llanuraGroup.clone();
  llanuraGroup3 = llanuraGroup.clone();

  // Mover las nuevas llanuras a posiciones diferentes
  llanuraGroup.position.set(0, 0, -50);
  llanuraGroup2.position.set(0, 0, -100);
  llanuraGroup3.position.set(0, 0, -150);

  // Añadir las nuevas llanuras a la escena
  scene.add(llanuraGroup2);
  scene.add(llanuraGroup3);

  // Ajustar cámaras y posiciones para las vistas laterales
  setupCameraForView(llanuraGroup, 50);
  setupCameraForView(llanuraGroup2, -50);
  setupCameraForView(llanuraGroup3, -100);
}

// Configurar cámara para vistas laterales
function setupCameraForView(llanuraGroup, distance) {
  if (!llanuraGroup.userData) {
    llanuraGroup.userData = {};
  }

  var llanuraBoundingBox = new THREE.Box3().setFromObject(llanuraGroup);
  var llanuraSize = llanuraBoundingBox.getSize(new THREE.Vector3());
  var llanuraCenter = llanuraBoundingBox.getCenter(new THREE.Vector3());

  var cameraPosition = llanuraCenter.clone().add(new THREE.Vector3(0, llanuraSize.y * 0.5, distance));

  // Configurar cámara para mirar al centro de la llanuraGroup
  llanuraGroup.userData.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  llanuraGroup.userData.camera.position.copy(cameraPosition);
  llanuraGroup.userData.camera.lookAt(llanuraCenter);
}
window.addEventListener('resize', function() {
  var newWidth = window.innerWidth;
  var newHeight = window.innerHeight;

  // Ajustar el tamaño del canvas principal
  renderer.setSize(newWidth, newHeight);
  camera.aspect = newWidth / newHeight;
  camera.updateProjectionMatrix();

  // Ajustar el tamaño de los canvas de las vistas adicionales
  var halfWidth = newWidth / 2;
  var halfHeight = newHeight / 2;

  renderer2.setSize(halfWidth, halfHeight);
  renderer3.setSize(halfWidth, halfHeight);
  renderer4.setSize(halfWidth, halfHeight);

  // Ajustar el tamaño de las cámaras de las vistas adicionales
  setupCameraForView(llanuraGroup, 50);
  setupCameraForView(llanuraGroup2, -50);
  setupCameraForView(llanuraGroup3, -100);
});


// Llamar a la función de configuración al cargar la página
window.onload = setup;


// Code block II

// Configuración de la API de reconocimiento de voz
const recognition = new webkitSpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;

const voiceButton = document.getElementById("voiceButton");
const voiceOutput = document.getElementById("voiceOutput");

voiceButton.addEventListener("click", () => {
  recognition.start();
});

recognition.onresult = (event) => {
  const result = event.results[event.results.length - 1];
  const transcript = result[0].transcript;
  voiceOutput.innerHTML = `Has dicho: ${transcript}`;
  processVoiceCommand(transcript);
};

recognition.onend = () => {
  recognition.start();
};

function processVoiceCommand(transcript) {
  if (transcript.includes("generar llanura")) {
    generarLlanura();
  } else if (transcript.includes("generar montañas pequeñas")) {
    const input = document.getElementById("mountainInput");
    input.value = "pequeñas";
    generarLlanura();
  } else if (transcript.includes("generar montañas grandes")) {
    const input = document.getElementById("mountainInput");
    input.value = "grandes";
    generarLlanura();
  }
}
body {
  font-family: Arial, sans-serif;
  background-color: #111;
  color: #fff;
  text-align: center;
  padding-top: 50px;
}

canvas {
  display: block;
}

input[type="text"] {
  width: 100%;
  padding: 10px;
  font-size: 16px;
  border: none;
  border-radius: 4px;
  margin-bottom: 20px;
  background-color: #222;
  color: #fff;
}

button {
  width: 100%;
  padding: 10px;
  font-size: 16px;
  border: none;
  border-radius: 4px;
  background-color: #222;
  color: #fff;
  cursor: pointer;
}

#canvas-container {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}

#canvas-container-small {
  width: 48%;
  display: flex;
  flex-direction: column;
}

#canvas2,
#canvas3,
#canvas4 {
  width: 100%;
  height: 200px;
  margin: 10px 0;
}

#voiceButton {
  position: absolute;
  top: 10px;
  right: 10px;
}


/* for Stack Overflow snippet only */

.as-console {
  color: black !important;
}
<input type="text" id="mountainInput" placeholder="Preferencias de Montañas (pequeñas o grandes)">
<button onclick="generarLlanura()">Generar Llanura</button>

<div id="canvas-container">
  <canvas id="canvas" style="position: absolute;"></canvas>
  <canvas id="canvas2" style="position: absolute;"></canvas>
  <canvas id="canvas3" style="position: absolute;"></canvas>
  <canvas id="canvas4" style="position: absolute;"></canvas>
</div>

<button id="voiceButton">Iniciar Reconocimiento de Voz</button>
<div id="voiceOutput"></div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

0

There are 0 answers