Threejs 让宝可梦随着页面滚动而变换位置
先预览一下最终效果:
已关注
Follow
Replay
Like
前端程序设计
Added to Top Stories
视频卡顿,建议切换到自动
已成功切换至自动模式
时长
00:37
0 / 0
当前播放进度00:00
时长00:37
转载
Threejs 让宝可梦随着页面滚动而变换位置
前端程序设计
Added to Top Stories
进度00:00
时长00:37
时长00:37
全屏
倍速播放中
继续观看
Threejs 让宝可梦随着页面滚动而变换位置
制作方法类似前面的这篇,这次做了更多的优化处理。
引入的js库:
代码总共分3个模块:建立场景、加载模型、制作动画。
2.1 代码前期准备:
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
2.2 建立场景类:
class Scene {
constructor(model) {
_defineProperty(this, "render",
() =>
{
for (var ii = 0; ii < this.views.length; ++ii) {
var view = this.views[ii];
var camera = view.camera;
var bottom = Math.floor(this.h * view.bottom);
var height = Math.floor(this.h * view.height);
this.renderer.setViewport(0, 0, this.w, this.h);
this.renderer.setScissor(0, bottom, this.w, height);
this.renderer.setScissorTest(true);
camera.aspect = this.w / this.h;
this.renderer.render(this.scene, camera);
}
});
_defineProperty(this, "onResize",
() =>{
this.w = window.innerWidth;
this.h = window.innerHeight;
for (var ii = 0; ii < this.views.length; ++ii) {
var view = this.views[ii];
var camera = view.camera;
camera.aspect = this.w / this.h;
let camZ = (screen.width - this.w * 1) / 3;
camera.position.z = camZ < 180 ? 180 : camZ;
camera.updateProjectionMatrix();
}
this.renderer.setSize(this.w, this.h);
this.render();
});
this.views = [{
bottom: 0,
height: 1
},
{
bottom: 0,
height: 0
}];
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(this.renderer.domElement); // scene
this.scene = new THREE.Scene();
for (var _ii = 0; _ii < this.views.length; ++_ii) {
var _view = this.views[_ii];
var _camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
_camera.position.fromArray([0, 0, 180]);
_camera.layers.disableAll();
_camera.layers.enable(_ii);
_view.camera = _camera;
_camera.lookAt(new THREE.Vector3(0, 5, 0));
} //light
// this.light = new THREE.PointLight(0xffffff, 0.75);
// this.light.position.z = 150;
// this.light.position.x = 70;
// this.light.position.y = -20;
// this.scene.add(this.light);
// this.softLight = new THREE.AmbientLight(0xffffff, 1.5);
// this.scene.add(this.softLight); // group
this.light = new THREE.AmbientLight( new THREE.Color(0xababab)); // soft white light
this.light.position.set(0,68,0);
this.scene.add( this.light );
this.dirLight = new THREE.DirectionalLight(new THREE.Color(0xababab));
this.dirLight.position.set(-19.354,66.112,38.46);
this.scene.add(this.dirLight);
this.onResize();
window.addEventListener('resize', this.onResize, false);
console.log(model.children[0])
var edges = new THREE.EdgesGeometry(model.children[0].geometry);
let line = new THREE.LineSegments(edges);
line.material.depthTest = false;
line.material.opacity = 0.5;
line.material.transparent = true;
line.position.x = 0.5;
line.position.z = -1;
line.position.y = 0.2;
this.modelGroup = new THREE.Group();
model.layers.set(0);
line.layers.set(1);
this.modelGroup.add(model);
this.modelGroup.add(line);
this.scene.add(this.modelGroup);
}
}
2.3 加载obj模型:
function loadModel() {
gsap.registerPlugin(ScrollTrigger);
var object;
function onModelLoaded() {
object.traverse(function(child) {
let mat = new THREE.MeshPhongMaterial({
color: 0xff0000,
specular: 0xD0CBC7,
shininess: 5,
flatShading: true
});
// child.material = mat;
});
setupAnimation(object);
}
var manager = new THREE.LoadingManager(onModelLoaded);
manager.onProgress = (item, loaded, total) => console.log(item, loaded, total);
var loader = new THREE.OBJLoader(manager);
loader.load('2.obj',
function(obj) {
object = obj;
});
const mtlLoader = new THREE.MTLLoader();
mtlLoader.load('2.mtl', (materials) => {
console.log(materials)
materials.preload();
loader.setMaterials(materials);
})
}
2.4 制作动画
function setupAnimation(model) {
let scene = new Scene(model);
let plane = scene.modelGroup;
//初始化位置
{
x: "50%",
autoAlpha: 0
},
{
duration: 1,
x: "0%",
autoAlpha: 1
});
{
autoAlpha: 0
});
{
opacity: 1
});
{
autoAlpha: 1
});
let tau = Math.PI * 2;
{
y: tau * -.5
});
{
x: -10,
y: -12,
z: 80
});
scene.render();
var sectionDuration = 1;
{
height: 1,
bottom: 0
},
{
height: 0,
bottom: 1,
ease: 'none',
scrollTrigger: {
trigger: ".blueprint",
scrub: true,
start: "bottom bottom",
end: "bottom top"
}
});
{
height: 0,
bottom: 0
},
{
height: 1,
bottom: 0,
ease: 'none',
scrollTrigger: {
trigger: ".blueprint",
scrub: true,
start: "top bottom",
end: "top top"
}
});
{
y: "30%",
scrollTrigger: {
trigger: ".ground-container",
scrub: true,
start: "top bottom",
end: "bottom top"
}
});
{
y: "25%",
scrollTrigger: {
trigger: ".ground-container",
scrub: true,
start: "top bottom",
end: "bottom top"
}
});
{
drawSVG: 100,
scrollTrigger: {
trigger: ".length",
scrub: true,
start: "top bottom",
end: "top top"
}
});
{
drawSVG: 100,
scrollTrigger: {
trigger: ".wingspan",
scrub: true,
start: "top 25%",
end: "bottom 50%"
}
});
{
drawSVG: 100,
scrollTrigger: {
trigger: ".phalange",
scrub: true,
start: "top 50%",
end: "bottom 100%"
}
});
{
opacity: 0,
drawSVG: 0,
scrollTrigger: {
trigger: ".length",
scrub: true,
start: "top top",
end: "bottom top"
}
});
{
opacity: 0,
drawSVG: 0,
scrollTrigger: {
trigger: ".wingspan",
scrub: true,
start: "top top",
end: "bottom top"
}
});
{
opacity: 0,
drawSVG: 0,
scrollTrigger: {
trigger: ".phalange",
scrub: true,
start: "top top",
end: "bottom top"
}
});
let tl = new gsap.timeline({
onUpdate: scene.render,
scrollTrigger: {
trigger: ".content",
scrub: true,
start: "top top",
end: "bottom bottom"
},
defaults: {
duration: sectionDuration,
ease: 'power2.inOut'
}
});
let delay = 0;
{
duration: 0.25,
opacity: 0
},
delay);
{
x: -10,
ease: 'power1.in'
},
delay);
delay += sectionDuration;
//1
{
x: tau * .25,
y: 0,
z: -tau * 0.05,
ease: 'power1.inOut'
},
delay);
{
x: -40,
y: 0,
z: -60,
ease: 'power1.inOut'
},
delay);
delay += sectionDuration;
//2
{
x: tau * .25,
y: 0,
z: tau * 0.05,
ease: 'power3.inOut'
},
delay);
{
x: 40,
y: 0,
z: -60,
ease: 'power2.inOut'
},
delay);
delay += sectionDuration;
//3
{
x: tau * .2,
y: 0,
z: -tau * 0.1,
ease: 'power3.inOut'
},
delay);
{
x: -40,
y: 0,
z: -30,
ease: 'power2.inOut'
},
delay);
delay += sectionDuration;
//4
{
x: 0,
z: 0,
y: tau * .25
},
delay);
{
x: 0,
y: -10,
z: 50
},
delay);
delay += sectionDuration;
delay += sectionDuration;
//5
{
x: tau * 0.25,
y: tau * .5,
z: 0,
ease: 'power4.inOut'
},
delay);
{
z: 30,
ease: 'power4.inOut'
},
delay);
delay += sectionDuration;
//6
{
x: tau * 0.25,
y: tau * .5,
z: 0,
ease: 'power4.inOut'
},
delay);
{
z: 60,
x: 30,
ease: 'power4.inOut'
},
delay);
delay += sectionDuration;
//7
{
x: tau * 0.35,
y: tau * .75,
z: tau * 0.6,
ease: 'power4.inOut'
},
delay);
{
z: 100,
x: 20,
y: 0,
ease: 'power4.inOut'
},
delay);
delay += sectionDuration;
//8
{
x: tau * 0.15,
y: tau * .85,
z: -tau * 0,
ease: 'power1.in'
},
delay);
{
z: -150,
x: 0,
y: 0,
ease: 'power1.inOut'
},
delay);
delay += sectionDuration;
//9
{
duration: sectionDuration,
x: -tau * 0.5,
y: -tau * 0.5,
z: -tau * 0.1,
ease: 'none'
},
delay);
{
duration: sectionDuration,
x: 0,
y: 30,
z: 320,
ease: 'power1.in'
},
delay);
{
duration: sectionDuration,
x: 0,
y: 0,
z: 0
},
delay);
}
下一篇要给这些小可爱加入动力学的碰撞。