├── .gitignore ├── README.md ├── abacus ├── 10-11-2024_092541.gif ├── README.md ├── abacus.blend ├── index.html └── index.js ├── airshow ├── blender │ ├── airbase_textures.png │ ├── blueangeltexture-edit.png │ ├── c-130 (1).blend │ ├── c-130.png │ ├── control-tower (2).blend │ ├── control_tower.png │ ├── f-16-edit.blend │ ├── f-16-final.blend │ ├── f-18hornet-edit (1).blend │ ├── f-35-final.blend │ ├── f16-1.001.png │ ├── f16-2.png │ ├── f18-2.png │ ├── f35-1.png │ └── grass2.jpg ├── index.html ├── index.js ├── notes.txt ├── pictures │ ├── airshow_demo.webp │ ├── rotation-example.gif │ └── screenshot.png └── readme.md ├── audio_visualization ├── 27-05-2022_153744.webp ├── README.md ├── index.html └── index.js ├── basketball ├── 12-05-2022_191525.gif ├── CannonDebugRenderer.js ├── index.html ├── index.js ├── readme.md ├── success.png └── success2.png ├── battleships ├── 25-09-2023_202551.gif ├── README.md ├── battleship-edit2.png ├── battleship2-edit.png ├── blender │ └── battleship-edit3.blend ├── index.html ├── index.js ├── screenshot.png ├── todo.txt └── waternormals.jpg ├── boombox ├── 28-12-2024_221744.gif ├── README.md ├── boombox.blend ├── index.html └── index.js ├── camerawork ├── 28-08-2021_102033.webp ├── index.html ├── index.js ├── notes.txt ├── readme.md ├── screenshot.png └── texture.png ├── car_demo ├── blender │ ├── maybeporsche911-final.blend │ ├── porschecolor1.png │ └── racetrack.blend ├── index.html ├── index.js ├── notes.txt ├── pictures │ ├── angle-correction.png │ ├── angle-correction2.png │ ├── car_demo.webp │ ├── debugging.gif │ ├── ideas.png │ ├── screenshot.png │ └── tilting_bad.png └── readme.md ├── character_demo ├── animation_state_map.json ├── blender │ └── humanoid-rig-with-gun.blend ├── index.html ├── index.js ├── notes.txt ├── pictures │ ├── character_demo.gif │ └── screenshot.png └── readme.md ├── curves ├── README.md ├── demo.gif ├── index.html ├── index.js └── notes.txt ├── dimsum ├── README.md ├── dim-sum.blend ├── index.html ├── index.js └── screenshot.png ├── dishwashing ├── 08-03-2022_141113.gif ├── blender │ ├── hand-edit.blend │ ├── kitchenware.blend │ └── sponge.blend ├── index.html ├── index.js ├── notes.txt └── readme.md ├── eslint.config.mjs ├── experiments ├── index.html ├── index.js ├── notes.txt └── texture.png ├── fps ├── 16-11-2024_124629.gif ├── animation_state_map.json ├── crosshairs.png ├── index.html ├── index.js └── readme.md ├── index.html ├── lava_lamp ├── README.md ├── index.html ├── index.js ├── lava-lamp.blend ├── lavalampidea.txt └── screenshot.png ├── libs ├── AnimationController.js ├── CurveModifier.js ├── GLTFLoader.js ├── JSKeyboard.js ├── MarchingCubes.js ├── OrbitControls.js ├── TrackballControls.js ├── cannon.js ├── partykals.js ├── stats.js ├── threex.keyboardstate.js ├── utils.js └── water-material.js ├── livery_editor ├── 04-06-2021_142020.gif ├── air-force-insignia-paste-example.png ├── index.html ├── index.js ├── notes.txt ├── pasteImageUtils.js ├── readme.md └── yuyushiki-itasha-example-lol.png ├── models ├── 080415pianobgm3popver-edit-steinway.ogg ├── abacus.gltf ├── airbase-edit.gltf ├── airbase.gltf ├── barrel.gltf ├── battleship-edit2.gltf ├── battleship2.glb ├── battleship2.gltf ├── boombox.gltf ├── box.gltf ├── cha-siu-bao.gltf ├── cloud.gltf ├── cow.gltf ├── dan-tat.gltf ├── dangerous-capsule-edit-final.glb ├── depositphotos_65970561-stock-photo-asphalt-texture.jpg ├── f-16.gltf ├── f-18.glb ├── f-35.gltf ├── f14.gltf ├── f5tiger.gltf ├── grass2.jpg ├── hand-edit.gltf ├── hill.gltf ├── humanoid-rig-with-gun-test.gltf ├── humanoid-rig.gltf ├── jellyfish-animated.gltf ├── lava-lamp.gltf ├── low-poly-human.gltf ├── m4carbine-final.gltf ├── oceanfloor.glb ├── pine-tree.gltf ├── plate.gltf ├── porsche.gltf ├── racetrack.gltf ├── rock.gltf ├── rubikscube.gltf ├── siu-mai-ha-gao.gltf ├── smallship-damaged.gltf ├── snowboard.gltf ├── snowboarder.gltf ├── spiky-thing.gltf ├── split-flap-idea.gltf ├── sponge.gltf ├── sten-mkII.gltf ├── submarine1.glb ├── target.gltf ├── trumpet.gltf ├── vending-machine-color.gltf ├── vending-machine.gltf ├── whale-shark-camo.glb └── whale-shark-final.gltf ├── new_project_template ├── README.md ├── index.html └── index.js ├── package-lock.json ├── package.json ├── rubikscube ├── 19-03-2024_192544.gif ├── README.md ├── blender │ ├── m1.png │ ├── m2.png │ ├── m3.png │ ├── m4.png │ ├── m5.png │ ├── m6.png │ ├── m7.png │ ├── r1.png │ ├── r2.png │ ├── r3.png │ ├── r4.png │ ├── r5.png │ ├── r6.png │ ├── r7.png │ ├── r8.png │ ├── r9.png │ ├── rubikscube.blend │ ├── t1.png │ ├── t2.png │ ├── t3.png │ ├── t4.png │ ├── t5.png │ ├── t6.png │ ├── t7.png │ ├── t8.png │ └── t9.png ├── index.html └── index.js ├── server.js ├── shaders ├── 27-06-2021_184151.webp ├── index.html ├── index.js ├── notes.txt ├── raymarching.png ├── readme.md └── shaders │ ├── glassShader.js │ ├── jetModelShader.js │ ├── jetModelShader2.js │ ├── raymarchShader.js │ ├── rippleShader.js │ ├── springyShardShader.js │ ├── toonShader.js │ └── whaleSharkShader.js ├── snowboard ├── 08-10-2023_103831.gif ├── 093023humanoid.blend ├── AnimationController.js ├── README.md ├── animation_state_map.json ├── index.html ├── index.js └── player-rotation-on-slope.png ├── split-flap_display ├── 05-11-2024_210722.gif ├── README.md ├── index.html ├── index.js ├── letters │ ├── a-bottom.png │ ├── a-top.png │ ├── b-bottom.png │ ├── b-top.png │ ├── c-bottom.png │ ├── c-top.png │ ├── d-bottom.png │ ├── d-top.png │ ├── e-bottom.png │ ├── e-top.png │ ├── f-bottom.png │ ├── f-top.png │ ├── g-bottom.png │ ├── g-top.png │ ├── h-bottom.png │ ├── h-top.png │ ├── i-bottom.png │ ├── i-top.png │ ├── j-bottom.png │ ├── j-top.png │ ├── k-bottom.png │ ├── k-top.png │ ├── l-bottom.png │ ├── l-top.png │ ├── m-bottom.png │ ├── m-top.png │ ├── n-bottom.png │ ├── n-top.png │ ├── o-bottom.png │ ├── o-top.png │ ├── p-bottom.png │ ├── p-top.png │ ├── q-bottom.png │ ├── q-top.png │ ├── r-bottom.png │ ├── r-top.png │ ├── s-bottom.png │ ├── s-top.png │ ├── t-bottom.png │ ├── t-top.png │ ├── u-bottom.png │ ├── u-top.png │ ├── v-bottom.png │ ├── v-top.png │ ├── w-bottom.png │ ├── w-top.png │ ├── x-bottom.png │ ├── x-top.png │ ├── y-bottom.png │ ├── y-top.png │ ├── z-bottom.png │ └── z-top.png └── split-flap-idea.blend ├── super_submarine ├── blender │ ├── battleship.png │ ├── battleship2.blend │ ├── dangerous_capsule-edit.blend │ ├── jellyfish-animated.blend │ ├── jellyfish.png │ ├── submarine1.blend │ ├── whale shark mat.png │ └── whale-shark-final.blend ├── index.html ├── index.js ├── notes.txt ├── pictures │ ├── screenshot.png │ ├── submarine_demo.webp │ └── whalesharkmotion.png ├── readme.md └── waternormals.jpg ├── trumpet ├── 080623-trpt-sample.wav ├── README.md ├── blender │ ├── trumpet.blend │ └── trumpet.png ├── demo.gif ├── index.html ├── index.js ├── notes │ ├── a4.ogg │ ├── a5.ogg │ ├── b4.ogg │ ├── b5.ogg │ ├── bb4.ogg │ ├── bb5.ogg │ ├── c4.ogg │ ├── c5.ogg │ ├── c6.ogg │ ├── cs4.ogg │ ├── cs5.ogg │ ├── d4.ogg │ ├── d5.ogg │ ├── ds4.ogg │ ├── ds5.ogg │ ├── e4.ogg │ ├── e5.ogg │ ├── f4.ogg │ ├── f5.ogg │ ├── fs4.ogg │ ├── fs5.ogg │ ├── g4.ogg │ ├── g5.ogg │ ├── gs4.ogg │ └── gs5.ogg └── todo.txt └── vending_machine ├── 11-02-2022_193916.webp ├── 29-08-2021_103845.gif ├── blender-notes.txt ├── blender ├── 1-key.png ├── 2-key.png ├── 3-key.png ├── A-key.png ├── B-key.png ├── C-key.png ├── D-key.png ├── E-key.png ├── vending-machine-front-panel-1.png ├── vending-machine-front-panel.png ├── vending-machine-left-panel.png ├── vending-machine-right-panel.png └── vending-machine.blend ├── helvetiker_bold.typeface.json ├── index.html ├── index.js └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # threejs-projects 2 | small projects using three.js with stuff I made in Blender! 3 | see them here: https://syncopika.github.io/threejs-projects/ 4 | 5 | ## how to run: 6 | If you have Python installed, `cd` into this repo after downloading and run `python -m http.server`. Then navigate to `http://localhost:8000/` and you should see a list of the projects! 7 | 8 | Otherwise, if you have Node.js and npm, you can use an Express server. `cd` into this repo after you have downloaded it and run `npm install`. Then run `node server.js` and open up a broswer and navigate to `http://localhost:3000/`. 9 | 10 | For convenience, I opted just to pull three.js from a CDN, which requires an internet connection anytime you want to open this project. Please keep that in mind when running locally. 11 | 12 | ## acknowledgements: 13 | many thanks to 14 | - mr.doob for three.js and its associated libraries (e.g. TrackballControls, GLTFLoader) and all the people who have contributed to them 15 | - Stefan Hedman for cannon.js 16 | - Ronen Ness for partykals.js 17 | - Jerome Etienne for threex.keyboardstate.js 18 | - jbouny et al. for the water shader 19 | - all the people who posted questions of StackOverflow + elsewhere and the authors of various blog posts that I referred to to make these things 20 | 21 | ## notes: 22 | Each project directory also has a readme with some additional info. 23 | 24 | Thanks for visiting and checking this project out! Feel free to use any of my .gltf assets in your own projects as well if you want - no attribution necessary. If you spot any bugs, please feel free to create a new issue (would prefer no PRs at this time though, please and sorry!). 25 | -------------------------------------------------------------------------------- /abacus/10-11-2024_092541.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/abacus/10-11-2024_092541.gif -------------------------------------------------------------------------------- /abacus/README.md: -------------------------------------------------------------------------------- 1 | # abacus/soroban demo 2 | 3 | a 3d abacus/soroban. 🧮 4 | 5 | ![screenshot](10-11-2024_092541.gif) -------------------------------------------------------------------------------- /abacus/abacus.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/abacus/abacus.blend -------------------------------------------------------------------------------- /abacus/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3d abacus 5 | 6 | 7 | 8 | 9 | 10 | 24 | 25 | 26 | 27 |

3D abacus

28 | 29 |
30 |
31 | 32 |

33 | 34 |

click and drag a bead on the abacus to move it up or down and see how the position of the bead affects the value displayed by the abacus.

35 |

This particular 3D abacus is a soroban. Also see https://en.wikipedia.org/wiki/Suanpan

36 | 37 | 38 | 40 | -------------------------------------------------------------------------------- /airshow/blender/airbase_textures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/airbase_textures.png -------------------------------------------------------------------------------- /airshow/blender/blueangeltexture-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/blueangeltexture-edit.png -------------------------------------------------------------------------------- /airshow/blender/c-130 (1).blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/c-130 (1).blend -------------------------------------------------------------------------------- /airshow/blender/c-130.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/c-130.png -------------------------------------------------------------------------------- /airshow/blender/control-tower (2).blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/control-tower (2).blend -------------------------------------------------------------------------------- /airshow/blender/control_tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/control_tower.png -------------------------------------------------------------------------------- /airshow/blender/f-16-edit.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f-16-edit.blend -------------------------------------------------------------------------------- /airshow/blender/f-16-final.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f-16-final.blend -------------------------------------------------------------------------------- /airshow/blender/f-18hornet-edit (1).blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f-18hornet-edit (1).blend -------------------------------------------------------------------------------- /airshow/blender/f-35-final.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f-35-final.blend -------------------------------------------------------------------------------- /airshow/blender/f16-1.001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f16-1.001.png -------------------------------------------------------------------------------- /airshow/blender/f16-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f16-2.png -------------------------------------------------------------------------------- /airshow/blender/f18-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f18-2.png -------------------------------------------------------------------------------- /airshow/blender/f35-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/f35-1.png -------------------------------------------------------------------------------- /airshow/blender/grass2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/blender/grass2.jpg -------------------------------------------------------------------------------- /airshow/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | airshow 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 43 | 44 | 45 |
46 |
47 | 48 |
49 |

current altitude: 1.0

50 |

current speed: 0.0

51 |

current state: taxi

52 |
53 | 54 |
55 | 56 |
57 |

controls:

58 |

press 1, 2 or 3 to change aircraft.

59 |

w,a,s,d to move forward, left, backwards and right.

60 |

q,e to roll left/right. up and down arrow to move up and down.

61 |

p to toggle smoke.

62 |

shift to change camera view.

63 |

caps lock to switch to takeoff mode, or landing mode when flying.

64 |
65 | 66 | 67 | 68 | 69 | 71 | -------------------------------------------------------------------------------- /airshow/notes.txt: -------------------------------------------------------------------------------- 1 | airshow! 2 | 3 | I love airshows and military aircraft. the one featured here is an f-18. hopefully I will build some more military aircraft to assemble 4 | some static displays! :D 5 | 6 | 7 | notes: 8 | - so when the f-18 controlled by the user reaches some vertical angle ( > 90 deg), the camera flips. not a big deal, but interesting. 9 | 10 | looks like the issue is with lookAt() 11 | this might help: https://discourse.threejs.org/t/solved-lookat-flips-cam-rotation-180-degrees-how-do-i-remove-this/2066/3 12 | and this: https://github.com/mrdoob/three.js/issues/688 13 | 14 | this dicussion also looks interesting: https://github.com/mrdoob/three.js/issues/1460 15 | 16 | - a more pressing matter is the way I handle rolls with Q and E. i'm manipulating the actual jet's mesh so the axis can get misaligned relative 17 | to the group object it's a child of, which then makes all my controls inverted. but it does make sense that that should happen but at 18 | the same time I'm not really sure what a proper experience should be like thinking about it more. maybe I'll reinstall BF2 and take a look :) 19 | 20 | - also, when I put the f18 in a group object the rolling behavior is exactly what i want. but when i try using just the f18 mesh itself, 21 | the rotation is not as good, i.e. it feels like there's some offset, rather than rotating the jet as if the z-axis was going through the 22 | middle of it. not really sure why but that's something to look into. 23 | // https://stackoverflow.com/questions/28848863/threejs-how-to-rotate-around-objects-own-center-instead-of-world-center 24 | 25 | todo: 26 | - better lighting + clouds 27 | - basic f-18 animations like: 28 | - flaps 29 | - rudders 30 | - landing gear deploy/retraction on key press 31 | - allow user to switch between aircraft 32 | - more camera modes 33 | - make more planes for static displays! 34 | -ideas: c-17, c-5, f-15, f-14 (even though retired lol), f-22, av-8b, p-8, tanks are good too, helicopters!! 35 | 36 | textures: 37 | http://hoodavirender.blogspot.com/2012/03/seamless-grass-texture.html 38 | borrowed top-view of Andrews Air Force Base from Google Maps 39 | https://www.goodfreephotos.com/united-states/colorado/rocky-mountains-national-park/colorado-rocky-mountains-national-park-mountains-in-the-horizon.jpg.php 40 | https://www.photos-public-domain.com/2011/03/02/blue-sky-with-white-clouds-texture/ 41 | 42 | http://www.aerodynamics4students.com/aircraft-performance/take-off-and-landing.php 43 | https://aviation.stackexchange.com/questions/9961/does-acceleration-increase-linearly-on-a-takeoff-roll -------------------------------------------------------------------------------- /airshow/pictures/airshow_demo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/pictures/airshow_demo.webp -------------------------------------------------------------------------------- /airshow/pictures/rotation-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/pictures/rotation-example.gif -------------------------------------------------------------------------------- /airshow/pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/airshow/pictures/screenshot.png -------------------------------------------------------------------------------- /airshow/readme.md: -------------------------------------------------------------------------------- 1 | # airshow 2 | 3 | For this project I wanted to make and fly some jets! 4 | 5 | ## notes: 6 | 7 | 1. rotating the plane 8 | Had some issues with this. Placing the plane mesh in a THREE.Group object and rotating the mesh got me the current effect, which I think is good. 9 | However, I am unsure why rotating the plane mesh within a THREE.Group is different than rotating the mesh (or the group object) by itself relative to its own axis, as seen below: 10 | 11 | example of not-so-great rotation (imo) when rotating the THREE.Group on its own axis in object space: 12 | ![bad rotation example](pictures/rotation-example.gif) 13 | 14 | One issue though with the current strategy and using the THREE.Group is that during a vertical loop the orientation of the axes change, which changes the direction of motion on key press. Definitely something to investigate further. 15 | 16 | 2. takeoff and landing 17 | For takeoff, the speed of the plane is increased exponentially (ex via Math.exp()), which looks fine to me visually. I also added a landing mode feature in which the plane descends at a constant speed while being parallel to the ground. 18 | 19 | 3. jet engine exhaust/smoke 20 | Used the partykals.js library by RonenNess (https://github.com/RonenNess/partykals) -------------------------------------------------------------------------------- /audio_visualization/27-05-2022_153744.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/audio_visualization/27-05-2022_153744.webp -------------------------------------------------------------------------------- /audio_visualization/README.md: -------------------------------------------------------------------------------- 1 | # audio visualization 2 | 3 | ![demo](27-05-2022_153744.webp) 4 | 5 | This demo utilizes the Web Audio API (in particular the AnalyserNode) to demonstrate how we can use audio data to help create 3D visualizations. -------------------------------------------------------------------------------- /audio_visualization/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | audio visualization 5 | 6 | 7 | 8 | 9 | 10 | 11 | 29 | 30 | 31 | 32 |

