自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

基于web創(chuàng)建逼真的3D圖形 | CSS技巧

新聞 前端 開發(fā)
在成為一名web開發(fā)者之前,我從事于視覺設(shè)計(jì)行業(yè),創(chuàng)造屢獲殊榮,電影和電視節(jié)目等高端3D效果,例如 Tron, The Thing, Resident Evil,和 Vikings ,為了能夠創(chuàng)造這些效果,我們需要使用高度復(fù)雜的動(dòng)畫軟件。

在成為一名web開發(fā)者之前,我從事于視覺設(shè)計(jì)行業(yè),創(chuàng)造屢獲殊榮,電影和電視節(jié)目等高端3D效果,例如 Tron, The Thing, Resident Evil,和 Vikings 。為了能夠創(chuàng)造這些效果,我們需要使用高度復(fù)雜的動(dòng)畫軟件,例如 Maya , 3Ds Max 或者 Houdini ,包括使用數(shù)以百計(jì)的機(jī)器 渲染機(jī)器 來做長時(shí)間的離線渲染。正因?yàn)槲夜ぷ饕詠硪恢笔褂眠@些工具,以至于我對(duì)現(xiàn)在的web技術(shù)感到很驚訝。我們可以創(chuàng)造和顯示高質(zhì)量的3D內(nèi)容在瀏覽器里面,實(shí)際上,就是使用webGL和Three.js。

這個(gè)項(xiàng)目例子 是使用這些技術(shù)創(chuàng)建的。在他們的網(wǎng)站里,你可以發(fā)現(xiàn)更多thress.js的項(xiàng)目。 

使用three.js的一些項(xiàng)目

這些由three.js構(gòu)建的網(wǎng)站表明,3D可視化在商業(yè),零售,娛樂和廣告領(lǐng)域擁有巨大的潛力。

WebGL是比較低級(jí)的JavaScript的API,它能夠通過使用GPU,來創(chuàng)造并將3D的內(nèi)容顯示在瀏覽器里面。不幸地是,既然WebGL是比較低的API,意味著它更加困難被使用。你需要編寫上百行代碼來運(yùn)行,即使是很簡單的任務(wù)。three.js,另一方面來說,是一個(gè)開放的JavaScript庫,抽象了WebGL的復(fù)雜性,同時(shí)允許你以更簡單的方式,創(chuàng)造實(shí)時(shí)的3D內(nèi)容。

在本教程中,我將介紹基礎(chǔ)的three.js庫。在介紹一個(gè)新的程序庫時(shí),先舉一個(gè)簡單的例子來更好地表達(dá)基本原理,但我想進(jìn)一步說明這一點(diǎn)。同時(shí),我還將建立一個(gè)場景,更加愉快和逼真。

我們就開始了一個(gè)簡單的平面和球面但最終它會(huì)看起來像這樣:

See the Pen learning-threejs-final by Engin Arslan ( @enginarslan ) on CodePen .

臨摹是計(jì)算機(jī)圖形學(xué)的頂峰,但是,在你的位置下,實(shí)現(xiàn)不一定是進(jìn)程中必要的因素,而是從你的工具箱中進(jìn)行智能部署。這里有一些技術(shù),你將會(huì)在本教程中學(xué)到,它將幫助實(shí)現(xiàn)照片寫實(shí)。

  • 顏色,凹凸和粗糙度圖。

  • 物理材料

  • 陰影照明

逼真的3D圖像 by Ian Spriggs

您將在這里學(xué)習(xí)的基本3D原理和技術(shù)在任何其他3D內(nèi)容創(chuàng)建環(huán)境中都是相關(guān)的,無論是混合機(jī)、Unity、瑪雅還是3ds max。

這將是一個(gè)漫長的教程。如果您是一個(gè)喜歡看視頻的人,或者您想了解更多的關(guān)于Three.js,您應(yīng)該看看我對(duì)這個(gè)問題培訓(xùn)的視頻。來自 Lynda.com .

要求

當(dāng)使用three.js時(shí),如果你在本地工作,它有助于通過本地服務(wù)器服務(wù)HTML文件,以便加載像外部三維幾何圖形、圖像等應(yīng)用場景。如果你在尋找一個(gè)很容易建立的服務(wù),你可以使用python來運(yùn)行簡單的HTTP服務(wù)器。python在很多操作系統(tǒng)上都有安裝。

