Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • nrpc
2 results

Target

Select target project
  • villard5/webgl25
  • vincen251u/webgl25
  • e47747u/webgl25
3 results
Select Git revision
  • main
  • patch-1
2 results
Show changes
Commits on Source (345)
Showing
with 43592 additions and 0 deletions
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}
\ No newline at end of file
{
"liveServer.settings.port": 5501
}
\ No newline at end of file
File moved
File added
- [X] Esthetisme
- [X] Mise en page de la page web
- [X] Paragraphe(s) d'explications techniques
- [ ] Légèreté du dossier (<2Mo)
- [X] Géométrie
- [X] Couleur
- [X] Transparence
- [X] Eclairage
- [X] Ombres portées
- [X] Position de la caméra
- [X] Brouillard
- [X] Effet miroir
- [X] Texture classique
- [X] Texture avec transparence
- [X] Sprites
- [ ] Environment map
- [X] Skybox
- [X] specular maps
- [ ] normal maps
- [X] Interaction par GUI
- [X] Animation
\ No newline at end of file
File moved
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Projet WebGL</title>
<style>
@font-face {
font-family: 'Parisienne';
src: url('./Parisienne.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
body {
margin: 0;
background-color: #f0e6d9;
width: 100%;
overflow-x: hidden;
font-family: 'Parisienne', arial;
display: flex;
flex-direction: column;
min-height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
.centre {
text-align: center;
}
header {
height: 80px;
width: 100%;
background-image: url(./textures/skybox2.png);
overflow: hidden;
display: flex;
justify-content: left;
align-items: center;
background-color: #2c3e50;
}
.vangogh {
border-radius: 50%;
height: 75px;
width: 75px;
background-image: url(./textures/vangogh.jpg);
background-size: cover;
background-position: center;
border: 2px solid #e74c3c;
margin: 40px;
}
.texte-degrade {
font-size: 80px;
font-weight: bold;
background: linear-gradient(to right, #e74c3c, #e67e22);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-family: 'Parisienne', arial;
}
.small {
font-size: 50px;
font-weight: bold;
background: linear-gradient(to right, #e74c3c, #e67e22);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-family: 'Parisienne', arial;
padding-left: 5em;
}
.presentation {
width: 100%;
padding-bottom: 5em;
}
.presentation img {
width: 300px;
justify-self: center;
align-items: center;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.center-section {
width: 100%;
align-items: center;
justify-content: center;
display: flex;
flex-direction: column;
}
.button {
height: 50px;
width: 200px;
border-radius: 25px;
background: linear-gradient(to right, #e67e22, #d35400);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-top: 5em;
margin-bottom: 3em;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
button {
color: white;
font-family: 'Parisienne', arial;
background-color: transparent;
border: none;
font-size: 30px;
cursor: pointer;
}
.checklist {
width: 100%;
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 10px;
background-color: #f9f9f9;
font-family: 'Parisienne', arial;
user-select: none;
pointer-events: none;
}
.checklist h3 {
font-size: 30px;
margin-bottom: 10px;
color: #333;
}
.checklist ul {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.checklist li {
flex: 1 1 calc(50% - 20px);
box-sizing: border-box;
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
font-size: 20px;
}
.checklist input[type="checkbox"] {
margin-right: 10px;
}
.webgl-container {
flex: 1;
}
.explanation-section {
text-align: center;
padding: 20px;
background-color: #f0e6d9;
}
.bottom-text {
font-size: 20px;
margin-bottom: 20px;
text-align: left;
max-width: 800px;
margin: 0 auto;
}
</style>
</head>
<body>
<header>
<div class="vangogh"></div>
</header>
<!-- Chargement du polyfill pour les import maps -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.138.0/build/three.module.js",
"three/addons/controls/OrbitControls.js": "https://cdn.jsdelivr.net/npm/three@0.138.0/examples/jsm/controls/OrbitControls.js",
"three/addons/loaders/OBJLoader.js": "https://cdn.jsdelivr.net/npm/three@0.138.0/examples/jsm/loaders/OBJLoader.js",
"Coordinates": "./lib/Coordinates.js",
"dat.gui": "https://cdn.jsdelivr.net/npm/dat.gui@0.7.9/build/dat.gui.module.js"
}
}
</script>
<!-- JQuery pour afficher les erreurs -->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<div class="webgl-container">
<h1 class="centre texte-degrade">Projet WebGL</h1>
<div id="webGL" class="centre"></div>
</div>
<!-- Votre script principal -->
<script type="module" src="index.js"></script>
<section class="presentation">
<h2 class="texte-degrade small">Notre tableau choisi :</h2>
<div class="center-section">
<img src="./img.jpg">
<section class="checklist">
<h3>Liste de vérification</h3>
<ul>
<li>
<input type="checkbox" id="item1" checked>
<label for="item1">Esthétisme</label>
</li>
<li>
<input type="checkbox" id="item2" checked>
<label for="item2">Mise en page de la page web</label>
</li>
<li>
<input type="checkbox" id="item3" checked>
<label for="item3">Paragraphe(s) d'explications techniques</label>
</li>
<li>
<input type="checkbox" id="item4">
<label for="item4">Légèreté du dossier (<2Mo)</label>
</li>
<li>
<input type="checkbox" id="item5" checked>
<label for="item5">Géométrie</label>
</li>
<li>
<input type="checkbox" id="item6" checked>
<label for="item6">Couleur</label>
</li>
<li>
<input type="checkbox" id="item7" checked>
<label for="item7">Transparence</label>
</li>
<li>
<input type="checkbox" id="item8" checked>
<label for="item8">Éclairage</label>
</li>
<li>
<input type="checkbox" id="item9" checked>
<label for="item9">Ombres portées</label>
</li>
<li>
<input type="checkbox" id="item10" checked>
<label for="item10">Position de la caméra</label>
</li>
<li>
<input type="checkbox" id="item11" checked>
<label for="item11">Brouillard</label>
</li>
<li>
<input type="checkbox" id="item12" checked>
<label for="item12">Effet miroir</label>
</li>
<li>
<input type="checkbox" id="item13" checked>
<label for="item13">Texture classique</label>
</li>
<li>
<input type="checkbox" id="item14" checked>
<label for="item14">Texture avec transparence</label>
</li>
<li>
<input type="checkbox" id="item15" checked>
<label for="item15">Sprites</label>
</li>
<li>
<input type="checkbox" id="item16">
<label for="item16">Environment map</label>
</li>
<li>
<input type="checkbox" id="item17" checked>
<label for="item17">Skybox</label>
</li>
<li>
<input type="checkbox" id="item18" checked>
<label for="item18">Specular maps</label>
</li>
<li>
<input type="checkbox" id="item19">
<label for="item19">Normal maps</label>
</li>
<li>
<input type="checkbox" id="item20" checked>
<label for="item20">Interaction par GUI</label>
</li>
<li>
<input type="checkbox" id="item21" checked>
<label for="item21">Animation</label>
</li>
</ul>
</section>
<div id="scrollButton" class="button">
<button>Voir notre projet</button>
</div>
</div>
</section>
<section class="explanation-section">
<h1 class="centre texte-degrade">Explications :</h1>
<p class="bottom-text">L’esthétisme de la scène est soigné grâce à une mise en page optimisée qui utilise un canevas prenant toute la largeur et la hauteur de l’écran. La géométrie des objets est variée, incluant des cubes, des sphères et des plans, permettant une diversité visuelle. Les couleurs sont personnalisables et appliquées à l’aide de matériaux spécifiques.
La transparence est gérée en modifiant l’opacité des matériaux, permettant de créer des effets réalistes. L’éclairage est mis en place avec une lumière directionnelle et une lumière ponctuelle, améliorant le rendu des ombres portées sur les objets.
La position de la caméra est ajustée pour offrir une vue optimale sur la scène, avec la possibilité de modifier l’angle de vue. Un effet de brouillard est ajouté pour donner une impression de profondeur et de réalisme.
Un effet miroir est utilisé pour refléter les objets sur un sol réfléchissant, créant ainsi un rendu plus immersif. Les textures classiques sont appliquées aux objets pour leur donner un aspect détaillé, tandis que des textures avec transparence permettent de jouer sur la visibilité de certaines parties.
Les sprites sont utilisés pour afficher des éléments en 2D dans l’espace 3D, comme des icônes ou des effets spéciaux. Une skybox est mise en place pour offrir un fond réaliste, donnant l’impression d’un ciel ou d’un environnement étendu.
L’interaction est assurée par une interface graphique via GUI, permettant à l’utilisateur de modifier en temps réel certains paramètres comme la couleur ou la transparence des objets. Enfin, une animation fluide est intégrée, rendant les objets dynamiques avec une rotation continue et des déplacements progressifs.</p>
</section>
<section class="explanation-section">
<h1 class="centre texte-degrade">Comment nous l'avons réalisé :</h1>
</section>
<script>
// Script pour le bouton
document.getElementById('scrollButton').addEventListener('click', function() {
window.scrollTo({
top: document.body.scrollHeight,
behavior: 'smooth'
});
});
</script>
</body>
</html>
import * as dat from 'https://cdn.jsdelivr.net/npm/dat.gui@0.7.9/build/dat.gui.module.js';
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.150.1/build/three.module.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.150.1/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.150.1/examples/jsm/loaders/GLTFLoader.js';
import { OBJLoader } from 'https://cdn.jsdelivr.net/npm/three@0.150.1/examples/jsm/loaders/OBJLoader.js';
import { Reflector } from 'https://cdn.jsdelivr.net/npm/three@0.150.1/examples/jsm/objects/Reflector.js';
// SCENE
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB);
scene.fog = new THREE.FogExp2(0xCCC8C4);
// CAMERA
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 5000);
camera.position.set(950, 400, 30);
// RENDERER
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// CONTROLS
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.maxDistance = 2000;
controls.minDistance = 50;
controls.target.set(0, 0, 0);
// Directional Light (Soleil)
const sunLight = new THREE.DirectionalLight(0xffddaa, 3);
sunLight.position.set(500, 500, -500);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 4096;
sunLight.shadow.mapSize.height = 4096;
sunLight.shadow.camera.near = 0.5;
sunLight.shadow.camera.far = 5000;
sunLight.shadow.camera.left = -1000;
sunLight.shadow.camera.right = 1000;
sunLight.shadow.camera.top = 1000;
sunLight.shadow.camera.bottom = -1000;
scene.add(sunLight);
// Lumière ambiante (éclaire toute la scène)
const ambientLight = new THREE.AmbientLight(0x404040, 2);
scene.add(ambientLight);
// Spotlight
const spotLight = new THREE.SpotLight(0xffffff, 5, 500, Math.PI / 6, 0.5, 2);
spotLight.position.set(250, 200, -50);
spotLight.castShadow = true;
scene.add(spotLight);
let boat1, boat2;
const loader = new GLTFLoader();
loader.load('modeles/old_bridge.glb', function (gltf) {
const bridge = gltf.scene;
bridge.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
scene.add(bridge);
bridge.position.set(0, 100, 0);
bridge.scale.set(0.5, 0.5, 0.5);
bridge.rotation.y = Math.PI / 2;
controls.target.copy(bridge.position);
controls.update();
}, undefined, function (error) {
console.error("Erreur de chargement du pont :", error);
});
loader.load('modeles/old_bridge.glb', function (gltf) {
const bridge2 = gltf.scene;
bridge2.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
scene.add(bridge2);
bridge2.position.set(-950, 100, 0);
bridge2.scale.set(0.5, 0.5, 0.5);
bridge2.rotation.y = Math.PI / 2;
controls.target.copy(bridge2.position);
controls.update();
}, undefined, function (error) {
console.error("Erreur de chargement du pont :", error);
});
loader.load('modeles/old_bridge.glb', function (gltf) {
const bridge3 = gltf.scene;
bridge3.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
scene.add(bridge3);
bridge3.position.set(100, 100, 126);
bridge3.scale.set(0.5, 0.5, 0.5);
bridge3.rotation.y = Math.PI / -2;
controls.target.copy(bridge3.position);
controls.update();
}, undefined, function (error) {
console.error("Erreur de chargement du pont :", error);
});
loader.load('modeles/old_bridge.glb', function (gltf) {
const bridge4 = gltf.scene;
bridge4.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
scene.add(bridge4);
bridge4.position.set(-850, 100, 126);
bridge4.scale.set(0.5, 0.5, 0.5);
bridge4.rotation.y = Math.PI / -2;
controls.target.copy(bridge4.position);
controls.update();
}, undefined, function (error) {
console.error("Erreur de chargement du pont :", error);
});
loader.load('modeles/bateau.glb', function (gltf) {
boat1 = gltf.scene.clone();
boat1.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
boat2 = gltf.scene.clone();
boat2.traverse((node) => {
if (node.isMesh) {
node.castShadow = true;
node.receiveShadow = true;
}
});
boat1.position.set(-300, 1, -500);
boat1.scale.set(0.3, 0.3, 0.3);
boat2.position.set(-200, 1, -600);
boat2.scale.set(0.3, 0.3, 0.3);
boat2.rotation.y = Math.PI / 4;
scene.add(boat1);
scene.add(boat2);
}, undefined, function (error) {
console.error("Erreur de chargement des bateaux :", error);
});
const textureLoader = new THREE.TextureLoader();
const groundTexture = textureLoader.load('textures/water2.jpg');
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set(10, 10);
// Specular maps
function generateSpecularTexture(color, width = 128, height = 128) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
context.fillStyle = color;
context.fillRect(0, 0, width, height);
return new THREE.CanvasTexture(canvas);
}
const specularTexture = generateSpecularTexture('#555555');
const groundMaterial = new THREE.MeshPhongMaterial({
map: groundTexture,
specularMap: specularTexture,
specular: new THREE.Color(0xffffff),
shininess: 500,
transparent: true,
opacity: 0.7
});
const solidGround = new THREE.Mesh(
new THREE.PlaneGeometry(10000, 10000, 100, 100),
groundMaterial
);
solidGround.rotation.x = -Math.PI / 2;
solidGround.position.y = -2;
solidGround.receiveShadow = true;
scene.add(solidGround);
// Effet miroir
const mirrorGeometry = new THREE.PlaneGeometry(10000, 10000);
const mirror = new Reflector(mirrorGeometry, {
clipBias: 0.003,
textureWidth: window.innerWidth * window.devicePixelRatio,
textureHeight: window.innerHeight * window.devicePixelRatio,
color: 0x777777
});
mirror.rotation.x = -Math.PI / 2;
mirror.position.y = -1.999;
mirror.material.transparent = true;
mirror.material.opacity = 0.5;
mirror.renderOrder = 1;
scene.add(mirror);
const objLoader = new OBJLoader();
objLoader.load('modeles/scream/Scream 3D-bl.obj', function (obj) {
const screamTexture = textureLoader.load('modeles/scream/Scream Texture.png');
obj.traverse((child) => {
if (child.isMesh) {
child.material = new THREE.MeshBasicMaterial({ map: screamTexture });
child.castShadow = true;
child.receiveShadow = true;
}
});
obj.position.set(250, -60, -30);
obj.scale.set(20, 20, 20);
obj.rotation.z = Math.PI / 2.5;
obj.rotation.y = Math.PI / -5;
spotLight.target = obj;
scene.add(obj);
}, undefined, function (error) {
console.error("Erreur de chargement du modèle Scream :", error);
});
const skyTexture = textureLoader.load('textures/skybox2.png');
const skyMaterial = new THREE.MeshBasicMaterial({
map: skyTexture,
side: THREE.BackSide
});
const skySphere = new THREE.Mesh(
new THREE.SphereGeometry(3000, 32, 32),
skyMaterial
);
skySphere.rotation.x = Math.PI / 2;
skySphere.rotation.z = Math.PI / -1;
scene.add(skySphere);
const spriteTexture = textureLoader.load('textures/sprite.png');
const spriteMaterial = new THREE.SpriteMaterial({ map: spriteTexture });
const sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(40, 160, -30);
sprite.scale.set(50, 100, 50);
scene.add(sprite);
const spriteTexture2 = textureLoader.load('textures/sprite2.png');
const spriteMaterial2 = new THREE.SpriteMaterial({ map: spriteTexture2 });
const sprite2 = new THREE.Sprite(spriteMaterial2);
sprite2.position.set(20, 160, 0);
sprite2.scale.set(50, 100, 50);
scene.add(sprite2);
const gui = new dat.GUI();
const cameraFolder = gui.addFolder("Zoom & Brouillard");
cameraFolder.add(camera, "fov", 10, 100).name("Zoom").onChange(() => {
camera.updateProjectionMatrix();
});
cameraFolder.add(scene.fog, "density", 0, 0.0015).name("Brouillard");
const sunFolder = gui.addFolder("Soleil");
const sunColor = { color: sunLight.color.getHex() };
sunFolder.add(sunLight, "intensity", 0, 10).name("Intensité Soleil");
sunFolder.addColor(sunColor, "color").name("Couleur Soleil").onChange((value) => {
sunLight.color.set(value);
});
sunFolder.add(sunLight.position, "x", -2000, 2000).name("Position X");
sunFolder.add(sunLight.position, "y", -2000, 2000).name("Position Y");
sunFolder.add(sunLight.position, "z", -2000, 2000).name("Position Z");
const ambientFolder = gui.addFolder("Lumière Ambiante");
const ambientColor = { color: ambientLight.color.getHex() };
ambientFolder.add(ambientLight, "intensity", 0, 5).name("Intensité Ambiante");
ambientFolder.addColor(ambientColor, "color").name("Couleur Ambiante").onChange((value) => {
ambientLight.color.set(value);
});
const spotFolder = gui.addFolder("Spotlight sur Le Cri");
const spotColor = { color: spotLight.color.getHex() };
spotFolder.add(spotLight, "intensity", 0, 10).name("Intensité Spotlight");
spotFolder.addColor(spotColor, "color").name("Couleur Spotlight").onChange((value) => {
spotLight.color.set(value);
});
spotFolder.add(spotLight.position, "x", -500, 500).name("Position X");
spotFolder.add(spotLight.position, "y", 50, 500).name("Position Y");
spotFolder.add(spotLight.position, "z", -500, 500).name("Position Z");
const specularFolder = gui.addFolder("Specular Maps");
specularFolder.add(groundMaterial, "shininess", 0, 1000).name("Shininess").onChange(() => {
groundMaterial.needsUpdate = true;
});
specularFolder.addColor({ specular: groundMaterial.specular.getHex() }, "specular").name("Specular Color").onChange((value) => {
groundMaterial.specular.setHex(value);
});
const groundParams = {
color: 0xffffff
};
const groundFolder = gui.addFolder("Eau");
groundFolder.addColor(groundParams, "color").name("Couleur Eau").onChange((value) => {
groundMaterial.color.set(value);
});
function animate() {
requestAnimationFrame(animate);
controls.update();
const t = Date.now() * 0.001;
const speed1 = 0.1;
const speed2 = 0.1;
if (boat1) {
const radius1 = 100;
const center1 = { x: -300, z: -500 };
boat1.position.x = center1.x + radius1 * Math.cos(t * speed1);
boat1.position.z = center1.z + radius1 * Math.sin(t * speed1);
boat1.rotation.y = -t * speed1;
}
if (boat2) {
const radius2 = 100;
const center2 = { x: -200, z: -600 };
boat2.position.x = center2.x + radius2 * Math.cos(-t * speed2);
boat2.position.z = center2.z + radius2 * Math.sin(-t * speed2);
boat2.rotation.y = t * speed2;
}
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
File added
File added
ALGUL-ERRAES-GRANDGIRARD/modeles/scream/1 (5).png

493 KiB

ALGUL-ERRAES-GRANDGIRARD/modeles/scream/2 (5).png

307 KiB

# Blender 4.0.2 MTL File: 'None'
# www.blender.org
newmtl Munk
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
illum 1
map_Kd Scream Texture.png
map_d Scream Texture.png
This diff is collapsed.
File added
# Blender MTL File: 'Scream 3D.blend'
# Material Count: 0
# Blender v3.3.1 OBJ File: 'Scream 3D.blend'
# www.blender.org
mtllib Scream 3D.mtl
No preview for this file type
ALGUL-ERRAES-GRANDGIRARD/modeles/scream/Scream Texture.png

4.3 MiB