audio visualization

33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |

audio file name

44 | 45 |

a very basic visualizer for audio! with trackball controls so you can view the visualizer at different angles. :D

46 |

the pink balls correspond to the time domain and the green-yellow cubes correspond to the frequency domain.

47 | 48 | 49 | 51 | -------------------------------------------------------------------------------- /basketball/12-05-2022_191525.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/basketball/12-05-2022_191525.gif -------------------------------------------------------------------------------- /basketball/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | basketball 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 33 | 34 | 35 | 36 |

basketball

37 |

press 1 and 2 keys to change camera view and spacebar to add impulse to the ball. press r to reset.

38 | 39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 | 49 | -------------------------------------------------------------------------------- /basketball/readme.md: -------------------------------------------------------------------------------- 1 | # basketball 2 | 3 | This demo utilizes the Cannon.js library (https://schteppe.github.io/cannon.js/) for handling physics! 4 | 5 | ![gif of basketball demo](12-05-2022_191525.gif) -------------------------------------------------------------------------------- /basketball/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/basketball/success.png -------------------------------------------------------------------------------- /basketball/success2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/basketball/success2.png -------------------------------------------------------------------------------- /battleships/25-09-2023_202551.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/25-09-2023_202551.gif -------------------------------------------------------------------------------- /battleships/README.md: -------------------------------------------------------------------------------- 1 | # battleships 2 | 3 | A game idea featuring 3d battleships! 4 | 5 | ![battleships gif](25-09-2023_202551.gif) 6 | 7 | This demo utilizes an orthographic camera for a top-down view of the map, as well as a perspective camera with orbit controls. -------------------------------------------------------------------------------- /battleships/battleship-edit2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/battleship-edit2.png -------------------------------------------------------------------------------- /battleships/battleship2-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/battleship2-edit.png -------------------------------------------------------------------------------- /battleships/blender/battleship-edit3.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/blender/battleship-edit3.blend -------------------------------------------------------------------------------- /battleships/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | battleships 5 | 6 | 7 | 8 | 9 | 17 | 18 | 23 | 24 | 69 | 70 | 71 | 72 |

battleships

73 | 74 |
75 | 76 | 77 | 78 | 79 |
80 | 81 |
82 |
83 | 84 |
85 |
86 | 87 |

enemy

88 |
89 |
90 |
91 | 92 |

player

93 |
94 |
95 | 96 |

click on the player ship and click anywhere in the yellow circle to move the ship. if you get close enough to another object, you can click on the object to attack it. when attacking, if 'toggle airstrike' is checked, an airstrike will be initiated :)

97 | 98 | 99 | 101 | -------------------------------------------------------------------------------- /battleships/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/screenshot.png -------------------------------------------------------------------------------- /battleships/todo.txt: -------------------------------------------------------------------------------- 1 | TODO: 2 | 3 | - prevent movement through obstacles? 4 | - check for collisions within player unit's select area (the yellow circle)? 5 | 6 | - enemy movement 7 | 8 | - ship animation? (e.g. moving cannons, cannon smoke) 9 | 10 | - brighter sky, night sky options? 11 | 12 | - fix perspective camera? (when using orbit control and rotating the camera, the ships sometimes disappear. is that a camera parameter issue?) 13 | 14 | - figure out why sometimes things don't show in orthographic camera until a certain y position is reached? 15 | e.g. the player selectarea needs to be at or past a certain y value to show up in the orthographic camera 16 | 17 | - more ships -------------------------------------------------------------------------------- /battleships/waternormals.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/battleships/waternormals.jpg -------------------------------------------------------------------------------- /boombox/28-12-2024_221744.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/boombox/28-12-2024_221744.gif -------------------------------------------------------------------------------- /boombox/README.md: -------------------------------------------------------------------------------- 1 | # boombox idea 2 | 3 | A 3D boombox :D 4 | 5 | The boombox model utilizes shape keys (morph targets in Three.js) to transform the play/stop buttons of the model, for rotating the dial to change the lowpass filter frequency and for enlarging the meshes of the speakers based on the audio data. 6 | This demo also adds spatial audio and a lowpass filter with the help of the Web Audio API. 7 | 8 | ![gif of boombox working](28-12-2024_221744.gif) -------------------------------------------------------------------------------- /boombox/boombox.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/boombox/boombox.blend -------------------------------------------------------------------------------- /boombox/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | boombox 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 |

boombox

28 | 29 |
30 |
31 | 32 |

audio file name

33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /camerawork/28-08-2021_102033.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/camerawork/28-08-2021_102033.webp -------------------------------------------------------------------------------- /camerawork/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | camerawork 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 43 | 44 | 45 |
46 |
47 | 48 |
49 |

50 |
51 | 52 |
53 |

controls:

54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | 66 |

w,s to move forward and backward. a,d to rotate left and right. q,e to roll left and right. up and down arrows to rotate up and down.

67 |

click on the canvas to add a new marker while the 'add marker' button is active.

68 |

click on any marker when the 'select marker' button is active. (they should change to red when clicked)

69 |

after markers have been selected, press the 'create path' button to connect the markers.

70 |

the 'ride path' button will move the camera along the created path. note that currently there is a 5 second duration for each created path.

71 | 72 | 73 |
74 | 75 | 76 | 78 | -------------------------------------------------------------------------------- /camerawork/notes.txt: -------------------------------------------------------------------------------- 1 | https://stackoverflow.com/questions/42309715/how-to-correctly-pass-mouse-coordinates-to-webgl 2 | https://stackoverflow.com/questions/57381278/threejs-2d-pixels-to-3d-coordinates-conversion 3 | https://stackoverflow.com/questions/27409074/converting-3d-position-to-2d-screen-position-r69 4 | https://stackoverflow.com/questions/11638883/thickness-of-lines-using-three-linebasicmaterial 5 | https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_cubes.html 6 | https://stackoverflow.com/questions/43414174/animate-object-along-a-path-in-three-js 7 | https://stackoverflow.com/questions/29656301/move-a-mesh-on-a-line-three-js 8 | https://sbcode.net/threejs/vector3-lerp/ 9 | https://forum.unity.com/threads/lerp-value-reaching-destination-before-lerp-ends.401896/ -> very important! 10 | 11 | todo: 12 | - import/export of marker+path data so we can demonstrate some useful ideas 13 | - make a useful demo 14 | - add some ui components to represent 'scenes'? i.e. 1 path == 1 scene? 15 | - be able to change speed 16 | - make camera movement smoother? that probably has to do with speed... 17 | - smooth turning about angles? bezier curves? 18 | -------------------------------------------------------------------------------- /camerawork/readme.md: -------------------------------------------------------------------------------- 1 | # camerawork 2 | ### an experiment with moving a camera along a user-created path 3 | 4 | the user can create markers and paths between markers. 5 | ![screenshot of markers and paths](screenshot.png) 6 | 7 | camera view when following a path: 8 | ![camera view on path](28-08-2021_102033.webp) 9 | 10 | For this demo, the camera is made to focus on the blue cube wireframe while it's moving along a path. -------------------------------------------------------------------------------- /camerawork/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/camerawork/screenshot.png -------------------------------------------------------------------------------- /camerawork/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/camerawork/texture.png -------------------------------------------------------------------------------- /car_demo/blender/maybeporsche911-final.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/blender/maybeporsche911-final.blend -------------------------------------------------------------------------------- /car_demo/blender/porschecolor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/blender/porschecolor1.png -------------------------------------------------------------------------------- /car_demo/blender/racetrack.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/blender/racetrack.blend -------------------------------------------------------------------------------- /car_demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | car demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 37 | 38 | 39 |
40 |
41 | 42 |
43 | 44 |
45 |

still a work-in-progress.

46 |
47 | 48 |
49 |

controls:

50 |

keys 1-4 control different camera views. z for changing to opposite camera view for front and side views.

51 |

w,s for forwards/backwards. a,d for turning left, right. p to toggle car body visibility. t to toggle racetrack visibility.

52 |

x for toggling racetrack wireframe. c for debug mode.

53 |
54 | 55 | 56 | 57 | 58 | 60 | -------------------------------------------------------------------------------- /car_demo/notes.txt: -------------------------------------------------------------------------------- 1 | for car turning physics later to make things more realistic/complicated: 2 | https://physics.stackexchange.com/questions/182689/what-causes-a-cars-velocity-to-follow-the-front-wheels-direction 3 | https://physics.stackexchange.com/questions/454887/the-dynamics-of-a-cornering-wheel 4 | 5 | What I want to do is to program at least somewhat realistic turning for the car. 6 | I thought to start with I could just rotate the car to match the rotation of the front wheels. this is tricky because 7 | I'm having trouble figuring out how a car's body rotates when turning. it should be independent of the front wheels' rotation I think? 8 | 9 | TODO: 10 | - fix the car rotation thing when turning. if you try turning the wheels from one side to another (i.e. keep alternating between 11 | A and D) after turning, the car's forward vector is stuck at an angle, which influences the forward movement. I think it has 12 | to do with the if condition I set up to determine whether the car should rotate to align with the front wheels. need to investigate 13 | further though. 14 | 15 | - fix lateral rotation. it kind of works but I still don't know what situations trigger the car to flip over, which happens sometimes. 16 | additionally, when you try to move the car along the big sloped turn, the lateral rotation usually looks pretty ok but then it looks 17 | as if the car got rotated about the Z axis where it's tipped forward at an angle. I think this has to do with the track having 18 | a bunch of segments such that the turns are very 'angular' and not smooth. so what might be level on one face is not on the next. 19 | 20 | objective: get car to be parallel with whatever plane it's on. sounds simple but it's so hard ;_; 21 | unity might help: https://answers.unity.com/questions/168097/orient-vehicle-to-ground-normal.html 22 | https://www.google.com/search?biw=2133&bih=1076&ei=jIyfX9PlBJ-oytMP_u6SwA4&q=unity+get+car+to+be+parallel+with+curved+plane&oq=unity+get+car+to+be+parallel+with+curved+plane&gs_lcp=CgZwc3ktYWIQAzIFCCEQoAEyBQghEKABOgQIABBHOgUIIRCrAjoICCEQFhAdEB46BwghEAoQoAFQijVYy1RgxlVoA3ACeACAAWGIAZELkgECMjCYAQCgAQGqAQdnd3Mtd2l6yAEIwAEB&sclient=psy-ab&ved=0ahUKEwjT29GyhOPsAhUflHIEHX63BOgQ4dUDCA0&uact=5 23 | 24 | this too? https://github.com/mrdoob/three.js/issues/1486 25 | 26 | new strategy: try raycast down once, get the normal of the face the raycast hits. do something with that info? 27 | you can definitely adjust the car's y position with that info so I don't need a separate function to adjust height. 28 | 29 | maybe: https://stackoverflow.com/questions/46336560/three-js-how-to-add-an-object-perpendicular-to-a-face-normal 30 | https://stackoverflow.com/questions/16268482/three-js-convert-face-normal-from-local-space-to-world-space 31 | https://stackoverflow.com/questions/23139442/how-to-get-correct-values-for-normals-in-threejs 32 | 33 | hmm this looks similar: https://stackoverflow.com/questions/23592427/rotate-an-object-according-to-a-plane-normal 34 | and this: https://answers.unity.com/questions/27340/rotating-an-object-to-equal-normals-of-object-belo.html 35 | 36 | ok, so now I can get a normal vector for each face of the racetrack that my raycast hits. great! and each normal vector looks like 37 | it's angled properly along the sloped parts of the track. now what I would like to happen is have the car rotate itself about 38 | the x-axis so that it's angled just like the normal for the face below it (i.e. the local y-axis of the car should be parallel 39 | to the normal) 40 | this is helpful! https://stackoverflow.com/questions/9038465/three-js-object3d-cylinder-rotation-to-align-to-a-vector 41 | 42 | cool, using thePlayer.quaternion.setFromUnitVectors seems to get the car to align with the normal vector of the surface it's on. 43 | but now a new problem - this rotation alignment causes issues with movement; it's forcing the car to face a certain way based 44 | on the normal vector. 45 | 46 | ok I'm very dumb lol. I ended up where I was like a couple days ago. I'm pretty sure the initial idea with getting the lateral rotation 47 | is fine (I just changed what I had to use quaternions lol) and is working - the 'tilting' forward of the car is due to the angled 48 | segments of the track and the fact that I'm only checking the angle of the car and the surface it's on in the middle of the car mesh. 49 | I think I should try adding a marker above the front and rear wheels? but then more rotations if the front wheels should be higher 50 | than the rear wheels ughhhhhhhhhhhhhhhhhh ;_;. I just need to get the car more leveled about the z-axis (check z-axis rotations?). 51 | 52 | ----- 53 | so it turns out it's pretty easy. just add a couple more height markers (one for the front and one for the rear of the car), just like 54 | what you do for the lateral rotation. and solve the problem the same way, except you're dealing with vectors that go along the x-axis. 55 | yay! :) the result looks pretty good. 56 | 57 | all that's left is to try to figure out how to get my rotations with the car and the front wheels (which rotate separately) 58 | when turning lined up properly. 59 | 60 | other/maybe helpful: 61 | https://stackoverflow.com/questions/25199173/how-to-find-rotation-matrix-between-two-vectors-in-three-js 62 | https://stackoverflow.com/questions/52977759/three-js-how-to-find-out-xyz-rotations-between-two-vectors 63 | https://stackoverflow.com/questions/43606135/split-quaternion-into-axis-rotations 64 | 65 | for turning the car: 66 | https://asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html -------------------------------------------------------------------------------- /car_demo/pictures/angle-correction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/angle-correction.png -------------------------------------------------------------------------------- /car_demo/pictures/angle-correction2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/angle-correction2.png -------------------------------------------------------------------------------- /car_demo/pictures/car_demo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/car_demo.webp -------------------------------------------------------------------------------- /car_demo/pictures/debugging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/debugging.gif -------------------------------------------------------------------------------- /car_demo/pictures/ideas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/ideas.png -------------------------------------------------------------------------------- /car_demo/pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/screenshot.png -------------------------------------------------------------------------------- /car_demo/pictures/tilting_bad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/car_demo/pictures/tilting_bad.png -------------------------------------------------------------------------------- /car_demo/readme.md: -------------------------------------------------------------------------------- 1 | # car demo 2 | 3 | For this project I originally just wanted to make a car and display it but then I decided to go further and explore car movement on an angled track. 4 | 5 | ## notes: 6 | 7 | 1. getting the car tilted the right way on an angled road 8 | One challenge was getting the car to tilt correctly when it was on a sloped part of the road. I had to adjust the lateral angle of the car (left-to-right) as well as the forward/backward (longitudinal?) tilt angle. 9 | Below is a sketch of my idea to solve this (it shows the lateral angle but the same idea is applied to the forward/backward angle, just on a different axis). 10 | 11 | ![diagram for getting the car angled with the track](pictures/ideas.png) 12 | 13 | You can see below some of the lines I drew to help debug. The cyan and red lines are normal vectors of the car model and of the face of the track model that the car was on. I tried to solve the problem using normal vectors but that didn't work out for me, but I left them in because it looks cool :). 14 | 15 | ![screenshot for getting the car angled with the track](pictures/angle-correction.png) 16 | 17 | ![screenshot for getting the car angled with the track](pictures/angle-correction2.png) 18 | 19 | 2. turning the car based on the front wheels' angle 20 | Another fun problem is getting the car model to turn based on the angle of the front wheels. Initially I thought I could just rotate the car model a bit when the front wheels are angled, which sort of works. 21 | 22 | I also found this amazingly helpful page (https://asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html), which I think helped me calculate a better amount to rotate my car when the front wheels are turned. 23 | 24 | One issue that still stands is that when turning the wheels quickly while moving, the car movement is not realistic possibly because I'm rotating the whole car, which includes the front wheels, when the front wheels are already angled. -------------------------------------------------------------------------------- /character_demo/animation_state_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "states": { 3 | "normal": { 4 | "idle-arms": { 5 | "actionName": "idlearmsonly", 6 | "loop": "repeat", 7 | "top": true 8 | }, 9 | "idle-legs": { 10 | "actionName": "idlelegsonly", 11 | "loop": "repeat", 12 | "bottom": true 13 | }, 14 | "run-arms": { 15 | "actionName": "runarmsonly", 16 | "loop": "repeat", 17 | "top": true 18 | }, 19 | "run-legs": { 20 | "actionName": "runlegsonly", 21 | "loop": "repeat", 22 | "bottom": true 23 | }, 24 | "walk-arms": { 25 | "actionName": "walkarmsonly", 26 | "loop": "repeat", 27 | "top": true 28 | }, 29 | "walk-legs": { 30 | "actionName": "walklegsonly", 31 | "loop": "repeat", 32 | "bottom": true 33 | }, 34 | "jump": { 35 | "actionName": "jump", 36 | "loop": "once" 37 | }, 38 | "drawgun": { 39 | "actionName": "drawgunarmsonly", 40 | "loop": "once", 41 | "top": true 42 | }, 43 | "leftlean": { 44 | "actionName": "leanleftgunarmsonly", 45 | "loop": "repeat", 46 | "top": true 47 | }, 48 | "rightlean": { 49 | "actionName": "leanrightgunarmsonly", 50 | "loop": "repeat", 51 | "top": true 52 | } 53 | }, 54 | "equip": { 55 | "idle-arms": { 56 | "actionName": "holdgunarmsonly", 57 | "loop": "repeat", 58 | "top": true 59 | }, 60 | "idle-legs": { 61 | "actionName": "idlelegsonly", 62 | "loop": "repeat", 63 | "bottom": true 64 | }, 65 | "walk-arms": { 66 | "actionName": "holdgunarmsonly", 67 | "loop": "repeat", 68 | "top": true 69 | }, 70 | "walk-legs": { 71 | "actionName": "walklegsonly", 72 | "loop": "repeat", 73 | "bottom": true 74 | }, 75 | "run-legs": { 76 | "actionName": "runlegsonly", 77 | "loop": "repeat", 78 | "bottom": true 79 | }, 80 | "run-arms": { 81 | "actionName": "holdgunarmsonly", 82 | "loop": "repeat", 83 | "top": true 84 | }, 85 | "reload": { 86 | "actionName": "reloadgun", 87 | "loop": "once", 88 | "top": true 89 | }, 90 | "drawgun": { 91 | "actionName": "drawgunarmsonly", 92 | "loop": "once", 93 | "top": true 94 | }, 95 | "leftlean": { 96 | "actionName": "leanleftgunarmsonly", 97 | "loop": "repeat", 98 | "top": true 99 | }, 100 | "rightlean": { 101 | "actionName": "leanrightgunarmsonly", 102 | "loop": "repeat", 103 | "top": true 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /character_demo/blender/humanoid-rig-with-gun.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/character_demo/blender/humanoid-rig-with-gun.blend -------------------------------------------------------------------------------- /character_demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | character animation test 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 39 | 40 | 41 |
42 |
43 | 44 |
45 |