您不必?fù)?dān)心設(shè)置本地開發(fā)服務(wù)器來執(zhí)行本教程。相反,您將依賴于數(shù)據(jù)URL來加載像圖片這樣的資源,以消除設(shè)置服務(wù)器的開銷。使用線上代碼編輯器像 CodePen ,你可以很輕松的運(yùn)行你的Three.js代碼場景。

本教程假設(shè)對(duì)前端JavaScript以及對(duì)前端Web開發(fā)的知識(shí)有一些了解。如果您不習(xí)慣使用JavaScript,但希望輕松上手,您可能需要查看課程/書籍。 ["Coding for Visual Learners: Learning JavaScript with p5.js"( http://www.codingforvisuallearners.com/ ). (免責(zé)聲明:我是作者)

讓我們開始在Web上建立3D圖形!

入門

我已經(jīng)準(zhǔn)備了 prepared a Pen 你可以跟隨本教程進(jìn)行操作。

您將使用的HTML代碼將是超級(jí)簡單的。它只需要有一個(gè)div元素來承載正在顯示3D圖形的畫布。它從CDN上加載Three.js庫(版本86)。

<div id="webgl"></div>
``<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js">``</script>

為了您的方便,CodeOpen隱藏了HTML結(jié)構(gòu)。如果您在其它在線編輯器或本地站點(diǎn)上構(gòu)建此場景,那么您的HTML將需要類似于下面代碼的內(nèi)容,其中 main.js 將是保存JavaScript代碼的文件。

<!DOCTYPE html>
<html>
<head>
    <title>Three.js</title>
    <style type="text/css">
        html, body {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="webgl"></div>
    ``<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js">``</script>
    ``<script src="./main.js">``</script>
</body>
</html>

請注意html中的簡單CSS聲明。這就是你在CodePen里的CSS標(biāo)簽:

html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

這是為了確保沒有任何的margin和padding值,可以通過您的瀏覽器應(yīng)用,不會(huì)出現(xiàn)滾動(dòng)條,因此可以有圖形填充整個(gè)屏幕。這就是我們開始構(gòu)建3D圖形需要的一切。

***部分 - Three.js 基本場景

當(dāng)我們平常用three.js和3D來工作時(shí),這里有幾個(gè)您需要掌握的對(duì)象。它們是 場景 , 相機(jī) 以及 渲染 。

首先,您需要?jiǎng)?chuàng)造一個(gè)場景。您可以把一個(gè)場景對(duì)象看作是您要處理的每一個(gè)3D對(duì)象的容器。它代表了您將要?jiǎng)?chuàng)造的3D世界。您可以像這樣來創(chuàng)造場景對(duì)象:

var scene = new THREE.Scene();`

另外一件事就是當(dāng)你使用3D工作時(shí),你需要相機(jī)。想象相機(jī)就像眼睛一樣,你會(huì)看到這個(gè)3D世界。當(dāng)使用2D可視化時(shí),相機(jī)的概念通常是不存在的。你看到什么就是什么。但是在3D的世界,你需要一個(gè)相機(jī)來定義你的觀點(diǎn),因?yàn)槟憧梢詮囊粋€(gè)場景中看到很多的位置和角度。相機(jī)不僅定義了位置,而且還定義了其他的信息,如視野或縱橫比。

var camera = new THREE.PerspectiveCamera(
    45, // field of view
    window.innerWidth / window.innerHeight, // aspect ratio
    1, // near clipping plane (beyond which nothing is visible)
    1000 // far clipping plane (beyond which nothing is visible)
);

相機(jī)捕捉場景以顯示目的,但我們實(shí)際上可以看到任何東西,3D數(shù)據(jù)需要轉(zhuǎn)換為2D圖像。這個(gè)過程稱為 正在渲染 ,同時(shí)你需要用 渲染器 在three.js的場景中來進(jìn)行渲染。你可以初始化渲染像這樣的:

var renderer = new THREE.WebGLRenderer();`

之后設(shè)置渲染器的大小。這將決定輸出圖像的大小。

renderer.setSize(window.innerWidth, window.innerHeight);`

為了能夠顯示你渲染的結(jié)果,你需要將渲染器的 domelement 屬性追加到HTML內(nèi)容里面。你會(huì)使用空的div元素,為此來創(chuàng)造id為 WebGL 的元素。

document.getElementById('webgl').appendChild(renderer.domElement);`

當(dāng)做完這一切,你可以視在渲染器上 渲染 的這種方法,是提供場景和相機(jī)作為參數(shù)對(duì)象。

