tp/src/standalone/rails.js (8468B)
1 import * as THREE from 'three'; 2 import * as dat from 'dat.gui'; 3 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; 4 5 import { ParametricGeometry } from 'three/addons/geometries/ParametricGeometry.js'; 6 import { ParametricGeometries } from 'three/examples/jsm/geometries/ParametricGeometries.js'; 7 import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'; 8 9 let scene, camera, renderer, container, terrainMaterial, instancedTrees; 10 let spherePath; 11 let railsPath; 12 let railsFoundationShape; 13 14 import tierraUrl from '../assets/tierra.jpg' 15 import rocaUrl from '../assets/roca.jpg' 16 import pastoUrl from '../assets/pasto.jpg' 17 import durmientesUrl from '../assets/durmientes.jpg' 18 19 const textures = { 20 tierra: { url: tierraUrl, object: null }, 21 roca: { url: rocaUrl, object: null }, 22 pasto: { url: pastoUrl, object: null }, 23 durmientes: { url: durmientesUrl, object: null }, 24 }; 25 26 function onResize() { 27 camera.aspect = container.offsetWidth / container.offsetHeight; 28 camera.updateProjectionMatrix(); 29 renderer.setSize(container.offsetWidth, container.offsetHeight); 30 } 31 32 function setupThreeJs() { 33 scene = new THREE.Scene(); 34 container = document.getElementById('mainContainer'); 35 36 renderer = new THREE.WebGLRenderer(); 37 renderer.setClearColor(0x606060); 38 container.appendChild(renderer.domElement); 39 40 camera = new THREE.PerspectiveCamera( 41 35, window.innerWidth / window.innerHeight, 0.1, 1000); 42 43 camera.position.set(-10, 15, -10); 44 camera.lookAt(0, 0, 0); 45 46 const controls = new OrbitControls(camera, renderer.domElement); 47 48 const ambientLight = new THREE.AmbientLight(0xffffff); 49 scene.add(ambientLight); 50 51 const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25); 52 scene.add(hemisphereLight); 53 54 const directionalLight = new THREE.DirectionalLight(0xffffff, 1); 55 directionalLight.position.set(100, 100, 100); 56 scene.add(directionalLight); 57 58 const gridHelper = new THREE.GridHelper(50, 20); 59 scene.add(gridHelper); 60 61 const axesHelper = new THREE.AxesHelper(5); 62 scene.add(axesHelper); 63 64 window.addEventListener('resize', onResize); 65 onResize(); 66 } 67 68 function onTextureLoaded(key, texture) { 69 texture.wrapS = texture.wrapT = THREE.RepeatWrapping; 70 textures[key].object = texture; 71 console.log('Texture `' + key + '` loaded'); 72 } 73 74 function loadTextures(callback) { 75 const loadingManager = new THREE.LoadingManager(); 76 77 loadingManager.onLoad = () => { 78 console.log('All textures loaded'); 79 callback(); 80 }; 81 82 for (const key in textures) { 83 console.log("Loading textures"); 84 const loader = new THREE.TextureLoader(loadingManager); 85 const texture = textures[key]; 86 texture.object = loader.load( 87 texture.url, 88 onTextureLoaded.bind(this, key), 89 null, 90 (error) => { 91 console.error(error); 92 } 93 ); 94 } 95 } 96 97 function parametricRailsFoundationFunction(u, v, target) { 98 const rotMatrix = new THREE.Matrix4(); 99 const translationMatrix = new THREE.Matrix4(); 100 const levelMatrix = new THREE.Matrix4(); 101 102 let railsPathPos = railsPath.getPointAt(v); 103 let railsFoundationShapePos = railsFoundationShape.getPointAt(u); 104 // TODO: make `railsFoundationShape` smaller and remove this multiplication 105 railsFoundationShapePos.multiplyScalar(0.5); 106 107 let tangente = new THREE.Vector3(); 108 let binormal = new THREE.Vector3(); 109 let normal = new THREE.Vector3(); 110 111 tangente = railsPath.getTangent(v); 112 113 tangente.normalize(); 114 binormal = new THREE.Vector3(0, 1, 0); 115 normal.crossVectors(tangente, binormal); 116 117 translationMatrix.makeTranslation(railsPathPos); 118 119 rotMatrix.identity(); 120 levelMatrix.identity(); 121 122 levelMatrix.makeTranslation(railsPathPos); 123 rotMatrix.makeBasis(normal, tangente, binormal); 124 levelMatrix.multiply(rotMatrix); 125 railsFoundationShapePos.applyMatrix4(levelMatrix); 126 127 const x = railsFoundationShapePos.x; 128 const y = railsFoundationShapePos.y; 129 const z = railsFoundationShapePos.z; 130 target.set(x, y, z); 131 } 132 133 export function buildRailsFoundation() { 134 railsFoundationShape = new THREE.CatmullRomCurve3([ 135 new THREE.Vector3( -2.00, 0.00, 0.00), 136 new THREE.Vector3( -1.00, 0.00, 0.50), 137 new THREE.Vector3( 0.00, 0.00, 0.55), 138 new THREE.Vector3( 1.00, 0.00, 0.50), 139 new THREE.Vector3( 2.00, 0.00, 0.00), 140 ], false); 141 142 /* 143 // show rails foundation shape 144 const points = railsFoundationShape.getPoints(50); 145 const geometry = new THREE.BufferGeometry().setFromPoints(points); 146 const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 }); 147 const curveObject = new THREE.Line(geometry, lineMaterial); 148 scene.add(curveObject); 149 */ 150 const pGeometry = new ParametricGeometry( 151 parametricRailsFoundationFunction, 100, 100); 152 153 textures.durmientes.object.wrapS = THREE.RepeatWrapping; 154 textures.durmientes.object.wrapT = THREE.RepeatWrapping; 155 textures.durmientes.object.repeat.set(1, 60); 156 textures.durmientes.object.anisotropy = 16; 157 158 /* 159 // load into `map` the example texture 160 const map = new THREE.TextureLoader().load('https://threejs.org/examples/textures/uv_grid_opengl.jpg'); 161 map.wrapS = map.wrapT = THREE.RepeatWrapping; 162 map.repeat.set(1, 30); 163 map.anisotropy = 16; 164 // map.rotation = Math.PI/2; 165 */ 166 167 const pMaterial = new THREE.MeshPhongMaterial({ 168 side: THREE.DoubleSide, 169 transparent: false, 170 opacity: 1.0, 171 shininess: 10, 172 map: textures.durmientes.object 173 }); 174 const pMesh = new THREE.Mesh(pGeometry, pMaterial); 175 pMesh.receiveShadow = true; 176 pMesh.castShadow = true; 177 scene.add(pMesh); 178 } 179 180 // `position` es de tipo `THREE.Vector3` y representa la translacion de la 181 // forma del rail con respecto al origen del sist. de coordenadas de modelado 182 function getParametricRailsFunction(radius, position) { 183 return function parametricRails(u, v, target) { 184 const rotMatrix = new THREE.Matrix4(); 185 const translationMatrix = new THREE.Matrix4(); 186 const levelMatrix = new THREE.Matrix4(); 187 188 let railsShape = new THREE.Vector3(); 189 190 let railsPathPos = railsPath.getPointAt(v); 191 let railsShapePos = new THREE.Vector3( 192 Math.cos(u*6.28) + position.x, 193 position.y, 194 Math.sin(u*6.28) + position.z); 195 196 railsShapePos.multiplyScalar(0.1*railsRadius); 197 198 let tangente = new THREE.Vector3(); 199 let binormal = new THREE.Vector3(); 200 let normal = new THREE.Vector3(); 201 202 // https://threejs.org/docs/index.html?q=curve#api/en/extras/core/Curve.getTangent 203 tangente = railsPath.getTangentAt(v); 204 binormal = new THREE.Vector3(0, 1, 0); 205 normal.crossVectors(tangente, binormal); 206 207 translationMatrix.makeTranslation(railsPathPos); 208 209 rotMatrix.identity(); 210 levelMatrix.identity(); 211 212 levelMatrix.makeTranslation(railsPathPos); 213 rotMatrix.makeBasis(normal, tangente, binormal); 214 levelMatrix.multiply(rotMatrix); 215 railsShapePos.applyMatrix4(levelMatrix); 216 217 const x = railsShapePos.x; 218 const y = railsShapePos.y; 219 const z = railsShapePos.z; 220 target.set(x, y, z); 221 } 222 } 223 224 const railsRadius = 0.35; 225 function buildRails() { 226 let railsGeometries = []; 227 228 const leftRailGeometryFunction = getParametricRailsFunction(railsRadius, 229 new THREE.Vector3( 6, 0, railsRadius+8)); 230 231 const rightRailGeometryFunction = getParametricRailsFunction(railsRadius, 232 new THREE.Vector3(-6, 0, railsRadius+8)); 233 234 const leftRailGeometry = new ParametricGeometry(leftRailGeometryFunction, 100, 500); 235 const rightRailGeometry = new ParametricGeometry(rightRailGeometryFunction, 100, 500); 236 237 railsGeometries.push(leftRailGeometry); 238 railsGeometries.push(rightRailGeometry); 239 240 const railsMaterial = new THREE.MeshPhongMaterial({ 241 side: THREE.DoubleSide, 242 transparent: false, 243 opacity: 1.0, 244 shininess: 10, 245 color: 0xFFFFFF 246 }); 247 248 const railsGeometry = mergeGeometries(railsGeometries); 249 const rails = new THREE.Mesh(railsGeometry, railsMaterial); 250 rails.castShadow = true; 251 scene.add(rails); 252 } 253 254 function mainLoop() { 255 requestAnimationFrame(mainLoop); 256 renderer.render(scene, camera); 257 } 258 259 function main() { 260 railsPath = new THREE.CatmullRomCurve3([ 261 new THREE.Vector3(-10, 0, 10), 262 new THREE.Vector3( 10, 0, 10), 263 new THREE.Vector3( 10, 0, -10), 264 new THREE.Vector3(-10, 0, -10), 265 ], true); 266 267 /* 268 // muestra la curva utilizada para el camino de `rails` 269 const railsPathPoints = railsPath.getPoints(50); 270 const railsPathGeometry = new THREE.BufferGeometry().setFromPoints(railsPathPoints); 271 const railsPathMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 }); 272 const railsPathMesh = new THREE.Line(railsPathGeometry, railsPathMaterial); 273 scene.add(railsPathMesh); 274 */ 275 276 buildRailsFoundation(); 277 buildRails(); 278 mainLoop(); 279 } 280 281 setupThreeJs(); 282 loadTextures(main);