46 |
47 | 48 |
49 | 50 |
51 |

controls:

52 |

w, s to move forward/backward. a, d to turn left/right. hold shift to run. g to toggle weapon equip. 1 to toggle first-person view.

53 |

note: the green cube in the location of the character's head serves as a starting point for the raycaster to use when adjusting the vertical position on uneven terrain.

54 |
55 | 56 | 57 | 58 | 59 | 61 | -------------------------------------------------------------------------------- /character_demo/notes.txt: -------------------------------------------------------------------------------- 1 | testing character animations/movement with a low-poly humanoid 2 | 3 | having trouble with the imported mesh :'( 4 | https://stackoverflow.com/questions/42886821/blender-exported-json-model-shows-wrong-animations-in-three-js 5 | 6 | outdated but maybe still useful: https://unboring.net/workflows/animation.html 7 | 8 | this is so helpful :'): https://gltf-viewer.donmccurdy.com/ 9 | 10 | when using animations in threejs, make sure to attach the root bone to the skinned mesh, otherwise everything will be weird. 11 | i.e. if child.type === "SkinnedMesh" -> child.add(child.skeleton.bones[0]) 12 | 13 | handling uneven terrain movement (panda3d looks like a good resource to learn a bunch of other things as well): 14 | https://docs.panda3d.org/1.10/python/programming/pandai/pathfinding/uneven-terrain 15 | 16 | -------------------------------------------------------------------------------- /character_demo/pictures/character_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/character_demo/pictures/character_demo.gif -------------------------------------------------------------------------------- /character_demo/pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/character_demo/pictures/screenshot.png -------------------------------------------------------------------------------- /character_demo/readme.md: -------------------------------------------------------------------------------- 1 | # character demo 2 | 3 | For this project I wanted to explore character movement! 4 | 5 | ## notes: 6 | 7 | 1. terrain adjustment 8 | Based on the character's current elevation relative to "ground" level, the character's y-position will change so it's always on the terrain properly. To do this I assumed an initial height as a baseline value for being leveled with 9 | the ground. I placed a 'dummy' object (a small green cube) placed in the middle of the character at a height around where the head is. In each update call, a raycast is made downwards from the 'dummy' object to the ground mesh and the distance is compared with the initial baseline distance. 10 | If the current distance is lower than the initial distance, then the character is on higher elevation and its y-position needs to be increased and vice-versa if the current distance is greater. 11 | This link is extremely helpful: https://docs.panda3d.org/1.10/python/programming/pandai/pathfinding/uneven-terrain 12 | 13 | 2. weapon attachment 14 | Attaching a weapon is fairly straight-forward. I just attached the weapon mesh to one of the hand bones in my character mesh as a child. It was a bit difficult to position the weapon though in the hand since it seemed 15 | the coordinate system of the weapon was different. 16 | 17 | 3. added an animation controller 18 | Animating with several actions and managing them became a bit difficult quickly without having an additional object to help. 19 | 20 | 4. Player model animations are split into two parts: a top and bottom so that each animation controls a separate set of bones so that we can mix and match different animations that only concern a specifc set of bones. This is useful (or perhaps necessary?) for handling instances like running with a weapon equipped vs. running without a weapon equipped or running while leaning left/right. Initially I had full character model animations but that proved to be too limiting (also it might be a bit less work to do half-body animations instead of full-body ones). -------------------------------------------------------------------------------- /curves/README.md: -------------------------------------------------------------------------------- 1 | # curves 2 | 3 | playing with curves (just Catmull-Rom though atm) and using them as paths for object movement (e.g. for aircraft :D). 4 | 5 | ![demo gif](demo.gif) -------------------------------------------------------------------------------- /curves/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/curves/demo.gif -------------------------------------------------------------------------------- /curves/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | curves 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 |

playing with curves

28 | 29 |
30 |
31 | 32 | 33 | 34 | 41 | 42 | 43 | 44 | 45 |

press keys 1-5 to change camera view.

46 | 47 | 48 | 50 | -------------------------------------------------------------------------------- /curves/notes.txt: -------------------------------------------------------------------------------- 1 | https://discourse.threejs.org/t/struggling-with-paths/26486/5 2 | https://discourse.threejs.org/t/moving-objects-along-curve-very-slowly-with-instanced-curve-modifier-instancedflow/31233 3 | https://stackoverflow.com/questions/24997066/three-js-why-is-my-object-flipping-whilst-travelling-along-a-spline 4 | https://stackoverflow.com/questions/11179327/orient-objects-rotation-to-a-spline-point-tangent-in-three-js 5 | https://stackoverflow.com/questions/49604847/object-rotating-while-travelling-along-a-curve-path 6 | 7 | https://mathworld.wolfram.com/Helix.html 8 | https://stackoverflow.com/questions/28195990/how-do-i-calculate-the-coordinates-of-the-points-of-an-helix 9 | 10 | // TODO 11 | maneuvers to try to implement: 12 | - barrel roll 13 | - aileron roll 14 | - simple vertical loop 15 | - immelmann turn 16 | - cuban eight 17 | 18 | add smoke 19 | 20 | maneuvers with multiple aircraft? 21 | -------------------------------------------------------------------------------- /dimsum/README.md: -------------------------------------------------------------------------------- 1 | # dimsum 2 | 3 | 😋 4 | 5 | ![dimsum screenshot](screenshot.png) -------------------------------------------------------------------------------- /dimsum/dim-sum.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dimsum/dim-sum.blend -------------------------------------------------------------------------------- /dimsum/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dim sum 5 | 6 | 7 | 8 | 9 | 10 | 11 | 46 | 47 | 48 | 49 |

dim sum

50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 |
58 |

selected item

59 |
60 |

description of selected item goes here

61 | 62 |
63 | 64 |

click on a food to learn more about it!

65 | 66 | 67 | 69 | -------------------------------------------------------------------------------- /dimsum/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dimsum/screenshot.png -------------------------------------------------------------------------------- /dishwashing/08-03-2022_141113.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dishwashing/08-03-2022_141113.gif -------------------------------------------------------------------------------- /dishwashing/blender/hand-edit.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dishwashing/blender/hand-edit.blend -------------------------------------------------------------------------------- /dishwashing/blender/kitchenware.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dishwashing/blender/kitchenware.blend -------------------------------------------------------------------------------- /dishwashing/blender/sponge.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/dishwashing/blender/sponge.blend -------------------------------------------------------------------------------- /dishwashing/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dishwashing 5 | 6 | 7 | 8 | 9 | 10 | 11 | 29 | 30 | 31 |

dishwashing

32 | 33 |
34 |
35 | 36 |
37 |

38 |
39 | 40 |
41 |

controls:

42 |

click on the plate and sponge (or press 'G' and 'S') to hold them.

43 |

use your mouse to clean the plate with the sponge :)

44 |
45 | 46 | 47 | 49 | -------------------------------------------------------------------------------- /dishwashing/notes.txt: -------------------------------------------------------------------------------- 1 | https://stackoverflow.com/questions/28630097/flip-mirror-any-object-with-three-js 2 | https://discourse.threejs.org/t/cloning-a-skinned-mesh/4775/18 3 | https://stackoverflow.com/questions/57381278/threejs-2d-pixels-to-3d-coordinates-conversion 4 | https://stackoverflow.com/questions/47799977/three-js-raycasting-performance 5 | https://stackoverflow.com/questions/42232001/three-js-performance-very-slow-using-onmousemove-with-raycaster 6 | 7 | TODO: 8 | - more plates/kitchenware 9 | - take into account sponge distance/movement 10 | 11 | https://r105.threejsfundamentals.org/threejs/lessons/threejs-offscreencanvas.html -------------------------------------------------------------------------------- /dishwashing/readme.md: -------------------------------------------------------------------------------- 1 | ## dishwashing 2 | just a little idea I had. probably would be more fun in VR :) 3 | 4 | ![dishwashing demo](08-03-2022_141113.gif) 5 | 6 | some concepts I reviewed here are using raycasting to select and move items (which involves converting mouse 2d coords to 3d coords), animation (e.g. using AnimationMixer), dealing with SkinnedMeshes and bones. 7 | 8 | unfortunately I spent way too much time trying to figure out how to work with a bad model I exported from Blender (even though it looked fine in Don McCurdy's gltf viewer, animations and all) and ended up remaking my hand model. 9 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // eslint.config.mjs 2 | // https://github.com/eslint/eslint/issues/17400 3 | 4 | //import js from '@eslint/js'; 5 | import html from '@html-eslint/eslint-plugin'; 6 | import parser from '@html-eslint/parser'; 7 | 8 | export default [ 9 | { 10 | rules: { 11 | 'semi': 'error', 12 | 'prefer-const': 'error', 13 | 'no-var': 'error', 14 | 'indent': ['error', 2], 15 | 'quotes': ['error', 'single'], 16 | 'no-unused-vars': 'warn', 17 | 'space-in-parens': ['error', 'never'], 18 | }, 19 | }, 20 | { 21 | ignores: [ 22 | '**/node_modules/**', 23 | 'libs/**/*', 24 | 'basketball/CannonDebugRenderer.js', 25 | ], 26 | }, 27 | { 28 | files: ['**/*.html'], 29 | plugins: { 30 | '@html-eslint': html, 31 | }, 32 | languageOptions: { 33 | parser, 34 | }, 35 | rules: { 36 | '@html-eslint/indent': ['error', 2], 37 | '@html-eslint/require-doctype': 'error', 38 | //'@html-eslint/require-closing-tags': 'error', 39 | }, 40 | }, 41 | ]; -------------------------------------------------------------------------------- /experiments/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | experiments 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |

36 |
37 | 38 |
39 |

controls:

40 |
41 | 42 | 43 | 45 | 46 | -------------------------------------------------------------------------------- /experiments/index.js: -------------------------------------------------------------------------------- 1 | 2 | const el = document.getElementById('container'); 3 | const fov = 60; 4 | const defaultCamera = new THREE.PerspectiveCamera(fov, el.clientWidth / el.clientHeight, 0.01, 1000); 5 | const keyboard = new THREEx.KeyboardState(); 6 | const container = document.querySelector('#container'); 7 | const raycaster = new THREE.Raycaster(); 8 | const loadingManager = new THREE.LoadingManager(); 9 | let animationController; 10 | 11 | const loader = new THREE.GLTFLoader(loadingManager); 12 | 13 | const renderer = new THREE.WebGLRenderer(); 14 | renderer.shadowMap.enabled = true; 15 | renderer.shadowMap.type = THREE.PCFSoftShadowMap; 16 | renderer.setSize(el.clientWidth, el.clientHeight); 17 | container.appendChild(renderer.domElement); 18 | 19 | const camera = defaultCamera; 20 | camera.position.set(0,5,15); 21 | 22 | const scene = new THREE.Scene(); 23 | scene.background = new THREE.Color(0xffffff); 24 | scene.add(camera); 25 | 26 | const pointLight = new THREE.PointLight(0xffffff, 1, 0); 27 | pointLight.position.set(0, 30, 0); 28 | pointLight.castShadow = true; 29 | pointLight.shadow.mapSize.width = 1024; 30 | pointLight.shadow.mapSize.height = 1024; 31 | pointLight.shadow.camera.near = 2; 32 | pointLight.shadow.camera.far = 100; 33 | pointLight.shadow.camera.fov = 70; 34 | scene.add(pointLight); 35 | 36 | /* 37 | const hemiLight = new THREE.HemisphereLight(0xffffff); 38 | hemiLight.position.set(0, 50, 0); 39 | scene.add(hemiLight); 40 | */ 41 | 42 | const clock = new THREE.Clock(); 43 | let sec = clock.getDelta(); 44 | let moveDistance = 60 * sec; 45 | let rotationAngle = (Math.PI / 2) * sec; 46 | 47 | // create some 'terrain' 48 | const texture = new THREE.TextureLoader().load('texture.png'); 49 | const terrainMat = new THREE.MeshPhongMaterial({color: 0xcccddd, specular: 0x009900, shininess: 3, shading: THREE.FlatShading});//new THREE.MeshBasicMaterial({map: texture}); 50 | const terrain = new THREE.PlaneGeometry(200, 200, 1); 51 | const plane = new THREE.Mesh(terrain, terrainMat); 52 | plane.position.set(0, -1, 0); 53 | plane.rotateX((3*Math.PI)/2); 54 | plane.receiveShadow = true; 55 | scene.add(plane); 56 | 57 | // create the player cube 58 | const cubeGeometry = new THREE.BoxGeometry(5,5,5); 59 | const material = new THREE.MeshBasicMaterial({color: 0x0000ff}); 60 | material.wireframe = true; 61 | const thePlayer = new THREE.Mesh(cubeGeometry, material); 62 | thePlayer.castShadow = true; 63 | 64 | const cube2g = new THREE.BoxGeometry(2,2,2); 65 | const mat = new THREE.MeshBasicMaterial({color: 0xff0000}); 66 | const cube = new THREE.Mesh(cube2g, mat); 67 | cube.castShadow = true; 68 | 69 | thePlayer.add(cube); 70 | cube.position.set(0, 3, 0); 71 | 72 | thePlayer.position.set(0, 2, 0); 73 | scene.add(thePlayer); 74 | 75 | let bgAxesHelper; 76 | 77 | const playerAxesHelper = new THREE.AxesHelper(5); 78 | const playerGroupAxesHelper = new THREE.AxesHelper(5); 79 | const playerCameraAxesHelper = new THREE.AxesHelper(5); 80 | 81 | thePlayer.add(playerAxesHelper); 82 | cube.add(playerGroupAxesHelper); 83 | 84 | let firstPersonViewOn = false; 85 | 86 | 87 | function keydown(evt){ 88 | if(evt.keyCode === 49){ 89 | // toggle first-person view 90 | firstPersonViewOn = !firstPersonViewOn; 91 | // make sure camera is in the head position 92 | // and that the camera is parented to the character mesh 93 | // so that it can rotate with the mesh 94 | if(firstPersonViewOn){ 95 | thePlayer.add(camera); 96 | 97 | //thePlayer.add(cube); 98 | //cube.position.set(0, 2, 0); 99 | 100 | //camera.position.copy(thePlayer.head.position); 101 | //camera.rotation.copy(thePlayer.rotation); 102 | camera.rotation.set(0, Math.PI, 0); 103 | camera.position.set(0, 2, 0); 104 | }else{ 105 | scene.add(camera); 106 | //scene.add(cube); 107 | } 108 | } 109 | } 110 | 111 | document.addEventListener('keydown', keydown); 112 | 113 | 114 | function update(){ 115 | sec = clock.getDelta(); 116 | moveDistance = 8 * sec; 117 | rotationAngle = (Math.PI / 2) * sec; 118 | let changeCameraView = false; 119 | 120 | if(keyboard.pressed('z')){ 121 | changeCameraView = true; 122 | } 123 | 124 | if(keyboard.pressed('W')){ 125 | // moving forwards 126 | thePlayer.translateZ(moveDistance); 127 | 128 | }else if(keyboard.pressed('S')){ 129 | // moving backwards 130 | thePlayer.translateZ(-moveDistance); 131 | } 132 | 133 | if(keyboard.pressed('J')){ 134 | // for jumping 135 | } 136 | 137 | if(keyboard.pressed('A')){ 138 | const axis = new THREE.Vector3(0, 1, 0); 139 | thePlayer.rotateOnAxis(axis, rotationAngle); 140 | } 141 | 142 | if(keyboard.pressed('D')){ 143 | const axis = new THREE.Vector3(0, 1, 0); 144 | thePlayer.rotateOnAxis(axis, -rotationAngle); 145 | } 146 | 147 | let relCameraOffset; 148 | 149 | if(firstPersonViewOn){ 150 | const newPos = new THREE.Vector3(); 151 | newPos.copy(thePlayer.position); 152 | newPos.z += 1; 153 | newPos.y -= 0.5; 154 | relCameraOffset = newPos; 155 | //camera.rotation.copy(thePlayer.rotation); 156 | }else if(!changeCameraView){ 157 | relCameraOffset = new THREE.Vector3(0, 3, -15); 158 | }else{ 159 | relCameraOffset = new THREE.Vector3(0, 3, 15); 160 | } 161 | 162 | if(!firstPersonViewOn){ 163 | const cameraOffset = relCameraOffset.applyMatrix4(thePlayer.matrixWorld); 164 | camera.position.x = cameraOffset.x; 165 | camera.position.y = cameraOffset.y; 166 | camera.position.z = cameraOffset.z; 167 | } 168 | 169 | if(!firstPersonViewOn) camera.lookAt(thePlayer.position); 170 | 171 | } 172 | 173 | function animate(){ 174 | requestAnimationFrame(animate); 175 | renderer.render(scene, camera); 176 | update(); 177 | } 178 | 179 | animate(); 180 | -------------------------------------------------------------------------------- /experiments/notes.txt: -------------------------------------------------------------------------------- 1 | https://stackoverflow.com/questions/36683707/how-do-shadows-work-in-three-js-r75 2 | https://r105.threejsfundamentals.org/threejs/lessons/threejs-shadows.html -------------------------------------------------------------------------------- /experiments/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/experiments/texture.png -------------------------------------------------------------------------------- /fps/16-11-2024_124629.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/fps/16-11-2024_124629.gif -------------------------------------------------------------------------------- /fps/animation_state_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "states": { 3 | "normal": { 4 | "idle-arms": { 5 | "actionName": "idlearmsonly", 6 | "loop": "repeat", 7 | "top": true 8 | }, 9 | "idle-legs": { 10 | "actionName": "idlelegsonly", 11 | "loop": "repeat", 12 | "bottom": true 13 | }, 14 | "run-arms": { 15 | "actionName": "runarmsonly", 16 | "loop": "repeat", 17 | "top": true 18 | }, 19 | "run-legs": { 20 | "actionName": "runlegsonly", 21 | "loop": "repeat", 22 | "bottom": true 23 | }, 24 | "walk-arms": { 25 | "actionName": "walkarmsonly", 26 | "loop": "repeat", 27 | "top": true 28 | }, 29 | "walk-legs": { 30 | "actionName": "walklegsonly", 31 | "loop": "repeat", 32 | "bottom": true 33 | }, 34 | "jump": { 35 | "actionName": "jump", 36 | "loop": "once" 37 | }, 38 | "drawgun": { 39 | "actionName": "drawgunarmsonly", 40 | "loop": "once", 41 | "top": true 42 | }, 43 | "leftlean": { 44 | "actionName": "leanleftgunarmsonly", 45 | "loop": "repeat", 46 | "top": true 47 | }, 48 | "rightlean": { 49 | "actionName": "leanrightgunarmsonly", 50 | "loop": "repeat", 51 | "top": true 52 | } 53 | }, 54 | "equip": { 55 | "idle-arms": { 56 | "actionName": "holdgunarmsonly", 57 | "loop": "repeat", 58 | "top": true 59 | }, 60 | "idle-legs": { 61 | "actionName": "idlelegsonly", 62 | "loop": "repeat", 63 | "bottom": true 64 | }, 65 | "walk-arms": { 66 | "actionName": "holdgunarmsonly", 67 | "loop": "repeat", 68 | "top": true 69 | }, 70 | "walk-legs": { 71 | "actionName": "walklegsonly", 72 | "loop": "repeat", 73 | "bottom": true 74 | }, 75 | "run-legs": { 76 | "actionName": "runlegsonly", 77 | "loop": "repeat", 78 | "bottom": true 79 | }, 80 | "run-arms": { 81 | "actionName": "holdgunarmsonly", 82 | "loop": "repeat", 83 | "top": true 84 | }, 85 | "reload": { 86 | "actionName": "reloadgun", 87 | "loop": "once", 88 | "top": true 89 | }, 90 | "drawgun": { 91 | "actionName": "drawgunarmsonly", 92 | "loop": "once", 93 | "top": true 94 | }, 95 | "leftlean": { 96 | "actionName": "leanleftgunarmsonly", 97 | "loop": "repeat", 98 | "top": true 99 | }, 100 | "rightlean": { 101 | "actionName": "leanrightgunarmsonly", 102 | "loop": "repeat", 103 | "top": true 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /fps/crosshairs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/fps/crosshairs.png -------------------------------------------------------------------------------- /fps/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | fps test 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 43 |
44 |
45 | 46 |
47 | 48 |
49 |