renderer.render(
    scene,
    camera
);

為了讓代碼更簡潔,在函數(shù) init 里面進(jìn)行調(diào)用和執(zhí)行功能。

init();`

也許你現(xiàn)在什么也看不見...除了黑屏。別急,這是正常的。這個(gè)場景是正常工作的,但是你沒有包含任何的對(duì)象再場景里面,你所看到的基本上是空的空間,接下來,你會(huì)使用3D對(duì)象填充這個(gè)場景。

看 the Pen learning-threejs-01 by Engin Arslan ( @enginarslan ) on CodePen .

向場景中添加對(duì)象

three.js里面的幾何對(duì)象是由兩部分組成的。一個(gè)幾何對(duì)象決定了一個(gè)對(duì)象的形狀和一個(gè)材料決定了其表面質(zhì)量,一個(gè)對(duì)象的外形,兩者的結(jié)合組成了three.js里面的網(wǎng)格,形成3D對(duì)象。

Three.js允許你創(chuàng)建一些簡單的形狀,如立方體、球體在一個(gè)簡單的方式。您可以通過創(chuàng)建一個(gè)簡單的球體的半徑值。

var geo = new THREE.SphereGeometry(1);`

這里有各種材料可以在幾何中使用。材料決定了一個(gè)對(duì)象對(duì)光場景的反應(yīng)。我們可以用一切材料使物體反光,粗糙,透明等。默認(rèn)的材料,像由 MeshBasicMaterial . MeshBasicMaterial 創(chuàng)造的three.js對(duì)象一點(diǎn)不受光場景的影響。這意味著即使你的場景中沒有燈光,你的幾何圖形也將可見。你可以用一個(gè)顏色屬性,可以為對(duì)象設(shè)置你想要的顏色 meshbasicmaterial hex值傳遞一個(gè)對(duì)象,您現(xiàn)在將使用此材料,但稍后更新它將使您的對(duì)象受到場景燈光的影響。你沒有任何照明的場景,現(xiàn)在 meshbasicmaterial 應(yīng)該是一個(gè)好的選擇。

var material = new THREE.MeshBasicMaterial({
        color: 0x00ff00
});

你可以結(jié)合幾何和材料創(chuàng)建一個(gè)網(wǎng)格,這將形成三維物體。

var mesh = new THREE.Mesh(geometry, material);`

創(chuàng)建一個(gè)函數(shù)來封裝創(chuàng)建球體的代碼。在本教程中,您不會(huì)創(chuàng)建多個(gè)球體,但保持整體整潔還是不錯(cuò)的。

function getSphere(radius) {
    var geometry = new THREE.SphereGeometry(radius);
    var material = new THREE.MeshBasicMaterial({
        color: 0x00ff00
    });
    var sphere = new THREE.Mesh(geometry, material);
    return sphere;
}

var sphere = getSphere(1);

然后,您需要將這個(gè)新創(chuàng)建的對(duì)象添加到場景中以使其可見。

scene.add(sphere);`

讓我們再次檢查這個(gè)場景,你還會(huì)看到這個(gè)黑屏。

看代碼 learning-threejs-02 by Engin Arslan ( @enginarslan ) on CodePen .

無論何時(shí)你往three.js里面添加場景對(duì)象,對(duì)象被放置在場景的中心,在x、y和z的坐標(biāo)為0, 0, 0,就是你什么都看不到的原因,這就意味著你目前的相機(jī)和球體處于同一位置。你應(yīng)該改變他們中的任何一個(gè)的位置,以便能夠開始看東西。

3D協(xié)調(diào)

讓我們把照相機(jī)20個(gè)單位移到z軸上。這是通過在攝像機(jī)上設(shè)置 * 位置的屬性來實(shí)現(xiàn)的。3D對(duì)象有 position , rotation 和 scale 屬性,可以允許你在3D空間里面任意旋轉(zhuǎn)它們。

camera.position.z = 20;`

你可以移動(dòng)攝像機(jī)以及其他軸。

camera.position.x = 0;
camera.position.y = 5;
camera.position.z = 20;

相機(jī)現(xiàn)在位置更高了,但是球體不再在框架的中心位置了。你需要把相機(jī)指向它。為了能夠做到這樣,你可以調(diào)用相機(jī)的一個(gè)方法稱為 lookAt 。通過相機(jī)上的 lookAt 方法確定哪些點(diǎn)是相機(jī)指向的。在三維空間中的點(diǎn)表示的是向量。所以,你可以通過一個(gè)新的 Vector3 對(duì)象,這 lookAt 方法能在0, 0, 0相機(jī)坐標(biāo)看。

camera.lookAt(new THREE.Vector3(0, 0, 0));`

