commit e7843b73235ee1c20d789e80e18e402a6b06e438
parent 539d4843099d9a32575ea03d006f275b31395cab
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Mon, 24 Jun 2024 14:11:49 -0300
add `rails` section
Diffstat:
3 files changed, 314 insertions(+), 0 deletions(-)
diff --git a/tp/index.html b/tp/index.html
@@ -28,6 +28,7 @@
<li><a href="terrain.html">Terreno</a></li>
<li><a href="trees.html">Arboles</a></li>
<li><a href="train.html">Tren</a></li>
+ <li><a href="rails.html">Vias</a></li>
</ul>
</body>
</html>
diff --git a/tp/rails.html b/tp/rails.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <title>Trabajo Practico Sistemas Graficos | Martin Klöckner</title>
+ <link rel="icon" href="data:,"> <!-- Do not request favicon -->
+ <style>
+ html, body, #mainContainer {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ </style>
+ </head>
+ <body>
+ <div id="mainContainer"></div>
+ <script type="module" src="/src/rails.js"></script>
+ </body>
+</html>
diff --git a/tp/src/rails.js b/tp/src/rails.js
@@ -0,0 +1,295 @@
+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/treesShaders.js';
+
+import { ParametricGeometry } from 'three/addons/geometries/ParametricGeometry.js';
+import { ParametricGeometries } from 'three/examples/jsm/geometries/ParametricGeometries.js';
+
+let scene, camera, renderer, container, terrainMaterial, instancedTrees;
+let spherePath;
+
+const textures = {
+ tierra: { url: '/assets/tierra.jpg', object: null },
+ roca: { url: '/assets/roca.jpg', object: null },
+ pasto: { url: '/assets/pasto.jpg', object: null },
+};
+
+function createPathWithSpheres() {
+ //Create a closed wavey loop
+ spherePath = new THREE.CatmullRomCurve3([
+ new THREE.Vector3(-10, 0, 10),
+ new THREE.Vector3( 10, 0, 10),
+ new THREE.Vector3( 10, 0, -10),
+ new THREE.Vector3(-10, 0, -10),
+ ], true);
+
+ const points = spherePath.getPoints(50);
+ const geometry = new THREE.BufferGeometry().setFromPoints(points);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0xff0000 });
+
+ // const geometry = new THREE.TubeGeometry( railsPath, 50, 1, 25, false );
+
+ const material = new THREE.MeshPhongMaterial({ color: 0xFF0000 });
+ const sphere = new THREE.SphereGeometry(0.5,20,20);
+ const instancedSphereGeo = new THREE.InstancedBufferGeometry();
+ instancedSphereGeo.copy(sphere);
+
+ let count = 10;
+ const instancedSpheres = new THREE.InstancedMesh(instancedSphereGeo, material, count);
+
+ // const sphere = new THREE.Mesh( geometry, material );
+ // scene.add( sphere );
+
+ const rotMatrix = new THREE.Matrix4();
+ const translationMatrix = new THREE.Matrix4();
+ const sphereMatrix = new THREE.Matrix4()
+
+ const dotGeo = new THREE.SphereGeometry()
+ let u, i;
+ for(u = 0.0, i = 0; u < 1.0; u += 1/count, i++) {
+ let position = spherePath.getPointAt(u);
+ translationMatrix.makeTranslation(position);
+ sphereMatrix.identity();
+ sphereMatrix.premultiply(rotMatrix);
+ sphereMatrix.premultiply(translationMatrix);
+ //rotMatrix.lookAt(0, 0, new THREE.Vector3(0, 1, 0));
+ instancedSpheres.setMatrixAt(i, sphereMatrix);
+ }
+
+ scene.add(instancedSpheres);
+
+ // Create the final object to add to the scene
+ const curveObject = new THREE.Line(geometry, lineMaterial);
+ // const curveObject = new THREE.Mesh(geometry, material);
+ scene.add(curveObject);
+}
+
+function getParametricPlaneFunction(width, height) {
+ return function (u, v, target) {
+ const x = -width / 2 + u * width;
+ const y = 0;
+ const z = -width / 2 + v * height;
+
+ target.set(x, y, z);
+ };
+}
+
+// buffer
+const vertices = [];
+const normals = [];
+const uvs = [];
+const indices = [];
+
+const vertex = new THREE.Vector3();
+const normal = new THREE.Vector3();
+const uv = new THREE.Vector2();
+
+function generateIndices(tubularSegments, radialSegments) {
+ for ( let j = 1; j <= tubularSegments; j ++ ) {
+ for ( let i = 1; i <= radialSegments; i ++ ) {
+ const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
+ const b = ( radialSegments + 1 ) * j + ( i - 1 );
+ const c = ( radialSegments + 1 ) * j + i;
+ const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
+
+ // faces
+ indices.push( a, b, d );
+ indices.push( b, c, d );
+ }
+ }
+}
+
+function generateSegment(i, frames, path, segments) {
+ // we use getPointAt to sample evenly distributed points from the given path
+ P = path.getPointAt(i/segments, P);
+
+ // retrieve corresponding normal and binormal
+ const N = frames.normals[i];
+ const B = frames.binormals[i];
+
+ // generate normals and vertices for the current segment
+ for (let j = 0; j <= radialSegments; j++) {
+ const v = j / radialSegments*Math.PI*2;
+
+ const sin = Math.sin(v);
+ const cos = - Math.cos(v);
+
+ // normal
+ normal.x = (cos*N.x + sin*B.x);
+ normal.y = (cos*N.y + sin*B.y);
+ normal.z = (cos*N.z + sin*B.z);
+ normal.normalize();
+
+ normals.push( normal.x, normal.y, normal.z );
+
+ // vertex
+ vertex.x = P.x + radius * normal.x;
+ vertex.y = P.y + radius * normal.y;
+ vertex.z = P.z + radius * normal.z;
+
+ vertices.push(vertex.x, vertex.y, vertex.z);
+ }
+}
+
+function generateBufferData(tubularSegments) {
+ for (let i = 0; i < tubularSegments; i++) {
+ generateSegment(i);
+ }
+
+ // if the geometry is not closed, generate the last row of vertices and normals
+ // at the regular position on the given path
+ //
+ // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
+ generateSegment( ( closed === false ) ? tubularSegments : 0 );
+
+ // uvs are generated in a separate function.
+ // this makes it easy compute correct values for closed geometries
+ generateUVs();
+
+ // finally create faces
+ generateIndices();
+}
+
+function createPath() {
+ //Create a closed wavey loop
+ const path = new THREE.CatmullRomCurve3([
+ new THREE.Vector3(-10, 0, 10),
+ new THREE.Vector3( 10, 0, 10),
+ new THREE.Vector3( 10, 0, -10),
+ new THREE.Vector3(-10, 0, -10),
+ ], true);
+
+ const points = path.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 pMaterial = new THREE.MeshPhongMaterial({
+ color: 0xFF0000,
+ side: THREE.DoubleSide,
+ transparent: false,
+ opacity: 0.7,
+ shininess: 10,
+ specular: 0XFFFFFF,
+ });
+
+ let close = true;
+ let segments = 10;
+
+ frames = path.computeFrenetFrames(segments, closed);
+
+ let P = new THREE.Vector3();
+
+ // setIndex( indices );
+ setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+ setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+ setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+
+ let samplingFunction = getParametricPlaneFunction(10, 10);
+
+ let pGeometry = new ParametricGeometry(samplingFunction, 50, 50);
+ let pMesh = new THREE.Mesh(pGeometry, pMaterial);
+ scene.add(pMesh);
+}
+
+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 createMenu() {
+ const gui = new dat.GUI({ width: 400 });
+ gui.add(terrainMaterial.uniforms.scale1, 'value', 0, 10).name('Texture scale');
+ gui.add(terrainMaterial.uniforms.mask1low, 'value', -1, 1).name('Mask1 Low');
+ gui.add(terrainMaterial.uniforms.mask1high, 'value', -1, 1).name('Mask1 High');
+ gui.add(terrainMaterial.uniforms.mask2low, 'value', -1, 1).name('Mask2 Low');
+ gui.add(terrainMaterial.uniforms.mask2high, 'value', -1, 1).name('Mask2 High');
+}
+
+function mainLoop() {
+ requestAnimationFrame(mainLoop);
+ renderer.render(scene, camera);
+}
+
+function main() {
+ buildScene();
+ // createMenu();
+ mainLoop();
+}
+
+setupThreeJs();
+createPath();
+main();
+// loadTextures(main);