controls:

50 |

w, s to move forward/backward. a, d to turn left/right. hold shift to run. g to toggle weapon equip. 1 to toggle first-person view. when weapon is equipped, click on the canvas to fire a projectile.

51 |

3 to toggle player mesh visibility. 4 to switch weapon (this is a bit buggy right now).

52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 | 63 | 64 | 65 | 67 | -------------------------------------------------------------------------------- /fps/readme.md: -------------------------------------------------------------------------------- 1 | # fps 2 | ### a small demo to explore some fps game mechanics 3 | 4 | ![fps gif](16-11-2024_124629.gif) 5 | 6 | This demo is a bit of an extension/combo of `character_demo` and `basketball`. It uses cannon.js to help with projectile collisions (although for the player character I instead chose to handle collisions manually since I couldn't figure out how to get a rigidbody properly set up for it). It doesn't really do much atm but you can launch cows :). 7 | 8 | TODO: 9 | - improve player model (specifically figure out how to set up model for first-person vs third-person mode) 10 | - be able to import any gltf model to use as projectile? 11 | - get lighting/shadows better -------------------------------------------------------------------------------- /lava_lamp/README.md: -------------------------------------------------------------------------------- 1 | # lava_lamp 2 | 3 | a 3D lava lamp implementation using metaballs (adapted from https://webglsamples.org/blob/blob.html) for the lava and a lamp I made in Blender. 4 | 5 | ![lava lamp screenshot](screenshot.png) -------------------------------------------------------------------------------- /lava_lamp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D lava lamp 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 |

lava lamp

39 | 40 |
41 |
42 | 43 |

with metaballs!

