使用Three.js讓二維圖片呈現(xiàn)3D效果

場(chǎng)景編輯器(NSDT)


聲明:本文涉及圖文和模型素材僅用于個(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.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扩借,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缤至,更是在濱河造成了極大的恐慌潮罪,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件领斥,死亡現(xiàn)場(chǎng)離奇詭異嫉到,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)月洛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門何恶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人嚼黔,你說我怎么就攤上這事细层。” “怎么了唬涧?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵疫赎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我碎节,道長(zhǎng)捧搞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮胎撇,結(jié)果婚禮上介粘,老公的妹妹穿的比我還像新娘。我一直安慰自己晚树,他們只是感情好姻采,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著题涨,像睡著了一般偎谁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纲堵,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天巡雨,我揣著相機(jī)與錄音,去河邊找鬼席函。 笑死铐望,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茂附。 我是一名探鬼主播正蛙,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼营曼!你這毒婦竟也來(lái)了乒验?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蒂阱,失蹤者是張志新(化名)和其女友劉穎锻全,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體录煤,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳄厌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妈踊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片了嚎。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖廊营,靈堂內(nèi)的尸體忽然破棺而出歪泳,到底是詐尸還是另有隱情,我是刑警寧澤赘风,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布夹囚,位于F島的核電站,受9級(jí)特大地震影響邀窃,放射性物質(zhì)發(fā)生泄漏荸哟。R本人自食惡果不足惜假哎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞍历。 院中可真熱鬧舵抹,春花似錦、人聲如沸劣砍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刑枝。三九已至香嗓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間装畅,已是汗流浹背靠娱。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掠兄,地道東北人像云。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蚂夕,于是被迫代替她去往敵國(guó)和親迅诬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容