球?qū)ο蟋F(xiàn)在看起來不是很圓。究其原因,是 spheregeometry 函數(shù)實(shí)際上接受兩個(gè)額外的參數(shù),寬度和高度細(xì)分,影響 resolution 表面。增加這些值,平滑的曲面會(huì)出現(xiàn)。我將此值設(shè)置為24的寬度和高度細(xì)分。

var geo = new THREE.SphereGeometry(radius, 24, 24);`

See the Pen learning-threejs-03 by Engin Arslan ( @enginarslan ) on CodePen .

現(xiàn)在,您將創(chuàng)建一個(gè)簡單的平面幾何的球體。 PlaneGeometry 函數(shù)要求有 width 和 height 參數(shù)。在3D中,2D對(duì)象沒有默認(rèn)的兩個(gè)側(cè)面,所以你需要將一個(gè) side 屬性傳遞給材質(zhì),使平面幾何體的兩邊呈現(xiàn)。

function getPlane(w, h) {
  var geo = new THREE.PlaneGeometry(w, h);
  var material = new THREE.MeshBasicMaterial({
    color: 0x00ff00,
    side: THREE.DoubleSide,
  });
  var mesh = new THREE.Mesh(geo, material);

  return mesh;
}

現(xiàn)在你可以往這個(gè)平面對(duì)象里添加場景。你會(huì)注意到,平面幾何的初始旋轉(zhuǎn)是平行于y軸,但你可能需要它是水平的,因?yàn)樗鳛橐粋€(gè)接地平面,你需要記住一件重要的事,那就是three.js里的旋轉(zhuǎn)。它們用 radians 為單位,不用 degrees 。弧度旋轉(zhuǎn)90度相當(dāng)于 π/ 2 數(shù)學(xué)。

var plane = getPlane(50, 50);
scene.add(plane);
plane.rotation.x = Math.PI/2;

當(dāng)你創(chuàng)造一個(gè)球?qū)ο螅盟闹行狞c(diǎn)定位。如果你想把它移動(dòng)到地面上,那么你可以只增加它的'位置' Y值的當(dāng)前半徑的數(shù)量。但這不會(huì)是一個(gè)綱領(lǐng)性的做事方式。如果你想讓球體停留在平面上,不管它的半徑值是多少,你都應(yīng)該利用半徑值來定位。

sphere.position.y = sphere.geometry.parameters.radius;`

看 the Pen learning-threejs-04 by Engin Arslan ( @enginarslan ) on CodePen .

動(dòng)畫

你幾乎完成了本教程的***部分。但在我們把它整合起來之前,我想說明一下如何用three.js來做動(dòng)畫。three.js動(dòng)畫中使用的 requestanimationframe 方法對(duì) 窗口 對(duì)象反復(fù)執(zhí)行一個(gè)給定的函數(shù)。它有點(diǎn)像一個(gè) setInterval 函數(shù),但它是繪制瀏覽器運(yùn)行性能。

創(chuàng)造一個(gè) update 函數(shù),通過渲染,場景,和相機(jī)在那里執(zhí)行渲染方法,在函數(shù)內(nèi)進(jìn)行渲染。你將會(huì)在內(nèi)部聲明 requestAnimationFrame 函數(shù),并將 更新 函數(shù),通過對(duì) requestanimationframe 函數(shù)遞歸進(jìn)行回調(diào),這樣說明代碼比寫出來更好。

function update(renderer, scene, camera) {
  renderer.render(scene, camera);

  requestAnimationFrame(function() {
    update(renderer, scene, camera);
  });
}

在這一點(diǎn)上一切看起來都一樣,但核心的區(qū)別是, requestanimationframe 函數(shù)是使場景渲染每秒約60幀遞歸調(diào)用的 更新 函數(shù)。這意味著如果你正在 update 函數(shù)里面執(zhí)行語句,該語句將以每秒60次的速度執(zhí)行。讓我們添加一個(gè)縮放動(dòng)畫球?qū)ο?。為了?nbsp;update 函數(shù)中選擇球體對(duì)象,您可以將它作為參數(shù)傳遞,但我們將使用不同的技術(shù)。首先,在球?qū)ο笊显O(shè)置一個(gè) name 屬性,并給它取一個(gè)你喜歡的名字。