44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 |
53 | 54 | 55 | 57 | -------------------------------------------------------------------------------- /lava_lamp/index.js: -------------------------------------------------------------------------------- 1 | // lava lamp 2 | // borrowed some code from https://threejs.org/examples/webgl_marchingcubes.html 3 | import { MarchingCubes } from '../libs/MarchingCubes.js'; 4 | 5 | const container = document.getElementById('container'); 6 | 7 | const fov = 60; 8 | const camera = new THREE.PerspectiveCamera(fov, container.clientWidth / container.clientHeight, 0.01, 1000); 9 | camera.position.set(0, 5, 8); 10 | 11 | const loadingManager = new THREE.LoadingManager(); 12 | setupLoadingManager(loadingManager); 13 | 14 | const loader = new THREE.GLTFLoader(loadingManager); 15 | 16 | const renderer = new THREE.WebGLRenderer({antialias: true}); 17 | renderer.shadowMap.enabled = true; 18 | renderer.shadowMap.type = THREE.PCFSoftShadowMap; 19 | renderer.toneMapping = THREE.LinearToneMapping; 20 | renderer.toneMappingExposure = 0.7; 21 | renderer.setSize(container.clientWidth, container.clientHeight); 22 | container.appendChild(renderer.domElement); 23 | 24 | const scene = new THREE.Scene(); 25 | scene.background = new THREE.Color(0xbbbbaa); 26 | scene.add(camera); 27 | 28 | const controls = new THREE.TrackballControls(camera, renderer.domElement); 29 | controls.rotateSpeed = 1.2; 30 | controls.zoomSpeed = 1.2; 31 | controls.panSpeed = 0.8; 32 | 33 | const spotLight = new THREE.SpotLight(0xffffff); 34 | spotLight.position.set(0, 50, -10); 35 | spotLight.castShadow = true; 36 | spotLight.shadow.mapSize.width = 1024; 37 | spotLight.shadow.mapSize.height = 1024; 38 | scene.add(spotLight); 39 | 40 | const spotLight2 = new THREE.SpotLight(0xffffff, 0.6); 41 | spotLight2.position.set(15, -1, 20); 42 | spotLight2.castShadow = true; 43 | spotLight2.shadow.mapSize.width = 1024; 44 | spotLight2.shadow.mapSize.height = 1024; 45 | scene.add(spotLight2); 46 | 47 | const clock = new THREE.Clock(); 48 | let time = 0; 49 | 50 | // marching cubes stuff 51 | const resolution = 28; // how smooth do you want the blobs 52 | let effect = null; 53 | let wall = null; 54 | let stand = null; 55 | let lampModel = null; 56 | const lavaColor = 0x39ff14; 57 | 58 | const material = new THREE.MeshPhongMaterial({color: lavaColor}); 59 | //material.wireframe = true; 60 | 61 | function getModel(modelFilePath){ 62 | return new Promise((resolve) => { 63 | loader.load( 64 | modelFilePath, 65 | function(gltf){ 66 | resolve(gltf.scene); 67 | }, 68 | // called while loading is progressing 69 | function(xhr){ 70 | console.log((xhr.loaded / xhr.total * 100) + '% loaded'); 71 | }, 72 | // called when loading has errors 73 | function(error){ 74 | console.log('An error happened'); 75 | console.log(error); 76 | } 77 | ); 78 | }); 79 | } 80 | getModel('../models/lava-lamp.gltf', 'lavalamp').then(obj => { 81 | lampModel = obj; 82 | 83 | lampModel.children[1].castShadow = true; 84 | const lampStructure = lampModel.children[0]; 85 | lampStructure.castShadow = true; 86 | //lampStructure.material.wireframe = true; 87 | lampStructure.material.metalness = 0.3; 88 | 89 | scene.add(lampModel); 90 | lampModel.position.set(0, -4, 0); 91 | lampModel.scale.set(1.5, 1.5, 1.5); 92 | 93 | // add the lamp lightbulb 94 | const lightbulb = new THREE.PointLight(0xffffff, 1.6); 95 | lampModel.add(lightbulb); 96 | lightbulb.translateY(3); 97 | lightbulb.distance = 7.0; 98 | 99 | // add the lava 100 | effect = new MarchingCubes(resolution, material, true, true, 100000); 101 | lampModel.add(effect); 102 | effect.translateY(2.9); 103 | effect.scale.set(0.54, 1.2, 0.54); 104 | effect.enableUvs = false; 105 | effect.enableColors = false; 106 | 107 | // add circular plane for the base of the blobs 108 | const planeGeometry = new THREE.CircleGeometry(0.7, 32); 109 | const planeMaterial = new THREE.MeshPhongMaterial({color: lavaColor}); 110 | const plane = new THREE.Mesh(planeGeometry, planeMaterial); 111 | plane.name = 'blobBase'; 112 | lampModel.add(plane); 113 | plane.translateY(1.95); 114 | plane.rotateX(-Math.PI / 2); 115 | 116 | lampModel.rotateX(-Math.PI / 8); 117 | 118 | // add a table 119 | const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); 120 | const cubeMaterial = new THREE.MeshPhongMaterial({color: 0xcccccc}); 121 | const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); 122 | cube.rotation.set(lampModel.rotation.x, lampModel.rotation.y, lampModel.rotation.z); 123 | cube.position.set(lampModel.position.x, lampModel.position.y - 1.74, lampModel.position.z + 0.8); 124 | cube.scale.set(4, 4, 4); 125 | cube.receiveShadow = true; 126 | stand = cube; 127 | scene.add(cube); 128 | 129 | // add a wall 130 | const wallGeometry = new THREE.BoxGeometry(4, 4, 0.05); 131 | const wallMaterial = new THREE.MeshPhongMaterial({color: 0xdddddd}); 132 | wall = new THREE.Mesh(wallGeometry, wallMaterial); 133 | wall.rotation.set(lampModel.rotation.x, lampModel.rotation.y, lampModel.rotation.z); 134 | wall.rotateY(Math.PI / 6); 135 | wall.position.set(lampModel.position.x - 12, lampModel.position.y + 3, lampModel.position.z - 16); 136 | wall.scale.set(4, 6, 4); 137 | wall.receiveShadow = true; 138 | scene.add(wall); 139 | 140 | //console.log(lampModel); 141 | }); 142 | 143 | // this controls content of marching cubes voxel field 144 | function updateCubes(object, time, numblobs, floor){ 145 | object.reset(); 146 | 147 | const subtract = 12; 148 | const strength = 1.8 / ((Math.sqrt(numblobs) - 1) / 4 + 1); 149 | 150 | for(let i = 0; i < numblobs; i ++){ 151 | const ballx = Math.sin(i + 1.26 * time * (1.03 + 0.5 * Math.cos(0.21 * i))) * 0.27 + 0.5; 152 | const bally = Math.abs(Math.cos(i + 1.12 * time * Math.cos(1.22 + 0.1424 * i))) * 0.77; // dip into the floor 153 | const ballz = Math.cos(i + 1.32 * time * 0.1 * Math.sin((0.92 + 0.53 * i))) * 0.27 + 0.5; 154 | object.addBall(ballx, bally, ballz, strength, subtract); 155 | } 156 | 157 | if(floor) object.addPlaneY(1, 6); 158 | 159 | object.update(); 160 | } 161 | 162 | function update(){ 163 | const delta = clock.getDelta(); 164 | 165 | time += delta * 1.0 * 0.5; 166 | 167 | // marching cubes 168 | if(effect) updateCubes(effect, time, 7, true); 169 | 170 | if(lampModel) lampModel.rotateY(delta / 5); 171 | 172 | // update trackball 173 | controls.update(); 174 | } 175 | 176 | document.getElementById('toggleWall').addEventListener('change', () => { 177 | wall.visible = !wall.visible; 178 | }); 179 | 180 | document.getElementById('toggleStand').addEventListener('change', () => { 181 | stand.visible = !stand.visible; 182 | }); 183 | 184 | document.getElementById('colorPickerInput').addEventListener('change', evt => { 185 | material.color = new THREE.Color(evt.target.value); 186 | lampModel.children.filter(child => child.name === 'blobBase')[0].material.color = new THREE.Color(evt.target.value); 187 | }); 188 | 189 | document.getElementById('toggleWireframe').addEventListener('change', () => { 190 | material.wireframe = !material.wireframe; 191 | }); 192 | 193 | function animate(){ 194 | requestAnimationFrame(animate); 195 | renderer.render(scene, camera); 196 | update(); 197 | } 198 | 199 | animate(); -------------------------------------------------------------------------------- /lava_lamp/lava-lamp.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/lava_lamp/lava-lamp.blend -------------------------------------------------------------------------------- /lava_lamp/lavalampidea.txt: -------------------------------------------------------------------------------- 1 | metaball notes 1/8/24 2 | 3 | idea: lava lamp implementation in 3d? 4 | 5 | vocab: 6 | - marching cubes 7 | - metaballs 8 | 9 | https://www.reddit.com/r/unrealengine/comments/7wxqth/lava_lamp_ideas_anyone/ 10 | https://polycoding.net/marching-cubes/part-1/ 11 | https://webglsamples.org/blob/blob.html 12 | https://threejs.org/examples/webgl_marchingcubes.html 13 | https://www.geisswerks.com/ryan/BLOBS/blobs.html 14 | https://www.cs.carleton.edu/cs_comps/0405/shape/marching_cubes.html#:~:text=The%20Marching%20cubes%20algorithm%20can,an%20arbitrary%20number%20of%20cubes. 15 | 16 | 17 | more ideas: 18 | - interpolate colors over time? 19 | - different blob shapes? 20 | - blob shaders? -------------------------------------------------------------------------------- /lava_lamp/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/lava_lamp/screenshot.png -------------------------------------------------------------------------------- /libs/AnimationController.js: -------------------------------------------------------------------------------- 1 | // this is a good idea: https://gist.github.com/rtpHarry/2d41811d04825935039dfc075116d0ad 2 | // should have functions just for playing clips forwards and backwards 3 | 4 | class AnimationController { 5 | 6 | mixer; // animation mixer 7 | clips; // all the clips for animation 8 | currState; // the state of character i.e. weapon equip or not 9 | character; // a reference to the mesh that this controller belongs to 10 | timeDivisor; // number to divide the time by when updating (i.e. a smaller num == faster animation) 11 | animationMap; // for knowing which actions correspond to which states 12 | topAnimation; 13 | bottomAnimation; 14 | 15 | constructor(character, animMixer, animClips, clock){ 16 | this.character = character; 17 | this.mixer = animMixer; 18 | this.clips = animClips; 19 | this.clock = clock; 20 | this.currState = ""; 21 | this.currActionTimescale = 1; 22 | this.animationMap = null; 23 | 24 | // separate character model animations based on area they affect 25 | this.topAnimation = null; 26 | this.bottomAnimation = null; 27 | 28 | this.objects = []; // objects that should have visibility turned on/off at some point 29 | 30 | fetch('animation_state_map.json') 31 | .then(response => response.json()) 32 | .then(data => { 33 | this.animationMap = data.states; 34 | 35 | // modify some clips as needed according to the animation map 36 | for(const state in data.states){ 37 | for(const action in data.states[state]){ 38 | const actionParams = data.states[state][action]; 39 | const actionClip = this.mixer.clipAction(this.clips[actionParams.actionName]); 40 | if(actionParams.loop === 'once'){ 41 | actionClip.paused = false; 42 | actionClip.setLoop(THREE.LoopOnce); 43 | } 44 | } 45 | } 46 | }); 47 | 48 | // since we can equip a weapon, 49 | // makes sure the draw-weapon animation gets played first and then 50 | // the corresponding idle animation is played directly after it 51 | // what if you want to equip while walking or running though? :/ 52 | // TODO: how bout running a promise that'll switch back to the idle animation 53 | // after equip if finished? 54 | this.mixer.addEventListener('finished', (evt) => { 55 | if(evt.action._clip.name.indexOf('DrawGunArmsOnly') > -1){ 56 | if(this.currActionTimescale === -1){ 57 | // de-equip == this animation played backwards 58 | // hide the weapon when de-equipping 59 | this.toggleObjectVisibility(); 60 | } 61 | // draw gun then go to idle with gun 62 | // we just want to play the gun draw animation once 63 | this.timeDivisor = .60; 64 | this.changeAction('idle-arms', 'top', 1); 65 | } 66 | }); 67 | } 68 | 69 | toggleObjectVisibility(){ 70 | for(const obj of this.objects){ 71 | obj.visible = !obj.visible; 72 | } 73 | } 74 | 75 | addObject(obj){ 76 | if(!this.objects.includes(obj)){ 77 | this.objects.push(obj); 78 | } 79 | } 80 | 81 | setUpdateTimeDivisor(num){ 82 | this.timeDivisor = num; 83 | } 84 | 85 | changeState(newState){ 86 | this.currState = newState; 87 | } 88 | 89 | needToChangeAction(actionName, location){ 90 | if(location === "top" && this.topAnimation){ 91 | return actionName !== this.topAnimation.name; 92 | }else if(location === "bottom" && this.bottomAnimation){ 93 | return actionName !== this.bottomAnimation.name; 94 | }else if(location === "top" && !this.topAnimation){ 95 | return true; 96 | }else if(location === "bottom" && !this.bottomAnimation){ 97 | return true; 98 | } 99 | return false; 100 | } 101 | 102 | changeAction(newAction, location, timeScale=1){ 103 | // if a diff state or timescale is different 104 | if(this.needToChangeAction(newAction, location) || timeScale !== this.currActionTimescale){ 105 | this.playAnimation(newAction, this.clock.getDelta(), timeScale); 106 | } 107 | } 108 | 109 | // for now, keep it specific until I figure out what I'm doing 110 | // https://stackoverflow.com/questions/57255000/how-to-animate-2-objects-with-2-different-animations-one-after-another-in-3-js 111 | // possibly irrelevant but a good read nonetheless: 112 | // https://stackoverflow.com/questions/25417547/observer-pattern-vs-mediator-pattern 113 | // 114 | // note that actionToPlay should be a generic action name like walk or run. 115 | // the real animation clip name is derived below using this.animationMap and 116 | // the current character state (i.e. normal (no weapon), weapon-equipped, etc.) 117 | playAnimation(actionToPlay, time, timeScale){ 118 | if(this.animationMap){ 119 | if(this.animationMap[this.currState][actionToPlay] === undefined){ 120 | return; 121 | } 122 | 123 | this.currActionTimescale = timeScale; 124 | 125 | const action = this.mixer.clipAction(this.clips[this.animationMap[this.currState][actionToPlay].actionName]); 126 | 127 | if(action.time === 0 && timeScale === -1) { 128 | action.time = action.getClip().duration; 129 | } 130 | 131 | const actionParams = this.animationMap[this.currState][actionToPlay]; 132 | 133 | if(actionParams.top){ 134 | if(this.topAnimation) this.topAnimation.action.stop(); 135 | this.topAnimation = {action, name: actionToPlay}; 136 | }else if(actionParams.bottom){ 137 | if(this.bottomAnimation) this.bottomAnimation.action.stop(); 138 | this.bottomAnimation = {action, name: actionToPlay}; 139 | } 140 | 141 | action.timeScale = timeScale; 142 | action.play(); 143 | } 144 | } 145 | 146 | update(){ 147 | this.mixer.update(this.clock.getDelta() / this.timeDivisor); 148 | } 149 | 150 | } 151 | 152 | export { 153 | AnimationController 154 | }; -------------------------------------------------------------------------------- /libs/JSKeyboard.js: -------------------------------------------------------------------------------- 1 | // javascript keyboard 2 | // for mobile use 3 | 4 | class JSKeyboard { 5 | constructor(container){ 6 | // if keyboard already exists, do nothing 7 | if(document.getElementById('keyboard')) return; 8 | 9 | this.createKeyboard(container); 10 | } 11 | 12 | createKeyboard(containerElement){ 13 | const keyboard = document.createElement('div'); 14 | keyboard.id = 'keyboard'; 15 | keyboard.style.display = 'flex'; 16 | keyboard.style.flexDirection = 'row'; 17 | keyboard.style.flexWrap = 'wrap'; 18 | keyboard.style.backgroundColor = '#fff'; 19 | keyboard.style.justifyContent = 'center'; 20 | 21 | const keys = { 22 | 'W': 87, 23 | 'S': 83, 24 | 'A': 65, 25 | 'D': 68, 26 | 'Q': 81, 27 | 'E': 69, 28 | 'G': 71, 29 | 'J': 74, 30 | 'X': 88, 31 | '↑': 38, 32 | '↓': 40, 33 | '1': 49, 34 | '2': 50, 35 | 'CapsLock': 20, 36 | 'Space': 32, 37 | }; 38 | 39 | Object.keys(keys).forEach(key => { 40 | const newKey = document.createElement('button'); 41 | newKey.className = 'keyboard-key'; 42 | newKey.style.border = '1px solid #000'; 43 | newKey.style.borderRadius = '10px'; 44 | newKey.style.padding = '10px'; 45 | newKey.style.backgroundColor = '#ccc'; 46 | newKey.style.margin = '3px'; 47 | newKey.style.userSelect = 'none'; 48 | newKey.textContent = key; 49 | 50 | newKey.oncontextmenu = (evt) => { 51 | evt.preventDefault(); 52 | evt.stopPropagation(); 53 | return false; 54 | } 55 | 56 | newKey.addEventListener('pointerdown', (evt) => { 57 | newKey.style.backgroundColor = '#fff'; 58 | evt.preventDefault(); 59 | document.dispatchEvent(new KeyboardEvent('keydown', { 60 | 'key': key.toLowerCase(), 61 | 'code': `Key${key}`, 62 | 'keyCode': keys[key], 63 | 'cancelable': true, 64 | 'bubbles': true, 65 | })); 66 | }); 67 | 68 | newKey.addEventListener('pointerup', (evt) => { 69 | newKey.style.backgroundColor = '#ccc'; 70 | evt.preventDefault(); 71 | document.dispatchEvent(new KeyboardEvent('keyup', { 72 | 'key': key.toLowerCase(), 73 | 'code': `Key${key}`, 74 | 'keyCode': keys[key], 75 | 'cancelable': true, 76 | 'bubbles': true, 77 | })); 78 | }); 79 | 80 | keyboard.appendChild(newKey); 81 | }); 82 | 83 | const hideKeyboard = document.createElement('button'); 84 | hideKeyboard.className = 'keyboard-key'; 85 | hideKeyboard.textContent = 'hide'; 86 | hideKeyboard.style.margin = '3px'; 87 | hideKeyboard.style.userSelect = 'none'; 88 | hideKeyboard.style.border = '1px solid #000'; 89 | hideKeyboard.style.borderRadius = '10px'; 90 | hideKeyboard.addEventListener('click', () => { 91 | keyboard.parentNode.removeChild(keyboard); 92 | }); 93 | keyboard.appendChild(hideKeyboard); 94 | 95 | containerElement.appendChild(keyboard); 96 | } 97 | } -------------------------------------------------------------------------------- /libs/stats.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var Stats = function () { 6 | 7 | var mode = 0; 8 | 9 | var container = document.createElement( 'div' ); 10 | container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000'; 11 | container.addEventListener( 'click', function ( event ) { 12 | 13 | event.preventDefault(); 14 | showPanel( ++ mode % container.children.length ); 15 | 16 | }, false ); 17 | 18 | // 19 | 20 | function addPanel( panel ) { 21 | 22 | container.appendChild( panel.dom ); 23 | return panel; 24 | 25 | } 26 | 27 | function showPanel( id ) { 28 | 29 | for ( var i = 0; i < container.children.length; i ++ ) { 30 | 31 | container.children[ i ].style.display = i === id ? 'block' : 'none'; 32 | 33 | } 34 | 35 | mode = id; 36 | 37 | } 38 | 39 | // 40 | 41 | var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0; 42 | 43 | var fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) ); 44 | var msPanel = addPanel( new Stats.Panel( 'MS', '#0f0', '#020' ) ); 45 | 46 | if ( self.performance && self.performance.memory ) { 47 | 48 | var memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) ); 49 | 50 | } 51 | 52 | showPanel( 0 ); 53 | 54 | return { 55 | 56 | REVISION: 16, 57 | 58 | dom: container, 59 | 60 | addPanel: addPanel, 61 | showPanel: showPanel, 62 | 63 | begin: function () { 64 | 65 | beginTime = ( performance || Date ).now(); 66 | 67 | }, 68 | 69 | end: function () { 70 | 71 | frames ++; 72 | 73 | var time = ( performance || Date ).now(); 74 | 75 | msPanel.update( time - beginTime, 200 ); 76 | 77 | if ( time >= prevTime + 1000 ) { 78 | 79 | fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 ); 80 | 81 | prevTime = time; 82 | frames = 0; 83 | 84 | if ( memPanel ) { 85 | 86 | var memory = performance.memory; 87 | memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 ); 88 | 89 | } 90 | 91 | } 92 | 93 | return time; 94 | 95 | }, 96 | 97 | update: function () { 98 | 99 | beginTime = this.end(); 100 | 101 | }, 102 | 103 | // Backwards Compatibility 104 | 105 | domElement: container, 106 | setMode: showPanel 107 | 108 | }; 109 | 110 | }; 111 | 112 | Stats.Panel = function ( name, fg, bg ) { 113 | 114 | var min = Infinity, max = 0, round = Math.round; 115 | var PR = round( window.devicePixelRatio || 1 ); 116 | 117 | var WIDTH = 80 * PR, HEIGHT = 48 * PR, 118 | TEXT_X = 3 * PR, TEXT_Y = 2 * PR, 119 | GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR, 120 | GRAPH_WIDTH = 74 * PR, GRAPH_HEIGHT = 30 * PR; 121 | 122 | var canvas = document.createElement( 'canvas' ); 123 | canvas.width = WIDTH; 124 | canvas.height = HEIGHT; 125 | canvas.style.cssText = 'width:160px;height:96px'; 126 | 127 | var context = canvas.getContext( '2d' ); 128 | context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif'; 129 | context.textBaseline = 'top'; 130 | 131 | context.fillStyle = bg; 132 | context.fillRect( 0, 0, WIDTH, HEIGHT ); 133 | 134 | context.fillStyle = fg; 135 | context.fillText( name, TEXT_X, TEXT_Y ); 136 | context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT ); 137 | 138 | context.fillStyle = bg; 139 | context.globalAlpha = 0.9; 140 | context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT ); 141 | 142 | return { 143 | 144 | dom: canvas, 145 | 146 | update: function ( value, maxValue ) { 147 | 148 | min = Math.min( min, value ); 149 | max = Math.max( max, value ); 150 | 151 | context.fillStyle = bg; 152 | context.globalAlpha = 1; 153 | context.fillRect( 0, 0, WIDTH, GRAPH_Y ); 154 | context.fillStyle = fg; 155 | context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y ); 156 | 157 | context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT ); 158 | 159 | context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT ); 160 | 161 | context.fillStyle = bg; 162 | context.globalAlpha = 0.9; 163 | context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) ); 164 | 165 | } 166 | 167 | }; 168 | 169 | }; 170 | 171 | //export { Stats as default }; -------------------------------------------------------------------------------- /libs/threex.keyboardstate.js: -------------------------------------------------------------------------------- 1 | // https://github.com/jeromeetienne/threex.keyboardstate/blob/master/threex.keyboardstate.js 2 | // THREEx.KeyboardState.js keep the current state of the keyboard. 3 | // It is possible to query it at any time. No need of an event. 4 | // This is particularly convenient in loop driven case, like in 5 | // 3D demos or games. 6 | // 7 | // # Usage 8 | // 9 | // **Step 1**: Create the object 10 | // 11 | // ```var keyboard = new THREEx.KeyboardState();``` 12 | // 13 | // **Step 2**: Query the keyboard state 14 | // 15 | // This will return true if shift and A are pressed, false otherwise 16 | // 17 | // ```keyboard.pressed("shift+A")``` 18 | // 19 | // **Step 3**: Stop listening to the keyboard 20 | // 21 | // ```keyboard.destroy()``` 22 | // 23 | // NOTE: this library may be nice as standaline. independant from three.js 24 | // - rename it keyboardForGame 25 | // 26 | // # Code 27 | // 28 | 29 | /** @namespace */ 30 | var THREEx = THREEx || {}; 31 | 32 | /** 33 | * - NOTE: it would be quite easy to push event-driven too 34 | * - microevent.js for events handling 35 | * - in this._onkeyChange, generate a string from the DOM event 36 | * - use this as event name 37 | */ 38 | THREEx.KeyboardState = function(domElement) 39 | { 40 | this.domElement= domElement || document; 41 | // to store the current state 42 | this.keyCodes = {}; 43 | this.modifiers = {}; 44 | 45 | // create callback to bind/unbind keyboard events 46 | var _this = this; 47 | this._onKeyDown = function(event){ _this._onKeyChange(event) } 48 | this._onKeyUp = function(event){ _this._onKeyChange(event) } 49 | 50 | // bind keyEvents 51 | this.domElement.addEventListener("keydown", this._onKeyDown, false); 52 | this.domElement.addEventListener("keyup", this._onKeyUp, false); 53 | 54 | // create callback to bind/unbind window blur event 55 | this._onBlur = function(){ 56 | for(var prop in _this.keyCodes) _this.keyCodes[prop] = false; 57 | for(var prop in _this.modifiers) _this.modifiers[prop] = false; 58 | } 59 | 60 | // bind window blur 61 | window.addEventListener("blur", this._onBlur, false); 62 | } 63 | 64 | /** 65 | * To stop listening of the keyboard events 66 | */ 67 | THREEx.KeyboardState.prototype.destroy = function() 68 | { 69 | // unbind keyEvents 70 | this.domElement.removeEventListener("keydown", this._onKeyDown, false); 71 | this.domElement.removeEventListener("keyup", this._onKeyUp, false); 72 | 73 | // unbind window blur event 74 | window.removeEventListener("blur", this._onBlur, false); 75 | } 76 | 77 | THREEx.KeyboardState.MODIFIERS = ['shift', 'ctrl', 'alt', 'meta']; 78 | THREEx.KeyboardState.ALIAS = { 79 | 'left' : 37, 80 | 'up' : 38, 81 | 'right' : 39, 82 | 'down' : 40, 83 | 'space' : 32, 84 | 'pageup' : 33, 85 | 'pagedown' : 34, 86 | 'tab' : 9, 87 | 'escape' : 27, 88 | 'capslock' : 20, // edit by syncopika 89 | }; 90 | 91 | /** 92 | * to process the keyboard dom event 93 | */ 94 | THREEx.KeyboardState.prototype._onKeyChange = function(event) 95 | { 96 | // log to debug 97 | //console.log("onKeyChange", event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey) 98 | event.preventDefault(); // edit by syncopika 99 | 100 | // update this.keyCodes 101 | var keyCode = event.keyCode 102 | var pressed = event.type === 'keydown' ? true : false 103 | this.keyCodes[keyCode] = pressed 104 | // update this.modifiers 105 | this.modifiers['shift'] = event.shiftKey 106 | this.modifiers['ctrl'] = event.ctrlKey 107 | this.modifiers['alt'] = event.altKey 108 | this.modifiers['meta'] = event.metaKey 109 | } 110 | 111 | /** 112 | * query keyboard state to know if a key is pressed of not 113 | * 114 | * @param {String} keyDesc the description of the key. format : modifiers+key e.g shift+A 115 | * @returns {Boolean} true if the key is pressed, false otherwise 116 | */ 117 | THREEx.KeyboardState.prototype.pressed = function(keyDesc){ 118 | var keys = keyDesc.split("+"); 119 | for(var i = 0; i < keys.length; i++){ 120 | var key = keys[i] 121 | var pressed = false 122 | if( THREEx.KeyboardState.MODIFIERS.indexOf( key ) !== -1 ){ 123 | pressed = this.modifiers[key]; 124 | }else if( Object.keys(THREEx.KeyboardState.ALIAS).indexOf( key ) != -1 ){ 125 | pressed = this.keyCodes[ THREEx.KeyboardState.ALIAS[key] ]; 126 | }else { 127 | pressed = this.keyCodes[key.toUpperCase().charCodeAt(0)] 128 | } 129 | if( !pressed) return false; 130 | }; 131 | return true; 132 | } 133 | 134 | /** 135 | * return true if an event match a keyDesc 136 | * @param {KeyboardEvent} event keyboard event 137 | * @param {String} keyDesc string description of the key 138 | * @return {Boolean} true if the event match keyDesc, false otherwise 139 | */ 140 | THREEx.KeyboardState.prototype.eventMatches = function(event, keyDesc) { 141 | event.preventDefault(); // edit by syncopika: - avoid auto scroll with spacebar, for example 142 | var aliases = THREEx.KeyboardState.ALIAS 143 | var aliasKeys = Object.keys(aliases) 144 | var keys = keyDesc.split("+") 145 | // log to debug 146 | // console.log("eventMatches", event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey) 147 | for(var i = 0; i < keys.length; i++){ 148 | var key = keys[i]; 149 | var pressed = false; 150 | if( key === 'shift' ){ 151 | pressed = (event.shiftKey ? true : false) 152 | }else if( key === 'ctrl' ){ 153 | pressed = (event.ctrlKey ? true : false) 154 | }else if( key === 'alt' ){ 155 | pressed = (event.altKey ? true : false) 156 | }else if( key === 'meta' ){ 157 | pressed = (event.metaKey ? true : false) 158 | }else if( aliasKeys.indexOf( key ) !== -1 ){ 159 | pressed = (event.keyCode === aliases[key] ? true : false); 160 | }else if( event.keyCode === key.toUpperCase().charCodeAt(0) ){ 161 | pressed = true; 162 | } 163 | if( !pressed ) return false; 164 | } 165 | return true; 166 | } -------------------------------------------------------------------------------- /livery_editor/04-06-2021_142020.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/livery_editor/04-06-2021_142020.gif -------------------------------------------------------------------------------- /livery_editor/air-force-insignia-paste-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/livery_editor/air-force-insignia-paste-example.png -------------------------------------------------------------------------------- /livery_editor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | livery customizer demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 62 | 63 | 64 | 69 |
70 |
71 |
72 |
73 | 90 |
91 | 92 | 93 |
94 |
95 |
96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /livery_editor/notes.txt: -------------------------------------------------------------------------------- 1 | https://discoverthreejs.com/book/first-steps/textures-intro/ 2 | https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_012_TexturesImagesSamplers.md 3 | https://nicedoc.io/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_002_BasicGltfStructure.md 4 | https://computergraphics.stackexchange.com/questions/3616/how-to-encode-decode-buffer-data-in-gltf 5 | https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings -> exploring the base64 buffer data uri in gltf files 6 | https://discourse.threejs.org/t/how-to-get-texture-file-bytes-embedded-in-glb-after-loading-it-in-the-scene-via-gltfloader/6569 7 | https://discourse.threejs.org/t/set-img-elements-src-from-texture-map-inside-material/9771/3 8 | https://stackoverflow.com/questions/41853580/three-js-export-a-texture-as-an-image 9 | https://discourse.threejs.org/t/solved-get-dimensions-of-material-texture-image-in-traverse/16875 -> the material.map.image got me what I wanted. pretty easy it turns out lol -_- 10 | https://stackoverflow.com/questions/18436431/three-js-update-texture-image 11 | https://discourse.threejs.org/t/updating-material-map/2381/2 12 | https://discourse.threejs.org/t/textures-map-incorrectly-to-gltf-object/11544/2 13 | https://stackoverflow.com/questions/41469623/preventdefault-and-stoppropagation-not-working-with-pointermove -------------------------------------------------------------------------------- /livery_editor/readme.md: -------------------------------------------------------------------------------- 1 | # livery_editor 2 | ### a small demo that allows the editing of textures and creation of new livery for models 3 | 4 | ![livery editor gif](04-06-2021_142020.gif) 5 | 6 | Features are limited since this is intended to be just a proof-of-concept. This could probably be extended though to include a more complete drawing/paintbrush tool and a smarter and/or easier way of editing textures perhaps. 7 | 8 | some other ideas: 9 | - is it possible to draw on the model itself? 10 | - can we achieve a mirroring effect on the model when drawing on a texture? 11 | - how about pasting images onto the texture like decals for plastic models? -------------------------------------------------------------------------------- /livery_editor/yuyushiki-itasha-example-lol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/livery_editor/yuyushiki-itasha-example-lol.png -------------------------------------------------------------------------------- /models/080415pianobgm3popver-edit-steinway.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/080415pianobgm3popver-edit-steinway.ogg -------------------------------------------------------------------------------- /models/battleship2.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/battleship2.glb -------------------------------------------------------------------------------- /models/dangerous-capsule-edit-final.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/dangerous-capsule-edit-final.glb -------------------------------------------------------------------------------- /models/depositphotos_65970561-stock-photo-asphalt-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/depositphotos_65970561-stock-photo-asphalt-texture.jpg -------------------------------------------------------------------------------- /models/f-18.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/f-18.glb -------------------------------------------------------------------------------- /models/grass2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/grass2.jpg -------------------------------------------------------------------------------- /models/oceanfloor.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/oceanfloor.glb -------------------------------------------------------------------------------- /models/submarine1.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/submarine1.glb -------------------------------------------------------------------------------- /models/whale-shark-camo.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/models/whale-shark-camo.glb -------------------------------------------------------------------------------- /new_project_template/README.md: -------------------------------------------------------------------------------- 1 | # new_project_template 2 | 3 | Talk about your new project. 4 | 5 | ![show a gif or screenshot here!]() -------------------------------------------------------------------------------- /new_project_template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | new_project_template 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 |

