feat: 新增Cell container,首页样式优化.

This commit is contained in:
dragonir 2022-01-07 08:19:13 +08:00
parent e7c3815445
commit c144181f3d
16 changed files with 309 additions and 28 deletions

View File

@ -5,6 +5,7 @@ import City from './containers/City/index';
import Earth from './containers/Earth/index';
import Demo from './containers/Demo/index';
import Lunar from './containers/Lunar/index';
import Cell from './containers/Cell/index';
function App() {
return (
@ -16,6 +17,7 @@ function App() {
<Route element={ <Earth /> } path="/earth" />
<Route element={ <Demo /> } path="/demo" />
<Route element={ <Lunar /> } path="/lunar" />
<Route element={ <Cell /> } path="/cell" />
</Routes>
</Router>
</div>

View File

@ -0,0 +1,47 @@
.cell_loading {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background: #03c03c;
background: -webkit-linear-gradient(to right, #64e06b, #03c03c);
background: linear-gradient(to right, #64e06b, #03c03c);
display: flex;
justify-content: space-around;
align-items: center;
font-size: 64px;
color: #FFFFFF;
text-shadow: 0 1px 0 hsl(174,5%,80%),
0 2px 0 hsl(174,5%,75%),
0 3px 0 hsl(174,5%,70%),
0 4px 0 hsl(174,5%,66%),
0 5px 0 hsl(174,5%,64%),
0 6px 0 hsl(174,5%,62%),
0 7px 0 hsl(174,5%,61%),
0 8px 0 hsl(174,5%,60%),
0 0 5px rgba(0,0,0,.05),
0 1px 3px rgba(0,0,0,.2),
0 3px 5px rgba(0,0,0,.2),
0 5px 10px rgba(0,0,0,.2),
0 10px 10px rgba(0,0,0,.2),
0 20px 20px rgba(0,0,0,.3);
}
.toggle_button {
position: fixed;
width: 160px;
height: 48px;
top: 100px;
left: 50%;
margin-left: -80px;
cursor: pointer;
background: rgba(255, 255, 255, .3);
border: 1px groove rgba(255, 255, 255, .5);
backdrop-filter: 2px;
font-size: 16px;
color: rgba(255, 255, 255, .8);
text-shadow: 0 0 1px rgba(0, 0, 0, .2);
border-radius: 24px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, .25);
}

View File

@ -0,0 +1,158 @@
/* eslint-disable */
import React from 'react';
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import plantCellModel from './models/plant_cell.glb';
import AnimalCellModel from './models/animal_cell.glb';
import './index.css';
export default class Cell extends React.Component {
constructor(props) {
super(props);
}
state = {
// 页面模型加载进度0未加载100加载完成
loadingProcess: 0,
showAnimal: false
}
componentDidMount() {
this.initThree()
}
initThree = () => {
var container, controls, stats;
var camera, scene, renderer, light, earthMeshes = [];
var _this = this;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
scene.background = new THREE.Color(0x03c03c);
_this.scene = scene;
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 16, 18);
camera.lookAt(new THREE.Vector3(0, 0, 0));
const cubeGeometry = new THREE.BoxGeometry(0.001, 0.001, 0.001);
const cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xdc161a });
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(0, 0, 0,);
light = new THREE.DirectionalLight(0x03c03c, 1);
light.intensity = 1.2;
light.position.set(-5, 10, 3);
light.castShadow = true;
light.target = cube;
light.shadow.mapSize.width = 512 * 12;
light.shadow.mapSize.height = 512 * 12;
light.shadow.camera.top = 10;
light.shadow.camera.bottom = - 5;
light.shadow.camera.left = - 5;
light.shadow.camera.right = 10;
scene.add(light);
var ambientLight = new THREE.AmbientLight(0xffffff);
ambientLight.intensity = 1.2;
scene.add(ambientLight);
// 模型加载进度管理
const manager = new THREE.LoadingManager();
manager.onStart = (url, loaded, total) => {};
manager.onLoad = () => {};
manager.onProgress = async(url, loaded, total) => {
if (Math.floor(loaded / total * 100) === 100) {
_this.loadingProcessTimeout && clearTimeout(_this.loadingProcessTimeout);
_this.loadingProcessTimeout = setTimeout(() => {
_this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
}, 800);
} else {
_this.setState({ loadingProcess: Math.floor(loaded / total * 100) });
}
};
var loader = new GLTFLoader(manager);
// 植物细胞
loader.load(plantCellModel, function (mesh) {
mesh.scene.traverse(function (child) {
if (child.isMesh) {
earthMeshes.push(child)
child.castShadow = true;
child.receiveShadow = true;
child.material.metalness = 1;
child.material.roughness = 0;
}
});
mesh.scene.position.set(0, 0, 0);
mesh.scene.scale.set(40, 40, 40);
_this.plantCell = mesh.scene;
scene.add(mesh.scene);
});
// 动物细胞
loader.load(AnimalCellModel, function (mesh) {
mesh.scene.traverse(function (child) {
if (child.isMesh) {
earthMeshes.push(child)
child.castShadow = true;
child.receiveShadow = true;
child.material.metalness = 1;
child.material.roughness = 0;
}
});
mesh.scene.position.set(0, -8, 0);
mesh.scene.scale.set(120, 120, 120);
_this.animalCell = mesh.scene;
});
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
stats && stats.update();
controls && controls.update();
}
}
handleToggle = () => {
this.scene.remove(this.state.showAnimal ? this.animalCell : this.plantCell);
this.scene.add(this.state.showAnimal ? this.plantCell : this.animalCell);
this.setState({
showAnimal: !this.state.showAnimal
})
}
render () {
return (
<div>
<div id="container"></div>
<button className="toggle_button" onClick={this.handleToggle}>查看{this.state.showAnimal ? '植物🌲' : '动物🐼'}细胞</button>
{this.state.loadingProcess === 100 ? '' : (
<div className="cell_loading">
<div className="box">{this.state.loadingProcess} %</div>
</div>
)
}
</div>
)
}
}

