const canvas = document.querySelector('.webgl');
const degreesToRadians = (degrees) => {
return degrees * (Math.PI / 180)
}
const random = (min, max, float = false) => {
const val = Math.random() * (max - min) + min
if (float) {
return val
}
return Math.floor(val)
}
// 화면 설정
const scene = new THREE.Scene();
// 렌더러 설정
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);
renderer.setSize(window.innerWidth, window.innerHeight);
// 카메라 설정
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5
scene.add(camera);
// 메쉬 설정
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0xffffff });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = degreesToRadians(30)
mesh.rotation.y = degreesToRadians(30)
// scene.add(mesh);
// 조명 설정
const lightDirectional = new THREE.DirectionalLight(0xffffff, 1);
lightDirectional.position.set(5, 5, 5)
scene.add(lightDirectional);
const lightAmbient = new THREE.AmbientLight(0x9eaeff, 0.2)
scene.add(lightAmbient)
// Figure
class Figure {
constructor(params) {
this.params = {
x: 0,
y: 0,
z: 0,
ry: 0,
...params
}
this.group = new THREE.Group();
this.group.rotation.y = degreesToRadians(20)
scene.add(this.group);
this.group.position.x = this.params.x
this.group.position.y = this.params.y
this.group.position.z = this.params.z
this.headHue = random(0, 360)
this.bodyHue = random(0, 360)
this.headLightness = random(40, 65)
this.headMaterial = new THREE.MeshLambertMaterial({ color: `hsl(${this.headHue}, 30%, ${this.headLightness}%)` })
this.bodyMaterial = new THREE.MeshLambertMaterial({ color: `hsl(${this.bodyHue}, 85%, 50%)` })
this.arms = []
}
createBody() {
this.body = new THREE.Group()
const geometry = new THREE.BoxGeometry(1, 1.5, 1)
const bodyMain = new THREE.Mesh(geometry, this.bodyMaterial)
this.body.add(bodyMain)
this.group.add(this.body)
this.createLegs()
}
createHead() {
this.head = new THREE.Group()
const geometry = new THREE.BoxGeometry(1.4, 1.4, 1.4)
const headMain = new THREE.Mesh(geometry, material)
this.head.add(headMain)
this.group.add(this.head);
this.head.position.y = 1.65;
this.createEyes()
}
createArms() {
const height = 0.85
for(let i = 0; i < 2; i++) {
const armGroup = new THREE.Group()
const geometry = new THREE.BoxGeometry(0.25, height, 0.25)
const arm = new THREE.Mesh(geometry, material)
const m = i % 2 === 0 ? 1 : -1
armGroup.add(arm)
this.body.add(armGroup)
arm.position.y = height * -0.5
armGroup.position.x = m * 0.8
armGroup.position.y = 0.6
armGroup.rotation.z = degreesToRadians(30 * m)
this.arms.push(armGroup)
}
}
createEyes() {
const eyes = new THREE.Group()
const geometry = new THREE.SphereGeometry(0.15, 12, 8)
// Define the eye material
const material = new THREE.MeshLambertMaterial({ color: 0x44445c })
for(let i = 0; i < 2; i++) {
const eye = new THREE.Mesh(geometry, material)
const m = i % 2 === 0 ? 1 : -1
// Add the eye to the group
eyes.add(eye)
// Position the eye
eye.position.x = 0.36 * m
}
this.head.add(eyes)
eyes.position.z = 0.7
}
createLegs() {
const legs = new THREE.Group()
const geometry = new THREE.BoxGeometry(0.25, 0.4, 0.25)
for(let i = 0; i < 2; i++) {
const leg = new THREE.Mesh(geometry, material)
const m = i % 2 === 0 ? 1 : -1
legs.add(leg)
leg.position.x = m * 0.22
}
this.group.add(legs)
legs.position.y = -1.15
this.body.add(legs)
}
bounce() {
this.group.rotation.y = this.params.ry
this.group.position.y = this.params.y
this.arms.forEach((arm, index) => {
const m = index % 2 === 0 ? 1 : -1
arm.rotation.z = this.params.armRotation * m
})
}
init() {
this.createHead();
this.createBody();
this.createArms();
this.createEyes();
this.createLegs();
}
}
const figure = new Figure()
figure.init();
gsap.set(figure.params, {
y: -1.5
})
gsap.to(figure.params, {
ry: degreesToRadians(360),
repeat: -1,
duration: 20
})
gsap.to(figure.params, {
y: 0,
armRotation: degreesToRadians(90),
repeat: -1,
yoyo: true,
duration: 0.5
})
gsap.ticker.add(() => {
figure.bounce()
render()
})
// 애니메이션 설정
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
// 화면 사이즈 설정
function resize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', resize);