new_project_template

28 | 29 |
30 |
31 | 32 |

instructions and stuff

33 | 34 | 35 | 37 | -------------------------------------------------------------------------------- /new_project_template/index.js: -------------------------------------------------------------------------------- 1 | // new project template 2 | const container = document.getElementById('container'); 3 | 4 | const fov = 60; 5 | const camera = new THREE.PerspectiveCamera(fov, container.clientWidth / container.clientHeight, 0.01, 1000); 6 | camera.position.set(0, 4, 10); 7 | 8 | // optional stuff 9 | //const keyboard = new THREEx.KeyboardState(); 10 | //const raycaster = new THREE.Raycaster(); 11 | //const mouse = new THREE.Vector2(); 12 | //const clock = new THREE.Clock(); 13 | 14 | /* set up trackball control if needed 15 | const controls = new THREE.TrackballControls(camera, renderer.domElement); 16 | controls.rotateSpeed = 3.2; 17 | controls.zoomSpeed = 1.2; 18 | controls.panSpeed = 0.8; 19 | */ 20 | 21 | const loadingManager = new THREE.LoadingManager(); 22 | setupLoadingManager(loadingManager); 23 | 24 | const loader = new THREE.GLTFLoader(loadingManager); 25 | 26 | const renderer = new THREE.WebGLRenderer({antialias: true}); 27 | renderer.shadowMap.enabled = true; 28 | renderer.shadowMap.type = THREE.PCFSoftShadowMap; 29 | renderer.setSize(container.clientWidth, container.clientHeight); 30 | container.appendChild(renderer.domElement); 31 | 32 | const scene = new THREE.Scene(); 33 | scene.background = new THREE.Color(0xeeeeee); 34 | scene.add(camera); 35 | 36 | const spotLight = new THREE.SpotLight(0xffffff); 37 | spotLight.position.set(0, 70, -8); 38 | spotLight.castShadow = true; 39 | spotLight.shadow.mapSize.width = 1024; 40 | spotLight.shadow.mapSize.height = 1024; 41 | scene.add(spotLight); 42 | 43 | //const pointLight = new THREE.PointLight(0xffffff, 1, 0); 44 | //pointLight.position.set(2, 10, 2); 45 | //pointLight.castShadow = true; 46 | //scene.add(pointLight); 47 | 48 | //const hemiLight = new THREE.HemisphereLight(0xffffff); 49 | //hemiLight.position.set(0, 10, 0); 50 | //scene.add(hemiLight); 51 | 52 | // add a plane and a sphere 53 | const planeGeometry = new THREE.PlaneGeometry(25, 25); 54 | const planeMaterial = new THREE.MeshLambertMaterial({color: 0x055C9D}); 55 | const plane = new THREE.Mesh(planeGeometry, planeMaterial); 56 | plane.rotateX(-Math.PI / 2); 57 | plane.receiveShadow = true; 58 | plane.castShadow = true; 59 | scene.add(plane); 60 | 61 | const sphereGeometry = new THREE.SphereGeometry(0.9, 32, 16); 62 | const sphereMaterial = new THREE.MeshPhongMaterial(); 63 | const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); 64 | sphere.receiveShadow = true; 65 | sphere.castShadow = true; 66 | sphere.position.x = 0; 67 | sphere.position.y = 4; 68 | sphere.position.z = 0; 69 | scene.add(sphere); 70 | 71 | function getModel(modelFilePath){ 72 | return new Promise((resolve) => { 73 | loader.load( 74 | modelFilePath, 75 | function(gltf){ 76 | resolve(gltf.scene); 77 | }, 78 | // called while loading is progressing 79 | function(xhr){ 80 | console.log((xhr.loaded / xhr.total * 100) + '% loaded'); 81 | }, 82 | // called when loading has errors 83 | function(error){ 84 | console.log('An error happened'); 85 | console.log(error); 86 | } 87 | ); 88 | }); 89 | } 90 | 91 | function update(){ 92 | // move stuff around, etc. 93 | } 94 | 95 | function keydown(evt){ 96 | if(evt.keyCode === 32){ 97 | // spacebar 98 | }else if(evt.keyCode === 49){ 99 | //1 key 100 | }else if(evt.keyCode === 50){ 101 | //2 key 102 | }else if(evt.keyCode === 82){ 103 | // r key 104 | } 105 | } 106 | document.addEventListener('keydown', keydown); 107 | 108 | 109 | function animate(){ 110 | //controls.update(); // update trackball control 111 | requestAnimationFrame(animate); 112 | renderer.render(scene, camera); 113 | update(); 114 | } 115 | 116 | animate(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "threejs-projects", 3 | "version": "1.0.0", 4 | "description": "small projects using three.js \r https://syncopika.github.io/threejs-projects/", 5 | "main": "server.js", 6 | "dependencies": { 7 | "@html-eslint/eslint-plugin": "^0.24.1", 8 | "@html-eslint/parser": "^0.24.1", 9 | "eslint": "^9.1.1", 10 | "express": "^4.17.1" 11 | }, 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "start": "node server.js", 15 | "lint": "eslint", 16 | "lint:fix": "eslint --fix" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/syncopika/threejs-projects.git" 21 | }, 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/syncopika/threejs-projects/issues" 26 | }, 27 | "homepage": "https://github.com/syncopika/threejs-projects#readme" 28 | } 29 | -------------------------------------------------------------------------------- /rubikscube/19-03-2024_192544.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/19-03-2024_192544.gif -------------------------------------------------------------------------------- /rubikscube/README.md: -------------------------------------------------------------------------------- 1 | # Rubik's Cube idea 2 | 3 | a Rubik's cube demo. future ideas include allowing the user to rotate a layer a certain direction to be able to solve the cube. :) 4 | 5 | ![example gif](19-03-2024_192544.gif) -------------------------------------------------------------------------------- /rubikscube/blender/m1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m1.png -------------------------------------------------------------------------------- /rubikscube/blender/m2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m2.png -------------------------------------------------------------------------------- /rubikscube/blender/m3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m3.png -------------------------------------------------------------------------------- /rubikscube/blender/m4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m4.png -------------------------------------------------------------------------------- /rubikscube/blender/m5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m5.png -------------------------------------------------------------------------------- /rubikscube/blender/m6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m6.png -------------------------------------------------------------------------------- /rubikscube/blender/m7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/m7.png -------------------------------------------------------------------------------- /rubikscube/blender/r1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r1.png -------------------------------------------------------------------------------- /rubikscube/blender/r2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r2.png -------------------------------------------------------------------------------- /rubikscube/blender/r3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r3.png -------------------------------------------------------------------------------- /rubikscube/blender/r4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r4.png -------------------------------------------------------------------------------- /rubikscube/blender/r5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r5.png -------------------------------------------------------------------------------- /rubikscube/blender/r6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r6.png -------------------------------------------------------------------------------- /rubikscube/blender/r7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r7.png -------------------------------------------------------------------------------- /rubikscube/blender/r8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r8.png -------------------------------------------------------------------------------- /rubikscube/blender/r9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/r9.png -------------------------------------------------------------------------------- /rubikscube/blender/rubikscube.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/rubikscube.blend -------------------------------------------------------------------------------- /rubikscube/blender/t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t1.png -------------------------------------------------------------------------------- /rubikscube/blender/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t2.png -------------------------------------------------------------------------------- /rubikscube/blender/t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t3.png -------------------------------------------------------------------------------- /rubikscube/blender/t4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t4.png -------------------------------------------------------------------------------- /rubikscube/blender/t5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t5.png -------------------------------------------------------------------------------- /rubikscube/blender/t6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t6.png -------------------------------------------------------------------------------- /rubikscube/blender/t7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t7.png -------------------------------------------------------------------------------- /rubikscube/blender/t8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t8.png -------------------------------------------------------------------------------- /rubikscube/blender/t9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/rubikscube/blender/t9.png -------------------------------------------------------------------------------- /rubikscube/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rubik's Cube 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 25 | 26 | 27 | 28 |

Rubik's Cube

29 | 30 |
31 |
32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const path = require('path'); 4 | const port = 3000; 5 | 6 | // ah, it expects the dfault file to serve to be called index.html. if named otherwise you'll get cannot GET 7 | // https://stackoverflow.com/questions/44524424/get-http-localhost3000-404-not-found 8 | app.use('/', express.static((path.join(__dirname, '')))); 9 | 10 | app.listen(port, () => console.log('listening on port: ' + port)); -------------------------------------------------------------------------------- /shaders/27-06-2021_184151.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/shaders/27-06-2021_184151.webp -------------------------------------------------------------------------------- /shaders/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | shader demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 62 | 63 | 64 |
65 |

shader demo

66 |

click and drag on the canvas to move around and use a mouse clickwheel to zoom in/out