Binary file not shown.

Binary file not shown.

View File

@ -118,7 +118,7 @@ export default class City extends React.Component {
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
controls.enableDamping = true;
window.addEventListener('resize', onWindowResize, false);
stats = new Stats();
@ -136,6 +136,7 @@ export default class City extends React.Component {
renderer.render(scene, camera);
stats && stats.update();
TWEEN && TWEEN.update();
controls && controls.update();
}
// 增加点击事件声明raycaster和mouse变量

View File

@ -73,7 +73,7 @@ export default class Earth extends React.Component {
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
controls.enableDamping = true;
window.addEventListener('resize', onWindowResize, false);
}
@ -88,6 +88,7 @@ export default class Earth extends React.Component {
renderer.render(scene, camera);
earth && (earth.rotation.y += 0.002)
stats && stats.update();
controls && controls.update();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

View File

@ -19,4 +19,27 @@
0 5px 10px rgba(0,0,0,.2),
0 10px 10px rgba(0,0,0,.2),
0 20px 20px rgba(0,0,0,.3);
}
.grid_item {
position: relative;
}
.three_logo {
position: absolute;
top: 14px;
right: 16px;
display: inline-block;
height: 24px;
width: 24px;
z-index: 2;
background: url('./images/3d.png') no-repeat center;
background-size: 100% 100%;
filter: drop-shadow(0px 0px 8px rgba(0, 0, 0, .5));
transition: all .5s linear;
opacity: .85;
}
.grid_item:hover .three_logo {
transform: rotate(360deg);
}

View File

@ -8,6 +8,10 @@ import cityImage from './images/city.png';
import panoramicImage from './images/panoramic.png';
import metaImage from './images/meta.png';
import earthImage from './images/earth.png';
import cellImage from './images/cell.png';
import lunarImage from './images/lunar.png';
import zeldaImage from './images/zelda.png';
import scanImage from './images/scan.png';
import './index.css';
const Item = styled(Paper)(({ theme }) => ({
@ -20,27 +24,57 @@ const Item = styled(Paper)(({ theme }) => ({
const workList = [
{
link: '#/city',
title: '🏙 3D 数字城市',
description: 'Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across all continents except Antarctica',
title: '🏙 数字城市',
description: 'Lizards are a widespread group of squamate reptiles.',
image: cityImage,
three: true
},
{
link: '#/city',
title: '🪐 3D META 元宇宙Logo',
description: 'Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across all continents except Antarctica',
link: 'https://dragonir.github.io/3d-meta-logo/',
title: '🪐 脸书Meta元宇宙Logo',
description: 'Lizards are a widespread group of squamate reptiles.',
image: metaImage,
three: true
},
{
link: '#/city',
title: '🕵️‍ 3D 全景侦探小游戏',
description: 'Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across all continents except Antarctica',
link: 'https://dragonir.github.io/3d-panoramic-vision/',
title: '🕵️‍ 全景侦探小游戏',
description: '使用Three.js全景功能实现侦探小游戏。',
image: panoramicImage,
three: true
},
{
link: '#/earth',
title: '🌏 3D Low Poly地球',
description: 'Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across all continents except Antarctica',
title: '🌏 Low Poly地球',
description: 'Lizards are a widespread group of squamate reptiles.',
image: earthImage,
three: true
},
{
link: '#/cell',
title: '👻 细胞',
description: '可以查看动物细胞和植物细胞的内部组成结构。',
image: cellImage,
three: true
},
{
link: '#/lunar',
title: '🐅 虎年春节创意页面',
description: 'Lizards are a widespread group of squamate reptiles.',
image: lunarImage,
three: true
},
{
link: 'https://dragonir.github.io/zelda-map/',
title: 'Zelda地图',
description: 'Lizards are a widespread group of squamate reptiles.',
image: zeldaImage,
},
{
link: 'https://dragonir.github.io/h5-scan-qrcode/',
title: '扫码',
description: 'Lizards are a widespread group of squamate reptiles.',
image: scanImage,
}
];
@ -54,8 +88,11 @@ export default class Home extends React.Component {
<Box sx={{ width: '100%' }} style={{ maxWidth: '1200px', margin: 'auto' }}>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
{workList.map((item, index) => (
<Grid item xs={6} key={index}>
<Item elevation={0}><MediaCard link={item.link} title={item.title} image={item.image} description={item.description} /></Item>
<Grid item xs={12} sm={6} md={4} key={index}>
<Item elevation={0} className="grid_item">
{item.three ? (<i className="three_logo"></i>) : '' }
<MediaCard link={item.link} title={item.title} image={item.image} description={item.description} />
</Item>
</Grid>
))}
</Grid>

View File

@ -1,3 +1,5 @@
# Three.js
THREE.OrbitControls参数控制
// Set to false to disable this control
//鼠标控制是否可用

View File

@ -43,14 +43,15 @@ export default class Lunar extends React.Component {
scene = new THREE.Scene();
scene.background = new THREE.TextureLoader().load(bgTexture);
scene.fog = new THREE.Fog(0xdddddd, 100, 120);
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(100, 100, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 网格
var grid = new THREE.GridHelper(100, 100, 0xfffc00, 0xfffc00);
grid.position.set(0, -10, 0)
grid.material.opacity = 0.1;
var grid = new THREE.GridHelper(100, 100, 0xefefef, 0xefefef);
grid.position.set(0, -8, 0);
grid.material.opacity = 0.2;
grid.material.transparent = true;
scene.add(grid);
@ -60,7 +61,7 @@ export default class Lunar extends React.Component {
var planeMaterial = new THREE.ShadowMaterial({ opacity: .5 });
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.set(0, -10, 0);
plane.position.set(0, -8, 0);
plane.receiveShadow = true;
scene.add(plane);
@ -69,7 +70,7 @@ export default class Lunar extends React.Component {
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(0, 0, 0);
light = new THREE.DirectionalLight(0xffffff, 1);
light.intensity = 1.5;
light.intensity = 1.2;
light.position.set(20, 20, 8);
light.castShadow = true;
light.target = cube;
@ -86,9 +87,17 @@ export default class Lunar extends React.Component {
// const lightCameraHelper = new THREE.CameraHelper(light.shadow.camera);
// scene.add(lightCameraHelper);
const ambientLight = new THREE.AmbientLight(0xefefef);
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
// 聚光灯
const spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-20, 20, -2);
spotLight.castShadow = false;
spotLight.target = plane;
scene.add(spotLight);
// 文字模型
const fbxLoader = new FBXLoader();
fbxLoader.load(textModel, mesh => {
@ -97,8 +106,8 @@ export default class Lunar extends React.Component {
meshes.push(mesh);
child.castShadow = true;
child.receiveShadow = true;
child.material.metalness = 0;
child.material.roughness = 1;
child.material.metalness = .2;
child.material.roughness = .8;
child.material.color = new THREE.Color(0x111111);
}
});
@ -108,7 +117,7 @@ export default class Lunar extends React.Component {
group.add(mesh);
});
// 老虎模型
// 模型加载进度管理
const manager = new THREE.LoadingManager();
manager.onStart = (url, loaded, total) => {};
manager.onLoad = () => {
@ -134,7 +143,8 @@ export default class Lunar extends React.Component {
child.castShadow = true;
child.receiveShadow = true;
child.material.metalness = 0;
child.material.roughness = 1;
child.material.roughness = .5;
child.material.transparent = true;
console.log(child)
}
});
@ -155,11 +165,11 @@ export default class Lunar extends React.Component {
controls.target.set(0, 0, 0);
// 开启缓动动画
controls.enableDamping = true;
// controls.dampingFactor = 0.25;
controls.maxDistance = 160;
window.addEventListener('resize', onWindowResize, false);
stats = new Stats();
document.documentElement.appendChild(stats.dom);
// 性能工具
// stats = new Stats();
// document.documentElement.appendChild(stats.dom);
}
function onWindowResize() {