Model from free3d.com. Use the arrow keys to move the camera.
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
overflow: hidden;
}
#loading {
font-family: "Helvetica Neue", sans-serif;
position: absolute;
text-align: center;
top: 33%;
width: 100%;
}
</style>
</head>
<body>
<div id="stats"></div>
<div id="scene"></div>
<div id="loading">Loading plant (<span class="percent"></span>%)</div>
<script src="https://unpkg.com/three@0.106.2/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.106.2/examples/js/libs/stats.min.js"></script>
<script src="https://unpkg.com/three@0.106.2/examples/js/libs/dat.gui.min.js"></script>
<script src="https://unpkg.com/three@0.106.2/examples/js/loaders/OBJLoader.js"></script>
<script src="https://unpkg.com/geometric@1.3.4/build/geometric.min.js"></script>
<script>
const controls = { rotate: false };
const gui = (_ => {
const gui = new dat.GUI();
gui.add(controls, "rotate");
return gui;
})();
let left = 0, right = 0, up = 0, down = 0;
addEventListener("keydown", e => {
switch (e.key) {
case "ArrowLeft":
left = 1;
e.preventDefault();
break;
case "ArrowRight":
right = 1;
e.preventDefault();
break;
case "ArrowUp":
up = 1;
e.preventDefault();
break;
case "ArrowDown":
down = 1;
e.preventDefault();
break;
}
});
addEventListener("keyup", e => {
switch (e.key) {
case "ArrowLeft":
left = 0;
e.preventDefault();
break;
case "ArrowRight":
right = 0;
e.preventDefault();
break;
case "ArrowUp":
up = 0;
e.preventDefault();
break;
case "ArrowDown":
down = 0;
e.preventDefault();
break;
}
});
const stats = (_ => {
const stats = new Stats();
stats.domElement.style.position = "absolute";
stats.domElement.style.left = "0px";
stats.domElement.style.top = "0px";
document.getElementById("stats").appendChild(stats.domElement);
return stats;
})();
const scene = (_ => {
const scene = new THREE.Scene();
scene.fog = new THREE.Fog("#eee", 0.010, 125);
return scene;
})();
const camera = (_ => {
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 1000);
camera.position.set(-30, 15, 0);
camera.lookAt(0, 5, 0);
return camera;
})();
const renderer = (_ => {
const renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#fff");
renderer.setPixelRatio(devicePixelRatio);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = 2;
document.getElementById("scene").appendChild(renderer.domElement);
return renderer;
})();
const plane = (_ => {
const geom = new THREE.PlaneBufferGeometry(33, 33);
const matl = new THREE.MeshLambertMaterial({ color: "#eee" });
const plane = new THREE.Mesh(geom, matl);
plane.rotation.x = -0.5 * Math.PI;
plane.receiveShadow = true;
scene.add(plane);
return plane;
})();
const ambientLight = (_ => {
const light = new THREE.AmbientLight("#000");
scene.add(light);
return light;
})();
const pointLight = (_ => {
const light = new THREE.PointLight("#e0e5cd", 0.4);
light.position.set(0, 50, 0);
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
scene.add(light);
return light;
})();
const spotLight = (_ => {
const light = new THREE.SpotLight("#fff", 1);
light.angle = Math.PI / 8;
light.position.set(-20, 50, 20);
light.castShadow = true;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
scene.add(light);
return light;
})();
const loader = (_ => {
const loader = new THREE.OBJLoader();
loader.load(
"01Alocasia_obj.obj",
object => {
const element = document.getElementById("loading");
element.parentNode.removeChild(element);
object.name = "plant";
object.rotation.y = 5
object.position.set(0, 0, 0);
object.scale.set(0.01, 0.01, 0.01);
object.children.forEach(child => {
if (child.name === "Pot") {
child.material = new THREE.MeshStandardMaterial({
color: "#ffe685",
metalness: .5,
roughness: .5
});
}
if (child.name.includes("Dirt")){
child.material.color = new THREE.Color("#877050");
}
if (child.name === "stem" || child.name.includes("Leaf") || child.name.includes("leaf") || child.name.includes("lef")){
child.material.color = new THREE.Color("#5a793a");
}
if (child.name === "Moh"){
child.material.color = new THREE.Color("#b7ad8f");
}
child.castShadow = true;
child.receiveShadow = true;
});
scene.add(object);
},
xhr => {
document.querySelector(".percent").innerHTML = (xhr.loaded / xhr.total * 100).toFixed(1);
},
err => {
console.log("Error:", err);
}
);
return loader;
})();
function getPlant(){
return scene.getObjectByName("plant", true);
}
function animate(){
requestAnimationFrame(animate);
stats.update();
if (getPlant() && controls.rotate){
getPlant().rotation.y += 0.01;
}
if (left){
[camera.position.x, camera.position.z] = geometric.pointRotate([camera.position.x, camera.position.z], 0.575);
camera.lookAt(0, 5, 0);
}
if (right){
[camera.position.x, camera.position.z] = geometric.pointRotate([camera.position.x, camera.position.z], -0.575);
camera.lookAt(0, 5, 0);
}
if (up){
camera.position.y += 0.575;
camera.lookAt(0, 5, 0);
}
if (down && camera.position.y >= 0.2){
camera.position.y -= 0.575;
camera.lookAt(0, 5, 0);
}
renderer.render(scene, camera);
}
animate();
function resize(){
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
resize();
onresize = resize;
</script>
</body>
</html>