sphere.name = 'sphere';`

在update函數(shù)內(nèi)部,你可以使用它的名字,并且使用 getObjectByName 方法在其父對(duì)象上,找到該對(duì)象,這個(gè)場景。

var sphere = scene.getObjectByName('sphere');
sphere.scale.x += 0.01;
sphere.scale.z += 0.01;

通過這段代碼,這個(gè)球的X和Z軸在縮放。盡管我們的意圖不是創(chuàng)造一個(gè)縮放的球。我們正在設(shè)置 update 函數(shù),以便我們以后可以使用不同的動(dòng)畫?,F(xiàn)在你已經(jīng)看到了它是如何工作的,你可以刪除這個(gè)縮放動(dòng)畫。

看代碼 learning-threejs-05 by Engin Arslan ( @enginarslan ) on CodePen .

第二部分 - 在場景中添加現(xiàn)實(shí)

目前,我們正在使用 MeshBasicMaterial ,即使在場景中沒有燈光時(shí),它也會(huì)顯示出給定的顏色,這會(huì)導(dǎo)致一個(gè)非常扁平的外觀。盡管真實(shí)世界的材料不會(huì)以這種方式進(jìn)行工作。真實(shí)世界可見的表面,取決于從表面反射回我們眼睛的光有多少。three.js有幾個(gè)不同的材料,提供更好的接近實(shí)際表面的行為,其中一個(gè)是 meshstandardmaterial 。 meshstandardmaterial 是一個(gè)基于物理的渲染材料,可以幫助你達(dá)到逼真的效果。這是現(xiàn)代游戲引擎的一種材料,如 Unreal or Unity,是游戲和視覺效果的行業(yè)標(biāo)準(zhǔn)。

讓我們開始在我們對(duì)象中使用 MeshStandardMaterial ,改變其顏色變?yōu)榘咨?/p>

var material = new THREE.MeshStandardMaterial({
  color: 0xffffff,
});

你將會(huì)在這個(gè)點(diǎn)上再次得到黑色渲染。這是正常的。對(duì)象在場景中需要光才能顯示。這對(duì)于 meshbasicmaterial 不是必須的,因?yàn)樗且粋€(gè)簡單的材料,在所有條件下,顯示給定的顏色,但其他材料需要與光的相互作用才可見。讓我們創(chuàng)造一個(gè) SpotLight 函數(shù),你將會(huì)用這個(gè)函數(shù)創(chuàng)造兩個(gè)聚光燈。

function getSpotLight(color, intensity) {
  var light = new THREE.SpotLight(color, intensity);

  return light;
}

var spotLight_01 = getSpotlight(0xffffff, 1);
scene.add(spotLight_01);

你也許在這個(gè)點(diǎn)上可以看到些事情。為了更好的取景和陰影,光線和相機(jī)的位置有點(diǎn)不同。同時(shí)創(chuàng)造一個(gè)輔助光。

var spotLight_02 = getSpotlight(0xffffff, 1);
scene.add(spotLight_02);

camera.position.x = 0;
camera.position.y = 6;
camera.position.z = 6;

spotLight_01.position.x = 6;
spotLight_01.position.y = 8;
spotLight_01.position.z = -20;

spotLight_02.position.x = -12;
spotLight_02.position.y = 6;
spotLight_02.position.z = -10;

做完這些,你場景中將有兩個(gè)光源,從兩個(gè)不同的位置照射球體。燈光有助于了解場景的維度。但在這一點(diǎn)上,事情仍然非常不真實(shí),因?yàn)檎彰魅鄙僖粋€(gè)關(guān)鍵的組成部分:陰影!

不幸地是,在three.js中渲染陰影不是很簡單。這是因?yàn)殛幱坝?jì)算上很費(fèi)成本,我們需要在多個(gè)地方激活陰影渲染。首先,你需要告訴渲染器開始渲染陰影:

var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;

然后,你需要告訴光線投射陰影。在 getSpotLight 函數(shù)里面進(jìn)行。

light.castShadow = true;`

你應(yīng)該告訴對(duì)象投射或者接收陰影。在這種情況下,你將會(huì)讓球體投射陰影并且用這個(gè)平面來接收陰影。

mesh.castShadow = true;
mesh.receiveShadow = true;

在設(shè)置了這些之后,我們應(yīng)該開始看場景中的陰影。首先,他們可能效果不是很好。您可以通過設(shè)置光影貼圖大小來提高陰影的分辨率。

