成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

光照渲染——用canvas模擬光照效果

jokester / 1421人閱讀

摘要:光照我們能看到物體,是因?yàn)楣庹丈湓谖矬w上然后反射到我們的眼睛當(dāng)中。這篇文章也是想通過(guò)這個(gè)簡(jiǎn)單的光照計(jì)算來(lái)引出,后面的文章我會(huì)用來(lái)重新實(shí)現(xiàn)這個(gè)效果。渲染的光照效果關(guān)于我的博客這篇文章到這里就結(jié)束了。

光照

我們能看到物體,是因?yàn)楣庹丈湓谖矬w上然后反射到我們的眼睛當(dāng)中。其中的影響因素非常多:觀察者的位置、光源的位置、光的顏色、物體表面的顏色、材質(zhì)和粗糙程度等等。以后我們將會(huì)詳細(xì)探究如何模擬物體的材質(zhì),在這篇文章中我們只討論光源。

平行光源

太陽(yáng)的尺度相對(duì)地球來(lái)說(shuō)非常大,所以可以認(rèn)為從太陽(yáng)照射來(lái)的光線都是平行的,即太陽(yáng)是一個(gè)平行光源。

模擬平行光源的光照非常簡(jiǎn)單,當(dāng)光垂直照射到平面上,即光線方向和平面呈90度角時(shí),這時(shí)光照是最強(qiáng)的。如果照射的角度不斷變大(或者說(shuō)光線和平面的夾角不斷變?。庹找矔?huì)隨之變?nèi)?,?dāng)光線方向完全和平面平行時(shí),這時(shí)沒(méi)有光能照射到平面上,光強(qiáng)變成了0。

可以總結(jié)出,平行光的光照情況和兩個(gè)方向有關(guān):光線的方向和受光照平面的朝向。

我們用一個(gè)垂直于平面的向量去描述平面的朝向,在圖形學(xué)中,一般把這個(gè)向量稱為“法向量”。

我們可以用向量的“點(diǎn)乘”運(yùn)算來(lái)計(jì)算光強(qiáng)變化。

點(diǎn)乘也叫數(shù)量積,是接受在實(shí)數(shù)R上的兩個(gè)向量并返回一個(gè)實(shí)數(shù)值標(biāo)量的二元運(yùn)算。點(diǎn)乘運(yùn)算規(guī)則非常簡(jiǎn)單,將兩個(gè)向量對(duì)應(yīng)坐標(biāo)的乘積求和就行了。

這里我們計(jì)算的是三維向量,我們用數(shù)組來(lái)表示向量,寫(xiě)一個(gè)簡(jiǎn)單的方法來(lái)計(jì)算點(diǎn)乘:

/**
 * 點(diǎn)乘運(yùn)算
 * @param {Array} v1 向量v1
 * @param {Array} v2 向量v2
 * @return {number} 點(diǎn)乘結(jié)果
 */
function dot( v1, v2 ) {
    return v1[ 0 ] * v2[ 0 ] + v1[ 1 ] * v2[ 1 ] + v1[ 2 ] * v2[ 2 ];
}

還有幾個(gè)重要的向量運(yùn)算我們也會(huì)用到,在這里我們提前定義好,為減小篇幅,這里省略掉具體實(shí)現(xiàn),代碼可以看最后的實(shí)例源碼。

/**
 * 將向量轉(zhuǎn)為單位向量
 * @param {Array} v
 * @return {Array} 單位向量
 */
function normalize( v ) { /* ... */ }


/**
 * 兩向量相減
 * @param {Array} v1
 * @param {Array} v2
 * @return {Array}
 */
function sub( v1, v2 ) { /* ... */ }


/**
 * 計(jì)算一個(gè)向量的反方向向量
 * @param {Array} v
 * @return {Array}
 */
function negate( v ) { /* ... */ }

我們假設(shè)頁(yè)面的左上角為原點(diǎn)O,右方向?yàn)閤軸正方向,下方向?yàn)閥軸正方向,垂直屏幕向外的方向?yàn)閦軸正方向。我們可以這樣定義一個(gè)寬高都為500的平面:

var plane = {
    center: [ 250, 250, 0 ],    // 平面中心點(diǎn)坐標(biāo)
    width: 500,                 // 寬
    height: 500,                // 高
    normal: [ 0, 0, 1 ],        // 朝向,即法向量     
    color: { r: 255, g: 0, b: 0 }   // 顏色為紅色
}

對(duì)于平行光,只需要關(guān)心它的方向和顏色,我們可以這樣來(lái)定義一個(gè)平行光源:

var directionalLight = {
    direction: [ 0, 0, -1 ],        // 從屏幕外垂直照向屏幕
    color: { r: 255, g: 255, b: 255 }   // 顏色為純白色
}

平行光的光線都是平行的,所以它照射到平面上各個(gè)位置的效果都是一樣的,換言之,整個(gè)平面都應(yīng)該是同一個(gè)顏色。
根據(jù)上面的規(guī)則(光強(qiáng)等于光線反方向向量點(diǎn)乘平面法向量),我們可以計(jì)算出這個(gè)顏色:

// ...
var reverseLightDirection = negate( directionalLight.direction );   // 計(jì)算平行光的反方向向量
var intensity = dot( reverseLightDirection, plane.normal );         // 計(jì)算兩向量點(diǎn)乘

// 計(jì)算有光照時(shí)的顏色
var color = {
    r: intensity * plane.color.r + intensity * directionalLight.r,
    g: intensity * plane.color.g + intensity * directionalLight.g,
    b: intensity * plane.color.b + intensity * directionalLight.g,
}

var canvas = document.getElementById( "canvas" );
var ctx = canvas.getElementById( "2d" );
ctx.rect( plane.center[ 0 ], plane.center[ 1 ], plane.width, plane.height );
ctx.fillStyle = "rgb(" + color.r + "," + color.g + "," + color.b ")";
ctx.fill();

我寫(xiě)了一個(gè)示例,可以調(diào)整光線方向來(lái)觀察不同方向下的光照效果。
在線運(yùn)行示例

點(diǎn)光源

在日常生活中,點(diǎn)光源更加常見(jiàn),白熾燈、臺(tái)燈等都可以認(rèn)為是點(diǎn)光源。

首先,我們先定義一個(gè)點(diǎn)光源,對(duì)于一個(gè)點(diǎn)光源來(lái)說(shuō),我們只需要關(guān)心它的位置和顏色:

var pointLight = {
    position: [ 250, 250, 100 ],    // 光源位于平面中心上方100處
    color: { r: 255, g: 255, b: 255 }   // 顏色為純白色
}

光強(qiáng)的計(jì)算規(guī)則仍然不變:光強(qiáng)等于光線反方向向量點(diǎn)乘平面法向量。但是點(diǎn)光源的光是從一個(gè)點(diǎn)發(fā)射出來(lái),它們照射到平面上時(shí),所有光線的方向都不一樣。所以,我們必須挨個(gè)計(jì)算平面上所有像素的光強(qiáng)。

這里需要用到canvas提供的putImageData,這個(gè)方法可以直接填入一個(gè)區(qū)域的像素顏色值來(lái)繪圖。代碼如下:

// ...
var imageData = ctx.createImageData( 500, 500 );    // 創(chuàng)建一個(gè)ImageData,用來(lái)保存像素?cái)?shù)據(jù)

for ( var x = 0; x < imageData.width; x++ ) {
    for ( var y = 0; y < imageData.height; y++ ) {
        var index = y * imageData.width + x;        // 當(dāng)前計(jì)算的像素點(diǎn)的索引

        var point = [ x, y, 0 ];
        var normal = [ 0, 0, 1 ];

        var reverseLightDirection = normalize( sub( pointLight.position, point ) );  // 光線方向的反方向向量

        var light = dot( reverseLightDirection, normal );

        imageData.data[ index * 4 ] = pointLight.color.r * intensity + plane.color.r * intensity;
        imageData.data[ index * 4 + 1 ] = pointLight.color.g * intensity + plane.color.g * intensity;
        imageData.data[ index * 4 + 2 ] = pointLight.color.b * intensity + plane.color.b * intensity;
        imageData.data[ index * 4 + 3 ] = 255;
    }
}

ctx.putImageData( imageData, 100, 100 );

這樣就可以看到結(jié)果了:

我寫(xiě)了一個(gè)更復(fù)雜一點(diǎn)的例子,可以通過(guò)鼠標(biāo)去移動(dòng)光源,滑動(dòng)滾輪來(lái)改變光源高度:
在線運(yùn)行示例

動(dòng)態(tài)圖看起來(lái)有很多圈圈,實(shí)際上并沒(méi)有,可以自己玩一下

WebGL的優(yōu)勢(shì)

對(duì)于一個(gè)500*500的平面,我們?nèi)ビ?jì)算它在點(diǎn)光源光照下的顏色,需要挨個(gè)計(jì)算平面上所有點(diǎn),需要循環(huán)500*500=250000次,這其實(shí)是非常低效的。并且在做復(fù)雜場(chǎng)景的渲染時(shí),不會(huì)只有一個(gè)光源,而且還會(huì)有投影等計(jì)算,計(jì)算量將會(huì)非常大。

