commit 54c80d2d07e11b69c59002e21b05d5518f185076
parent 1287c5fbc3f17fc02584765d9afa29915c48a348
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Thu, 27 Jun 2024 19:42:31 -0300
make all elements in scene a module an import them in `scene.js`
Diffstat:
M | tp/src/bridge.js | | | 72 | +++++++++++------------------------------------------------------------- |
M | tp/src/rails.js | | | 176 | ++++++++++++++++++++++--------------------------------------------------------- |
M | tp/src/scene.js | | | 430 | +++++++++++++++++++++++++------------------------------------------------------ |
M | tp/src/terrain.js | | | 213 | +++---------------------------------------------------------------------------- |
M | tp/src/track-map.js | | | 288 | ++++++++++++++++++++++++++++++------------------------------------------------- |
M | tp/src/train.js | | | 89 | ++++++------------------------------------------------------------------------- |
M | tp/src/tunnel.js | | | 128 | +++---------------------------------------------------------------------------- |
7 files changed, 321 insertions(+), 1075 deletions(-)
diff --git a/tp/src/bridge.js b/tp/src/bridge.js
@@ -1,56 +1,11 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
-let scene, camera, renderer, container;
-
const textures = {
tierra: { url: '/assets/tierraSeca.jpg', object: null },
ladrillos: { url: '/assets/pared-de-ladrillos.jpg', object: null },
};
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- // renderer.setClearColor(0xFFFFFF);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
- camera.position.set(25, 25, 25);
- camera.lookAt(10, 10, 10);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xaaaaaa);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const gridHelper = new THREE.GridHelper(50, 20);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper(5);
- scene.add(axesHelper);
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
function onTextureLoaded(key, texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
textures[key].object = texture;
@@ -92,7 +47,7 @@ const bridgeWallThickness = 2.5;
const bridgeLen = arcCount*(columnWidth+arcWidth)+columnWidth+startPadding+endPadding;
const bridgeHeight = columnHeight+arcRadius+topPadding;
-function generateBridgeWall() {
+export function generateBridgeWallGeometry() {
const path = new THREE.Path();
// generate the arcs
@@ -227,14 +182,16 @@ function generateBridgeCage(squaresCount = 3) {
return bridgeCage;
}
-function generateBridge() {
+export function generateBridge() {
+ const bridge = new THREE.Object3D();
+
const bridgeWidth = 10;
const roadwayHeight = 2;
- const leftWallGeometry = generateBridgeWall();
+ const leftWallGeometry = generateBridgeWallGeometry();
leftWallGeometry.translate(0, 0, -bridgeWidth/2);
- const rightWallGeometry = generateBridgeWall();
+ const rightWallGeometry = generateBridgeWallGeometry();
rightWallGeometry.translate(0, 0, bridgeWidth/2)
const bridgeColumnsGeometry = mergeGeometries([leftWallGeometry, rightWallGeometry]);
@@ -277,7 +234,7 @@ function generateBridge() {
*/
const bridgeColumns = new THREE.Mesh(bridgeColumnsGeometry, bridgeMaterial);
- scene.add(bridgeColumns);
+ bridge.add(bridgeColumns);
// para reutilizar la textura de ladrillos usada en los arcos se escalan las
// coordenadas uv de la geometria de la parte superior
@@ -287,7 +244,7 @@ function generateBridge() {
}
const bridgeRoadway = new THREE.Mesh(bridgeRoadwayGeometry, bridgeMaterial);
- scene.add(bridgeRoadway);
+ bridge.add(bridgeRoadway);
const cageGeometry = generateBridgeCage()
cageGeometry.translate(0, bridgeHeight+roadwayHeight-squareTubeRadius*2, 0);
@@ -301,7 +258,7 @@ function generateBridge() {
});
const bridgeCage = new THREE.Mesh(cageGeometry, cageMaterial);
- scene.add(bridgeCage);
+ bridge.add(bridgeCage);
const roadwayFloorGeometry = new THREE.PlaneGeometry(
bridgeWidth+bridgeWallThickness,
@@ -325,18 +282,11 @@ function generateBridge() {
});
const roadwayFloor = new THREE.Mesh(roadwayFloorGeometry, roadwayFloorMaterial);
- scene.add(roadwayFloor)
-}
-
-function mainLoop() {
- requestAnimationFrame(mainLoop);
- renderer.render(scene, camera);
+ bridge.add(roadwayFloor)
+ return bridge;
}
function main() {
- generateBridge();
- mainLoop();
}
-setupThreeJs();
loadTextures(main);
diff --git a/tp/src/rails.js b/tp/src/rails.js
@@ -1,15 +1,19 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { ParametricGeometry } from 'three/addons/geometries/ParametricGeometry.js';
import { ParametricGeometries } from 'three/examples/jsm/geometries/ParametricGeometries.js';
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
-let scene, camera, renderer, container, terrainMaterial, instancedTrees;
-let spherePath;
let railsPath;
-let railsFoundationShape;
+
+export const railsFoundationShape = new THREE.CatmullRomCurve3([
+ new THREE.Vector3( -2.00, 0.00, 0.00),
+ new THREE.Vector3( -1.00, 0.00, 0.50),
+ new THREE.Vector3( 0.00, 0.00, 0.55),
+ new THREE.Vector3( 1.00, 0.00, 0.50),
+ new THREE.Vector3( 2.00, 0.00, 0.00),
+], false);
+
const textures = {
tierra: { url: '/assets/tierra.jpg', object: null },
@@ -18,77 +22,6 @@ const textures = {
durmientes: { url: '/assets/durmientes.jpg', object: null },
};
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(
- 35, window.innerWidth / window.innerHeight, 0.1, 1000);
-
- camera.position.set(-10, 15, -10);
- camera.lookAt(0, 0, 0);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xffffff);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const gridHelper = new THREE.GridHelper(50, 20);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper(5);
- scene.add(axesHelper);
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
-function onTextureLoaded(key, texture) {
- texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
- textures[key].object = texture;
- console.log('Texture `' + key + '` loaded');
-}
-
-function loadTextures(callback) {
- const loadingManager = new THREE.LoadingManager();
-
- loadingManager.onLoad = () => {
- console.log('All textures loaded');
- callback();
- };
-
- for (const key in textures) {
- console.log("Loading textures");
- const loader = new THREE.TextureLoader(loadingManager);
- const texture = textures[key];
- texture.object = loader.load(
- texture.url,
- onTextureLoaded.bind(this, key),
- null,
- (error) => {
- console.error(error);
- }
- );
- }
-}
-
function parametricRailsFoundationFunction(u, v, target) {
const rotMatrix = new THREE.Matrix4();
const translationMatrix = new THREE.Matrix4();
@@ -125,53 +58,26 @@ function parametricRailsFoundationFunction(u, v, target) {
target.set(x, y, z);
}
-function buildRailsFoundation() {
- railsFoundationShape = new THREE.CatmullRomCurve3([
- new THREE.Vector3( -2.00, 0.00, 0.00),
- new THREE.Vector3( -1.00, 0.00, 0.50),
- new THREE.Vector3( 0.00, 0.00, 0.55),
- new THREE.Vector3( 1.00, 0.00, 0.50),
- new THREE.Vector3( 2.00, 0.00, 0.00),
- ], false);
-
+// devuelve la geometria del terraplen de la via
+export function buildRailsFoundationGeometry() {
+ /*
// show rails foundation shape
const points = railsFoundationShape.getPoints(50);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
const curveObject = new THREE.Line(geometry, lineMaterial);
scene.add(curveObject);
+ */
const pGeometry = new ParametricGeometry(
parametricRailsFoundationFunction, 100, 100);
- textures.durmientes.object.wrapS = THREE.RepeatWrapping;
- textures.durmientes.object.wrapT = THREE.RepeatWrapping;
- textures.durmientes.object.repeat.set(1, 60);
- textures.durmientes.object.anisotropy = 16;
-
- /*
- // load into `map` the example texture
- const map = new THREE.TextureLoader().load('https://threejs.org/examples/textures/uv_grid_opengl.jpg');
- map.wrapS = map.wrapT = THREE.RepeatWrapping;
- map.repeat.set(1, 30);
- map.anisotropy = 16;
- // map.rotation = Math.PI/2;
- */
-
- const pMaterial = new THREE.MeshPhongMaterial({
- side: THREE.DoubleSide,
- transparent: false,
- opacity: 1.0,
- shininess: 10,
- map: textures.durmientes.object
- });
- const pMesh = new THREE.Mesh(pGeometry, pMaterial);
- scene.add(pMesh);
+ return pGeometry;
}
// `position` es de tipo `THREE.Vector3` y representa la translacion de la
// forma del rail con respecto al origen del sist. de coordenadas de modelado
-function getParametricRailsFunction(radius, position) {
+function getParametricRailsFunction(railsRadius = 0.50, position) {
return function parametricRails(u, v, target) {
const rotMatrix = new THREE.Matrix4();
const translationMatrix = new THREE.Matrix4();
@@ -213,8 +119,8 @@ function getParametricRailsFunction(radius, position) {
}
}
-const railsRadius = 0.35;
-function buildRails() {
+// devuelve la geometria de los rieles
+export function buildRailsGeometry(railsRadius = 0.35) {
let railsGeometries = [];
const leftRailGeometryFunction = getParametricRailsFunction(railsRadius,
@@ -229,22 +135,37 @@ function buildRails() {
railsGeometries.push(leftRailGeometry);
railsGeometries.push(rightRailGeometry);
- const railsMaterial = new THREE.MeshPhongMaterial({
- side: THREE.DoubleSide,
- transparent: false,
- opacity: 1.0,
- shininess: 10,
- color: 0xFFFFFF
- });
-
const railsGeometry = mergeGeometries(railsGeometries);
- const rails = new THREE.Mesh(railsGeometry, railsMaterial);
- scene.add(rails);
+ return railsGeometry;
+}
+
+function onTextureLoaded(key, texture) {
+ texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+ textures[key].object = texture;
+ console.log('Texture `' + key + '` loaded');
}
-function mainLoop() {
- requestAnimationFrame(mainLoop);
- renderer.render(scene, camera);
+function loadTextures(callback) {
+ const loadingManager = new THREE.LoadingManager();
+
+ loadingManager.onLoad = () => {
+ console.log('All textures loaded');
+ callback();
+ };
+
+ for (const key in textures) {
+ console.log("Loading textures");
+ const loader = new THREE.TextureLoader(loadingManager);
+ const texture = textures[key];
+ texture.object = loader.load(
+ texture.url,
+ onTextureLoaded.bind(this, key),
+ null,
+ (error) => {
+ console.error(error);
+ }
+ );
+ }
}
function main() {
@@ -264,10 +185,9 @@ function main() {
scene.add(railsPathMesh);
*/
- buildRailsFoundation();
- buildRails();
- mainLoop();
+ // buildRailsFoundation();
+ // buildRails();
}
-setupThreeJs();
+// setupThreeJs();
loadTextures(main);
diff --git a/tp/src/scene.js b/tp/src/scene.js
@@ -3,7 +3,18 @@ import * as dat from 'dat.gui';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { vertexShader, fragmentShader } from '/assets/shaders.js';
-let scene, camera, renderer, container, terrainMaterial, terrainGeometry, terrain;
+import { generateTunnelGeometry } from '/src/tunnel.js';
+import { createInstancedTrees } from '/src/track-map.js';
+import { elevationGeometry } from '/src/terrain.js';
+import {
+ buildRailsGeometry,
+ buildRailsFoundationGeometry
+} from '/src/rails.js';
+import { buildTrain } from '/src/train.js';
+import { generateBridge } from '/src/bridge.js';
+import { updateTrainCrankPosition } from '/src/train.js';
+
+let scene, camera, renderer, container, terrainMaterial, terrainGeometry, terrain, time;
let treesForbiddenMapData, treesForbiddenMap, elevationMap, elevationMapData;
const widthSegments = 100;
@@ -12,13 +23,19 @@ const amplitude = 8;
const amplitudeBottom = -1.00;
const textures = {
- tierra: { url: '/assets/tierra.jpg', object: null },
roca: { url: '/assets/roca.jpg', object: null },
pasto: { url: '/assets/pasto.jpg', object: null },
+ tierra: { url: '/assets/tierra.jpg', object: null },
+ madera: { url: '/assets/madera.jpg', object: null },
+ durmientes: { url: '/assets/durmientes.jpg', object: null },
elevationMap: { url: '/assets/elevation_map2.png', object: null },
treeForbiddenMap: { url: '/assets/tree_forbidden_zone_map.png', object: null }
};
+let settings = {
+ animationEnable: true,
+};
+
function onResize() {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
@@ -33,9 +50,8 @@ function setupThreeJs() {
renderer.setClearColor(0x606060);
container.appendChild(renderer.domElement);
- camera = new THREE.PerspectiveCamera(
- 35, window.innerWidth/window.innerHeight, 0.1, 1000);
- camera.position.set(100, 120, -100);
+ camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
+ camera.position.set(-50, 60, 50);
camera.lookAt(0, 0, 0);
const controls = new OrbitControls(camera, renderer.domElement);
@@ -44,266 +60,110 @@ function setupThreeJs() {
scene.add(ambientLight);
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- //scene.add(hemisphereLight);
+ scene.add(hemisphereLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(100, 100, 100);
scene.add(directionalLight);
- const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
- // scene.add(directionalLightHelper);
+ const gridHelper = new THREE.GridHelper(150, 150);
+ scene.add(gridHelper);
- const gridHelper = new THREE.GridHelper(150, 150);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper( 5 );
- scene.add( axesHelper );
+ const axesHelper = new THREE.AxesHelper(5);
+ scene.add(axesHelper);
window.addEventListener('resize', onResize);
onResize();
}
-const imgWidth = 512;
-const imgHeight = 512;
-
-// (x, y) ∈ [imgHeight, imgWidth] -> son un punto de la imagen
-function getPixelIndex(x, y) {
- return Math.floor(x + y*imgWidth*4);
-}
-
-function getPixel(imgData, index) {
- let i = index*4, d = imgData.data
- return [d[i],d[i+1],d[i+2],d[i+3]] // Returns array [R,G,B,A]
+function onTextureLoaded(key, texture) {
+ texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+ textures[key].object = texture;
+ console.log('Texture `' + key + '` loaded');
}
-function getPixelXY(imgData, x, y) {
- return getPixel(imgData, y*imgData.width+x)
-}
+function loadTextures(callback) {
+ const loadingManager = new THREE.LoadingManager();
-// position: Vector3
-function isForbbidenPosition(position) {
- const x = Math.floor(position.x);
- const y = position.y;
- const z = Math.floor(position.z);
+ loadingManager.onLoad = () => {
+ console.log('All textures loaded');
+ callback();
+ };
- /*
- if((y > 5.0) || (y < 2.65)){
- console.log("(" + position.x + ", " + position.y + ", " + position.z + ") is not valid ");
- return true;
- }
- */
-
- let pixelArray = getPixelXY(treesForbiddenMap, x, z);
- const R = pixelArray[0]; // Red
- const G = pixelArray[1]; // Green
- const B = pixelArray[2]; // Blue
- const A = pixelArray[3]; // Alpha
- // const pixel = new THREE.Vector4(R, G, B, A);
-
- if(((R <= 10) && (G >= 250) && (B <= 10))
- || (R <= 80) && (G <= 80) && (B <= 80)
- || (R >= 200) && (G >= 200) && (B >= 200)) {
- // console.log("(" + position.x + ", " + position.y + ", " + position.z + ") is not valid ");
- return true;
+ for (const key in textures) {
+ console.log("Loading textures");
+ const loader = new THREE.TextureLoader(loadingManager);
+ const texture = textures[key];
+ texture.object = loader.load(
+ texture.url,
+ onTextureLoaded.bind(this, key),
+ null,
+ (error) => {
+ console.error(error);
+ }
+ );
}
-
- console.log("(" + position.x + ", " + position.y + ") is valid ");
- return false;
}
-// obtiene una posicion aleatoria en el terreno, para obtener la altura del
-// terreno utiliza el mapa de elevacion.
-// `padding` permite definir un borde del cual no se toman puntos
-function getRandomPositionInTerrain(padding = 0) {
- const x = Math.floor(Math.random() * (widthSegments-(padding*2)));
- const z = Math.floor(Math.random() * (heightSegments-(padding*2)));
-
- const pixelArray = getPixelXY(elevationMap, x, z); // array [R,G,B,A]
- const y = (pixelArray[0]/255)*amplitude;
-
- const position = new THREE.Vector3(x+padding, y, z+padding);
- return position;
+function buildBridge() {
+ const bridge = generateBridge();
+ scene.add(bridge);
}
-function createInstancedTrees(count) {
- console.log('Generating `' + count + '` instances of tree');
-
- let logHeight = 4.0;
- const treeLogGeometry = new THREE.CylinderGeometry(
- 0.30, 0.30, logHeight, 40, 40);
- treeLogGeometry.translate(0, logHeight/2.0, 0);
- const instancedTreeLogGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLogGeometry.copy(treeLogGeometry);
- const treeLogMaterial = new THREE.MeshPhongMaterial({color: 0x7c3f00});
- const instancedTreeLogs = new THREE.InstancedMesh(
- instancedTreeLogGeometry,
- treeLogMaterial,
- count);
-
- const treeLeavesGeometry = new THREE.SphereGeometry(1.75,40,40);
- const instancedTreeLeavesGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLeavesGeometry.copy(treeLeavesGeometry);
- const treeLeavesMaterial = new THREE.MeshPhongMaterial({color: 0x365829});
- const instancedTreeLeaves = new THREE.InstancedMesh(
- instancedTreeLeavesGeometry,
- treeLeavesMaterial,
- count);
-
- const rotMatrix = new THREE.Matrix4();
- const translationMatrix = new THREE.Matrix4();
- const treeLogMatrix = new THREE.Matrix4();
- const treeLeavesMatrix = new THREE.Matrix4();
-
- const treesBorderPadding = 3.0;
- for (let i = 0; i < count; i++) {
- let position = getRandomPositionInTerrain(treesBorderPadding);
- for(let j = 0; isForbbidenPosition(position); ++j) {
- position = getRandomPositionInTerrain(treesBorderPadding);
- if(j++ == 1000) { // maximo de iteraciones
- break;
- }
- }
-
- if(isForbbidenPosition(position)) {
- continue;
- }
-
- position.x -= widthSegments/2;
- position.y += amplitudeBottom;
- position.z -= heightSegments/2;
- translationMatrix.makeTranslation(position);
- treeLogMatrix.identity();
- treeLeavesMatrix.identity();
-
- let scale = 0.5 + (Math.random()*(logHeight/3));
- treeLogMatrix.makeScale(1, scale, 1);
- treeLogMatrix.premultiply(translationMatrix);
-
- position.y += scale * logHeight;
- translationMatrix.makeTranslation(position);
- treeLeavesMatrix.premultiply(translationMatrix);
-
- instancedTreeLogs.setMatrixAt(i, treeLogMatrix);
- instancedTreeLeaves.setMatrixAt(i, treeLeavesMatrix);
- }
-
- console.log('Done generating `' + count + '` instances of tree');
- return [instancedTreeLogs, instancedTreeLeaves];
+// loco -> locomotora/locomotive
+function buildLoco() {
+ const train = buildTrain();
+ train.scale.set(0.35, 0.35, 0.35)
+ scene.add(train);
}
+function buildRailsFoundation() {
+ const railsFoundationGeometry = buildRailsFoundationGeometry();
-// La funcion devuelve una geometria de Three.js
-// width: Ancho del plano
-// height: Alto del plano
-// amplitude: Amplitud de la elevacion
-// widthSegments: Numero de segmentos en el ancho
-// heightSegments: Numero de segmentos en el alto
-function elevationGeometry(width, height, amplitude, widthSegments, heightSegments) {
- console.log('Generating terrain geometry');
- let geometry = new THREE.BufferGeometry();
-
- const positions = [];
- const indices = [];
- const normals = [];
- const uvs = [];
-
- let imageData = elevationMap;
- let data = elevationMapData;
-
- const quadsPerRow = widthSegments - 1;
-
- // Recorremos los segmentos horizontales y verticales
- for (let x = 0; x < widthSegments - 1; x++) {
- for (let y = 0; y < heightSegments - 1; y++) {
- // valor del pixel en el mapa de elevacion en la posicion i, j
-
- let pixel = getPixelXY(imageData, x, y);
-
- // se utiliza el canal rojo [R, G, B, A];
- let z0 = pixel[0] / 255;
- const z = amplitude * z0;
-
- // valores de los píxeles de los puntos adyacentes
- let xPrev, xNext, yPrev, yNext;
-
- xPrev = (x > 0) ? getPixelXY(imageData, x-1, y)[0]/255 : undefined;
- xNext = (x < widthSegments-1) ? getPixelXY(imageData, x+1, y)[0]/255 : undefined;
-
- yPrev = (y > 0) ? getPixelXY(imageData, x, y+1)[0]/255 : undefined;
- yNext = (y < heightSegments-1) ? getPixelXY(imageData, x, y+1)[0]/255 : undefined;
-
- // diferencia entre los valores de los píxeles adyacentes en el eje
- // `x` y en el eje `y` de la imagen en el espacio de la textura
- let deltaX;
- if (xPrev == undefined) {
- deltaX = xNext - z0;
- } else if (yNext == undefined) {
- deltaX = xPrev - z0;
- } else {
- deltaX = (xNext - xPrev) / 2;
- }
-
- let deltaY;
- if (yPrev == undefined) {
- deltaY = yNext - z0;
- } else if (yNext == undefined) {
- deltaY = yPrev - z0;
- } else {
- deltaY = (yNext - yPrev) / 2;
- }
-
- // Añadimos los valores de los puntos al array de posiciones
- positions.push((width * x) / widthSegments - width / 2);
- positions.push(z);
- positions.push((height * y) / heightSegments - height / 2);
-
- // vectores tangentes a la superficie en el eje `x` y en el eje `y`
- let tanX = new THREE.Vector3(width / widthSegments, deltaX * amplitude, 0);
- let tanY = new THREE.Vector3(0, deltaY * amplitude, height / heightSegments);
-
- tanX.normalize();
- tanY.normalize();
+ textures.durmientes.object.wrapS = THREE.RepeatWrapping;
+ textures.durmientes.object.wrapT = THREE.RepeatWrapping;
+ textures.durmientes.object.repeat.set(1, 60);
+ textures.durmientes.object.anisotropy = 16;
- let normal = new THREE.Vector3().crossVectors(tanY, tanX);
-
- normals.push(normal.x);
- normals.push(normal.y);
- normals.push(normal.z);
-
- uvs.push(x / (widthSegments - 1));
- uvs.push(y / (heightSegments - 1));
-
- if ((x == widthSegments-2) || (y == heightSegments-2)) continue;
-
- // Ensamblamos los triangulos
- indices.push(x + y*quadsPerRow);
- indices.push(x + 1 + y*quadsPerRow);
- indices.push(x + 1 + (y+1)*quadsPerRow);
+ const railsFoundationMaterial = new THREE.MeshPhongMaterial({
+ side: THREE.DoubleSide,
+ transparent: false,
+ opacity: 1.0,
+ shininess: 10,
+ map: textures.durmientes.object
+ });
- indices.push(x + y*quadsPerRow);
- indices.push(x + 1 + (y+1)*quadsPerRow);
- indices.push(x + (y+1)*quadsPerRow);
- }
- }
+ const railsFoundation = new THREE.Mesh(railsFoundationGeometry, railsFoundationMaterial);
+ railsFoundation.scale.set(5, 5, 5);
+ scene.add(railsFoundation);
+}
- geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
- geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
- geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
- geometry.setIndex(indices);
+function buildRails() {
+ const railsGeometry = buildRailsGeometry();
+ const railsMaterial = new THREE.MeshPhongMaterial({
+ side: THREE.DoubleSide,
+ transparent: false,
+ opacity: 1.0,
+ shininess: 10,
+ color: 0xFFFFFF
+ });
- return geometry;
+ const rails = new THREE.Mesh(railsGeometry, railsMaterial);
+ rails.scale.set(5, 5, 5);
+ scene.add(rails);
}
-function buildScene() {
- console.log('Building scene');
+function buildTerrain() {
+ // console.log('Building scene');
- const width = widthSegments;
- const height = heightSegments;
+ const width = 100;
+ const height = 100;
terrainGeometry = elevationGeometry(
width, height,
amplitude,
- widthSegments, heightSegments);
+ widthSegments, heightSegments,
+ textures.elevationMap.object);
console.log('Applying textures');
terrainMaterial = new THREE.RawShaderMaterial({
@@ -328,91 +188,73 @@ function buildScene() {
terrain.position.set(0, amplitudeBottom, 0);
scene.add(terrain);
- const waterGeometry = new THREE.PlaneGeometry(width/2, height-1.55);
+ console.log('Generating water');
+ const waterGeometry = new THREE.PlaneGeometry(width/2, height);
const waterMaterial = new THREE.MeshPhongMaterial( {color: 0x12ABFF, side: THREE.DoubleSide} );
const water = new THREE.Mesh( waterGeometry, waterMaterial );
water.rotateX(Math.PI/2);
- water.position.set(0, 0.75, -1.00);
+ water.position.set(0, 0.75, 0);
scene.add(water);
-
- const [treeLogs, treeLeaves] = createInstancedTrees(250);
- scene.add(treeLogs);
- scene.add(treeLeaves);
}
-function onTextureLoaded(key, texture) {
- texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
- textures[key].object = texture;
- console.log('Texture `' + key + '` loaded');
-}
+function buildTunnel() {
+ const tunnelGeometry = generateTunnelGeometry();
-function loadTextures(callback) {
- const loadingManager = new THREE.LoadingManager();
+ textures.madera.object.wrapS = THREE.RepeatWrapping;
+ textures.madera.object.wrapT = THREE.RepeatWrapping;
+ textures.madera.object.repeat.set(0.10, 0.10);
+ textures.madera.object.anisotropy = 16;
- loadingManager.onLoad = () => {
- console.log('All textures loaded');
- callback();
- };
+ const tunnelMaterial = new THREE.MeshPhongMaterial({
+ side: THREE.DoubleSide,
+ transparent: false,
+ opacity: 1.0,
+ shininess: 10,
+ map: textures.madera.object
+ });
- for (const key in textures) {
- console.log("Loading textures");
- const loader = new THREE.TextureLoader(loadingManager);
- const texture = textures[key];
- texture.object = loader.load(
- texture.url,
- onTextureLoaded.bind(this, key),
- null,
- (error) => {
- console.error(error);
- }
- );
- }
+ const mesh = new THREE.Mesh(tunnelGeometry, tunnelMaterial) ;
+ scene.add(mesh);
+}
+
+function buildTrees(count = 50) {
+ const [treeLogs, treeLeaves] = createInstancedTrees(count);
+ scene.add(treeLogs);
+ scene.add(treeLeaves);
}
function createMenu() {
- const gui = new dat.GUI({ width: 400 });
- gui.add(terrainMaterial.uniforms.scale, 'value', 1.00, 5.00).name('Terrain texture scale');
- gui.add(terrainMaterial.uniforms.dirtStepWidth, 'value', 0.0, 1.0).name('dirt step width');
- gui.add(terrainMaterial.uniforms.rockStepWidth, 'value', 0.10, 0.50).name('rock step width');
+ const gui = new dat.GUI({ width: 250 });
+ gui.add(settings, 'animationEnable', true).name('Animations enabled');
+ // console.log(settings.animationEnable);
+}
+
+function buildScene() {
+ console.log('Building scene');
+ buildTunnel();
+ // buildTrees(100);
+ // buildTerrain();
+ buildRailsFoundation();
+ buildRails();
+ buildLoco();
+ // buildBridge();
}
function mainLoop() {
requestAnimationFrame(mainLoop);
renderer.render(scene, camera);
-}
-
-function loadMapsData() {
- console.log("Loading maps data");
-
- // Creamos un canvas para poder leer los valores de los píxeles de la textura
- let canvas = document.createElement('canvas');
- let ctx = canvas.getContext('2d');
- let treesForbiddenMapImage = textures.treeForbiddenMap.object.image;
- let elevationMapImage = textures.elevationMap.object.image;
-
- // ambos mapas deben tener el mismo tamaño
- const imgWidth = widthSegments;
- const imgHeight = heightSegments;
-
- canvas.width = imgWidth;
- canvas.height = imgHeight;
-
- ctx.drawImage(treesForbiddenMapImage, 0, 0, imgWidth, imgHeight);
- treesForbiddenMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
- treesForbiddenMapData = treesForbiddenMap.data;
-
- ctx.drawImage(elevationMapImage, 0, 0, imgWidth, imgHeight);
- elevationMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
- elevationMapData = elevationMap.data
-
- console.log("All maps data loaded succesfully");
+ time += 0.05;
+ if(settings.animationEnable) {
+ updateTrainCrankPosition(time);
+ }
+ renderer.render(scene, camera);
}
function main() {
- loadMapsData();
+ time = 0.00;
buildScene();
- // getTrainTrackShape();
+ createMenu();
mainLoop();
}
diff --git a/tp/src/terrain.js b/tp/src/terrain.js
@@ -1,13 +1,11 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { vertexShader, fragmentShader } from '/assets/shaders.js';
-let scene, camera, renderer, container, terrainMaterial, terrainGeometry, terrain;
+let terrainMaterial, terrainGeometry, terrain;
-const widthSegments = 100;
-const heightSegments = 100;
-const amplitude = 8;
+const widthSegments = 100;
+const heightSegments = 100;
+const amplitude = 8;
const amplitudeBottom = -1.00;
const textures = {
@@ -17,141 +15,6 @@ const textures = {
elevationMap: { url: '/assets/elevation_map2.png', object: null },
};
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(
- 35, window.innerWidth/window.innerHeight, 0.1, 1000);
- camera.position.set(100, 120, -100);
- camera.lookAt(0, 0, 0);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xffffff);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- //scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
- // scene.add(directionalLightHelper);
-
- const gridHelper = new THREE.GridHelper(150, 150);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper( 5 );
- scene.add( axesHelper );
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
-// obtiene una posicion aleatoria en el terreno, para obtener la altura del
-// terreno utiliza el mapa de elevacion
-function getRandomPositionInTerrain() {
- let canvas = document.createElement('canvas');
- let ctx = canvas.getContext('2d');
- let img = textures.elevationMap.object.image;
-
- canvas.width = widthSegments;
- canvas.height = heightSegments;
-
- ctx.drawImage(img, 0, 0, widthSegments, heightSegments);
- let imageData = ctx.getImageData(0, 0, widthSegments, heightSegments);
- let data = imageData.data;
- const quadsPerRow = widthSegments - 1;
-
- const x = Math.random();
- const z = Math.random();
-
- const elevationMapData = Math.floor((x + z) * widthSegments);
- const indexX = Math.floor(x * widthSegments);
- const indexZ = Math.floor(z * heightSegments);
- const y = data[(indexX + indexZ * widthSegments) * 4] / 255;
-
- const position = new THREE.Vector3((
- x - 0.5) * widthSegments,
- y * amplitude,
- (z - 0.5) * heightSegments);
-
- return position;
-}
-
-function createInstancedTrees(count) {
- console.log('Generating `' + count + '` instances of tree');
-
- let logHeight = 4.0;
- const treeLogGeometry = new THREE.CylinderGeometry(
- 0.30, 0.30, logHeight, 40, 40);
- treeLogGeometry.translate(0, logHeight/2.0, 0);
- const instancedTreeLogGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLogGeometry.copy(treeLogGeometry);
- const treeLogMaterial = new THREE.MeshPhongMaterial({color: 0x7c3f00});
- const instancedTreeLogs = new THREE.InstancedMesh(
- instancedTreeLogGeometry,
- treeLogMaterial,
- count);
-
- const treeLeavesGeometry = new THREE.SphereGeometry(1.75,40,40);
- const instancedTreeLeavesGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLeavesGeometry.copy(treeLeavesGeometry);
- const treeLeavesMaterial = new THREE.MeshPhongMaterial({color: 0x365829});
- const instancedTreeLeaves = new THREE.InstancedMesh(
- instancedTreeLeavesGeometry,
- treeLeavesMaterial,
- count);
-
- const rotMatrix = new THREE.Matrix4();
- const translationMatrix = new THREE.Matrix4();
- const treeLogMatrix = new THREE.Matrix4();
- const treeLeavesMatrix = new THREE.Matrix4();
-
- for (let i = 0; i < count; i++) {
- let position = getRandomPositionInTerrain();
- let j = 0;
- while((position.y > 4.0) || (position.y < 2.5)) {
- position = getRandomPositionInTerrain();
- // console.log(position);
- if(j++ == 100) {
- break;
- }
- }
-
- position.y += amplitudeBottom;
- translationMatrix.makeTranslation(position);
- treeLogMatrix.identity();
- treeLeavesMatrix.identity();
-
- let scale = 0.5 + (Math.random()*(logHeight/3));
- treeLogMatrix.makeScale(1, scale, 1);
- treeLogMatrix.premultiply(translationMatrix);
-
- position.y += scale * logHeight;
- translationMatrix.makeTranslation(position);
- treeLeavesMatrix.premultiply(translationMatrix);
-
- instancedTreeLogs.setMatrixAt(i, treeLogMatrix);
- instancedTreeLeaves.setMatrixAt(i, treeLeavesMatrix);
- }
-
- return [instancedTreeLogs, instancedTreeLeaves];
-}
-
// La funcion devuelve una geometria de Three.js
// width: Ancho del plano
// height: Alto del plano
@@ -159,7 +22,7 @@ function createInstancedTrees(count) {
// widthSegments: Numero de segmentos en el ancho
// heightSegments: Numero de segmentos en el alto
// texture: Textura que se usara para la elevacion
-function elevationGeometry(width, height, amplitude, widthSegments, heightSegments, texture) {
+export function elevationGeometry(width, height, amplitude, widthSegments, heightSegments, texture) {
console.log('Generating terrain geometry');
let geometry = new THREE.BufferGeometry();
@@ -272,54 +135,6 @@ function elevationGeometry(width, height, amplitude, widthSegments, heightSegmen
return geometry;
}
-function buildScene() {
- console.log('Building scene');
-
- const width = 100;
- const height = 100;
-
- terrainGeometry = elevationGeometry(
- width, height,
- amplitude,
- widthSegments, heightSegments,
- textures.elevationMap.object);
-
- console.log('Applying textures');
- terrainMaterial = new THREE.RawShaderMaterial({
- uniforms: {
- dirtSampler: { type: 't', value: textures.tierra.object },
- rockSampler: { type: 't', value: textures.roca.object },
- grassSampler: { type: 't', value: textures.pasto.object },
- scale: { type: 'f', value: 3.0 },
- terrainAmplitude: { type: 'f', value: amplitude },
- terrainAmplitudeBottom: { type: 'f', value: amplitudeBottom },
- worldNormalMatrix: { type: 'm4', value: null },
- dirtStepWidth: { type: 'f', value: 0.20 },
- rockStepWidth: { type: 'f', value: 0.15 },
- },
- vertexShader: vertexShader,
- fragmentShader: fragmentShader,
- side: THREE.DoubleSide,
- });
- terrainMaterial.needsUpdate = true;
-
- terrain = new THREE.Mesh(terrainGeometry, terrainMaterial);
- terrain.position.set(0, amplitudeBottom, 0);
- scene.add(terrain);
-
- console.log('Generating water');
- const waterGeometry = new THREE.PlaneGeometry(width/2, height);
- const waterMaterial = new THREE.MeshPhongMaterial( {color: 0x12ABFF, side: THREE.DoubleSide} );
- const water = new THREE.Mesh( waterGeometry, waterMaterial );
- water.rotateX(Math.PI/2);
- water.position.set(0, 0.75, 0);
- scene.add(water);
-
- const [treeLogs, treeLeaves] = createInstancedTrees(100);
- scene.add(treeLogs);
- scene.add(treeLeaves);
-}
-
function onTextureLoaded(key, texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
textures[key].object = texture;
@@ -349,23 +164,7 @@ function loadTextures(callback) {
}
}
-function createMenu() {
- const gui = new dat.GUI({ width: 400 });
- gui.add(terrainMaterial.uniforms.scale, 'value', 1.00, 5.00).name('Terrain texture scale');
- gui.add(terrainMaterial.uniforms.dirtStepWidth, 'value', 0.0, 1.0).name('dirt step width');
- gui.add(terrainMaterial.uniforms.rockStepWidth, 'value', 0.10, 0.50).name('rock step width');
-}
-
-function mainLoop() {
- requestAnimationFrame(mainLoop);
- renderer.render(scene, camera);
+function main() {
}
-setupThreeJs();
loadTextures(main);
-
-function main() {
- buildScene();
- createMenu();
- mainLoop();
-}
diff --git a/tp/src/track-map.js b/tp/src/track-map.js
@@ -1,76 +1,19 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
-import { vertexShader, fragmentShader } from '/assets/shaders.js';
-let scene, camera, renderer, container, terrainMaterial, terrainGeometry, terrain;
let treesForbiddenMapData, treesForbiddenMap, elevationMap, elevationMapData;
-const widthSegments = 100;
-const heightSegments = 100;
-const amplitude = 8;
-const amplitudeBottom = -1.00;
-
const textures = {
- tierra: { url: '/assets/tierra.jpg', object: null },
- roca: { url: '/assets/roca.jpg', object: null },
- pasto: { url: '/assets/pasto.jpg', object: null },
elevationMap: { url: '/assets/elevation_map2.png', object: null },
treeForbiddenMap: { url: '/assets/tree_forbidden_zone_map.png', object: null }
};
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(
- 35, window.innerWidth/window.innerHeight, 0.1, 1000);
- camera.position.set(100, 120, -100);
- camera.lookAt(0, 0, 0);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xffffff);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- //scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
- // scene.add(directionalLightHelper);
-
- const gridHelper = new THREE.GridHelper(150, 150);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper( 5 );
- scene.add( axesHelper );
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
+const widthSegments = 100;
+const heightSegments = 100;
+const amplitude = 8;
+const amplitudeBottom = -1.00;
const imgWidth = 512;
const imgHeight = 512;
-// (x, y) ∈ [imgHeight, imgWidth] -> son un punto de la imagen
-function getPixelIndex(x, y) {
- return Math.floor(x + y*imgWidth*4);
-}
-
function getPixel(imgData, index) {
let i = index*4, d = imgData.data
return [d[i],d[i+1],d[i+2],d[i+3]] // Returns array [R,G,B,A]
@@ -125,76 +68,6 @@ function getRandomPositionInTerrain(padding = 0) {
return position;
}
-function createInstancedTrees(count) {
- console.log('Generating `' + count + '` instances of tree');
-
- let logHeight = 4.0;
- const treeLogGeometry = new THREE.CylinderGeometry(
- 0.30, 0.30, logHeight, 40, 40);
- treeLogGeometry.translate(0, logHeight/2.0, 0);
- const instancedTreeLogGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLogGeometry.copy(treeLogGeometry);
- const treeLogMaterial = new THREE.MeshPhongMaterial({color: 0x7c3f00});
- const instancedTreeLogs = new THREE.InstancedMesh(
- instancedTreeLogGeometry,
- treeLogMaterial,
- count);
-
- const treeLeavesGeometry = new THREE.SphereGeometry(1.75,40,40);
- const instancedTreeLeavesGeometry = new THREE.InstancedBufferGeometry();
- instancedTreeLeavesGeometry.copy(treeLeavesGeometry);
- const treeLeavesMaterial = new THREE.MeshPhongMaterial({color: 0x365829});
- const instancedTreeLeaves = new THREE.InstancedMesh(
- instancedTreeLeavesGeometry,
- treeLeavesMaterial,
- count);
-
- const rotMatrix = new THREE.Matrix4();
- const translationMatrix = new THREE.Matrix4();
- const treeLogMatrix = new THREE.Matrix4();
- const treeLeavesMatrix = new THREE.Matrix4();
-
- const treesBorderPadding = 3.0;
- for (let i = 0; i < count; i++) {
- let position = getRandomPositionInTerrain(treesBorderPadding);
- for(let j = 0; isForbbidenPosition(position); ++j) {
- position = getRandomPositionInTerrain(treesBorderPadding);
- if(j++ == 1000) { // maximo de iteraciones
- break;
- }
- }
-
- if(isForbbidenPosition(position)) {
- continue;
- }
-
- const treeOffset = 0.25;
- // 1.50 numbero magico para posicionar correctamente los arboles con
- // respecto al terreno
- position.x -= (widthSegments+treesBorderPadding+1.50)/2;
- position.y += amplitudeBottom - treeOffset;
- position.z -= (heightSegments+treesBorderPadding)/2;
- translationMatrix.makeTranslation(position);
- treeLogMatrix.identity();
- treeLeavesMatrix.identity();
-
- let scale = 0.6 + (Math.random()*(logHeight/3));
- treeLogMatrix.makeScale(1, scale, 1);
- treeLogMatrix.premultiply(translationMatrix);
-
- position.y += scale*logHeight;
- translationMatrix.makeTranslation(position);
- treeLeavesMatrix.premultiply(translationMatrix);
-
- instancedTreeLogs.setMatrixAt(i, treeLogMatrix);
- instancedTreeLeaves.setMatrixAt(i, treeLeavesMatrix);
- }
-
- console.log('Done generating `' + count + '` instances of tree');
- return [instancedTreeLogs, instancedTreeLeaves];
-}
-
-
// La funcion devuelve una geometria de Three.js
// width: Ancho del plano
// height: Alto del plano
@@ -297,7 +170,79 @@ function elevationGeometry(width, height, amplitude, widthSegments, heightSegmen
return geometry;
}
-function buildScene() {
+// devuelve un arreglo de 2 `instancedMesh` con los troncos y copas de los arboles
+export function createInstancedTrees(count) {
+ console.log('Generating `' + count + '` instances of tree');
+
+ let logHeight = 4.0;
+ const treeLogGeometry = new THREE.CylinderGeometry(
+ 0.30, 0.30, logHeight, 40, 40);
+ treeLogGeometry.translate(0, logHeight/2.0, 0);
+ const instancedTreeLogGeometry = new THREE.InstancedBufferGeometry();
+ instancedTreeLogGeometry.copy(treeLogGeometry);
+ const treeLogMaterial = new THREE.MeshPhongMaterial({color: 0x7c3f00});
+ const instancedTreeLogs = new THREE.InstancedMesh(
+ instancedTreeLogGeometry,
+ treeLogMaterial,
+ count);
+
+ const treeLeavesGeometry = new THREE.SphereGeometry(1.75,40,40);
+ const instancedTreeLeavesGeometry = new THREE.InstancedBufferGeometry();
+ instancedTreeLeavesGeometry.copy(treeLeavesGeometry);
+ const treeLeavesMaterial = new THREE.MeshPhongMaterial({color: 0x365829});
+ const instancedTreeLeaves = new THREE.InstancedMesh(
+ instancedTreeLeavesGeometry,
+ treeLeavesMaterial,
+ count);
+
+ const rotMatrix = new THREE.Matrix4();
+ const translationMatrix = new THREE.Matrix4();
+ const treeLogMatrix = new THREE.Matrix4();
+ const treeLeavesMatrix = new THREE.Matrix4();
+
+ const treesBorderPadding = 3.0;
+ for (let i = 0; i < count; i++) {
+ let position = getRandomPositionInTerrain(treesBorderPadding);
+ for(let j = 0; isForbbidenPosition(position); ++j) {
+ position = getRandomPositionInTerrain(treesBorderPadding);
+ if(j++ == 1000) { // maximo de iteraciones
+ break;
+ }
+ }
+
+ if(isForbbidenPosition(position)) {
+ continue;
+ }
+
+ const treeOffset = 0.25;
+ // 1.50 numbero magico para posicionar correctamente los arboles con
+ // respecto al terreno
+ position.x -= (widthSegments+treesBorderPadding+1.50)/2;
+ position.y += amplitudeBottom - treeOffset;
+ position.z -= (heightSegments+treesBorderPadding)/2;
+ translationMatrix.makeTranslation(position);
+ treeLogMatrix.identity();
+ treeLeavesMatrix.identity();
+
+ let scale = 0.6 + (Math.random()*(logHeight/3));
+ treeLogMatrix.makeScale(1, scale, 1);
+ treeLogMatrix.premultiply(translationMatrix);
+
+ position.y += scale*logHeight;
+ translationMatrix.makeTranslation(position);
+ treeLeavesMatrix.premultiply(translationMatrix);
+
+ instancedTreeLogs.setMatrixAt(i, treeLogMatrix);
+ instancedTreeLeaves.setMatrixAt(i, treeLeavesMatrix);
+ }
+
+ console.log('Done generating `' + count + '` instances of tree');
+ return [instancedTreeLogs, instancedTreeLeaves];
+}
+
+
+
+function buildTrees() {
console.log('Building scene');
const width = widthSegments;
@@ -336,11 +281,40 @@ function buildScene() {
const water = new THREE.Mesh( waterGeometry, waterMaterial );
water.rotateX(Math.PI/2);
water.position.set(0, 0.75, -1.00);
- scene.add(water);
+ // scene.add(water);
const [treeLogs, treeLeaves] = createInstancedTrees(250);
- scene.add(treeLogs);
- scene.add(treeLeaves);
+ return
+ // scene.add(treeLogs);
+ // scene.add(treeLeaves);
+}
+
+function loadMapsData() {
+ console.log("Loading maps data");
+
+ // Creamos un canvas para poder leer los valores de los píxeles de la textura
+ let canvas = document.createElement('canvas');
+ let ctx = canvas.getContext('2d');
+
+ let treesForbiddenMapImage = textures.treeForbiddenMap.object.image;
+ let elevationMapImage = textures.elevationMap.object.image;
+
+ // ambos mapas deben tener el mismo tamaño
+ const imgWidth = widthSegments;
+ const imgHeight = heightSegments;
+
+ canvas.width = imgWidth;
+ canvas.height = imgHeight;
+
+ ctx.drawImage(treesForbiddenMapImage, 0, 0, imgWidth, imgHeight);
+ treesForbiddenMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
+ treesForbiddenMapData = treesForbiddenMap.data;
+
+ ctx.drawImage(elevationMapImage, 0, 0, imgWidth, imgHeight);
+ elevationMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
+ elevationMapData = elevationMap.data
+
+ console.log("All maps data loaded succesfully");
}
function onTextureLoaded(key, texture) {
@@ -372,52 +346,10 @@ function loadTextures(callback) {
}
}
-function createMenu() {
- const gui = new dat.GUI({ width: 400 });
- gui.add(terrainMaterial.uniforms.scale, 'value', 1.00, 5.00).name('Terrain texture scale');
- gui.add(terrainMaterial.uniforms.dirtStepWidth, 'value', 0.0, 1.0).name('dirt step width');
- gui.add(terrainMaterial.uniforms.rockStepWidth, 'value', 0.10, 0.50).name('rock step width');
-}
-
-function mainLoop() {
- requestAnimationFrame(mainLoop);
- renderer.render(scene, camera);
-}
-
-function loadMapsData() {
- console.log("Loading maps data");
-
- // Creamos un canvas para poder leer los valores de los píxeles de la textura
- let canvas = document.createElement('canvas');
- let ctx = canvas.getContext('2d');
-
- let treesForbiddenMapImage = textures.treeForbiddenMap.object.image;
- let elevationMapImage = textures.elevationMap.object.image;
-
- // ambos mapas deben tener el mismo tamaño
- const imgWidth = widthSegments;
- const imgHeight = heightSegments;
-
- canvas.width = imgWidth;
- canvas.height = imgHeight;
-
- ctx.drawImage(treesForbiddenMapImage, 0, 0, imgWidth, imgHeight);
- treesForbiddenMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
- treesForbiddenMapData = treesForbiddenMap.data;
-
- ctx.drawImage(elevationMapImage, 0, 0, imgWidth, imgHeight);
- elevationMap = ctx.getImageData(0, 0, imgWidth, imgHeight);
- elevationMapData = elevationMap.data
-
- console.log("All maps data loaded succesfully");
-}
function main() {
loadMapsData();
- buildScene();
- // getTrainTrackShape();
- mainLoop();
+ // buildScene();
}
-setupThreeJs();
loadTextures(main);
diff --git a/tp/src/train.js b/tp/src/train.js
@@ -1,56 +1,6 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
-
-let scene, camera, renderer, container, terrainMaterial, instancedTrees;
-
-let time = 0.0;
-
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
- camera.position.set(-50, 60, 50);
- camera.lookAt(0, 0, 0);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xAAAAAA);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
- // scene.add(directionalLightHelper);
-
- const gridHelper = new THREE.GridHelper(50, 20);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper(5);
- scene.add(axesHelper);
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
const steamChamberLen = 20;
const steamChamberRad = 5;
const steamChamberEndRad = steamChamberRad+0.75;
@@ -186,9 +136,9 @@ function buildTrainChassis() {
return chassis;
}
-function buildTrain() {
+export function buildTrain() {
console.log('Building train');
- const train = new THREE.Group();
+ const train = new THREE.Object3D();
const chassisGeometry = buildTrainChassis();
const chassisMaterial = new THREE.MeshPhongMaterial({
@@ -240,7 +190,6 @@ function buildTrain() {
a2.position.set(0, wheelOffset, wheelRad*2.5);
a3.position.set(0, wheelOffset, -wheelRad*2.5);
-
const cylinderLeft = new THREE.CylinderGeometry(2.25, 2.5, steamCylindersLen);
cylinderLeft.rotateX(Math.PI/2);
cylinderLeft.translate(steamChamberRad-0.25, 0, steamChamberLen-steamCylindersLen/1.5);
@@ -294,30 +243,14 @@ function buildTrain() {
chassis.add(crankLeft);
chassis.add(crankRight);
- chassis.translateY(-wheelOffset);
+ // chassis.translateY(-wheelOffset);
+ updateTrainCrankPosition();
- train.position.set(0, 2, 0);
+ train.position.set(0, 1.9, 0);
return train;
}
-function buildScene() {
- console.log('Building scene');
-
- const train = buildTrain();
- scene.add(train);
-}
-
-function onTextureLoaded(key, texture) {
- texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
- textures[key].object = texture;
- console.log('Texture `' + key + '` loaded');
-}
-
-function mainLoop() {
- time += 0.05;
-
- requestAnimationFrame(mainLoop);
-
+export function updateTrainCrankPosition(time = 0.0) {
crankLeft.position.set(-steamChamberRad-crankWidth/2,
wheelOffset+1.00*(Math.sin(time*Math.PI/2)),
crankOffset - 1.00*(Math.cos(time*Math.PI/2)));
@@ -325,14 +258,4 @@ function mainLoop() {
crankRight.position.set(steamChamberRad+crankWidth/2,
wheelOffset+1.00*(Math.sin(time*Math.PI/2)),
crankOffset - 1.00*(Math.cos(time*Math.PI/2)));
-
- renderer.render(scene, camera);
}
-
-function main() {
- buildScene();
- mainLoop();
-}
-
-setupThreeJs();
-main();
diff --git a/tp/src/tunnel.js b/tp/src/tunnel.js
@@ -1,91 +1,8 @@
import * as THREE from 'three';
-import * as dat from 'dat.gui';
-import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
-let scene, camera, renderer, container;
-
-const textures = {
- madera: { url: '/assets/madera.jpg', object: null },
-};
-
-function onResize() {
- camera.aspect = container.offsetWidth / container.offsetHeight;
- camera.updateProjectionMatrix();
- renderer.setSize(container.offsetWidth, container.offsetHeight);
-}
-
-function setupThreeJs() {
- scene = new THREE.Scene();
- container = document.getElementById('mainContainer');
-
- renderer = new THREE.WebGLRenderer();
- renderer.setClearColor(0x606060);
- container.appendChild(renderer.domElement);
-
- camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
- camera.position.set(-50, 60, 50);
- camera.lookAt(0, 0, 0);
-
- const controls = new OrbitControls(camera, renderer.domElement);
-
- const ambientLight = new THREE.AmbientLight(0xffffff);
- scene.add(ambientLight);
-
- const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
- scene.add(hemisphereLight);
-
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
- directionalLight.position.set(100, 100, 100);
- scene.add(directionalLight);
-
- const gridHelper = new THREE.GridHelper(50, 20);
- scene.add(gridHelper);
-
- const axesHelper = new THREE.AxesHelper(5);
- scene.add(axesHelper);
-
- window.addEventListener('resize', onResize);
- onResize();
-}
-
-function buildScene() {
- console.log('Building scene');
-}
-
-function onTextureLoaded(key, texture) {
- texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
- textures[key].object = texture;
- console.log('Texture `' + key + '` loaded');
-}
-
-function loadTextures(callback) {
- const loadingManager = new THREE.LoadingManager();
-
- loadingManager.onLoad = () => {
- console.log('All textures loaded');
- callback();
- };
-
- for (const key in textures) {
- console.log("Loading textures");
- const loader = new THREE.TextureLoader(loadingManager);
- const texture = textures[key];
- texture.object = loader.load(
- texture.url,
- onTextureLoaded.bind(this, key),
- null,
- (error) => {
- console.error(error);
- }
- );
- }
-}
-
-function generateTunnel() {
- const tunnelHeight = 20;
- const tunnelWidth = 14;
- const tunnelWallThickness = 0.5;
- const tunnelLen = 26;
+export function generateTunnelGeometry(
+ tunnelHeight = 20, tunnelWidth = 14,
+ tunnelWallThickness = 0.5, tunnelLen = 26) {
const path = new THREE.Path();
path.moveTo(-tunnelWidth/2, 0);
@@ -115,15 +32,6 @@ function generateTunnel() {
path.moveTo(-tunnelWidth/2, 0);
const points = path.getPoints();
-
- /*
- // muestra la curva utilizada para la extrusión
- const geometry = new THREE.BufferGeometry().setFromPoints(points);
- const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
- const curveObject = new THREE.Line(geometry, lineMaterial);
- scene.add(curveObject);
- */
-
const shape = new THREE.Shape(points);
const extrudeSettings = {
@@ -134,33 +42,5 @@ function generateTunnel() {
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
geometry.translate(0, 0, -tunnelLen/2);
-
- textures.madera.object.wrapS = THREE.RepeatWrapping;
- textures.madera.object.wrapT = THREE.RepeatWrapping;
- textures.madera.object.repeat.set(0.10, 0.10);
- textures.madera.object.anisotropy = 16;
-
- const tunnelMaterial = new THREE.MeshPhongMaterial({
- side: THREE.DoubleSide,
- transparent: false,
- opacity: 1.0,
- shininess: 10,
- map: textures.madera.object
- });
-
- const mesh = new THREE.Mesh(geometry, tunnelMaterial) ;
- scene.add(mesh);
-}
-
-function mainLoop() {
- requestAnimationFrame(mainLoop);
- renderer.render(scene, camera);
-}
-
-function main() {
- generateTunnel();
- mainLoop();
+ return geometry;
}
-
-setupThreeJs();
-loadTextures(main);