light.shadow.mapSize.x = 4096;
light.shadow.mapSize.y = 4096;

MeshStandardMaterial 有很多屬性,例如 roughness 和 metalness 控制表面與光的相互作用。這些屬性取值在0到1之間,它們控制著相應(yīng)的表面行為。增加平面材料的粗糙度值到1,使表面看起來更像一個(gè)橡膠,作為反射而使其變得模糊。

// material adjustments
var planeMaterial = plane.material;
planeMaterial.roughness = 1;

盡管如此,在本教程中我們不會(huì)將其值設(shè)為 1 。您可以自由試驗(yàn)值,但可以將其設(shè)置為0.65,用于粗糙度和0.75的金屬。

planeMaterial.roughness = 0.65;
planeMaterial.metalness = 0.75;

盡管現(xiàn)在的場景看起來更有希望,但仍然很難稱之為現(xiàn)實(shí)。事實(shí)是,在不使用紋理貼圖的情況下,很難在三維中建立光致主義。

看代碼 learning-threejs-06 by Engin Arslan ( @enginarslan ) on CodePen .

紋理映射

材質(zhì)貼圖是二維圖像,可以在材質(zhì)上進(jìn)行映射,以提供表面細(xì)節(jié)。到目前為止,你只能在表面上得到純色,但使用紋理貼圖,你可以在一個(gè)表面上繪制任何你想要的圖像。紋理貼圖不僅被用來操縱表面的顏色信息,而且還可以用來操縱表面的其他特性,如反射性、亮度、粗糙度等。

紋理可以從照片來源獲得,也可以從草稿中繪制。對(duì)于一個(gè)在3D環(huán)境中有用的紋理,它應(yīng)該以某種方式被捕獲。圖像中有反射或陰影,或圖像過于扭曲的圖像,不會(huì)產(chǎn)生很好的紋理貼圖。有幾個(gè)專門的網(wǎng)站在網(wǎng)上尋找紋理。其中一個(gè)是 textures.com ,它有一個(gè)很好的存檔。他們有一些免費(fèi)的下載選項(xiàng),但你需要注冊才能做到這一點(diǎn)。另一個(gè)3D材質(zhì)的網(wǎng)站是 Megascans ,它的高分辨率,高質(zhì)量的環(huán)境掃描,高質(zhì)量的產(chǎn)品質(zhì)量。

我使用了一個(gè)名為 mb3d.co.uk 的網(wǎng)站上的例子。這個(gè)網(wǎng)站提供了無縫的、免費(fèi)的紋理。無縫紋理意味著一種紋理,可以在表面上多次重復(fù),而不會(huì)在邊緣遇到任何不連續(xù)性的情況下發(fā)生. 這是鏈接 我用的紋理文件。我已經(jīng)將圖片文件的大小縮小到512px,并使用一個(gè)名為 ezgif 的在線服務(wù)將圖像文件轉(zhuǎn)換為數(shù)據(jù)URI,以將其作為JavaScript代碼的一部分,而不是將其作為單獨(dú)的資產(chǎn)加載。(提示:如果要使用該服務(wù),不要將標(biāo)記包含在數(shù)據(jù)中)

創(chuàng)建一個(gè)函數(shù),返回我們生成的數(shù)據(jù)URI,這樣我們就不必在代碼的中間放置一個(gè)大的字符串。

function getTexture() {
    var data = 'data:image/jpeg;base64,/...'; // paste your data URI inside the quotation marks.
    return data
}

接下來,你需要加載紋理并將其應(yīng)用到平面上。為此您將使用three.js。在加載紋理之后,你會(huì)將紋理加載到所需材質(zhì)的地圖屬性中,將其作為一種顏色地圖在表面上。

var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load(getTexture());
planeMaterial.map = texture;

現(xiàn)在的東西看起來很難看,因?yàn)楸砻娴募y理像素化了。這張圖片拉伸得太大了,無法覆蓋整個(gè)表面。你可以做的是讓圖像重復(fù),而不是縮放,這樣就不會(huì)像素化了。為此,您需要設(shè)置 wrapSand wrapT 屬性為 THREE.RepeatWrapping 。重復(fù)包裝并指定重復(fù)值。因?yàn)槟阋矔?huì)為其他類型的地圖做這個(gè)(比如凹凸或粗糙貼圖),***是為它創(chuàng)建一個(gè)循環(huán):

var repetition = 6;
var textures = ['map']// we will add 'bumpMap' and 'roughnessMap'
textures.forEach((mapName) => {
  planeMaterial[mapName].wrapS = THREE.RepeatWrapping;
  planeMaterial[mapName].wrapT = THREE.RepeatWrapping;
  planeMaterial[mapName].repeat.set(repetition, repetition);
});

這看起來應(yīng)該更好。因?yàn)槟闼褂玫募y理是無縫的,你不會(huì)注意到有重復(fù)發(fā)生的邊緣的任何不連接。

紋理的加載實(shí)際上是一個(gè)異步操作。這意味著您的3D場景是在加載圖像文件之前生成的。但是由于您一直在使用 requestAnimationFrame 不斷地呈現(xiàn)場景,因此在本例中不會(huì)造成任何問題。如果不這樣做,則需要使用回調(diào)或其他異步方法來管理加載順序。

看代碼 learning-threejs-07 by Engin Arslan ( @enginarslan ) on CodePen .

其他紋理地圖

正如上一章所提到的,紋理不僅被用來定義表面的顏色,而且還用來定義它的其他性質(zhì)。貼圖的另一種方式是 凹凸貼圖 。當(dāng)被用作凹凸貼圖時(shí),紋理的亮度值會(huì)模擬一個(gè)高度的效果。

planeMaterial.bumpMap = texture;`

凹凸貼圖也應(yīng)該使用與顏色貼圖相同的重復(fù)配置,所以在 textures 數(shù)組中包含它。

var textures = ['map', 'bumpMap'];`

使用凹凸貼圖,加亮一個(gè)像素的值,相應(yīng)的表面看起來會(huì)更高。但是凹凸貼圖并沒有改變表面,它只是在操縱光與表面的相互作用產(chǎn)生一種不均勻拓?fù)涞腻e(cuò)覺?,F(xiàn)在的碰撞量看起來有點(diǎn)太大了。凹凸貼圖在使用時(shí)效果很好。因此,讓我們將 bumpScale 參數(shù)更改為更低的值,以獲得更細(xì)微的效果。

