TA159

Notas, resueltos y trabajos practicos de la materia Sistemas Gráficos
Index Commits Files Refs Submodules README LICENSE
tp/src/standalone/trees.js (6283B)
   1 import * as THREE from 'three';
   2 import * as dat from 'dat.gui';
   3 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
   4 import { vertexShader, fragmentShader } from '/src/treesShaders.js';
   5 
   6 let scene, camera, renderer, container, terrainMaterial, instancedTrees;
   7 
   8 import tierraUrl from '../assets/tierra.jpg'
   9 import rocaUrl   from '../assets/roca.jpg'
  10 import pastoUrl  from '../assets/pasto.jpg'
  11 
  12 const textures = {
  13     tierra: { url: tierraUrl,       object: null },
  14     roca:   { url: rocaUrl,         object: null },
  15     pasto:  { url: pastoUrl,        object: null },
  16 };
  17 
  18 function onResize() {
  19     camera.aspect = container.offsetWidth / container.offsetHeight;
  20     camera.updateProjectionMatrix();
  21     renderer.setSize(container.offsetWidth, container.offsetHeight);
  22 }
  23 
  24 function setupThreeJs() {
  25     scene = new THREE.Scene();
  26     container = document.getElementById('mainContainer');
  27 
  28     renderer = new THREE.WebGLRenderer();
  29     renderer.setClearColor(0x606060);
  30     container.appendChild(renderer.domElement);
  31 
  32     camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 1000);
  33     camera.position.set(-50, 60, 50);
  34     camera.lookAt(0, 0, 0);
  35 
  36     const controls = new OrbitControls(camera, renderer.domElement);
  37 
  38     const ambientLight = new THREE.AmbientLight(0xffffff);
  39     scene.add(ambientLight);
  40 
  41     const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x000000, 0.25);
  42     scene.add(hemisphereLight);
  43 
  44     const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  45     directionalLight.position.set(100, 100, 100);
  46     scene.add(directionalLight);
  47 
  48     const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
  49     // scene.add(directionalLightHelper);
  50 
  51     //const gridHelper = new THREE.GridHelper(50, 20);
  52     //scene.add(gridHelper);
  53 
  54     const axesHelper = new THREE.AxesHelper(5);
  55     scene.add(axesHelper);
  56 
  57     window.addEventListener('resize', onResize);
  58     onResize();
  59 }
  60 
  61 function createInstancedTrees(count) {
  62     console.log('Generating `' + count + '` instances of tree');
  63 
  64     let logHeight = 4.0;
  65 
  66     const treeLogGeometry    = new THREE.CylinderGeometry(0.30, 0.30, logHeight, 40, 40);
  67     const treeLeavesGeometry = new THREE.SphereGeometry(1.75,40,40);
  68 
  69     treeLogGeometry.translate(0, logHeight/2.0, 0);
  70 
  71     const instancedTreeLogGeometry = new THREE.InstancedBufferGeometry();
  72     instancedTreeLogGeometry.copy(treeLogGeometry);
  73 
  74     const instancedTreeLeavesGeometry = new THREE.InstancedBufferGeometry();
  75     instancedTreeLeavesGeometry.copy(treeLeavesGeometry);
  76 
  77     const treeLogMaterial   = new THREE.MeshPhongMaterial({color: 0x7c3f00});
  78     const instancedTreeLogs = new THREE.InstancedMesh(instancedTreeLogGeometry, treeLogMaterial, count);
  79 
  80     const treeLeavesMaterial  = new THREE.MeshPhongMaterial({color: 0x365829});
  81     const instancedTreeLeaves = new THREE.InstancedMesh(instancedTreeLeavesGeometry, treeLeavesMaterial, count);
  82 
  83     const rotMatrix = new THREE.Matrix4();
  84 
  85     const translationMatrix = new THREE.Matrix4();
  86     const treeLogMatrix    = new THREE.Matrix4();
  87     const treeLeavesMatrix = new THREE.Matrix4();
  88 
  89     //let origin = new THREE.Vector3();
  90     const RANGE = 50 - 4/2;
  91 
  92     for (let i = 0; i < count; i++) {
  93         let position = new THREE.Vector3(
  94             (Math.random() - 0.5) * RANGE,
  95             0,
  96             (Math.random() - 0.5) * RANGE
  97         );
  98 
  99         translationMatrix.makeTranslation(position);
 100 
 101         //rotMatrix.lookAt(0, 0, new THREE.Vector3(0, 1, 0));
 102         treeLogMatrix.identity();
 103         treeLeavesMatrix.identity();
 104 
 105         let scale = 0.5 + (Math.random()*(logHeight/3));
 106         treeLogMatrix.makeScale(1, scale, 1);
 107         //matrix.premultiply(rotMatrix);
 108 
 109         treeLogMatrix.premultiply(translationMatrix);
 110 
 111         position.y = scale*logHeight;
 112         translationMatrix.makeTranslation(position);
 113         treeLeavesMatrix.premultiply(translationMatrix);
 114 
 115         instancedTreeLogs.setMatrixAt(i, treeLogMatrix);
 116         instancedTreeLeaves.setMatrixAt(i, treeLeavesMatrix);
 117     }
 118 
 119     scene.add(instancedTreeLogs);
 120     scene.add(instancedTreeLeaves);
 121 }
 122 
 123 function buildScene() {
 124     console.log('Building scene');
 125 
 126     console.log('Generating terrain');
 127     const terrainGeometry = new THREE.PlaneGeometry(50, 50);
 128     //const terrainMaterial = new THREE.MeshPhongMaterial( {color: 0x365829, side: THREE.DoubleSide} );
 129     terrainMaterial = new THREE.RawShaderMaterial({
 130         uniforms: {
 131             tierraSampler: { type: 't', value: textures.tierra.object },
 132             rocaSampler: { type: 't', value: textures.roca.object },
 133             pastoSampler: { type: 't', value: textures.pasto.object },
 134             scale1: { type: 'f', value: 2.0 },
 135 
 136             mask1low: { type: 'f', value: -0.38 },
 137             mask1high: { type: 'f', value: 0.1 },
 138 
 139             mask2low: { type: 'f', value: 0.05 },
 140             mask2high: { type: 'f', value: -0.70 },
 141         },
 142         vertexShader: vertexShader,
 143         fragmentShader: fragmentShader,
 144         side: THREE.DoubleSide,
 145     });
 146     terrainMaterial.needsUpdate = true;
 147 
 148     const terrain = new THREE.Mesh(terrainGeometry, terrainMaterial);
 149     terrain.rotateX(Math.PI/2);
 150     terrain.position.set(0, 0, 0);
 151     scene.add(terrain);
 152 
 153     console.log('Generating trees');
 154     createInstancedTrees(35);
 155 }
 156 
 157 function onTextureLoaded(key, texture) {
 158     texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
 159     textures[key].object = texture;
 160     console.log('Texture `' + key + '` loaded');
 161 }
 162 
 163 function loadTextures(callback) {
 164     const loadingManager = new THREE.LoadingManager();
 165 
 166     loadingManager.onLoad = () => {
 167         console.log('All textures loaded');
 168         callback();
 169     };
 170 
 171     for (const key in textures) {
 172         console.log("Loading textures");
 173         const loader = new THREE.TextureLoader(loadingManager);
 174         const texture = textures[key];
 175         texture.object = loader.load(
 176             texture.url,
 177             onTextureLoaded.bind(this, key),
 178             null,
 179             (error) => {
 180                 console.error(error);
 181             }
 182         );
 183     }
 184 }
 185 
 186 
 187 function createMenu() {
 188     const gui = new dat.GUI({ width: 400 });
 189     gui.add(terrainMaterial.uniforms.scale1, 'value', 0, 10).name('Texture scale');
 190     gui.add(terrainMaterial.uniforms.mask1low, 'value', -1, 1).name('Mask1 Low');
 191     gui.add(terrainMaterial.uniforms.mask1high, 'value', -1, 1).name('Mask1 High');
 192     gui.add(terrainMaterial.uniforms.mask2low, 'value', -1, 1).name('Mask2 Low');
 193     gui.add(terrainMaterial.uniforms.mask2high, 'value', -1, 1).name('Mask2 High');
 194 }
 195 
 196 function mainLoop() {
 197     requestAnimationFrame(mainLoop);
 198     renderer.render(scene, camera);
 199 }
 200 
 201 function main() {
 202     buildScene();
 203     createMenu();
 204     mainLoop();
 205 }
 206 
 207 setupThreeJs();
 208 loadTextures(main);