forked from tongChong/BingDwenDwen
feat: Olympic页面添加雪花效果、树、五环、冰墩墩冬奥会吉祥物.
This commit is contained in:
parent
5838e715d2
commit
5b3f768eed
|
|
@ -1 +1,14 @@
|
|||
# Three.js实现3D冬奥会创意页面
|
||||
|
||||
<!-- 迎冬奥向未来 -->
|
||||
|
||||
冰墩墩模型来源 https://www.justeasy.cn/3dmodel/OGxVUFg4Zy9UWnJYZkoxQXBwSndJZz09.html
|
||||
|
||||
3dx
|
||||
|
||||
模型转换
|
||||
https://anyconv.com/tw/max-zhuan-obj/
|
||||
|
||||
|
||||
在blender2.8中怎么给模型贴图
|
||||
blender 模型贴图 https://jingyan.baidu.com/article/363872ecf6367f2f4ba16f95.html
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 886 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 857 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 358 B |
Binary file not shown.
|
After Width: | Height: | Size: 486 KiB |
|
|
@ -1,8 +1,14 @@
|
|||
/* eslint-disable */
|
||||
import React from 'react';
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
import Stats from "three/examples/jsm/libs/stats.module";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import landModel from './models/land.glb';
|
||||
import pandaModel from './models/panda.gltf';
|
||||
import bingdundunModel from './models/bingdundun.glb';
|
||||
import skyTexture from './images/sky.jpg';
|
||||
import snowTexture from './images/snow.png';
|
||||
import treeTexture from './images/tree.png';
|
||||
|
||||
export default class Olympic extends React.Component {
|
||||
|
||||
|
|
@ -16,11 +22,12 @@ export default class Olympic extends React.Component {
|
|||
|
||||
initThree = () => {
|
||||
var container, controls, stats;
|
||||
var camera, scene, renderer, light, earth = null, meshes = [];
|
||||
var camera, scene, renderer, light, land = null, meshes = [], points = [];
|
||||
var fiveCyclesGroup = new THREE.Group();
|
||||
var mouseX = 0, mouseY = 0;
|
||||
var windowHalfX = window.innerWidth / 2;
|
||||
var windowHalfY = window.innerHeight / 2;
|
||||
|
||||
init();
|
||||
animate();
|
||||
function init() {
|
||||
|
|
@ -32,13 +39,13 @@ export default class Olympic extends React.Component {
|
|||
container.appendChild(renderer.domElement);
|
||||
|
||||
scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x2d2d2d);
|
||||
scene.background = new THREE.TextureLoader().load(skyTexture);
|
||||
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
camera.position.set(0, 10, 20);
|
||||
camera.position.set(0, -2, 20);
|
||||
camera.lookAt(new THREE.Vector3(0, 0, 0));
|
||||
|
||||
var axes = new THREE.AxisHelper(30);
|
||||
scene.add(axes);
|
||||
// var axes = new THREE.AxisHelper(30);
|
||||
// scene.add(axes);
|
||||
|
||||
// 性能工具
|
||||
stats = new Stats();
|
||||
|
|
@ -64,6 +71,87 @@ export default class Olympic extends React.Component {
|
|||
var ambientLight = new THREE.AmbientLight(0xdddddd);
|
||||
scene.add(ambientLight);
|
||||
|
||||
// 添加地面
|
||||
var loader = new GLTFLoader();
|
||||
loader.load(landModel, function (mesh) {
|
||||
mesh.scene.traverse(function (child) {
|
||||
if (child.isMesh) {
|
||||
meshes.push(child)
|
||||
if (child.name === 'Mesh_2') {
|
||||
child.material.metalness = .1
|
||||
child.material.roughness = .8
|
||||
child.material.color = new THREE.Color(0xffffff)
|
||||
}
|
||||
}
|
||||
});
|
||||
mesh.scene.rotation.y = Math.PI / 4;
|
||||
mesh.scene.position.set(15, -20, 0);
|
||||
mesh.scene.scale.set(.9, .9, .9);
|
||||
land = mesh.scene;
|
||||
scene.add(land);
|
||||
});
|
||||
|
||||
// bingdundun
|
||||
loader.load(bingdundunModel, function (mesh) {
|
||||
mesh.scene.traverse(function (child) {
|
||||
if (child.isMesh) {
|
||||
meshes.push(child)
|
||||
if (child.name === 'oldtiger001') {
|
||||
child.material.metalness = .5
|
||||
}
|
||||
if (child.name === 'oldtiger002') {
|
||||
child.material.transparent = true;
|
||||
child.material.opacity = .5
|
||||
}
|
||||
}
|
||||
});
|
||||
mesh.scene.rotation.y = Math.PI / 24;
|
||||
mesh.scene.position.set(-8, -10, 0);
|
||||
mesh.scene.scale.set(24, 24, 24);
|
||||
scene.add(mesh.scene);
|
||||
});
|
||||
|
||||
// 添加树
|
||||
let pandaMaterial = new THREE.MeshPhysicalMaterial({
|
||||
map: new THREE.TextureLoader().load(treeTexture),
|
||||
transparent: true,
|
||||
side: THREE.DoubleSide,
|
||||
metalness: .2,
|
||||
roughness: .8,
|
||||
depthTest: true,
|
||||
depthWrite: false,
|
||||
skinning: false,
|
||||
fog: false,
|
||||
reflectivity: 0.1,
|
||||
refractionRatio: 0,
|
||||
});
|
||||
let pandaCustomDepthMaterial = new THREE.MeshDepthMaterial({
|
||||
depthPacking: THREE.RGBADepthPacking,
|
||||
map: new THREE.TextureLoader().load(treeTexture),
|
||||
alphaTest: 0.5
|
||||
});
|
||||
loader.load(pandaModel, function (mesh) {
|
||||
mesh.scene.traverse(function (child) {
|
||||
if (child.isMesh) {
|
||||
meshes.push(child)
|
||||
child.material = pandaMaterial
|
||||
child.custromMaterial = pandaCustomDepthMaterial
|
||||
}
|
||||
});
|
||||
mesh.scene.position.set(14, -8, 0);
|
||||
mesh.scene.scale.set(16, 16, 16);
|
||||
scene.add(mesh.scene);
|
||||
let tree2 = mesh.scene.clone();
|
||||
tree2.position.set(8, -8, -14);
|
||||
tree2.scale.set(18, 18, 18);
|
||||
scene.add(tree2)
|
||||
|
||||
let tree3 = mesh.scene.clone();
|
||||
tree3.position.set(-16, -8, -16);
|
||||
tree3.scale.set(18, 18, 18);
|
||||
scene.add(tree3)
|
||||
});
|
||||
|
||||
// 创建五环
|
||||
const fiveCycles = [
|
||||
{
|
||||
|
|
@ -92,7 +180,6 @@ export default class Olympic extends React.Component {
|
|||
position: { x: 115, y: -100, z: 10 }
|
||||
}
|
||||
];
|
||||
|
||||
fiveCycles.map(item => {
|
||||
let cycleMesh = new THREE.Mesh(new THREE.TorusGeometry(100, 10, 10, 50), new THREE.MeshLambertMaterial({
|
||||
color: new THREE.Color(item.color),
|
||||
|
|
@ -102,15 +189,47 @@ export default class Olympic extends React.Component {
|
|||
meshes.push(cycleMesh);
|
||||
fiveCyclesGroup.add(cycleMesh);
|
||||
});
|
||||
fiveCyclesGroup.scale.set(.025, .025, .025)
|
||||
fiveCyclesGroup.position.set(0, 0, 0)
|
||||
scene.add(fiveCyclesGroup)
|
||||
fiveCyclesGroup.scale.set(.03, .03, .03);
|
||||
fiveCyclesGroup.position.set(0, 8, -5);
|
||||
scene.add(fiveCyclesGroup);
|
||||
|
||||
// 创建雪花
|
||||
let texture = new THREE.TextureLoader().load(snowTexture);
|
||||
let geometry = new THREE.Geometry();
|
||||
let pointsMaterial = new THREE.PointsMaterial({
|
||||
size: 1,
|
||||
transparent: true,
|
||||
opacity: 0.8,
|
||||
map: texture,
|
||||
blending: THREE.AdditiveBlending,
|
||||
sizeAttenuation: true,
|
||||
depthTest: false
|
||||
});
|
||||
let range = 100;
|
||||
let vertices = []
|
||||
for (let i = 0; i < 1500; i++) {
|
||||
let vertice = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range * 1.5, Math.random() * range - range / 2);
|
||||
// 纵向移动速度
|
||||
vertice.velocityY = 0.1 + Math.random() / 3;
|
||||
// 横向移动速度
|
||||
vertice.velocityX = (Math.random() - 0.5) / 3;
|
||||
// 将顶点加入几何
|
||||
geometry.vertices.push(vertice);
|
||||
}
|
||||
geometry.center();
|
||||
points = new THREE.Points(geometry, pointsMaterial);
|
||||
points.position.y = -30;
|
||||
scene.add(points);
|
||||
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.target.set(0, 0, 0);
|
||||
controls.enableDamping = true;
|
||||
controls.enablePan = false;
|
||||
controls.enableZoom = false;
|
||||
// 最大仰角
|
||||
controls.minPolarAngle = 1.4;
|
||||
controls.maxPolarAngle = 1.8;
|
||||
window.addEventListener('resize', onWindowResize, false);
|
||||
// window.addEventListener('mousemove', onDocumentMouseMove, false);
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
|
|
@ -129,11 +248,34 @@ export default class Olympic extends React.Component {
|
|||
renderer.render(scene, camera);
|
||||
stats && stats.update();
|
||||
controls && controls.update();
|
||||
|
||||
// camera.position.x += (mouseX - camera.position.x) * 0.005;
|
||||
// camera.position.y += (-mouseY - camera.position.y) * 0.005;
|
||||
// camera.lookAt(scene.position);
|
||||
fiveCyclesGroup && (fiveCyclesGroup.rotation.y += .01)
|
||||
let vertices = points.geometry.vertices;
|
||||
vertices.forEach(function (v) {
|
||||
v.y = v.y - (v.velocityY);
|
||||
v.x = v.x - (v.velocityX);
|
||||
if (v.y <= 0) v.y = 60;
|
||||
if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;
|
||||
});
|
||||
// 顶点变动之后需要更新,否则无法实现雨滴特效
|
||||
points.geometry.verticesNeedUpdate = true;
|
||||
}
|
||||
|
||||
// 增加点击事件,声明raycaster和mouse变量
|
||||
var raycaster = new THREE.Raycaster();
|
||||
var mouse = new THREE.Vector2();
|
||||
function onMouseClick(event) {
|
||||
// 通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1.
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
||||
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
// 获取raycaster直线和所有模型相交的数组集合
|
||||
var intersects = raycaster.intersectObjects(meshes);
|
||||
if (intersects.length > 0) {
|
||||
console.log(intersects[0].object)
|
||||
}
|
||||
}
|
||||
window.addEventListener('click', onMouseClick, false);
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,232 @@
|
|||
{
|
||||
"asset" : {
|
||||
"generator" : "Khronos glTF Blender I/O v1.3.48",
|
||||
"version" : "2.0"
|
||||
},
|
||||
"scene" : 0,
|
||||
"scenes" : [
|
||||
{
|
||||
"name" : "Scene",
|
||||
"nodes" : [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes" : [
|
||||
{
|
||||
"name" : "Light",
|
||||
"rotation" : [
|
||||
0.16907575726509094,
|
||||
0.7558803558349609,
|
||||
-0.27217137813568115,
|
||||
0.570947527885437
|
||||
],
|
||||
"translation" : [
|
||||
4.076245307922363,
|
||||
5.903861999511719,
|
||||
-1.0054539442062378
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Camera",
|
||||
"rotation" : [
|
||||
0.483536034822464,
|
||||
0.33687159419059753,
|
||||
-0.20870360732078552,
|
||||
0.7804827094078064
|
||||
],
|
||||
"translation" : [
|
||||
7.358891487121582,
|
||||
4.958309173583984,
|
||||
6.925790786743164
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh" : 0,
|
||||
"name" : "\u5e73\u9762_1",
|
||||
"rotation" : [
|
||||
-0.5896493196487427,
|
||||
0,
|
||||
0.807659387588501,
|
||||
7.263876966590033e-08
|
||||
],
|
||||
"scale" : [
|
||||
0.009999999776482582,
|
||||
0.009999999776482582,
|
||||
0.009999999776482582
|
||||
],
|
||||
"translation" : [
|
||||
0,
|
||||
0.5100772976875305,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh" : 1,
|
||||
"name" : "\u5e73\u9762",
|
||||
"rotation" : [
|
||||
-0.9880464673042297,
|
||||
0,
|
||||
0.1541563719511032,
|
||||
7.459543382992706e-08
|
||||
],
|
||||
"scale" : [
|
||||
0.009999999776482582,
|
||||
0.009999999776482582,
|
||||
0.009999999776482582
|
||||
],
|
||||
"translation" : [
|
||||
0,
|
||||
0.5100772976875305,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"materials" : [
|
||||
{
|
||||
"doubleSided" : true,
|
||||
"name" : "\u6750\u8d28.001",
|
||||
"pbrMetallicRoughness" : {}
|
||||
}
|
||||
],
|
||||
"meshes" : [
|
||||
{
|
||||
"name" : "\u7f51\u683c",
|
||||
"primitives" : [
|
||||
{
|
||||
"attributes" : {
|
||||
"POSITION" : 0,
|
||||
"NORMAL" : 1,
|
||||
"TEXCOORD_0" : 2
|
||||
},
|
||||
"indices" : 3,
|
||||
"material" : 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "\u7f51\u683c.001",
|
||||
"primitives" : [
|
||||
{
|
||||
"attributes" : {
|
||||
"POSITION" : 4,
|
||||
"NORMAL" : 5,
|
||||
"TEXCOORD_0" : 6
|
||||
},
|
||||
"indices" : 3,
|
||||
"material" : 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"max" : [
|
||||
28.603322982788086,
|
||||
48.00337219238281,
|
||||
0
|
||||
],
|
||||
"min" : [
|
||||
-28.603322982788086,
|
||||
-48.00337219238281,
|
||||
0
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 1,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 2,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"type" : "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView" : 3,
|
||||
"componentType" : 5123,
|
||||
"count" : 6,
|
||||
"type" : "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView" : 4,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"max" : [
|
||||
28.603322982788086,
|
||||
48.00337219238281,
|
||||
0
|
||||
],
|
||||
"min" : [
|
||||
-28.603322982788086,
|
||||
-48.00337219238281,
|
||||
0
|
||||
],
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 5,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"type" : "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView" : 6,
|
||||
"componentType" : 5126,
|
||||
"count" : 4,
|
||||
"type" : "VEC2"
|
||||
}
|
||||
],
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 48,
|
||||
"byteOffset" : 0
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 48,
|
||||
"byteOffset" : 48
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 32,
|
||||
"byteOffset" : 96
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 12,
|
||||
"byteOffset" : 128
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 48,
|
||||
"byteOffset" : 140
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 48,
|
||||
"byteOffset" : 188
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteLength" : 32,
|
||||
"byteOffset" : 236
|
||||
}
|
||||
],
|
||||
"buffers" : [
|
||||
{
|
||||
"byteLength" : 268,
|
||||
"uri" : "data:application/octet-stream;base64,m9PkQXQDQEIAAACAm9PkQXQDQMIAAACAm9PkwXQDQMIAAACAm9PkwXQDQEIAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPwAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAEAAgAAAAIAAwCb0+RBdANAQgAAAICb0+RBdANAwgAAAICb0+TBdANAwgAAAICb0+TBdANAQgAAAIAAAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPw=="
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue