TA159

Notas, resueltos y trabajos practicos de la materia Sistemas Gráficos
Index Commits Files Refs Submodules README LICENSE
tp/src/bridge.js (9486B)
   1 import * as THREE from 'three';
   2 import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
   3 
   4 import tierraSecaUrl from './assets/tierra_seca.jpg'
   5 import ladrillosUrl  from './assets/pared_de_ladrillo.jpg'
   6 
   7 const textures = {
   8     tierra:     { url: tierraSecaUrl, object: null },
   9     ladrillos:  { url: ladrillosUrl, object: null },
  10 };
  11 
  12 function onTextureLoaded(key, texture) {
  13     texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
  14     textures[key].object = texture;
  15     console.log('Texture `' + key + '` loaded');
  16 }
  17 
  18 function loadTextures(callback) {
  19     const loadingManager = new THREE.LoadingManager();
  20 
  21     loadingManager.onLoad = () => {
  22         console.log('All textures loaded');
  23         callback();
  24     };
  25 
  26     for (const key in textures) {
  27         console.log("Loading textures");
  28         const loader = new THREE.TextureLoader(loadingManager);
  29         const texture = textures[key];
  30         texture.object = loader.load(
  31             texture.url,
  32             onTextureLoaded.bind(this, key),
  33             null,
  34             (error) => {
  35                 console.error(error);
  36             }
  37         );
  38     }
  39 }
  40 
  41 // const arcRadius    = 3;
  42 // const arcCount     = 1;
  43 // const columnHeight = 0;
  44 // const columnWidth  = 1.00;
  45 // const arcWidth     = arcRadius*2;
  46 // const startPadding = 12;
  47 // const endPadding   = startPadding;
  48 // const bridgeHeight        = columnHeight+arcRadius+topPadding;
  49 
  50 const topPadding   = 0.25;
  51 const bridgeWallThickness = 2.5;
  52 const bridgeWidth   = 10;
  53 const roadwayHeight = 0.65;
  54 
  55 function generateBridgeWallGeometry(
  56         arcCount=2, arcRadius=3, columnWidth=1, columnHeight=0, padding=10) {
  57 
  58     const arcWidth = arcRadius*2;
  59     const startPadding = padding;
  60     const endPadding = padding;
  61     const bridgeLen = arcCount*(columnWidth+arcWidth)+columnWidth+startPadding+endPadding;
  62     const bridgeHeight = columnHeight+arcRadius+topPadding;
  63     const path = new THREE.Path();
  64 
  65     // generate the arcs
  66     for(let i = 1; i <= arcCount; ++i) {
  67         path.lineTo(startPadding+i*columnWidth+((i-1)*arcWidth), 0);
  68         path.moveTo(startPadding+i*columnWidth+((i-1)*arcWidth), 0);
  69         path.lineTo(startPadding+i*columnWidth+((i-1)*arcWidth), columnHeight);
  70         path.arc(arcRadius, 0, arcRadius, Math.PI, 0, true)
  71         path.moveTo(startPadding+i*(columnWidth+arcWidth), 0);
  72         path.lineTo(startPadding+i*(columnWidth+arcWidth), 0);
  73     }
  74 
  75     // no we close the curve
  76     path.lineTo(bridgeLen, 0);
  77     path.lineTo(bridgeLen, bridgeHeight);
  78 
  79     path.lineTo(0, bridgeHeight);
  80     path.lineTo(0, 0);
  81 
  82     /*
  83     // muestra la curva utilizada para la extrusión
  84     const geometry = new THREE.BufferGeometry().setFromPoints(points);
  85     const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
  86     const curveObject = new THREE.Line(geometry, lineMaterial);
  87     scene.add(curveObject);
  88     */
  89 
  90     const points = path.getPoints();
  91     const shape = new THREE.Shape(points);
  92 
  93     const extrudeSettings = {
  94         curveSegments: 24,
  95         steps: 50,
  96         depth: bridgeWallThickness,
  97         bevelEnabled: false
  98     };
  99 
 100     const bridgeWallGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
 101     bridgeWallGeometry.translate(-bridgeLen/2, 0, -bridgeWallThickness/2);
 102     return bridgeWallGeometry;
 103 }
 104 
 105 function generateBridgeCage(squaresCount=3, squareTubeRadius=0.15) {
 106     const squareLen = bridgeWidth - 0.25;
 107     const bridgeCageLen  = squaresCount * squareLen;
 108 
 109     let geometries = []
 110 
 111     let cylinderBase, cylinderCorner, cylinderCrossbar;
 112     for(let square = 0; square < squaresCount; ++square) {
 113         // 0 -> 00
 114         // 1 -> 01
 115         // 2 -> 10
 116         // 3 -> 11
 117         for(let i = 0; i < 4; ++i) {
 118             cylinderBase = new THREE.CylinderGeometry(
 119                 squareTubeRadius, squareTubeRadius, squareLen);
 120 
 121             cylinderCorner = cylinderBase.clone();
 122 
 123             const squareHypotenuse = Math.sqrt(2*squareLen*squareLen);
 124             cylinderCrossbar = new THREE.CylinderGeometry(
 125                 squareTubeRadius, squareTubeRadius, squareHypotenuse);
 126 
 127             if((i % 2) == 0) {
 128                 cylinderBase.rotateZ(Math.PI/2);
 129                 cylinderBase.translate(
 130                     0,
 131                     square*(squareLen),
 132                     ((-1)**(i>>1))*squareLen/2);
 133 
 134                 cylinderCrossbar.rotateZ((-1)**((i>>1))*Math.PI/4);
 135                 cylinderCrossbar.translate(
 136                     0,
 137                     square*(squareLen)+(squareLen/2),
 138                     ((-1)**(i>>1))*squareLen/2);
 139 
 140                 cylinderCorner.translate(
 141                     ((-1)**(i>>1))*squareLen/2,
 142                     square*(squareLen)+(squareLen/2),
 143                     ((-1)**(i&1))*squareLen/2);
 144             } else {
 145                 cylinderBase.rotateX(Math.PI/2);
 146                 cylinderBase.translate(
 147                     ((-1)**(i>>1))*squareLen/2,
 148                     square*(squareLen),
 149                     0);
 150 
 151                 cylinderCrossbar.rotateX((-1)**((i>>1))*Math.PI/4);
 152                 cylinderCrossbar.translate(
 153                     ((-1)**(i>>1))*squareLen/2,
 154                     square*(squareLen)+(squareLen/2),
 155                     0);
 156 
 157                 cylinderCorner.translate(
 158                     ((-1)**(i>>1))*squareLen/2,
 159                     square*(squareLen)+(squareLen/2),
 160                     ((-1)**(i&1))*squareLen/2);
 161             }
 162             geometries.push(cylinderBase);
 163             geometries.push(cylinderCrossbar);
 164             geometries.push(cylinderCorner);
 165         }
 166 
 167         // agregamos un cuadrado mas para 'cerrar' la 'jaula'
 168         if((square + 1) == squaresCount) {
 169             for(let i = 0; i < 4; ++i) {
 170                 cylinderBase = new THREE.CylinderGeometry(
 171                     squareTubeRadius, squareTubeRadius, squareLen);
 172 
 173                 if((i % 2) == 0) {
 174                     cylinderBase.rotateZ(Math.PI/2);
 175                     cylinderBase.translate(
 176                         0,
 177                         (square+1)*(squareLen),
 178                         ((-1)**(i>>1))*squareLen/2);
 179                 } else {
 180                     cylinderBase.rotateX(Math.PI/2);
 181                     cylinderBase.translate(
 182                         ((-1)**(i>>1))*squareLen/2,
 183                         (square+1)*(squareLen), 0);
 184                 }
 185                 geometries.push(cylinderBase);
 186             }
 187         }
 188     }
 189 
 190     const bridgeCage = mergeGeometries(geometries);
 191     bridgeCage.rotateZ(Math.PI/2);
 192     bridgeCage.translate(bridgeCageLen/2, squareLen/2, 0);
 193     return bridgeCage;
 194 }
 195 
 196 export function generateBridge(arcCount=1, arcRadius=3,
 197     columnWidth=0, columnHeight=0, padding=10, squaresCount=0, squareLen=1) {
 198 
 199     const arcWidth     = arcRadius*2;
 200     const startPadding = padding;
 201     const endPadding   = padding;
 202     const bridgeHeight = columnHeight+arcRadius+topPadding;
 203     const bridgeLen    = arcCount*(columnWidth+arcWidth)+columnWidth+startPadding+endPadding;
 204     const squareTubeRadius = 0.30;
 205 
 206     const bridge = new THREE.Object3D();
 207 
 208     const leftWallGeometry = generateBridgeWallGeometry(
 209         arcCount, arcRadius, columnWidth, columnHeight, padding);
 210 
 211     // const leftWallGeometry = generateBridgeWallGeometry();
 212     leftWallGeometry.translate(0, 0, -bridgeWidth/2);
 213 
 214     const rightWallGeometry = generateBridgeWallGeometry(
 215         arcCount, arcRadius, columnWidth, columnHeight, padding);
 216 
 217     // const rightWallGeometry = generateBridgeWallGeometry();
 218     rightWallGeometry.translate(0, 0, bridgeWidth/2)
 219 
 220     const bridgeColumnsGeometry = mergeGeometries([leftWallGeometry, rightWallGeometry]);
 221 
 222     const bridgeRoadwayGeometry = new THREE.BoxGeometry(
 223         bridgeLen, roadwayHeight, bridgeWidth+bridgeWallThickness,
 224     );
 225 
 226     bridgeRoadwayGeometry.translate(0, bridgeHeight+roadwayHeight/2, 0);
 227 
 228     textures.ladrillos.object.wrapS = THREE.RepeatWrapping;
 229     textures.ladrillos.object.wrapT = THREE.RepeatWrapping;
 230     textures.ladrillos.object.repeat.set(0.75*0.15, 0.75*0.35);
 231     // textures.ladrillos.object.anisotropy = 16;
 232 
 233     const bridgeMaterial = new THREE.MeshPhongMaterial({
 234         side: THREE.FrontSide,
 235         map: textures.ladrillos.object
 236     });
 237 
 238     /*
 239     textures.ladrillos2.object.wrapS = THREE.RepeatWrapping;
 240     textures.ladrillos2.object.wrapT = THREE.RepeatWrapping;
 241     textures.ladrillos2.object.repeat.set(0.75*5, 0.75*0.75);
 242     textures.ladrillos2.object.anisotropy = 16;
 243 
 244     const roadwayMaterial = new THREE.MeshPhongMaterial({
 245         side: THREE.DoubleSide,
 246         transparent: false,
 247         opacity: 1.0,
 248         shininess: 10,
 249         map: textures.ladrillos2.object
 250         // color: 0xFF0000
 251     });
 252 
 253     const bridgeRoadway = new THREE.Mesh(bridgeRoadwayGeometry, roadwayMaterial);
 254     scene.add(bridgeRoadway);
 255     */
 256 
 257     const bridgeColumns = new THREE.Mesh(bridgeColumnsGeometry, bridgeMaterial);
 258     bridgeColumns.castShadow    = true;
 259     bridgeColumns.receiveShadow = true;
 260 
 261     bridge.add(bridgeColumns);
 262 
 263     // para reutilizar la textura de ladrillos usada en los arcos se escalan las
 264     // coordenadas uv de la geometria de la parte superior
 265     let uvs = bridgeRoadwayGeometry.attributes.uv.array;
 266     for (let i = 0, len = uvs.length; i < len; i++) {
 267         uvs[i] = (i % 2) ? uvs[i]*2.50 : uvs[i]*30.0;
 268     }
 269 
 270     const bridgeRoadway = new THREE.Mesh(bridgeRoadwayGeometry, bridgeMaterial);
 271     bridge.add(bridgeRoadway);
 272 
 273     bridgeRoadway.castShadow    = true;
 274     bridgeRoadway.receiveShadow = true;
 275 
 276     const cageGeometry = generateBridgeCage(squaresCount)
 277     cageGeometry.translate(0, bridgeHeight+roadwayHeight-squareTubeRadius*2, 0);
 278 
 279     const cageMaterial = new THREE.MeshPhongMaterial({
 280         side: THREE.FrontSide,
 281         transparent: false,
 282         opacity: 1.0,
 283         shininess: 10,
 284         color: 0xFFFFFF
 285     });
 286 
 287     const bridgeCage = new THREE.Mesh(cageGeometry, cageMaterial);
 288 
 289     bridgeCage.castShadow    = true;
 290     bridgeCage.receiveShadow = true;
 291 
 292     bridge.add(bridgeCage);
 293 
 294     const roadwayFloorGeometry = new THREE.BoxGeometry(
 295         bridgeWidth+bridgeWallThickness+0.01,
 296         bridgeLen+0.01, 0.10);
 297 
 298     roadwayFloorGeometry.rotateZ(Math.PI/2)
 299     roadwayFloorGeometry.rotateX(Math.PI/2)
 300     roadwayFloorGeometry.translate(0, bridgeHeight+roadwayHeight, 0)
 301 
 302     textures.tierra.object.wrapS = THREE.MirroredRepeatWrapping;
 303     textures.tierra.object.wrapT = THREE.MirroredRepeatWrapping;
 304     textures.tierra.object.repeat.set(1, 5);
 305     textures.tierra.object.anisotropy = 16;
 306 
 307     const roadwayFloorMaterial = new THREE.MeshPhongMaterial({
 308         side: THREE.FrontSide,
 309         map: textures.tierra.object
 310     });
 311 
 312     const roadwayFloor = new THREE.Mesh(roadwayFloorGeometry, roadwayFloorMaterial);
 313     roadwayFloor.receiveShadow = true;
 314     roadwayFloor.castShadow = false;
 315 
 316     bridge.add(roadwayFloor)
 317     return bridge;
 318 }
 319 
 320 function main() {
 321 }
 322 
 323 loadTextures(main);