"use strict"; /* globals THREE, $, TweenLite, Power3, TimelineMax */ var camera = undefined, scene = undefined, renderer = undefined; var plane = undefined; var raycaster = new THREE.Raycaster(); var normalizedMouse = { x: 0, y: -180 }; // let lightBlue = { // r: 34, // g: 183, // b: 236 // }; var darkBlue = { r: 0, g: 52, b: 74 }; var baseColorRGB = darkBlue; var baseColor = "rgb(" + baseColorRGB.r + "," + baseColorRGB.g + "," + baseColorRGB.b + ")"; var nearStars = undefined, farStars = undefined, farthestStars = undefined; function init() { scene = new THREE.Scene(); // 远景相机(PerspectiveCamera) 第一个参数 相机视锥体垂直视角,从下到上的观察角度。但好像跟观察事物大小也有关 // 最后两个是构成可视范围的近远值 超过这两个范围的 都不会渲染出来 也就是不会显示 camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.1, 1000); renderer = new THREE.WebGLRenderer(); // Canvas渲染器(CanvasRenderer) // Scene initialization camera.position.z = 50; //镜头Z轴高度 renderer.setClearColor("#121212", 1.0); //这个颜色看不出有啥用 renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); //屏幕分辨率 document.body.appendChild(renderer.domElement); // Lights //灯光 因为是立体模型 所有上下两个灯光 显得透亮些 var topLight = new THREE.DirectionalLight(0xffffff, 1); topLight.position.set(0, 1, 1).normalize(); scene.add(topLight); var bottomLight = new THREE.DirectionalLight(0xffffff, 0.4); bottomLight.position.set(1, -1, 1).normalize(); scene.add(bottomLight); //天空的灯光 真是没看出有什么用 var skyLightRight = new THREE.DirectionalLight(0x666666, 0.2); skyLightRight.position.set(-1, -1, 0.2).normalize(); scene.add(skyLightRight); var skyLightCenter = new THREE.DirectionalLight(0x666666, 0.2); skyLightCenter.position.set(-0, -1, 0.2).normalize(); scene.add(skyLightCenter); var skyLightLeft = new THREE.DirectionalLight(0x666666, 0.2); skyLightLeft.position.set(1, -1, 0.2).normalize(); scene.add(skyLightLeft); // Mesh creation var geometry = new THREE.PlaneGeometry(400, 400, 70, 70); //平面模型(PlaneGeometry) 后面两个70 是平面创造多少个截面 //Phong网孔材料(MeshPhongMaterial) - 用于表面有光泽的材料 比如金属 var darkBlueMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, shading: THREE.FlatShading, //定义着色类型 THREE.SmoothShading 带有过渡的着色接近真实 THREE.FlatShading 平面着色,也称之为“恒量着色” 也就是颜色没有过渡 side: THREE.DoubleSide, //这些常量用来定义几何体哪些面需要应用材料。注意3D空间一个表面有内外两边,默认情况下是THREE.FrontSide(前外面)。 vertexColors: THREE.FaceColors //就是上色 不过点和面区别不大 //THREE.FaceColors:顶点使用面的颜色 //THREE.VertexColors:顶点使用顶点的颜色。 //THREE.NoColors:顶点没有颜色 }); //vertices 是这个几何模型里所有点的数组 上面最后两个参数就是分段 这样交叉就会有点 geometry.vertices.forEach(function(vertice) { //console.log(geometry.vertices); vertice.x += (Math.random() - 0.5) * 4; //移动这个点的坐标 vertice.y += (Math.random() - 0.5) * 4; vertice.z += (Math.random() - 0.5) * 4; vertice.dx = Math.random() - 0.5; //后面这几个都是自定义的 vertice.dy = Math.random() - 0.5; vertice.randomDelay = Math.random() * 5; //随机延迟 好像上面的摆动的延迟 }); //console.log( geometry.vertices.length); //geometry.faces 三角面数组 for (var i = 0; i < geometry.faces.length; i++) { geometry.faces[i].color.setStyle(baseColor); //给面上色 这个如果没有就是白色 geometry.faces[i].baseColor = baseColorRGB; //这个没有就彻底黑了//这个可能是自定义的吧 //看下面函数 这个真是自定义的 } plane = new THREE.Mesh(geometry, darkBlueMaterial); //网孔(Mesh 几何模型(Geometry). //材料(Material) (optional). scene.add(plane); // Create stars //创建星星 函数在下面 farthestStars = createStars(1200, 420, "#0952BD"); //第一个是个数,第二个是y坐标,第三个是颜色 farStars = createStars(1200, 370, "#A5BFF0"); nearStars = createStars(1200, 290, "#118CD6"); scene.add(farthestStars); scene.add(farStars); scene.add(nearStars); //这是自转效果,会使得星星有点眨眼睛的效果 farStars.rotation.x = 0.25; nearStars.rotation.x = 0.25; //自己玩的盒子 // var geometry = new THREE.BoxGeometry( 100, 100, 100 ); // //这么写移动有点笨,上面这么写是为了做成波浪效果 // // geometry.vertices.forEach(function(vertice) { // // vertice.z += 100; // // vertice.y += 200; // // }); // geometry.translate (0,200,100); //对应的是mesh.position // geometry.rotateY(20); //根据文档这个函数操作的就是对象mesh的 .rotation // var material = new THREE.MeshPhongMaterial( { color: 0xffff00 } ); // var mesh = new THREE.Mesh( geometry, material ); // //mesh.rotation.y = 0.6; //效果一直这两个 // // mesh.rotateY(6); // mesh.position.y = 50; //喔 他现在改变的量 是基于上面模型的位置坐标系 // scene.add( mesh ); // Uncomment for testing second camera position // camera.rotation.x = Math.PI / 2; // camera.position.y = -0; // camera.position.z = 20; // plane.scale.x = 2; } function createStars(amount, yDistance,color="0x000000") { //这... 可以定义默认值啊 为啥多此一举 不懂 //var color = arguments.length <= 2 || arguments[2] === undefined ? "0x000000" : arguments[2]; //默认颜色 js不能参数定义么 var opacity = Math.random(); var starGeometry = new THREE.Geometry(); //几何模型 var starMaterial = new THREE.PointsMaterial({ //点材料 color: color, opacity: opacity }); for (var i = 0; i < amount; i++) { var vertex = new THREE.Vector3(); vertex.z = (Math.random() - 0.5) * 1500; vertex.y = yDistance; vertex.x = (Math.random() - 0.5) * 2000; // 固定y值这样就是个扁平的面 调整z可以发现 数值小 离远了 就能看出是在一条直线上 离近了则出现高低 这是因为摄像机有角度 // vertex.z = (Math.random() - 0.5) * 1500; // vertex.y = 20; // vertex.x = (Math.random() - 0.5) * 1500; starGeometry.vertices.push(vertex); } return new THREE.Points(starGeometry, starMaterial); } var timer = 0; function render() { //这是html自带函数 不断刷新动画 详细介绍 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame requestAnimationFrame(render); //console.log(Math.sin(timer + 5) / 40 * (Math.random() - 0.5));// 这是正负值都有的 //Math.random() 在0~1之间的值 timer += 0.01; var vertices = plane.geometry.vertices; //改变点的位置 使面不停移动 做出动态效果 Math.sin(x) x 的正玄值。返回值在 -1.0 到 1.0 之间; for (var i = 0; i < vertices.length; i++) { // Ease back to original vertice position while still maintaining sine wave // 这应该是个公式 是个正弦波动 就是平面动态波纹的感觉 就是Ease那个动态感觉 下面也有 只不过好像没法来对点作用 vertices[i].x -= Math.sin(timer + vertices[i].randomDelay) / 40 * vertices[i].dx; //向左移动 vertices[i].y += Math.sin(timer + vertices[i].randomDelay) / 40 * vertices[i].dy; //像上移动 // ((vertices[i].x - vertices[i].originalPosition.x) * 0.1) + } // Determine where ray is being projected from camera view 确定从相机视图中投射光线的位置 (不懂这个有啥用) raycaster.setFromCamera(normalizedMouse, camera); //光线投射器(Raycaster) arg1 鼠标的二维坐标 arg2 射线起点处的相机,即把射线起点设置在该相机位置处。 // Send objects being intersected into a variable var intersects = raycaster.intersectObjects([plane]); //这段好像就是 鼠标跟随改变每个面的颜色 if (intersects.length > 0) { (function() { var faceBaseColor = intersects[0].face.baseColor; //被鼠标改变颜色后恢复原本颜色 plane.geometry.faces.forEach(function(face) { face.color.r *= 255; face.color.g *= 255; face.color.b *= 255; face.color.r += (faceBaseColor.r - face.color.r) * 0.01; face.color.g += (faceBaseColor.g - face.color.g) * 0.01; face.color.b += (faceBaseColor.b - face.color.b) * 0.01; var rInt = Math.floor(face.color.r); var gInt = Math.floor(face.color.g); var bInt = Math.floor(face.color.b); var newBasecol = "rgb(" + rInt + "," + gInt + "," + bInt + ")"; face.color.setStyle(newBasecol); }); //更新颜色 plane.geometry.colorsNeedUpdate = true; intersects[0].face.color.setStyle("#006ea0"); //最初那块颜色//这应该鼠标所指那个面吧 plane.geometry.colorsNeedUpdate = true; })(); } plane.geometry.verticesNeedUpdate = true; //更新点 plane.geometry.elementsNeedUpdate = true; //更新面 farthestStars.rotation.y -= 0.00001; //哦 是向左转 不过因为是面 但视角关系 看远方是向右走 farStars.rotation.y -= 0.00005; nearStars.rotation.y -= 0.00011; renderer.render(scene, camera); } init(); window.addEventListener("resize", function() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); //监听鼠标位置 window.addEventListener("mousemove", function(event) { // Normalize mouse coordinates normalizedMouse.x = event.clientX / window.innerWidth * 2 - 1; normalizedMouse.y = -(event.clientY / window.innerHeight) * 2 + 1; //y是负的 可能是因为坐标系不同吧 }); var introContainer = $('.intro-container'); var skyContainer = $('.sky-container'); var xMark = $('.x-mark'); $('.shift-camera-button').click(function() { var introTimeline = new TimelineMax(); introTimeline.add([TweenLite.fromTo(introContainer, 0.5, { opacity: 1 //透明度 转动镜头后把原本的层隐藏掉 否则都会显示 }, { opacity: 0, ease: Power3.easeIn }), TweenLite.to(camera.rotation, 3, { //to()的参数 1:对象,2:动画完成时间,3:参数(这是前面对象的参数) //转动镜头 x: Math.PI / 2, ease: Power3.easeInOut }), TweenLite.to(camera.position, 2.5, { z: 20, ease: Power3.easeInOut }), TweenLite.to(camera.position, 3, { y: 120, ease: Power3.easeInOut }), TweenLite.to(plane.scale, 3, { x: 2, ease: Power3.easeInOut })]); introTimeline.add([TweenLite.to(xMark, 0.5, { opacity: 1, ease: Power3.easeInOut }), TweenLite.to(skyContainer, 2, { opacity: 1, ease: Power3.easeInOut })]); }); //更上面一样了 也是转换镜头 $('.x-mark').click(function() { var outroTimeline = new TimelineMax(); outroTimeline.add([TweenLite.to(xMark, 0.5, { opacity: 0, ease: Power3.easeInOut }), TweenLite.to(skyContainer, 0.5, { opacity: 0, ease: Power3.easeInOut }), TweenLite.to(camera.rotation, 3, { x: 0, ease: Power3.easeInOut }), TweenLite.to(camera.position, 3, { z: 50, ease: Power3.easeInOut }), TweenLite.to(camera.position, 2.5, { y: 0, ease: Power3.easeInOut }), TweenLite.to(plane.scale, 3, { x: 1, ease: Power3.easeInOut })]); outroTimeline.add([TweenLite.to(introContainer, 0.5, { opacity: 1, ease: Power3.easeIn })]); }); render();
<script src="https://code.jquery.com/jquery-2.2.4.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r78/three.min.js"></script> <!-- This pen isn't a fan of small view heights, check it out in fullpage view for optimal viewing --> <div class="x-mark"> <div class="container"> <div class="left"></div> <div class="right"></div> </div> </div> <div class="intro-container"> <h2 class="fancy-text">Christopher Lis</h2> <h1>ONE WITH AN EVERLASTING DESIRE <br> FOR THE UNKNOWN & UNTOLD</h1> <div class="button shift-camera-button"> <div class="border"> <div class="left-plane"></div> <div class="right-plane"></div> </div> <div class="text">To The Stars</div> </div> </div> <div class="sky-container"> <div class="text-right sky-container__left"> <h2 class="portfolio"> PORTFOLIO </h2> <h2 class="resurrection"> resurrection </h2> </div> <div class="text-left sky-container__right"> <h2 class="08"> 08 </h2> <h2 class="thirty-one"> 31 </h2> <h2 class="2016"> 2016 </h2> </div> </div>
body { position: relative; margin: 0; overflow: hidden; } .intro-container { position: absolute; top: 50%; transform: translateY(-50%); color: white; text-align: center; margin: 0 auto; right: 0; left: 0; } h1 { font-family: 'Brandon Grotesque', sans-serif; font-weight: bold; margin-top: 0px; margin-bottom: 0; font-size: 20px; } @media screen and (min-width: 860px) { h1 { font-size: 40px; line-height: 52px; } } .fancy-text { font-family: "adobe-garamond-pro", sans-serif; font-style: italic; letter-spacing: 1px; margin-bottom: 17px; } .button { position: relative; cursor: pointer; display: inline-block; font-family: 'Brandon Grotesque', sans-serif; text-transform: uppercase; min-width: 200px; margin-top: 30px; } .button:hover .border { box-shadow: 0px 0px 10px 0px white; } .button:hover .border .left-plane, .button:hover .border .right-plane { transform: translateX(0%); } .button:hover .text { color: #121212; } .button .border { border: 1px solid white; transform: skewX(-20deg); height: 32px; border-radius: 3px; overflow: hidden; position: relative; transition: .10s ease-out; } .button .border .left-plane, .button .border .right-plane { position: absolute; background: white; height: 32px; width: 100px; transition: .15s ease-out; } .button .border .left-plane { left: 0; transform: translateX(-100%); } .button .border .right-plane { right: 0; transform: translateX(100%); } .button .text { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); transition: .15s ease-out; } .x-mark { right: 10px; top: 10px; position: absolute; cursor: pointer; opacity: 0; } .x-mark:hover .right { transform: rotate(-45deg) scaleY(1.2); } .x-mark:hover .left { transform: rotate(45deg) scaleY(1.2); } .x-mark .container { position: relative; width: 20px; height: 20px; } .x-mark .left, .x-mark .right { width: 2px; height: 20px; background: white; position: absolute; border-radius: 3px; transition: .15s ease-out; margin: 0 auto; left: 0; right: 0; } .x-mark .right { transform: rotate(-45deg); } .x-mark .left { transform: rotate(45deg); } .sky-container { position: absolute; color: white; text-transform: uppercase; margin: 0 auto; right: 0; left: 0; top: 2%; text-align: center; opacity: 0; } @media screen and (min-width: 860px) { .sky-container { top: 18%; right: 12%; left: auto; } } .sky-container__left, .sky-container__right { display: inline-block; vertical-align: top; font-weight: bold; } .sky-container__left h2, .sky-container__right h2 { font-family: 'Brandon Grotesque', sans-serif; font-size: 26px; line-height: 26px; margin: 0; } @media screen and (min-width: 860px) { .sky-container__left h2, .sky-container__right h2 { font-size: 72px; line-height: 68px; } } .sky-container__left { margin-right: 5px; } .sky-container .thirty-one { letter-spacing: 4px; } .text-right { text-align: right; } .text-left { text-align: left; } .social:hover a { transform: rotate(-45deg) scale(1.05); } .social:hover i { color: #21c2ff; } a { position: absolute; bottom: -40px; right: -75px; background: white; color: white; box-shadow: -1px -1px 20px 0px rgba(0, 0, 0, 0.3); display: inline-block; width: 150px; height: 80px; transform-origin: 50% 50%; transform: rotate(-45deg); transition: .15s ease-out; } i { position: absolute; bottom: 7px; right: 7px; pointer-events: none; color: #00ACED; z-index: 1000; font-size: 100px; transition: .15s ease-out; }