從更底層的角度來(lái)說(shuō),這是因?yàn)槊看斡?jì)算都是由CPU完成的,而CPU只能串行計(jì)算,它只能完成一個(gè)計(jì)算以后才能開(kāi)始下一次計(jì)算,所以非常緩慢。

這種復(fù)雜的渲染其實(shí)更適合用WebGL來(lái)做,因?yàn)槊恳淮斡?jì)算其實(shí)前后無(wú)關(guān),WebGL可以利用GPU的并行計(jì)算能力,同時(shí)去計(jì)算所有點(diǎn)的光照強(qiáng)度。一個(gè)500*500的平面,理論上只需要花一次計(jì)算的時(shí)間,這個(gè)提升是非常大的。

這篇文章也是想通過(guò)這個(gè)簡(jiǎn)單的光照計(jì)算來(lái)引出WebGL,后面的文章我會(huì)用WebGL來(lái)重新實(shí)現(xiàn)這個(gè)效果。


WebGL渲染的光照效果

關(guān)于我的博客

這篇文章到這里就結(jié)束了。

我計(jì)劃寫(xiě)一系列關(guān)于前端圖形渲染的文章,將會(huì)涵蓋常用的前端圖形繪制技術(shù):canvas、svg和WebGL。希望通過(guò)這一系列文章能讓讀者對(duì)前端的各種圖形繪制接口以及圖像處理、圖形學(xué)的基礎(chǔ)知識(shí)有所了解。希望在分享的同時(shí),也能鞏固和復(fù)習(xí)自己所學(xué)知識(shí),和大家共同進(jìn)步。

系列博客地址:https://github.com/hujiulong/...

如果能幫助到你,歡迎star,這樣也能及時(shí)追蹤博客的更新。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/90764.html

相關(guān)文章

  • three.js 簡(jiǎn)介

    摘要:對(duì)于自身不能發(fā)光的物體,需要給場(chǎng)景添加光源從而達(dá)到可視的效果。中渲染陰影的開(kāi)銷(xiāo)比較大,所以默認(rèn)物體是沒(méi)有陰影的,需要單獨(dú)開(kāi)啟。主要用于檢測(cè)動(dòng)畫(huà)運(yùn)行時(shí)的幀數(shù),可以顯示表示每秒多少幀和每幀多少毫秒,越大越好,但太大會(huì)影響性能,一般為左右。 一、WebGL 與 three.js WebGL(Web Graphics Library)是一種3D繪圖協(xié)議,它允許把JavaScript和OpenG...

    yankeys 評(píng)論0 收藏0
  • 產(chǎn)品三維模型在線預(yù)覽

    摘要:次時(shí)代傳統(tǒng)的方式就是創(chuàng)建次時(shí)代模型,對(duì)應(yīng)中的材質(zhì)是高光網(wǎng)格材質(zhì)對(duì)象,通常貼圖文件包含顏色貼圖法線貼圖和高光貼圖。 產(chǎn)品在線展示案例預(yù)覽 玉鐲在線預(yù)覽:http://www.yanhuangxueyuan.co... 汽車(chē)在線預(yù)覽:http://www.yanhuangxueyuan.co... Web3D技術(shù)歷史 可通過(guò)插件或WebGL技術(shù)實(shí)現(xiàn)Web3D,在線網(wǎng)頁(yè)上預(yù)覽操作三維...

    DirtyMind 評(píng)論0 收藏0
  • 【Three.js】Three.js學(xué)習(xí)記錄

    摘要:上帝覺(jué)得缺少了些生氣,便用泥巴捏了一個(gè)小人兒,不叫亞當(dāng),她叫小芳。接下來(lái)預(yù)先恭喜你,你可以成為這網(wǎng)頁(yè)世界的一個(gè)小上帝。使用可以向場(chǎng)景中發(fā)射光線。在下述案例中,從攝像機(jī)的位置向場(chǎng)景中鼠標(biāo)的點(diǎn)擊位置發(fā)射光線。 先得擺出幾個(gè)關(guān)鍵詞:場(chǎng)景、燈光、模型、材質(zhì)、貼圖與紋理、相機(jī)、渲染器。然后我開(kāi)始裝模作樣地解釋: 上帝說(shuō),要有場(chǎng)景!于是就有了場(chǎng)景,場(chǎng)景去納這萬(wàn)事萬(wàn)物。 上帝說(shuō),要有光!于是就有了光...

    chanthuang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

jokester

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<