├── .gitignore
├── .idea
├── inspectionProfiles
│ └── Project_Default.xml
└── vcs.xml
├── README.md
├── assets
├── 2-0.png
├── 2-1.png
├── b.jpg
├── c.jpg
├── d.jpg
├── niu.png
├── wx.png
└── xigua.png
├── index.html
└── libs
├── anime.min.js
├── css.min.css
├── deri.js
├── fastclick.js
├── imgs
├── 001_electric.jpg
├── book.jpg
├── bookall.png
├── icon-earth.png
├── icon-water.png
├── lightray_red.jpg
├── logo.png
├── page2back.png
├── photo.jpg
├── skybox
│ ├── negx.jpg
│ ├── negy.jpg
│ ├── negz.jpg
│ ├── posx.jpg
│ ├── posy.jpg
│ └── posz.jpg
├── up.jpg
├── users
│ ├── niu.png
│ └── xigua.png
├── water1.jpg
└── water2.jpg
├── index.js
├── jquery-3.3.1.min.js
├── music
├── 0.mp3
└── 1.mp3
├── three.min.js
├── three
├── CSS2DRenderer.js
├── CopyShader.js
├── DigitalGlitch.js
├── EffectComposer.js
├── FXAAShader.js
├── GlitchPass.js
├── OrbitControls.js
├── OutlinePass.js
├── Reflector.js
├── RenderPass.js
├── ShaderPass.js
├── THREE.MeshLine.js
└── three.lib.js
└── tween.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /tests/e2e/videos/
6 | /tests/e2e/screenshots/
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
4 | 初版 做完了
5 |
6 | - 老夫就是要用 jquery
7 | - THREE.JS v92, IE11+以上支持
8 | - 页面排版 简单排了排,没有什么设计能力
9 |
10 | ## 地址
11 |
12 | 国际:https://isluo.com/work/water/
13 |
14 | ## 关于《三体》
15 |
16 | 《三体》是刘慈欣 大刘的长篇科幻小说,共 3 部。获得了星云奖、雨果奖等国际奖项。
17 |
18 | > 初次看见《三体》时,是在上初三的时候,借的同学的《科幻世界》杂志,第 1 篇文章就是《三体》,看了一遍,发现讲的是文化大革命,耐着性子看完了第 1 集,根本没出现任何"科幻"的东西。
19 | > 十几年匆匆而过,直到我参加工作了,才重新想起三体,发现已经完结了。于是抄起手机就开始看。哇塞,我觉得这就是想象力的极限了,我沉浸其中无法自拔。
20 | > 人的一生是多么短暂呵,在那遥远的时间的终点,又会有怎样的光景呢。
21 |
22 | ## 版权及免责声明
23 |
24 | - 本网站是根据刘慈欣《三体》中的情节构建的,摘抄了部分原文。
25 | - 图片均来源于网络
26 | - 本网站仅作为我的个人作品,如有侵权请联系我。
27 | - 本网站源代码可供转发修改,但不得用于商业用途
28 |
29 |
30 |
在西边的天际,正在下沉的夕阳仿佛被融化着
37 |如血在云海和太空中弥漫,映出一大片壮丽的红色
38 |"这是人类的落日",叶文洁轻轻地说。
39 |这是2.0版本的"水滴"
配置了曲率驱动引擎及强互作用力外壳
由半人马星座α星系朝着太阳系行进
约4个地球年后抵达
国家天文台已能捕获其图像
'; 529 | const label2 = new THREE.CSS2DObject(label2Div); 530 | label2.position.set(10, 50, 0); 531 | water_mesh.add(label2); 532 | } 533 | 534 | /** 初始化所有后处理特效 **/ 535 | function initComposer() { 536 | /** 铭牌渲染器 **/ 537 | labelRenderer = new THREE.CSS2DRenderer(); 538 | labelRenderer.setSize(window.innerWidth, window.innerHeight); 539 | labelRenderer.domElement.style.position = "absolute"; 540 | labelRenderer.domElement.style.top = 0; 541 | document.getElementById("canvas-box").appendChild(labelRenderer.domElement); 542 | 543 | /** 后处理 - 后期渲染器 **/ 544 | composer = new THREE.EffectComposer(renderer); 545 | var renderPass = new THREE.RenderPass(scene, camera); 546 | composer.addPass(renderPass); 547 | 548 | /** 后处理 - 外边框 **/ 549 | outlinePass = new THREE.OutlinePass( 550 | new THREE.Vector2(window.innerWidth, window.innerHeight), 551 | scene, 552 | camera 553 | ); 554 | outlinePass.edgeStrength = 0.1; // 0就看不见了 555 | outlinePass.edgeGlow = 1; 556 | outlinePass.edgeThickness = 3; 557 | outlinePass.selectedObjects = [water_mesh]; 558 | composer.addPass(outlinePass); 559 | 560 | /** 后处理 - 抗锯齿 **/ 561 | effectFXAA = new THREE.ShaderPass(THREE.FXAAShader); 562 | effectFXAA.uniforms["resolution"].value.set( 563 | 1 / window.innerWidth, 564 | 1 / window.innerHeight 565 | ); 566 | effectFXAA.renderToScreen = true; 567 | composer.addPass(effectFXAA); 568 | 569 | /** 后处理 - 屏幕闪动 **/ 570 | glitchPass = new THREE.GlitchPass(1); 571 | glitchPass.renderToScreen = true; 572 | glitchPass.goWild = false; 573 | } 574 | 575 | /** 初始化射线相关 **/ 576 | function initRaycaster() { 577 | raycaster = new THREE.Raycaster(); 578 | mouse = new THREE.Vector2(10000, 10000); 579 | } 580 | 581 | /** 鼠标移动记录位置 **/ 582 | function onMouseMove(e) { 583 | mouse.x = (e.clientX / window.innerWidth) * 2 - 1; 584 | mouse.y = -(e.clientY / window.innerHeight) * 2 + 1; 585 | } 586 | 587 | function checkLoading() { 588 | loadingPercent += 1; 589 | speedDom.innerText = ((loadingPercent / loadingCount) * 100).toFixed(2); 590 | if (loadingPercent >= loadingCount) { 591 | init(); 592 | } 593 | } 594 | 595 | /** 加载所有纹理和图片 **/ 596 | function initAllTexturesAndImgs() { 597 | const loader = new THREE.TextureLoader(); 598 | const cubeLoader = new THREE.CubeTextureLoader(); 599 | loader.load( 600 | "./libs/imgs/lightray_red.jpg", 601 | function (texture) { 602 | cone_texture = texture; 603 | checkLoading(); 604 | }, 605 | null, 606 | function (err) { 607 | console.log("光锥纹理加载失败", err); 608 | } 609 | ); 610 | 611 | loader.load( 612 | "./libs/imgs/001_electric.jpg", 613 | function (texture) { 614 | tunnel_texture = texture; 615 | checkLoading(); 616 | }, 617 | null, 618 | function (err) { 619 | console.log("时空隧道纹理加载失败", err); 620 | } 621 | ); 622 | 623 | cubeLoader.load( 624 | [ 625 | "libs/imgs/skybox/posx.jpg", 626 | "libs/imgs/skybox/negx.jpg", 627 | "libs/imgs/skybox/posy.jpg", 628 | "libs/imgs/skybox/negy.jpg", 629 | "libs/imgs/skybox/posz.jpg", 630 | "libs/imgs/skybox/negz.jpg", 631 | ], 632 | function (texture) { 633 | skybox_texture = texture; 634 | checkLoading(); 635 | }, 636 | null, 637 | function (err) { 638 | console.log("天空盒纹理加载失败", err); 639 | } 640 | ); 641 | } 642 | 643 | /** 窗体大小改变时重置分辨率等参数 **/ 644 | function onResize() { 645 | camera.aspect = window.innerWidth / window.innerHeight; 646 | camera.updateProjectionMatrix(); 647 | renderer.setSize(window.innerWidth, window.innerHeight); 648 | composer.setSize(window.innerWidth, window.innerHeight); 649 | labelRenderer.setSize(window.innerWidth, window.innerHeight); 650 | effectFXAA.uniforms["resolution"].value.set( 651 | 1 / window.innerWidth, 652 | 1 / window.innerHeight 653 | ); 654 | } 655 | 656 | /** animate动画相关 **/ 657 | let count = 0; 658 | let hoverToDo = false; // 选中后,是否已经在执行霓虹灯效果 659 | let noHoverToDo = false; // 非选中后,是否需要重置霓虹灯状态 660 | let nowNum = 0; // 当前霓虹灯走到哪一个了 661 | function animate() { 662 | requestAnimationFrame(animate); 663 | animate_basic(); 664 | 665 | if (showType > 2) { 666 | // 第2阶段完毕后才开始射线 667 | animate_rayhover(); 668 | } 669 | 670 | if (showType === 2) { 671 | TWEEN.update(); 672 | if (animeObj.star_speed > -10) { 673 | animeObj.star_speed -= 0.02; 674 | } 675 | } else if (showType === 3) { 676 | if (animeObj.star_speed > -40) { 677 | // 初阶段加速 678 | animeObj.star_speed -= 0.08; 679 | tunnel.material.opacity += 0.001; 680 | outlinePass.edgeStrength += 0.005; 681 | } else { 682 | // 开始特效 683 | showType = 4; 684 | composer.addPass(glitchPass); 685 | skybox.visible = false; 686 | cloud.visible = false; 687 | cloud2.visible = false; 688 | lineMesh.visible = true; 689 | lineMesh2.visible = true; 690 | tunnel.material.opacity = 1; 691 | setTimeout(function () { 692 | showType = 5; 693 | glitchPass.renderToScreen = false; 694 | $("#ship-type-ul").css("transform", "translateY(-100px)"); 695 | speedRipple(); 696 | }, 400); 697 | } 698 | skybox.position.x -= 2; 699 | skybox.scale.x += 2; 700 | } else if (showType === 5) { 701 | if (outlinePass.edgeStrength > 0.05) { 702 | outlinePass.edgeStrength -= 0.01; 703 | } else { 704 | showType = 6; 705 | } 706 | } 707 | 708 | if (count % 2 === 0) { 709 | cubeMeterial.envMap = cubeCamera1.renderTarget.texture; 710 | cubeCamera2.update(renderer, scene); 711 | } else { 712 | cubeMeterial.envMap = cubeCamera2.renderTarget.texture; 713 | cubeCamera1.update(renderer, scene); 714 | } 715 | count++; 716 | count = count > 1000000 ? 1 : count; 717 | 718 | labelRenderer.render(scene, camera); 719 | if (showType === 6) { 720 | renderer.render(scene, camera); 721 | } else { 722 | composer.render(); 723 | } 724 | } 725 | 726 | // 速度脉动 727 | function speedRipple() { 728 | animeObj.shipSpeed = 729 | animeObj.shipSpeed > 1079252848.7 ? 1079252848.7 : 1079252848.8; 730 | speedDom.innerText = animeObj.shipSpeed.toFixed(2); 731 | setTimeout(speedRipple, Math.random() * 600 + 100); 732 | } 733 | // 基本运动 734 | function animate_basic() { 735 | line_group.rotation.x += 0.01; 736 | dash1_mesh.rotation.x -= 0.01; 737 | cloud.position.x += animeObj.star_speed; // 低速星空速度 738 | cloud2.position.x += animeObj.star_speed; 739 | lineMesh.position.x -= 40; 740 | lineMesh2.position.x -= 40; 741 | q4_mesh.rotation.x -= 0.04; 742 | q5_mesh.rotation.x -= 0.04; 743 | tunnel_texture.offset.x += 0.01; 744 | tunnel_texture.offset.y -= 0.06; 745 | 746 | if (cloud.position.x <= -1500) { 747 | cloud.position.x = 2500; 748 | } 749 | if (cloud2.position.x <= -1500) { 750 | cloud2.position.x = 2500; 751 | } 752 | if (lineMesh.position.x <= -3000) { 753 | lineMesh.position.x = 3000; 754 | } 755 | if (lineMesh2.position.x <= -3000) { 756 | lineMesh2.position.x = 3000; 757 | } 758 | } 759 | 760 | // 射线hover效果处理 761 | function animate_rayhover() { 762 | raycaster.setFromCamera(mouse, camera); 763 | if (raycaster.intersectObjects([water_mesh]).length) { 764 | // 被选中 765 | title2d && !title2d.hasClass("show") && title2d.addClass("show"); 766 | label2d && !label2d.hasClass("show") && label2d.addClass("show"); 767 | // 前面中圈 768 | if (line1_mesh.position.x < 20) { 769 | line1_mesh.position.x += 1; 770 | } 771 | if (line1_mesh.scale.x < 3) { 772 | const scale = line1_mesh.scale.x + 0.1; 773 | line1_mesh.scale.set(scale, scale, scale); 774 | } 775 | // 前面大圈 776 | if (line2_mesh.position.x < 17) { 777 | line2_mesh.position.x += 1; 778 | } 779 | if (line2_mesh.scale.x < 8) { 780 | const scale = line2_mesh.scale.x + 0.4; 781 | line2_mesh.scale.set(scale, scale, scale); 782 | } 783 | // 后面小圈 784 | if (line3_mesh.position.x > -23) { 785 | line3_mesh.position.x -= 1; 786 | } 787 | if (line3_mesh.scale.x < 1.5) { 788 | const scale = (line3_mesh.scale.x += 0.1); 789 | line3_mesh.scale.set(scale, scale, scale); 790 | } 791 | // 前面红色小圈 792 | if (q4_mesh.position.x < 16) { 793 | q4_mesh.position.x += 1; 794 | } 795 | if (q4_mesh.scale.x < 1.5) { 796 | const scale = (q4_mesh.scale.x += 0.1); 797 | q4_mesh.scale.set(scale, scale, scale); 798 | } 799 | // 后面红色小圈 800 | if (q5_mesh.position.x > -23.5) { 801 | q5_mesh.position.x -= 1; 802 | } 803 | if (q5_mesh.scale.x < 1.5) { 804 | const scale = (q5_mesh.scale.x += 0.1); 805 | q5_mesh.scale.set(scale, scale, scale); 806 | } 807 | // 前面虚线中圈 808 | if (dash1_mesh.material.uniforms.opacity.value < 1) { 809 | dash1_mesh.material.uniforms.opacity.value += 0.02; 810 | } 811 | if (dash1_mesh.scale.x > 3.3) { 812 | const scale = (dash1_mesh.scale.x -= 0.1); 813 | dash1_mesh.scale.set(scale, scale, scale); 814 | } 815 | // 三个三角形的材质 816 | if (ship_red_line.uniforms.opacity.value < 1) { 817 | ship_red_line.uniforms.opacity.value += 0.01; 818 | } 819 | // 实现蓝色线圈材质 820 | if (ship_line.uniforms.opacity.value < 1) { 821 | ship_line.uniforms.opacity.value = 1; 822 | } 823 | 824 | /** 被选中,处理cone_group **/ 825 | if (count % 200 === 0 && !hoverToDo) { 826 | hoverToDo = true; 827 | noHoverToDo = true; 828 | nowNum = 0; 829 | } 830 | if (hoverToDo) { 831 | nowNum += 0.15; 832 | const now = Math.floor(nowNum) * 2; 833 | 834 | if (now > cone_group.children.length + 2) { 835 | hoverToDo = false; 836 | } 837 | 838 | for (let i = 0; i < cone_group.children.length; i += 2) { 839 | if (i === now && cone_group.children[now].scale.x < 1) { 840 | const scale = cone_group.children[now].scale.x + 0.1; 841 | cone_group.children[now].scale.set(scale, 1, scale); 842 | cone_group.children[now + 1].scale.set(scale, 1, scale); 843 | cone_group1.children[now].scale.set(scale, 1, scale); 844 | cone_group1.children[now + 1].scale.set(scale, 1, scale); 845 | cone_group2.children[now].scale.set(scale, 1, scale); 846 | cone_group2.children[now + 1].scale.set(scale, 1, scale); 847 | } else if (i !== now && cone_group.children[i].scale.x > 0) { 848 | const scale = cone_group.children[i].scale.x - 0.05; 849 | cone_group.children[i].scale.set(scale, scale, scale); 850 | cone_group.children[i + 1].scale.set(scale, scale, scale); 851 | cone_group1.children[i].scale.set(scale, scale, scale); 852 | cone_group1.children[i + 1].scale.set(scale, scale, scale); 853 | cone_group2.children[i].scale.set(scale, scale, scale); 854 | cone_group2.children[i + 1].scale.set(scale, scale, scale); 855 | } 856 | } 857 | } 858 | } else { 859 | // 未被选中 860 | title2d && title2d.hasClass("show") && title2d.removeClass("show"); 861 | label2d && label2d.hasClass("show") && label2d.removeClass("show"); 862 | // 前面中圈 863 | if (line1_mesh.position.x > 10) { 864 | line1_mesh.position.x -= 1; 865 | } 866 | if (line1_mesh.scale.x > 0) { 867 | const scale = line1_mesh.scale.x - 0.1; 868 | line1_mesh.scale.set(scale, scale, scale); 869 | } 870 | // 前面大圈 871 | if (line2_mesh.position.x > 10) { 872 | line2_mesh.position.x -= 1; 873 | } 874 | if (line2_mesh.scale.x > 0) { 875 | const scale = line2_mesh.scale.x - 0.4; 876 | line2_mesh.scale.set(scale, scale, scale); 877 | } 878 | // 后面小圈 879 | if (line3_mesh.position.x < -13) { 880 | line3_mesh.position.x += 1; 881 | } 882 | if (line3_mesh.scale.x > 0) { 883 | const scale = (line3_mesh.scale.x -= 0.1); 884 | line3_mesh.scale.set(scale, scale, scale); 885 | } 886 | // 前面红色小圈 887 | if (q4_mesh.position.x > 6) { 888 | q4_mesh.position.x -= 1; 889 | } 890 | if (q4_mesh.scale.x > 0) { 891 | const scale = (q4_mesh.scale.x -= 0.1); 892 | q4_mesh.scale.set(scale, scale, scale); 893 | } 894 | // 后面红色小圈 895 | if (q5_mesh.position.x < -13.5) { 896 | q5_mesh.position.x += 1; 897 | } 898 | if (q5_mesh.scale.x > 0) { 899 | const scale = (q5_mesh.scale.x -= 0.1); 900 | q5_mesh.scale.set(scale, scale, scale); 901 | } 902 | // 前面虚线中圈 903 | if (dash1_mesh.material.uniforms.opacity.value > 0) { 904 | dash1_mesh.material.uniforms.opacity.value = 0; 905 | } 906 | if (dash1_mesh.scale.x < 7) { 907 | dash1_mesh.scale.set(7, 7, 7); 908 | } 909 | // 三个三角形的材质 910 | if (ship_red_line.uniforms.opacity.value > 0) { 911 | ship_red_line.uniforms.opacity.value = 0; 912 | } 913 | // 实现蓝色线圈材质 914 | if (ship_line.uniforms.opacity.value > 0) { 915 | ship_line.uniforms.opacity.value -= 0.05; 916 | } 917 | 918 | if (noHoverToDo) { 919 | noHoverToDo = false; 920 | hoverToDo = false; 921 | nowNum = 0; 922 | for (let i = 0; i < cone_group.children.length; i++) { 923 | cone_group.children[i].scale.set(0.001, 0.001, 0.001); 924 | cone_group1.children[i].scale.set(0.001, 0.001, 0.001); 925 | cone_group2.children[i].scale.set(0.001, 0.001, 0.001); 926 | } 927 | } 928 | } 929 | } 930 | 931 | function initNames() { 932 | users.sort(function (a, b) { 933 | return b.s - a.s; 934 | }); 935 | let str = ""; 936 | let num = 0; 937 | for (let i = 0; i < users.length; i++) { 938 | let n = ""; 939 | if (users[i].n instanceof Array) { 940 | n = users[i].n 941 | .map(function (item, index) { 942 | return item.indexOf("libs/") > -1 ? '