67 |
68 |
69 |
70 | 71 |
72 | 84 |
85 | 86 |
87 |
88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /shaders/notes.txt: -------------------------------------------------------------------------------- 1 | https://aerotwist.com/tutorials/an-introduction-to-shaders-part-1/ 2 | http://aerotwist.com/tutorials/an-introduction-to-shaders-part-2/ 3 | https://thebookofshaders.com/02/ -> this only concerns the fragment shader 4 | https://threejs.org/docs/#api/en/materials/ShaderMaterial 5 | https://stackoverflow.com/questions/37398013/animating-custom-shader-in-webgl-three-js 6 | https://shader-tutorial.dev/basics/vertex-shader/ 7 | https://threejsfundamentals.org/threejs/lessons/threejs-shadertoy.html 8 | https://blog.scottlogic.com/2019/10/17/sculpting-shapes-with-webgl-fragment-shader.html 9 | https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_rawshader.html 10 | https://github.com/mrdoob/three.js/blob/master/examples/webgl2_volume_cloud.html 11 | https://stackoverflow.com/questions/66741338/simple-square-using-buffergeometry 12 | http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ 13 | https://discourse.threejs.org/t/shader-randomize-point-positions-from-origins/6689/2 14 | https://stackoverflow.com/questions/23899887/passing-pointlight-info-to-a-custom-shader-with-three-js 15 | https://stackoverflow.com/questions/42170992/three-js-change-attributes-value-in-vertex-shader-and-pass-to-buffer -> this is interesting 16 | https://observablehq.com/@camargo/three-js-utah-teapot-with-a-custom-phong-shader-material 17 | https://stackoverflow.com/questions/17537879/in-webgl-what-are-the-differences-between-an-attribute-a-uniform-and-a-varying 18 | https://threejs.org/docs/#api/en/core/Uniform 19 | 20 | notes 21 | might need to grab the uv coords of my imported model and pass them to the shaders? https://jsfiddle.net/f2Lommf5/16541/ 22 | -> nope, just needed make sure the texture's flipY was set to false 23 | 24 | colors for rgba channels in shaders range from 0-1, not 0-255!! somehow I didn't notice that even when the alpha channel was set to 1 and I 25 | wasted a ton of time trying to figure out why different colors weren't working -_-. -------------------------------------------------------------------------------- /shaders/raymarching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/shaders/raymarching.png -------------------------------------------------------------------------------- /shaders/readme.md: -------------------------------------------------------------------------------- 1 | ## shaders 2 | 3 | having fun with shaders. there's so much you can do with them! :O 4 | 5 | 1. jet 6 | - the color and position of vertices of the model changes based on time to create a bit of a "morphing" jet 7 | 8 | 2. jet2 9 | - another jet model but this time featuring the Blinn-Phong reflection model 10 | 11 | 3. whale shark 12 | - a colorful, glowing whale shark (the color (plus a bit of noise) changes over time on the white parts of the shark) 13 | 14 | 4. springy shards 15 | - a bunch of rotating squares whose vertices and colors change over time to form a swirling pattern 16 | - the squares are created using BufferGeometry and the shaders are attached to the BufferGeometry 17 | 18 | 5. raymarching 19 | - a basic, minimal raymarching example -------------------------------------------------------------------------------- /shaders/shaders/glassShader.js: -------------------------------------------------------------------------------- 1 | // "glass" shader derived from my toon shader 2 | // not that great atm but a starting point at least? 3 | // needs refraction 4 | // 5 | // ideas and things to read: 6 | // https://godotshaders.com/shader-tag/glass/ 7 | // https://kylehalladay.com/blog/tutorial/2014/02/18/Fresnel-Shaders-From-The-Ground-Up.html 8 | // https://blog.maximeheckel.com/posts/refraction-dispersion-and-other-shader-light-effects/ 9 | // https://community.khronos.org/t/refraction-shader/60635 10 | 11 | const glassShader = { 12 | vertexShader: ` 13 | varying vec2 vUv; 14 | varying vec3 vNormal; 15 | varying float fresnel; // Fresnel factor 16 | 17 | void main() { 18 | vUv = uv; 19 | vNormal = normal; 20 | gl_Position = projectionMatrix * 21 | modelViewMatrix * 22 | vec4(position, 1.0); 23 | 24 | // calculate Fresnel factor 25 | vec3 I = normalize(gl_Position.xyz - cameraPosition); // we get cameraPosition for free! (https://threejs.org/docs/#api/en/renderers/webgl/WebGLProgram) 26 | fresnel = pow(1.0 + dot(I, normal), 3.5); 27 | } 28 | `, 29 | 30 | fragShader: ` 31 | varying vec2 vUv; 32 | varying vec3 vNormal; 33 | varying float fresnel; 34 | uniform sampler2D img; 35 | 36 | vec3 diffuseLightDir = vec3(1, 1, 0); // change? 37 | vec4 diffuseColor = vec4(1, 1, 1, 0.3); 38 | float diffuseIntensity = 1.5; 39 | 40 | void main() { 41 | float intensity = dot(normalize(diffuseLightDir), vNormal); 42 | if(intensity < 0.){ 43 | intensity = 0.; 44 | } 45 | 46 | float alpha = 0.82; // for transparency 47 | 48 | vec4 txColor = vec4(1, 1, 1, 1) * diffuseColor * diffuseIntensity; // change color here 49 | 50 | if(intensity > 0.95){ 51 | gl_FragColor = vec4(1, 1, 1, alpha) * vec4(txColor.rgba); 52 | }else if(intensity > 0.5){ 53 | gl_FragColor = vec4(0.7, 0.7, 0.7, alpha) * vec4(txColor.rgba); 54 | }else if(intensity > 0.05){ 55 | gl_FragColor = vec4(0.35, 0.35, 0.35, alpha) * vec4(txColor.rgba); 56 | }else{ 57 | gl_FragColor = vec4(0.1, 0.1, 0.1, alpha) * vec4(txColor.rgba); 58 | } 59 | 60 | gl_FragColor = mix(txColor, gl_FragColor, fresnel); 61 | } 62 | `, 63 | }; -------------------------------------------------------------------------------- /shaders/shaders/jetModelShader.js: -------------------------------------------------------------------------------- 1 | const jetModelShader = { 2 | vertexShader: ` 3 | varying vec2 vUv; 4 | uniform float u_time; 5 | 6 | // http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ 7 | mat4 getRotationMat(vec3 axis, float angle){ 8 | float s = sin(angle); 9 | float c = cos(angle); 10 | float oc = 1.0 - c; 11 | 12 | return mat4( 13 | oc*axis.x*axis.x + c, oc*axis.x*axis.y - axis.z*s, oc*axis.z*axis.x + axis.y*s, 0.0, 14 | oc*axis.x*axis.y + axis.z*s, oc*axis.y*axis.y + c, oc*axis.y*axis.z + axis.x*s, 0.0, 15 | oc*axis.x*axis.z - axis.y*s, oc*axis.y*axis.z + axis.x*s, oc*axis.z*axis.z + c, 0.0, 16 | 0.0, 0.0, 0.0, 1.0 17 | ); 18 | } 19 | 20 | float rand(vec2 pos){ 21 | return fract(sin(dot(pos, vec2(12.9898,78.233)))*43758.5453123); 22 | } 23 | 24 | void main() { 25 | vUv = uv; 26 | 27 | mat4 rotZ = getRotationMat(vec3(0, 0, 1), sin(0.5*u_time)); 28 | 29 | float randVal = rand(uv); 30 | 31 | float xDelta = position.x*randVal*sin(0.8*u_time); 32 | float zDelta = position.z*randVal*cos(0.7*u_time); 33 | 34 | gl_Position = projectionMatrix * 35 | modelViewMatrix * 36 | rotZ * 37 | vec4(position.x+xDelta, position.y, position.z+zDelta, 1.0); 38 | } 39 | `, 40 | fragShader: ` 41 | varying vec2 vUv; 42 | uniform sampler2D img; 43 | uniform float u_time; 44 | uniform vec2 u_resolution; // dimensions of renderer 45 | 46 | float interpolate(float val){ 47 | return clamp(smoothstep(0.2, 1.0, val), 0.3, 1.0); // let lowest possible val be 0.3 48 | } 49 | 50 | void main() { 51 | vec2 pt = gl_FragCoord.xy/u_resolution.xy; 52 | 53 | vec4 txColor = texture2D(img, vUv); 54 | 55 | gl_FragColor = vec4( 56 | interpolate(txColor.r*abs(sin(u_time))), 57 | interpolate(txColor.g*abs(sin(u_time))), 58 | interpolate(txColor.b*abs(sin(u_time))), 59 | 1.0); 60 | } 61 | `, 62 | }; -------------------------------------------------------------------------------- /shaders/shaders/jetModelShader2.js: -------------------------------------------------------------------------------- 1 | // PPBS - per-pixel blinn-phong shading 2 | 3 | const jetModelShader2 = { 4 | vertexShader: ` 5 | uniform vec4 lightPosition[1]; 6 | 7 | out vec4 direction[1]; 8 | out vec4 halfVectors[1]; 9 | out vec4 norm; 10 | out vec2 vUv; 11 | 12 | void main() { 13 | vUv = uv; 14 | 15 | vec4 vertexPos = modelViewMatrix * vec4(position, 1.0); 16 | vec4 viewPos = normalize(-vertexPos); 17 | 18 | vec4 dir = normalize(lightPosition[0] - vertexPos); 19 | direction[0] = dir; 20 | 21 | // calculate halfway vector 22 | vec4 halfVector = normalize(dir + viewPos); 23 | halfVectors[0] = halfVector; 24 | 25 | norm = vec4((normalMatrix * normal), 0); // normalMatrix comes for free 26 | 27 | gl_Position = projectionMatrix * 28 | modelViewMatrix * 29 | vec4(position, 1.0); 30 | } 31 | `, 32 | 33 | fragShader: ` 34 | uniform sampler2D img; 35 | uniform float u_time; 36 | uniform vec2 u_resolution; 37 | uniform float shininess; 38 | uniform vec3 diffuseLight[1]; 39 | uniform vec3 specularLight[1]; 40 | uniform vec4 lightIntensity[1]; 41 | 42 | // variables passed in from the vertex shader 43 | in vec4 direction[1]; // light direction 44 | in vec4 halfVectors[1]; 45 | in vec4 norm; 46 | in vec2 vUv; 47 | 48 | void main() { 49 | vec4 color = texture2D(img, vUv); 50 | 51 | // calculate ndotl (normal dot light direction) here 52 | float ndotl = max(dot(norm, direction[0]), 0.); 53 | 54 | // calculate specular contribution via (halfVector*normal)^shininess 55 | float specular = pow(max(dot(halfVectors[0], norm), 0.), shininess); 56 | 57 | vec4 diff = ndotl * vec4(diffuseLight[0], 0); 58 | vec4 spec = specular * vec4(specularLight[0], 0); 59 | color = (lightIntensity[0] * (diff + spec + color)); 60 | 61 | gl_FragColor = color; 62 | } 63 | `, 64 | 65 | }; -------------------------------------------------------------------------------- /shaders/shaders/raymarchShader.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/50363915/curve-rotation-in-glsl-fragment-shader 2 | // https://riccardoscalco.it/blog/volume-ray-casting/ 3 | // https://stackoverflow.com/questions/9066836/opengl-point-sprites-rotation-in-fragment-shader 4 | // https://math.stackexchange.com/questions/3360969/scale-rotate-skew-a-2d-shape-to-look-like-3d 5 | // this one is pretty useful and minimal so it's easy to understand - https://www.shadertoy.com/view/fdB3Rh 6 | // https://adrianb.io/2016/10/01/raymarching.html#fun-with-distance-fields - useful and helps explain stuff like opU() 7 | // and of course Inigo Quilez's sdf primitives demo (but pretty complicated and hard to break down into easy-to-understand parts): https://www.shadertoy.com/view/Xds3zN 8 | 9 | const raymarchShader = { 10 | vertexShader: ` 11 | out vec2 vUv; 12 | void main() { 13 | vUv = uv; 14 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 15 | } 16 | `, 17 | 18 | fragShader: ` 19 | #define pi 3.141592653 20 | 21 | uniform float u_time; 22 | uniform vec2 u_resolution; 23 | 24 | in vec2 vUv; 25 | 26 | float sdfSphere(vec3 p, float s){ 27 | return length(p)-s; 28 | } 29 | 30 | float sdfPlane(vec3 p){ 31 | return p.y; 32 | } 33 | 34 | // union function to return the closest position - necessary when raymarching 35 | vec2 opU(vec2 d1, vec2 d2){ 36 | return (d1.x < d2.x) ? d1 : d2; 37 | } 38 | 39 | // add all the objects in the scene 40 | vec2 assembleScene(vec3 p){ 41 | // put shapes into position 42 | 43 | // sphere 1 44 | vec3 pos1 = p - vec3(-2., 0.3, 8.); 45 | pos1.x += 0.3*cos(u_time); 46 | pos1.z += 0.3*cos(u_time); 47 | pos1.y += sin(u_time); 48 | 49 | vec2 s1 = vec2(sdfSphere(pos1, 0.7), 0.); 50 | 51 | // sphere 2 52 | vec3 pos2 = p - vec3(2.5, 1.2, 20.); 53 | pos2.x += cos(u_time); 54 | pos2.y -= 0.8*sin(u_time); 55 | vec2 s2 = vec2(sdfSphere(pos2, 1.5), 0.); 56 | 57 | // add sphere 1 and 2 58 | vec2 ret = opU(s1, s2); 59 | 60 | // add some more spheres 61 | int numSpheres = 8; 62 | float radSlice = (360. / float(numSpheres)) * (3.14159 / 180.); 63 | for(float i = 0.; i < float(numSpheres); i++){ 64 | vec3 pos = p - vec3(cos(i*radSlice), 0.5, 5.+sin(i*radSlice)); 65 | 66 | pos.x += cos(i*radSlice+u_time); 67 | pos.z += cos(i*radSlice+u_time); 68 | pos.y += sin(radSlice+u_time); 69 | 70 | vec2 s = vec2(sdfSphere(pos, 0.2), 0.); 71 | 72 | ret = opU(s, ret); 73 | } 74 | 75 | //ret = opU(vec2(sdfPlane(p)), ret); 76 | 77 | return ret; 78 | } 79 | 80 | // https://www.shadertoy.com/view/Xds3zN 81 | vec3 generateNormal(vec3 p){ 82 | vec2 e = vec2(1.0,-1.0)*0.5773*0.0005; 83 | return normalize( e.xyy*assembleScene( p + e.xyy ).x + 84 | e.yyx*assembleScene( p + e.yyx ).x + 85 | e.yxy*assembleScene( p + e.yxy ).x + 86 | e.xxx*assembleScene( p + e.xxx ).x ); 87 | } 88 | 89 | // https://adrianb.io/2016/10/01/raymarching.html#fun-with-distance-fields 90 | // ro = ray origin 91 | // rd = ray direction 92 | vec3 raymarch(vec3 ro, vec3 rd){ 93 | vec3 ret = vec3(1.); 94 | 95 | int maxSteps = 60; 96 | float currRayDist = 0.; 97 | 98 | for(int i = 0; i < maxSteps; i++){ 99 | vec3 p = ro+rd*currRayDist; 100 | vec2 d = assembleScene(p); 101 | 102 | if(d.x < 0.0001){ 103 | vec3 n = generateNormal(p); 104 | 105 | // calculate color here (https://www.shadertoy.com/view/fdB3Rh) 106 | vec3 lightPos = vec3(0.0, 0.0, 1.0); 107 | //lightPos.xy += vec2(sin(u_time), cos(u_time)) * 2.; 108 | vec3 l = normalize(lightPos - p); 109 | float diff = clamp(dot(n, l), 0.0, 1.0); 110 | 111 | return vec3(0.9*abs(cos(u_time)), 0.9*abs(sin(u_time)), 0.9*abs(cos(u_time))) * diff; 112 | } 113 | 114 | currRayDist += d.x; 115 | } 116 | 117 | return ret; 118 | } 119 | 120 | 121 | void main() { 122 | vec2 st = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / u_resolution.y; // TODO: how to get frag coord relative to plane mesh and not canvas? 123 | 124 | vec3 ro = vec3(0, 1, 0); 125 | vec3 rd = normalize(vec3(st.x, st.y, 1)); 126 | vec3 d = raymarch(ro, rd); 127 | 128 | gl_FragColor = vec4(d, 1.0); 129 | } 130 | `, 131 | 132 | }; -------------------------------------------------------------------------------- /shaders/shaders/rippleShader.js: -------------------------------------------------------------------------------- 1 | // https://github.com/twostraws/ShaderKit/blob/main/Shaders/SHKCircleWaveBlended.fsh 2 | // https://github.com/syncopika/music-visualizer/commit/e19ef49c5397e2a37332ca93cbff27ea2796d33f#diff-335967cf3a911f85b6f20eaedc439032b6722b9a81b0938d60d0cf6a18f94c7c 3 | 4 | const rippleShader = { 5 | vertexShader: ` 6 | out vec2 vUv; 7 | 8 | void main() { 9 | vUv = uv; 10 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 11 | } 12 | `, 13 | 14 | fragShader: ` 15 | uniform float u_time; 16 | uniform vec2 u_resolution; 17 | 18 | in vec2 vUv; 19 | 20 | // ripple parameters 21 | uniform vec2 center; 22 | uniform vec4 color; 23 | uniform float speed; 24 | uniform float density; 25 | uniform float strength; 26 | uniform float brightness; 27 | 28 | void main() { 29 | vec2 pt = vUv.xy; //gl_FragCoord.xy/u_resolution.xy; -> this gets a fragment's position relative to viewport and not relative to mesh 30 | vec4 col = color; 31 | 32 | float waveSpeed = -(u_time * speed * 10.0); 33 | 34 | vec3 brightness = vec3(brightness); 35 | float pixelDist = distance(pt, center); 36 | 37 | if(pixelDist > 0.5){ 38 | gl_FragColor = vec4(1.0, 1.0, 1.0, 0.0); 39 | return; 40 | } 41 | 42 | if(color.r == 1.0 && color.g == 1.0 && color.b == 1.0 && color.a == 0.0){ 43 | gl_FragColor = vec4(1.0, 1.0, 1.0, 0.0); 44 | return; 45 | } 46 | 47 | vec3 gradientColor = vec3(color.r, color.g, color.b) * brightness; 48 | 49 | // we can tune the ripple to audio data! e.g. 50 | // set gradient color to be a function of the freq bin delta 51 | // if (freqBinDelta > 0) gradientColor *= freqBinDelta * 2.0; 52 | 53 | float colorStrength = pow(1.0 - pixelDist, 3.0); 54 | colorStrength *= strength; 55 | 56 | float waveDensity = density * pixelDist; 57 | float cosine = cos(waveSpeed + waveDensity); 58 | float cosAdjust = (0.5 * cosine) + 0.5; 59 | 60 | float lumi = colorStrength * (strength + cosAdjust); 61 | lumi *= 1.0 - (pixelDist * 2.0); 62 | lumi = max(0.0, lumi); 63 | 64 | vec3 newColor = gradientColor * lumi; 65 | vec4 final = vec4(newColor.r, newColor.g, newColor.b, lumi); 66 | vec4 finalColor = mix(col, final, lumi) * col.w; 67 | 68 | // make alpha be a function of distance from center 69 | finalColor.a = pixelDist / 4.0; 70 | 71 | gl_FragColor = finalColor; 72 | 73 | } 74 | `, 75 | 76 | }; -------------------------------------------------------------------------------- /shaders/shaders/springyShardShader.js: -------------------------------------------------------------------------------- 1 | const springyShardShader = { 2 | vertexShader: ` 3 | uniform float u_time; 4 | 5 | attribute vec4 color; 6 | varying vec4 vColor; 7 | 8 | // https://thebookofshaders.com/10/ 9 | float rand(vec2 pos){ 10 | return fract(sin(dot(pos, vec2(12.9898,78.233)))*43758.5453123); 11 | } 12 | 13 | // http://www.neilmendoza.com/glsl-rotation-about-an-arbitrary-axis/ 14 | mat4 getRotationMat(vec3 axis, float angle){ 15 | float s = sin(angle); 16 | float c = cos(angle); 17 | float oc = 1.0 - c; 18 | 19 | return mat4( 20 | oc*axis.x*axis.x + c, oc*axis.x*axis.y - axis.z*s, oc*axis.z*axis.x + axis.y*s, 0.0, 21 | oc*axis.x*axis.y + axis.z*s, oc*axis.y*axis.y + c, oc*axis.y*axis.z + axis.x*s, 0.0, 22 | oc*axis.x*axis.z - axis.y*s, oc*axis.y*axis.z + axis.x*s, oc*axis.z*axis.z + c, 0.0, 23 | 0.0, 0.0, 0.0, 1.0 24 | ); 25 | } 26 | 27 | void main() { 28 | vColor = color; 29 | 30 | float randVal = rand(vec2(position.xy)); 31 | 32 | mat4 rotZ = getRotationMat(vec3(0,0,1), randVal*cos(u_time)); // rotate about the z axis 33 | 34 | // rotate and move the squares along the z axis 35 | gl_Position = projectionMatrix * modelViewMatrix * rotZ * vec4(position.x, position.y, (1.+randVal)*position.z*abs(cos(0.3*u_time)), 1.0); 36 | } 37 | `, 38 | 39 | fragShader: ` 40 | uniform sampler2D img; 41 | uniform float u_time; 42 | uniform vec2 u_resolution; // dimensions of renderer canvas 43 | varying vec4 vColor; 44 | 45 | void main() { 46 | gl_FragColor = vec4( 47 | vColor.r*abs(cos(u_time))*1.3, 48 | vColor.g*abs(sin(u_time))*1.6, 49 | vColor.b*abs(cos(u_time))*1.2, 50 | 1.0); 51 | } 52 | `, 53 | }; -------------------------------------------------------------------------------- /shaders/shaders/toonShader.js: -------------------------------------------------------------------------------- 1 | // http://rbwhitaker.wikidot.com/toon-shader 2 | 3 | const toonShader = { 4 | vertexShader: ` 5 | varying vec2 vUv; 6 | varying vec3 vNormal; 7 | 8 | // toon shader properties 9 | //vec4 lineColor = vec4(0, 0, 0, 1); 10 | //float lineThickness = .03; 11 | 12 | // TODO: need to add outline 13 | // do I need to add a separate pass shader? 14 | 15 | void main() { 16 | vUv = uv; 17 | vNormal = normal; 18 | gl_Position = projectionMatrix * 19 | modelViewMatrix * 20 | vec4(position, 1.0); 21 | } 22 | `, 23 | 24 | fragShader: ` 25 | varying vec2 vUv; 26 | varying vec3 vNormal; 27 | uniform sampler2D img; 28 | 29 | vec3 diffuseLightDir = vec3(1, 1, 0); // change? 30 | vec4 diffuseColor = vec4(1, 1, 1, 1); 31 | float diffuseIntensity = 1.5; 32 | 33 | void main() { 34 | float intensity = dot(normalize(diffuseLightDir), vNormal); 35 | if(intensity < 0.){ 36 | intensity = 0.; 37 | } 38 | 39 | vec4 txColor = vec4(0, 0, 1, 1.0) * diffuseColor * diffuseIntensity; // some shade of blue 40 | 41 | if(intensity > 0.95){ 42 | gl_FragColor = vec4(1, 1, 1, 1.0) * vec4(txColor.rgb, 1.0); 43 | }else if(intensity > 0.5){ 44 | gl_FragColor = vec4(0.7, 0.7, 0.7, 1.0) * vec4(txColor.rgb, 1.0); 45 | }else if(intensity > 0.05){ 46 | gl_FragColor = vec4(0.35, 0.35, 0.35, 1.0) * vec4(txColor.rgb, 1.0); 47 | }else{ 48 | gl_FragColor = vec4(0.1, 0.1, 0.1, 1.0) * vec4(txColor.rgb, 1.0); 49 | } 50 | } 51 | `, 52 | }; -------------------------------------------------------------------------------- /shaders/shaders/whaleSharkShader.js: -------------------------------------------------------------------------------- 1 | const whaleSharkShader = { 2 | vertexShader: ` 3 | varying vec2 vUv; 4 | uniform float u_time; 5 | 6 | void main() { 7 | vUv = uv; 8 | 9 | gl_Position = projectionMatrix * 10 | modelViewMatrix * 11 | vec4(position, 1.0); 12 | } 13 | `, 14 | 15 | fragShader: ` 16 | varying vec2 vUv; 17 | uniform sampler2D img; 18 | uniform float u_time; 19 | uniform vec2 u_resolution; // dimensions of renderer 20 | 21 | float rand(vec2 pos){ 22 | return fract(sin(dot(pos, vec2(12.9898,78.233)))*43758.5453123); 23 | } 24 | 25 | void main() { 26 | vec2 pt = gl_FragCoord.xy/u_resolution.xy; 27 | 28 | vec4 txColor = texture2D(img, vUv); 29 | 30 | // color only certain parts of the shark! 31 | if(txColor.r < 0.5 && txColor.g < 0.5 && txColor.b < 0.5){ 32 | gl_FragColor = vec4(txColor.rgb, 1.0); 33 | }else{ 34 | gl_FragColor = vec4( 35 | 1.-txColor.r*abs(sin(0.2*u_time))*rand(pt), // rand(pt) adds some noise 36 | 1.-txColor.g*abs(cos(u_time))*rand(pt), 37 | 1.- txColor.b*abs(sin(0.1*u_time)), 38 | 1.0); 39 | } 40 | } 41 | `, 42 | }; -------------------------------------------------------------------------------- /snowboard/08-10-2023_103831.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/snowboard/08-10-2023_103831.gif -------------------------------------------------------------------------------- /snowboard/093023humanoid.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/snowboard/093023humanoid.blend -------------------------------------------------------------------------------- /snowboard/AnimationController.js: -------------------------------------------------------------------------------- 1 | // animation controller for snowboard demo. this one is a bit different from the animation controller 2 | // used for the character and fps demos since the snowboarder model utilizes full-body animations 3 | // instead of half-body animations. 4 | 5 | class AnimationController { 6 | 7 | mixer; // animation mixer 8 | clips; // all the clips for animation 9 | currAction; // current animation of character (action name) - rename to currAction 10 | currState; // the state of character e.g. object equip or not 11 | character; // a reference to the mesh that this controller belongs to 12 | timeDivisor; // number to divide the time by when updating (i.e. a smaller num == faster animation) 13 | animationMap; // for knowing which actions correspond to which states 14 | 15 | constructor(character, animMixer, animClips, clock){ 16 | this.character = character; 17 | this.mixer = animMixer; 18 | this.clips = animClips; 19 | this.clock = clock; 20 | this.currAction = ''; 21 | this.currState = ''; 22 | this.currActionTimescale = 1; 23 | this.animationMap = null; 24 | 25 | fetch('animation_state_map.json') 26 | .then(response => response.json()) 27 | .then(data => { 28 | this.animationMap = data.states; 29 | // modify some clips as needed according to the animation map 30 | for(const state in data.states){ 31 | for(const action in data.states[state]){ 32 | const actionParams = data.states[state][action]; 33 | if(actionParams.loop === 'once'){ 34 | const actionClip = this.mixer.clipAction(this.clips[actionParams.actionName]); 35 | actionClip.paused = false; 36 | actionClip.setLoop(THREE.LoopOnce); 37 | actionClip.clampWhenFinished = true; 38 | } 39 | } 40 | } 41 | }); 42 | } 43 | 44 | toggleObjectVisibility(){ 45 | for(const obj of this.objects){ 46 | obj.visible = !obj.visible; 47 | } 48 | } 49 | 50 | addObject(obj){ 51 | this.objects.push(obj); 52 | } 53 | 54 | setUpdateTimeDivisor(num){ 55 | this.timeDivisor = num; 56 | } 57 | 58 | changeState(newState){ 59 | this.currState = newState; 60 | } 61 | 62 | changeAction(newAction, timeScale=1){ 63 | // if a diff state or timescale is different 64 | if(newAction !== this.currAction || timeScale !== this.currActionTimescale){ 65 | this.playAnimation(newAction, this.clock.getDelta(), timeScale); 66 | } 67 | } 68 | 69 | // for now, keep it specific until I figure out what I'm doing 70 | // https://stackoverflow.com/questions/57255000/how-to-animate-2-objects-with-2-different-animations-one-after-another-in-3-js 71 | // possibly irrelevant but a good read nonetheless: 72 | // https://stackoverflow.com/questions/25417547/observer-pattern-vs-mediator-pattern 73 | // 74 | // note that actionToPlay should be a generic action name like walk or run. 75 | // the real animation clip name is derived below using this.animationMap and 76 | // the current character state (i.e. normal (no weapon), weapon-equipped, etc.) 77 | playAnimation(actionToPlay, time, timeScale){ 78 | if(this.animationMap){ 79 | if(this.animationMap[this.currState][actionToPlay] === undefined){ 80 | return; 81 | } 82 | 83 | this.currActionTimescale = timeScale; 84 | this.mixer.stopAllAction(); 85 | 86 | this.currAction = actionToPlay; 87 | actionToPlay = this.animationMap[this.currState][actionToPlay]['actionName']; 88 | 89 | const action = this.mixer.clipAction(this.clips[actionToPlay]); 90 | 91 | // https://stackoverflow.com/questions/31274674/reverse-keyframe-animation-in-three-js 92 | if(action.time === 0 && timeScale === -1) { 93 | action.time = action.getClip().duration; 94 | } 95 | 96 | action.timeScale = timeScale; 97 | action.play(); 98 | } 99 | } 100 | 101 | // https://discourse.threejs.org/t/animations-looks-different-and-wrong-when-i-play-them-on-three-js/55410/2 102 | update(clockDelta){ 103 | this.mixer.update((clockDelta ? clockDelta : this.clock.getDelta()) / this.timeDivisor); 104 | } 105 | 106 | } 107 | 108 | export { 109 | AnimationController 110 | }; -------------------------------------------------------------------------------- /snowboard/README.md: -------------------------------------------------------------------------------- 1 | # snowboarding 2 | 3 | This demo attempts to implement a snowboarding game without physics (so no colliders, gravity, etc.)! It extends some concepts from character demo and explores some new ones. 4 | 5 | some notes: 6 | - getting the snowboarder to match the angle of incline/decline when on a sloped surface 7 | assume forward vector is always (0, 0, 1) (so looking straight ahead relative to the snowboarder model) and find the angle needed to match the angle of the vector 8 | formed by the point on the slope that's hit by the raycast. 9 | 10 | I think I've sorta tackled this problem as well in a different way in my car demo. 11 | 12 | ![sketch of angle calculation on slope](player-rotation-on-slope.png) 13 | 14 | - jumping logic was a bit tricky 15 | needed to know if player was still in the air by the time "jumping" should've ended (which means 1 full arc via sin()). for this I used another raycast to determine if the player is within a certain distance to be considered "on the ground". 16 | 17 | ![gif of demo](08-10-2023_103831.gif) -------------------------------------------------------------------------------- /snowboard/animation_state_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "states": { 3 | "normal": { 4 | "idle": { 5 | "actionName": "idle", 6 | "loop": "repeat" 7 | }, 8 | "moving": { 9 | "actionName": "moving1", 10 | "loop": "repeat" 11 | }, 12 | "jump": { 13 | "actionName": "jump", 14 | "loop": "once" 15 | }, 16 | "braking": { 17 | "actionName": "braking", 18 | "loop": "repeat" 19 | }, 20 | "turnleft": { 21 | "actionName": "turnleft", 22 | "loop": "repeat" 23 | }, 24 | "turnright": { 25 | "actionName": "turnright", 26 | "loop": "repeat" 27 | }, 28 | "grab": { 29 | "actionName": "grab", 30 | "loop": "repeat" 31 | }, 32 | "tailgrab": { 33 | "actionName": "tailgrab", 34 | "loop": "repeat" 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /snowboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | snowboarding 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 25 | 26 | 27 | 28 |

