Referências

  • TODO

Modelos Básicos

Objetos Básicos

Geometria por Faces (indexada)

  1. Instalar vite: npm install -D vite.

  2. Criar index.html e main.js como abaixo.

  3. Correr o "projeto": npx vite.

index.html

<!DOCTYPE html>
<html lang="pt">

<head>
    <meta charset="utf8">
    <link rel="icon" href="favicon.ico" />

    <title>3JS - 2024</title>
    <script type='module' src='main.js' defer></script>
</head>

<body>
    <h1>3JS - 2024</h1>
    <div>
        <span id="terminal">(empty)</span>
        <span id="container" tabindex="0"></span>
        <span id="debug"></span>
    </div>
</body>

</html>

main.js

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

const div_container = document.getElementById("container");
const terminal = document.getElementById("terminal");

function indexed_faces_geometry(coords, faces, points, sectors) {
    //
    //  Geometry: "Indexed Face Set"
    //
    //  Generate all the vertexes in the XYZ plane
    const positions = [];
    for (const i of faces) {
        const xyz_point = coords.slice(3 * i, 3 * i + 3);
        positions.push(...xyz_point);
    }
    //
    //  Generate all the points in the UV plane
    const uvs = [];
    for (const i of sectors) {
        const uv_point = points.slice(2 * i, 2 * i + 2);
        uvs.push(...uv_point);
    }
    //
    const geo = new THREE.BufferGeometry();
    //
    geo.setAttribute("position",
        new THREE.Float32BufferAttribute(positions, 3));
    geo.setAttribute("uv",
        new THREE.Float32BufferAttribute(uvs, 2));
    //
    geo.computeVertexNormals();
    geo.computeBoundingSphere();
    //
    return geo;
}

function create_model() {
    //
    //  Lights
    //
    const ambient_light = new THREE.AmbientLight(0xFFFFFF);
    const directional_light = new THREE.DirectionalLight( 0xffffff, 1.0 );
    //
    //  Material
    //
    const loader = new THREE.TextureLoader();
    const diffuseMap = loader.load("tri_textures/tri_d.png");
    const specularMap = loader.load("tri_textures/tri_s.png");
    const normalMap = loader.load("tri_textures/tri_n.png");
    //
    const grob_material = new THREE.MeshPhongMaterial({
        specular: "black",
        map: diffuseMap,
        specularMap: specularMap,
        normalMap: normalMap,
    });
    //
    //  Geometry: "Indexed Face Set"
    //
    //  Vertexes in the XYZ space
    const coords = [
        0.0, 1.0, 0.0,
        1.0, 0.0, 1.0,
        1.0, 0.0, -1.0,
        -1.0, 0.0, -1.0,
        -1.0, 0.0, 1.0,
    ];
    //
    //  Faces are triangles in the XYZ space
    const faces = [
        0, 4, 1,
        0, 1, 2,
        0, 2, 3,
        0, 3, 4,
        // ----
        1, 4, 3,
        1, 3, 2,
    ];
    //
    //  Points in the UV plane
    const points = [
        0.0, 0.0,
        1.0, 0.0,
        0.5, 1.0,
        1.0, 1.0,
        0.0, 1.0,
    ];
    //
    //  Segments are triangles in the UV plane
    const sectors = [
        2, 0, 1,
        2, 0, 1,
        2, 0, 1,
        2, 0, 1,
        0, 1, 3,
        0, 3, 4,
    ];
    //
    const grob_geometry = indexed_faces_geometry(coords, faces, points, sectors);
    //
    const grob = new THREE.Mesh(grob_geometry, grob_material);

    return [ambient_light, directional_light, grob];
}
/**
* Setup the rendering context and build a model
**/
function init(objects) {
    //
    const renderer = new THREE.WebGLRenderer({
        alpha: true,
        antialias: true,
    });
    //let size = Math.min(parent.innerWidth, parent.innerHeight, 1024);
    const size = 512;
    renderer.setSize(size, size);
    renderer.setClearColor("skyblue", 0.1);
    div_container.appendChild(renderer.domElement);
    //
    const scene = new THREE.Scene();
    //
    //  Camera (and TrackballControls)
    //
    const camera = new THREE.PerspectiveCamera(
        90, // abertura
        1.0, // proporção largura/altura
        0.01, // corte perto
        100 // corte longe
    );
    camera.position.set(2, 1, 1);
    camera.lookAt(scene.position);
    //
    const controls = new OrbitControls(camera, renderer.domElement);
    div_container.addEventListener("keydown", (e) => {
        if (e.key === "R" || e.key === "r") {
            controls.reset();
        }
    });
    //
    //
    for (const object of objects) {
        scene.add(object);
    }

    return {
        age: 1,
        camera: camera,
        scene: scene,
        renderer: renderer,
        controls: controls
    }
}
/**
* Animate the model
*/
function animate(step) {
    requestAnimationFrame(() => animate(step));
    step.age += 1;
    terminal.innerHTML = `${step.age}`;
    step.controls.update();
    step.renderer.render(step.scene, step.camera);
}
/**
*  Entry function
*/
function main() {
    const model = create_model();
    const step = init(model);
    animate(step);
}

terminal.innerHTML = "START";
main();
terminal.innerHTML = "DONE";