planeMaterial.bumpScale = 0.01;`

注意,這種紋理在外觀上有很大的不同。反射不再***了,但卻被***地分割了,就像現(xiàn)實(shí)生活中那樣。另一種可用于標(biāo)準(zhǔn)材料的 StandardMaterial 是 roughness map 。紋理貼圖是一個(gè)粗糙的貼圖,你可以使用給定圖像的亮度值來控制反射的銳度。

planeMaterial.roughnessMap = texture;
var textures = ['map', 'bumpMap', 'roughnessMap'];

根據(jù)這three.js文檔,當(dāng)與 environment map 一起使用時(shí),標(biāo)準(zhǔn)材料的工作效果***。環(huán)境圖模擬了一個(gè)遙遠(yuǎn)的環(huán)境,反映了場景中的反射面。當(dāng)你試圖模擬物體的反射率時(shí),這真的很有幫助。在三個(gè)環(huán)境地圖。js以 立方體地圖 的形式出現(xiàn)。多維數(shù)據(jù)集映射是一個(gè)在多維數(shù)據(jù)集內(nèi)映射的場景的全景視圖。一個(gè)立方體地圖由6個(gè)獨(dú)立的圖像組成,這些圖像對(duì)應(yīng)一個(gè)立方體的每個(gè)面。由于在一個(gè)在線編輯器中加載6個(gè)模式圖像將會(huì)有太多的工作,所以在本例中不會(huì)實(shí)際使用環(huán)境映射。但是為了使這個(gè)球面對(duì)象更加有趣,也可以添加一個(gè)粗糙度圖。你會(huì)使用這個(gè) 紋理 ,但是是320px*320px數(shù)據(jù)URI。

創(chuàng)建一個(gè)名為 getMetalTexture 紋理的新函數(shù)。

function getMetalTexture() {
    var data = 'data:image/jpeg;base64,/...'; // paste your data URI inside the quotation marks.
    return data
}

把它應(yīng)用在球面上,比如 bumpMap 和 roughnessMap :

var sphereMaterial = sphere.material;
var metalTexture = textureLoader.load(getMetalTexture());

sphereMaterial.bumpMap = metalTexture;
sphereMaterial.roughnessMap = metalTexture;
sphereMaterial.bumpScale = 0.01;
sphereMaterial.roughness = 0.75;
sphereMaterial.metalness = 0.25;

看代碼 learning-threejs-08 by Engin Arslan ( @enginarslan ) on CodePen .

封裝起來

你幾乎完成了!在這里,你只需要做一些小小的調(diào)整??梢钥吹竭@個(gè)場景文件的最終版本 in this Pen .

給燈光提供一種非白色的顏色。注意,如何實(shí)際使用CSS顏色值作為字符串來指定顏色:

var spotLight_01 = getSpotlight('rgb(145, 200, 255)', 1);
var spotLight_02 = getSpotlight('rgb(255, 220, 180)', 1);

然后在燈光中添加一些微妙的隨機(jī)動(dòng)畫,為場景添加一些生命。首先,將名稱屬性分配給燈光,這樣您就可以使用 getObjectByName 方法在 update 函數(shù)中找到它們。

spotLight_01.name = 'spotLight_01';
spotLight_02.name = 'spotLight_02';

之后,在 update 函數(shù)里面,使用 Math.random() 函數(shù)創(chuàng)造動(dòng)畫,

var spotLight_01 = scene.getObjectByName('spotLight_01');
spotLight_01.intensity += (Math.random() - 0.5) * 0.15;
spotLight_01.intensity = Math.abs(spotLight_01.intensity);

var spotLight_02 = scene.getObjectByName('spotLight_02');
spotLight_02.intensity += (Math.random() - 0.5) * 0.05;
spotLight_02.intensity = Math.abs(spotLight_02.intensity);

作為一個(gè)額外的獎(jiǎng)勵(lì),在場景文件中,我已經(jīng)包含了 OrbitControls 腳本。three.js攝像機(jī),這意味著你可以把你的鼠標(biāo)拖到場景上與攝像頭互動(dòng)!我也這樣做了,這樣場景就會(huì)隨著窗口大小的變化而調(diào)整。為了方便起見,我使用外部腳本實(shí)現(xiàn)了這一點(diǎn)。

看代碼 learning-threejs-final by Engin Arslan ( @enginarslan ) on CodePen .

現(xiàn)在,這個(gè)場景有點(diǎn)接近現(xiàn)實(shí)主義了。盡管如此,仍有許多缺失的部分。由于缺少反射和周圍的光線,球體球太暗了。地面平面在看的角度看得太平了。球體的輪廓太***了——它是CG(計(jì)算機(jī)圖形)***的。照明實(shí)際上并不像它所能的那樣真實(shí);它不會(huì)隨著源的距離而衰減(失去強(qiáng)度)。你還應(yīng)該添加粒子效果,相機(jī)動(dòng)畫,以及后期處理濾鏡,如果你想要這樣做的話。但這仍然是一個(gè)很好的例子來說明three.js的力量。以及你可以在瀏覽器中創(chuàng)建的圖形質(zhì)量。有關(guān)可以實(shí)現(xiàn)使用這個(gè)神奇的庫的更多信息,你應(yīng)該看看我的新課程 Lynda.com 的項(xiàng)目!

謝謝你閱讀到這里!希望你喜歡這篇文章,如果有任何問題,你可以在Twitter上 @inspiratory或在我 網(wǎng)站 上, 隨時(shí)聯(lián)系我。

責(zé)任編輯:張燕妮 來源: 眾成翻譯
相關(guān)推薦

2021-01-03 17:30:10

3D人像ARVR

2013-01-30 16:15:40

adobeHTML5css3

2010-02-14 15:27:25

2022-06-29 10:21:33

3d打印輔助工具

2017-03-22 11:57:57

3D XPoint存儲(chǔ)英特爾

2022-08-03 13:52:22

AI建筑師

2021-11-08 06:02:17

CSS 技巧代碼重構(gòu)

2024-07-03 14:29:38

2023-12-01 09:00:00

NeRF技術(shù)人工智能

2012-05-10 10:55:03

CSS

2021-06-18 05:59:37

Css前端CSS 特效

2009-03-10 18:16:49

2017-07-11 15:00:04

前端CSS3D視角

2021-08-30 06:20:39

CSS 技巧3D 效果

2013-11-18 17:33:48

微軟Windows 8.1應(yīng)用

2009-08-27 18:10:58

PHP繪制3D圖形

2009-03-26 09:00:12

Mozilla瀏覽器3D圖形加速

2013-07-25 09:32:26

OpenGL ESAndroid4.3

2021-06-09 08:30:52

CSS33D旋轉(zhuǎn)視圖3D動(dòng)畫

2013-05-31 15:48:44

Atheer增強(qiáng)現(xiàn)實(shí)D11
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)