snowboarding

29 | 30 |
31 |
32 | 33 |
34 | 35 |

press W to move, A and D to turn, spacebar to slow down, J to jump, G or T (while jumping) to do a grab, shift to change camera view

36 | 37 | 38 | 39 | 40 | 42 | -------------------------------------------------------------------------------- /snowboard/player-rotation-on-slope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/snowboard/player-rotation-on-slope.png -------------------------------------------------------------------------------- /split-flap_display/05-11-2024_210722.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/05-11-2024_210722.gif -------------------------------------------------------------------------------- /split-flap_display/README.md: -------------------------------------------------------------------------------- 1 | # split-flap display idea 2 | 3 | This is an implementation of a [split-flap display](https://en.wikipedia.org/wiki/Split-flap_display#) idea I had. 4 | 5 | I'm cheating a bit though in that I only have one animation that rotates the split-flap display about 45 degrees. Running the animation repeatedly though, at least in my opinion, makes it appear that the display is actually rotating all the way around and moving the flaps. Every time the animation ends, I switch the textures of the top and bottom flaps to a new, random letter from the alphabet. 6 | 7 | ![gif demo](05-11-2024_210722.gif) -------------------------------------------------------------------------------- /split-flap_display/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | split-flap display 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 |

split-flap display

28 | 29 |
30 |
31 | 32 |

https://en.wikipedia.org/wiki/Split-flap_display

33 | 34 | 35 | 36 | 37 | 39 | -------------------------------------------------------------------------------- /split-flap_display/letters/a-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/a-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/a-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/a-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/b-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/b-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/b-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/b-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/c-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/c-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/c-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/c-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/d-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/d-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/d-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/d-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/e-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/e-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/e-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/e-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/f-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/f-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/f-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/f-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/g-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/g-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/g-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/g-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/h-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/h-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/h-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/h-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/i-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/i-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/i-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/i-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/j-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/j-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/j-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/j-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/k-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/k-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/k-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/k-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/l-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/l-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/l-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/l-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/m-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/m-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/m-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/m-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/n-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/n-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/n-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/n-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/o-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/o-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/o-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/o-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/p-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/p-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/p-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/p-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/q-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/q-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/q-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/q-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/r-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/r-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/r-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/r-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/s-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/s-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/s-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/s-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/t-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/t-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/t-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/t-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/u-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/u-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/u-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/u-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/v-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/v-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/v-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/v-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/w-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/w-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/w-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/w-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/x-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/x-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/x-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/x-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/y-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/y-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/y-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/y-top.png -------------------------------------------------------------------------------- /split-flap_display/letters/z-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/z-bottom.png -------------------------------------------------------------------------------- /split-flap_display/letters/z-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/letters/z-top.png -------------------------------------------------------------------------------- /split-flap_display/split-flap-idea.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/split-flap_display/split-flap-idea.blend -------------------------------------------------------------------------------- /super_submarine/blender/battleship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/battleship.png -------------------------------------------------------------------------------- /super_submarine/blender/battleship2.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/battleship2.blend -------------------------------------------------------------------------------- /super_submarine/blender/dangerous_capsule-edit.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/dangerous_capsule-edit.blend -------------------------------------------------------------------------------- /super_submarine/blender/jellyfish-animated.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/jellyfish-animated.blend -------------------------------------------------------------------------------- /super_submarine/blender/jellyfish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/jellyfish.png -------------------------------------------------------------------------------- /super_submarine/blender/submarine1.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/submarine1.blend -------------------------------------------------------------------------------- /super_submarine/blender/whale shark mat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/whale shark mat.png -------------------------------------------------------------------------------- /super_submarine/blender/whale-shark-final.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/blender/whale-shark-final.blend -------------------------------------------------------------------------------- /super_submarine/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | super submarine! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 40 | 41 | 42 |
43 |

controls:

44 |

45 | w,a,s,d to move forward, left, backwards and right. 46 | q,e to roll left/right. 47 | up and down arrow to move up and down. 48 | shift to change camera view. 49 | x to turn on a spotlight. 50 |

51 |
52 |
53 |
54 |
55 | 56 | 57 | 58 | 60 | 61 | -------------------------------------------------------------------------------- /super_submarine/notes.txt: -------------------------------------------------------------------------------- 1 | notes: 2 | 3 | You are a submarine tasked with providing underwater reconnaisance for the mother ship! 4 | Survey the ocean floor beneath the mother ship to find and disarm dangerous things, as well as to find and collect potentially useful things! 5 | 6 | Be careful not to hit anything or else your submarine will get damaged. if you get damaged enough, you shall perish. :( 7 | 8 | W = forward 9 | S = backward 10 | A = turn left 11 | D = turn right 12 | Q = spin left 13 | E = spin right 14 | up arrow key = turn upwards 15 | down arrow key = turn downwards 16 | 17 | references: 18 | if imported models are being difficult to orientate a certain way, just put them in a group object: 19 | https://stackoverflow.com/questions/59446956/how-can-i-change-the-position-of-an-imported-model-in-three-js 20 | 21 | Dr. Stemkoski's work is extremely helpful! 22 | https://github.com/stemkoski/stemkoski.github.com/blob/master/Three.js/Chase-Camera.html 23 | http://stemkoski.github.io/Three.js/Chase-Camera.html 24 | 25 | threex keyboard from Jerome Etienne to help with key bindings is super awesome as well 26 | https://github.com/jeromeetienne/threex.keyboardstate 27 | 28 | loading/progress bar 29 | https://stackoverflow.com/questions/35575065/how-to-make-a-loading-screen-in-three-js 30 | 31 | other stuff --------------- 32 | https://stackoverflow.com/questions/38305408/threejs-get-center-of-object 33 | https://stackoverflow.com/questions/11473755/how-to-detect-collision-in-three-js 34 | 35 | interesting idea: 36 | https://gamedev.stackexchange.com/questions/35013/how-to-handle-3d-collisions-using-raycasting-with-a-reflection-vector 37 | 38 | user a height map for terrain? 39 | https://stackoverflow.com/questions/15687678/issue-with-terrain-collision-using-three-js 40 | 41 | keydown firing multiple times (i.e. for key X) even though I press it only once: 42 | https://stackoverflow.com/questions/23386127/keydown-fires-multiple-times-before-keyup 43 | 44 | oooh good resource: 45 | https://threejsfundamentals.org/threejs/lessons/threejs-scenegraph.html 46 | 47 | 48 | to do --------------- 49 | - item collection 50 | - trackball rotation 51 | - rocks, seaweed, animals (i.e. sharks?) 52 | -------------------------------------------------------------------------------- /super_submarine/pictures/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/pictures/screenshot.png -------------------------------------------------------------------------------- /super_submarine/pictures/submarine_demo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/pictures/submarine_demo.webp -------------------------------------------------------------------------------- /super_submarine/pictures/whalesharkmotion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/pictures/whalesharkmotion.png -------------------------------------------------------------------------------- /super_submarine/readme.md: -------------------------------------------------------------------------------- 1 | # super submarine 2 | 3 | You are a submarine tasked with some important objectives! you must disarm a dangerous capsule and recover some things from a sunken ship. 4 | 5 | ## notes: 6 | 7 | 1. rotating an object on a circular path 8 | I wanted to get the whale shark to swim in a circle while adjusting the direction its facing (currently not perfect but I think close enough). 9 | To do this, during each update call I place the whale shark at the origin, rotate it, then place it at the next point along the path. 10 | However, in terms of matrix multiplication, these steps need to be done backwards. 11 | 12 | ![whale shark motion diagram](pictures/whalesharkmotion.png) 13 | 14 | 2. togglable submarine spotlight 15 | Turning on/off the submarine's spotlight (via changing its visible property to true/false) is an expensive operation for rendering and causes some noticeable lag when toggled. -------------------------------------------------------------------------------- /super_submarine/waternormals.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/super_submarine/waternormals.jpg -------------------------------------------------------------------------------- /trumpet/080623-trpt-sample.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/080623-trpt-sample.wav -------------------------------------------------------------------------------- /trumpet/README.md: -------------------------------------------------------------------------------- 1 | # Bb trumpet 2 | 3 | a 3D Bb trumpet! You can move the valves with the 1, 2 and 3 keyboard keys or play a demo that plays notes according to their fingerings. 4 | 5 | I also explored a bit how to get pitch from audio data and borrowed some of [Chris Wilson's code](https://github.com/cwilso/PitchDetect/blob/main/js/pitchdetect.js), which uses a technique called autocorrelation to determine pitch. 6 | 7 | You can try importing audio and see the trumpet fingerings sync with the calculated pitch on playback. A monophonic audio sample will likely work best. I've provided a .wav sample of me playing an excerpt of the main theme for the game "Medal of Honor: Pacific Assault", composed by Christoper Lennertz. Please don't expect too much :) 8 | 9 | ![gif of demo](demo.gif) -------------------------------------------------------------------------------- /trumpet/blender/trumpet.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/blender/trumpet.blend -------------------------------------------------------------------------------- /trumpet/blender/trumpet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/blender/trumpet.png -------------------------------------------------------------------------------- /trumpet/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/demo.gif -------------------------------------------------------------------------------- /trumpet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Bb trumpet 5 | 6 | 7 | 8 | 9 | 10 | 31 | 32 | 33 | 34 |
35 |

a Bb trumpet

36 |

use keys 1, 2 and 3 on the keyboard to move the valves of the trumpet! then press 'shift' to play a note that corresponds with the current fingering.

37 |

in this demo I'm using shape keys/morph targets to make the valves 'move'.

38 |
39 | 40 |
41 |
42 | 43 |

44 | 45 | 46 | 50 | 51 | 56 | 57 | 58 | 59 |
60 | 61 | 62 | 63 | 64 |

65 |
66 | 67 | 68 | 70 | -------------------------------------------------------------------------------- /trumpet/notes/a4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/a4.ogg -------------------------------------------------------------------------------- /trumpet/notes/a5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/a5.ogg -------------------------------------------------------------------------------- /trumpet/notes/b4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/b4.ogg -------------------------------------------------------------------------------- /trumpet/notes/b5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/b5.ogg -------------------------------------------------------------------------------- /trumpet/notes/bb4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/bb4.ogg -------------------------------------------------------------------------------- /trumpet/notes/bb5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/bb5.ogg -------------------------------------------------------------------------------- /trumpet/notes/c4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/c4.ogg -------------------------------------------------------------------------------- /trumpet/notes/c5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/c5.ogg -------------------------------------------------------------------------------- /trumpet/notes/c6.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/c6.ogg -------------------------------------------------------------------------------- /trumpet/notes/cs4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/cs4.ogg -------------------------------------------------------------------------------- /trumpet/notes/cs5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/cs5.ogg -------------------------------------------------------------------------------- /trumpet/notes/d4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/d4.ogg -------------------------------------------------------------------------------- /trumpet/notes/d5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/d5.ogg -------------------------------------------------------------------------------- /trumpet/notes/ds4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/ds4.ogg -------------------------------------------------------------------------------- /trumpet/notes/ds5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/ds5.ogg -------------------------------------------------------------------------------- /trumpet/notes/e4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/e4.ogg -------------------------------------------------------------------------------- /trumpet/notes/e5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/e5.ogg -------------------------------------------------------------------------------- /trumpet/notes/f4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/f4.ogg -------------------------------------------------------------------------------- /trumpet/notes/f5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/f5.ogg -------------------------------------------------------------------------------- /trumpet/notes/fs4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/fs4.ogg -------------------------------------------------------------------------------- /trumpet/notes/fs5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/fs5.ogg -------------------------------------------------------------------------------- /trumpet/notes/g4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/g4.ogg -------------------------------------------------------------------------------- /trumpet/notes/g5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/g5.ogg -------------------------------------------------------------------------------- /trumpet/notes/gs4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/gs4.ogg -------------------------------------------------------------------------------- /trumpet/notes/gs5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/trumpet/notes/gs5.ogg -------------------------------------------------------------------------------- /trumpet/todo.txt: -------------------------------------------------------------------------------- 1 | TODO: 2 | - add ability to play note on keypress with given valve combo + given octave 3 | - more piece ideas 4 | - add a mouthpiece 5 | - C trumpet? different finishes? -------------------------------------------------------------------------------- /vending_machine/11-02-2022_193916.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/11-02-2022_193916.webp -------------------------------------------------------------------------------- /vending_machine/29-08-2021_103845.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/29-08-2021_103845.gif -------------------------------------------------------------------------------- /vending_machine/blender-notes.txt: -------------------------------------------------------------------------------- 1 | blender notes 2 | 3 | vending machine coil/spring thingy 4 | https://blender.stackexchange.com/questions/21710/coil-mechanism-for-vending-machine 5 | https://blender.stackexchange.com/questions/15923/duplicated-objects-copy-animation 6 | 7 | 8 | for neon glow effects with three.js: 9 | https://stackoverflow.com/questions/54915037/how-to-make-a-line-or-curve-emit-light-with-three-js 10 | https://www.reddit.com/r/threejs/comments/76rsju/unreal_bloom_pass/ 11 | https://stackoverflow.com/questions/69142975/threejs-selective-bloom-disable-bloom-for-scene-background 12 | https://discourse.threejs.org/t/how-to-use-bloom-effect-not-for-all-object-in-scene/24244/13 13 | https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_unreal_bloom_selective.html -------------------------------------------------------------------------------- /vending_machine/blender/1-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/1-key.png -------------------------------------------------------------------------------- /vending_machine/blender/2-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/2-key.png -------------------------------------------------------------------------------- /vending_machine/blender/3-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/3-key.png -------------------------------------------------------------------------------- /vending_machine/blender/A-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/A-key.png -------------------------------------------------------------------------------- /vending_machine/blender/B-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/B-key.png -------------------------------------------------------------------------------- /vending_machine/blender/C-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/C-key.png -------------------------------------------------------------------------------- /vending_machine/blender/D-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/D-key.png -------------------------------------------------------------------------------- /vending_machine/blender/E-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/E-key.png -------------------------------------------------------------------------------- /vending_machine/blender/vending-machine-front-panel-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/vending-machine-front-panel-1.png -------------------------------------------------------------------------------- /vending_machine/blender/vending-machine-front-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/vending-machine-front-panel.png -------------------------------------------------------------------------------- /vending_machine/blender/vending-machine-left-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/vending-machine-left-panel.png -------------------------------------------------------------------------------- /vending_machine/blender/vending-machine-right-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/vending-machine-right-panel.png -------------------------------------------------------------------------------- /vending_machine/blender/vending-machine.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syncopika/threejs-projects/92a4a4db278b14396136eb50a5932acfa38dc048/vending_machine/blender/vending-machine.blend -------------------------------------------------------------------------------- /vending_machine/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | vending machine 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 46 | 47 | 48 |

a vending machine :)

49 | 50 |
51 |
52 | 53 |
54 | 55 | 56 | 57 |

controls:

58 |

click on the black buttons on the right side of the machine to get an item. note that an item corresponds to a code of 1 letter and 1 number (e.g. 'A1').

59 |

use the mouse clickwheel to zoom in and out.

60 |

you can click on the item when it's in the drop area!

61 |
62 | 63 | 64 | 66 | -------------------------------------------------------------------------------- /vending_machine/readme.md: -------------------------------------------------------------------------------- 1 | # vending-machine 2 | 3 | a vending machine that has clickable buttons! :D 4 | not super exciting but included in this demo is an example of using fonts/creating text with three.js (and more animation!), 5 | as well as using a Bloom effect shader for a "neon glow" effect. 6 | 7 | ![vending machine neon glow](11-02-2022_193916.webp) 8 | ![vending machine](29-08-2021_103845.gif) --------------------------------------------------------------------------------