聲明:本文涉及圖文和模型素材僅用于個(gè)人學(xué)習(xí)坟乾、研究和欣賞,請(qǐng)勿二次修改蝶防、非法傳播甚侣、轉(zhuǎn)載、出版间学、商用殷费、及進(jìn)行其他獲利行為。
背景
逛?sketchfab?網(wǎng)站的時(shí)候我看到有很多二維平面轉(zhuǎn)?3D?的模型例子菱鸥,于是仿照他們的例子宗兼,使用?Three.js?+?React?技術(shù)棧,將二維漫畫圖片轉(zhuǎn)化為三維視覺效果氮采。本文包含的內(nèi)容主要包括:THREE.Group?層級(jí)模型殷绍、MeshPhongMaterial?高光網(wǎng)格材質(zhì)、正弦余弦函數(shù)?創(chuàng)建模型移動(dòng)軌跡等鹊漠。
效果
實(shí)現(xiàn)效果如????下圖所示:頁(yè)面主要有背景圖主到、漫畫圖片主體以及??? Boom?爆炸背景圖片構(gòu)成茶行,按住鼠標(biāo)左鍵移動(dòng)模型可以獲得不同視圖,讓圖片在視覺上有?3D?景深效果登钥。
已適配:
???PC端
???移動(dòng)端
???在線預(yù)覽:https://dragonir.github.io/3d/#/comic
實(shí)現(xiàn)
本文實(shí)現(xiàn)比較簡(jiǎn)單畔师,和我前面幾篇文章實(shí)現(xiàn)基本上是相同的,流程也比較簡(jiǎn)單牧牢,主要是素材準(zhǔn)備流程比較復(fù)雜看锉。下面看看具體實(shí)現(xiàn)方法硬梁。
素材制作
準(zhǔn)備一張自己喜歡的圖片作為素材原圖麻车,圖片內(nèi)容最好可以分成多個(gè)層級(jí),以實(shí)現(xiàn)?3D?景深效果宿百,本實(shí)例中使用的是一張漫畫圖片轮纫,剛好可以切分成多個(gè)層級(jí)腔寡。
在?Photoshop?中打開圖片,根據(jù)自己需要的分層數(shù)量掌唾,創(chuàng)建若干圖層放前,并將地圖復(fù)制到每個(gè)圖層上,然后根據(jù)對(duì)圖層景深層級(jí)的劃分糯彬,編輯每個(gè)圖層凭语,結(jié)合使用魔棒工具和套索工具刪除多余的部分,然后將每個(gè)圖層單獨(dú)導(dǎo)出作為素材情连。我分為????如上?7?個(gè)圖層叽粹,外加一個(gè)邊框,一共有?8?個(gè)圖層却舀。
資源引入
其中?OrbitControls?用于鏡頭軌道控制虫几、TWEEN?用于鏡頭補(bǔ)間動(dòng)畫。
import React from 'react';
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";
場(chǎng)景初始化
初始化渲染容器挽拔、場(chǎng)景辆脸、攝像機(jī)、光源螃诅。攝像機(jī)初始位置設(shè)置為位于偏左方的?(-12, 0, 0)啡氢,以便于后面使用?TWEEN?實(shí)現(xiàn)翻轉(zhuǎn)動(dòng)畫效果。
// 場(chǎng)景
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
// 添加背景圖片
scene.background = new THREE.TextureLoader().load(background);
// 相機(jī)
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(-12, 0, 0);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 直射光
light = new THREE.DirectionalLight(0xffffff, 1);
light.intensity = .2;
light.position.set(10, 10, 30);
light.castShadow = true;
light.shadow.mapSize.width = 512 * 12;
light.shadow.mapSize.height = 512 * 12;
light.shadow.camera.top = 100;
light.shadow.camera.bottom = - 50;
light.shadow.camera.left = - 50;
light.shadow.camera.right = 100;
scene.add(light);
// 環(huán)境光
ambientLight = new THREE.AmbientLight(0xdddddd);
scene.add(ambientLight);
創(chuàng)建漫畫主體
首先創(chuàng)建一個(gè)?Group术裸,用于添加圖層網(wǎng)格倘是,然后遍歷圖層背景圖片數(shù)組,在循環(huán)體中創(chuàng)建每個(gè)面的網(wǎng)格袭艺,該網(wǎng)格使用平面立方體?PlaneGeometry搀崭,材質(zhì)使用物理材質(zhì)?MeshPhysicalMaterial,對(duì)每個(gè)網(wǎng)格位置設(shè)置相同的x軸和y軸值和不同的z軸值以創(chuàng)建景深效果猾编。最后將?Group?添加到場(chǎng)景?Scene?中瘤睹。
var layerGroup = new THREE.Group();
let aspect = 18;
for (let i=0; i<layers.length; i++) {
? let mesh = new THREE.Mesh(new THREE.PlaneGeometry(10.41, 16), new THREE.MeshPhysicalMaterial({
? ? map: new THREE.TextureLoader().load(layers[i]),
? ? transparent: true,
? ? side: THREE.DoubleSide
? }));
? mesh.position.set(0, 0, i);
? mesh.scale.set(1 - (i / aspect), 1 - (i / aspect), 1 - (i / aspect));
? layerGroup.add(mesh);
? // 文字
? if (i === 5) {
? ? mesh.material.metalness = .6;
? ? mesh.material.emissive = new THREE.Color(0x55cfff);
? ? mesh.material.emissiveIntensity = 1.6;
? ? mesh.material.opacity = .9;
? }
? // 會(huì)話框
? if (i === 6) {
? ? mesh.scale.set(1.5, 1.5, 1.5);
? ? animateLayer = mesh;
? }
}
layerGroup.scale.set(1.2, 1.2, 1.2);
到這一步升敲,實(shí)現(xiàn)效果如下圖所示:
???THREE.Group 層級(jí)模型
將具有相同主體的網(wǎng)格可以通過?Group?合并在一起,以便于提高運(yùn)行效率轰传。Three.js?層級(jí)模型?Group?的基類是?Object3D驴党,它是?Three.js?中大部分對(duì)象的基類,提供了一系列的屬性和方法來(lái)對(duì)三維空間中的物體進(jìn)行操縱获茬。如可以通過?.add(object)?方法來(lái)將對(duì)象進(jìn)行組合港庄,該方法將對(duì)象添加為子對(duì)象。
但最好使用?Group?來(lái)作為父對(duì)象锦茁,因?yàn)?Group?相比較Object3D?更語(yǔ)義化攘轩,可以使用?Group?作為點(diǎn)、線码俩、網(wǎng)格等模型的父對(duì)象,用來(lái)構(gòu)建一個(gè)層級(jí)模型歼捏。
創(chuàng)建Boom背景
為了加強(qiáng)視覺效果稿存,我添加了一個(gè)?? Boom?爆炸圖形平面作為背景,用鼠標(biāo)移動(dòng)的時(shí)候隨著光線的變化瞳秽,可以看到該圖案有金屬漸變效果瓣履,這種效果主要是通過高光材質(zhì)?MeshPhongMaterial?的?specular?和?shininess?屬性實(shí)現(xiàn)的。
const boom = new THREE.Mesh(new THREE.PlaneGeometry(36.76, 27.05), new THREE.MeshPhongMaterial({
? map: new THREE.TextureLoader().load(boomImage),
? transparent: true,
? shininess: 160,
? specular: new THREE.Color(0xff6d00),
? opacity: .7
}));
boom.scale.set(.8, .8, .8);
boom.position.set(0, 0, -3);
layerGroup.add(boom)
scene.add(layerGroup);
添加后效果:
???MeshPhongMaterial 高光網(wǎng)格材質(zhì)
MeshPhongMaterial?是一種用于具有鏡面高光的光澤表面的材質(zhì)练俐。該材質(zhì)使用非物理的?Blinn-Phong?模型來(lái)計(jì)算反射率袖迎。 與?MeshLambertMaterial?中使用的?Lambertian?模型不同,該材質(zhì)可以模擬具有鏡面高光的光澤表面腺晾,如涂漆木材燕锥。
構(gòu)造函數(shù):
MeshPhongMaterial(parameters: Object)
parameters:可選,用于定義材質(zhì)外觀的對(duì)象悯蝉,具有一個(gè)或多個(gè)屬性归形。 材質(zhì)的任何屬性都可以從此處傳入(包括從Material繼承的任何屬性)。
特殊屬性:
.emissive[Color]:材質(zhì)的放射光顏色鼻由,基本上是不受其他光照影響的固有顏色暇榴。默認(rèn)為?黑色。
.emissiveMap[Texture]:設(shè)置發(fā)光貼圖蕉世。默認(rèn)值為?null蔼紧。放射貼圖顏色由放射顏色和強(qiáng)度所調(diào)節(jié)。
.emissiveIntensity[Float]:放射光強(qiáng)度狠轻。調(diào)節(jié)發(fā)光顏色奸例。默認(rèn)為?1。
.envMap[TextureCube]:環(huán)境貼圖哈误。默認(rèn)值為?null哩至。
.isMeshPhongMaterial[Boolean]:用于檢查此類或派生類是否為?Phong?網(wǎng)格材質(zhì)躏嚎。默認(rèn)值為?true。
.lightMap[Texture]:光照貼圖菩貌。默認(rèn)值為?null卢佣。
.lightMapIntensity[Float]:烘焙光的強(qiáng)度。默認(rèn)值為?1箭阶。
.reflectivity[Float]:環(huán)境貼圖對(duì)表面的影響程度虚茶。默認(rèn)值為?1,有效范圍介于?0(無(wú)反射)?和?1(完全反射)?之間仇参。
.refractionRatio[Float]:空氣的折射率除以材質(zhì)的折射率嘹叫。折射率不應(yīng)超過?1。默認(rèn)值為?0.98诈乒。
.shininess[Float]:.specular?高亮的程度罩扇,越高的值越閃亮。默認(rèn)值為?30怕磨。
.skinning[Boolean]:材質(zhì)是否使用蒙皮喂饥。默認(rèn)值為?false。
.specular[Color]:材質(zhì)的高光顏色肠鲫。默認(rèn)值為?0x111111?的顏色?Color员帮。這定義了材質(zhì)的光澤度和光澤的顏色。
.specularMap[Texture]:鏡面反射貼圖值會(huì)影響鏡面高光以及環(huán)境貼圖對(duì)表面的影響程度导饲。默認(rèn)值為?null捞高。
???使用?Phong?著色模型計(jì)算著色時(shí),會(huì)計(jì)算每個(gè)像素的陰影渣锦,與?MeshLambertMaterial?使用的?Gouraud?模型相比硝岗,該模型的結(jié)果更準(zhǔn)確,但代價(jià)是犧牲一些性能泡挺。
鏡頭控制辈讶、縮放適配、動(dòng)畫
鏡頭補(bǔ)間動(dòng)畫娄猫,鏡頭切換到正確位置贱除。
Animations.animateCamera(camera, controls, { x: 0, y: 0, z: 20 }, { x: 0, y: 0, z: 0 }, 3600, () => { });
鏡頭控制,本示例中顯示了模型平移以及水平垂直旋轉(zhuǎn)的角度媳溺,以達(dá)到最好的預(yù)覽效果月幌。
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enablePan = false;
// 垂直旋轉(zhuǎn)角度限制
controls.minPolarAngle = 1.2;
controls.maxPolarAngle = 1.8;
// 水平旋轉(zhuǎn)角度限制
controls.minAzimuthAngle = -.6;
controls.maxAzimuthAngle = .6;
屏幕縮放適配。
window.addEventListener('resize', () => {
? camera.aspect = window.innerWidth / window.innerHeight;
? camera.updateProjectionMatrix();
? renderer.setSize(window.innerWidth, window.innerHeight);
}, false);
對(duì)于會(huì)話框圖層網(wǎng)格悬蔽,我給它添加了在一條光滑曲線上左右移動(dòng)的動(dòng)畫效果扯躺,主要是通過修改它在?x?軸和?y?軸上的?position?來(lái)實(shí)現(xiàn)的 。
function animate() {
? requestAnimationFrame(animate);
? renderer.render(scene, camera);
? controls && controls.update();
? TWEEN && TWEEN.update();
? // 會(huì)話框擺動(dòng)動(dòng)畫
? step += 0.01;
? animateLayer.position.x = 2.4 + Math.cos(step);
? animateLayer.position.y = .4 + Math.abs(Math.sin(step));
}
???正弦余弦函數(shù)創(chuàng)建模型移動(dòng)軌跡
使用?step?變量并在函數(shù)?Math.cos()?和?Math.sin()?的幫助下 ,創(chuàng)建出一條光滑的軌跡录语。step+= 0.01?定義的是球的彈跳速度倍啥。
到此,本示例的完整實(shí)現(xiàn)都描述完畢了澎埠,大家感興趣的話虽缕,可以動(dòng)手試著把自己喜歡的圖片改造成?3D?視圖。拜托蒲稳,使用?Three.js?這樣展示圖片超酷的好嗎氮趋!???
???完整代碼:https://github.com/dragonir/3d/tree/master/src/containers/Comic
總結(jié)
本文知識(shí)點(diǎn)主要包含的的新知識(shí):
THREE.Group?層級(jí)模型
MeshPhongMaterial?高光網(wǎng)格材質(zhì)
正弦余弦函數(shù)?創(chuàng)建模型移動(dòng)軌跡
想了解場(chǎng)景初始化、光照江耀、陰影剩胁、基礎(chǔ)幾何體、網(wǎng)格祥国、材質(zhì)及其他?Three.js?的相關(guān)知識(shí)昵观,可閱讀我往期文章。轉(zhuǎn)載請(qǐng)注明原文地址和作者舌稀。如果覺得文章對(duì)你有幫助索昂,不要忘了一鍵三連哦 ??。
轉(zhuǎn)載:https://www.cnblogs.com/dragonir/p/15921635.html
Sign up for more like this.