天天看點

three.js WebGLRenderTarget

今天郭先生說一說WebGLRenderTarget,它是一個緩沖,就是在這個緩沖中,視訊卡為正在背景渲染的場景繪制像素。 它用于不同的效果,例如把它做為貼圖使用或者圖像後期處理。線案例請點選部落格原文。

three.js WebGLRenderTarget

話不多說,下來看看他的屬性了方法。

1. WebGLRenderTarget的屬性和方法

WebGLRenderTarget的構造器有三個參數,分别是width,height和options。寬高就是RenderTarget的高,設定的同時也會把它們指派給texture.image的width和height屬性。options包含以下屬性

屬性 預設值 描述
wrapS ClampToEdgeWrapping 包裹模式--使用RepeatWrapping,紋理将簡單地重複到無窮大。使用ClampToEdgeWrapping紋理中的最後一個像素将延伸到網格的邊緣。使用MirroredRepeatWrapping, 紋理将重複到無窮大,在每次重複時将進行鏡像。
wrapT ClampToEdgeWrapping 同上
magFilter LinearFilter 放大濾鏡--NearestFilter傳回與指定紋理坐标(在曼哈頓距離之内)最接近的紋理元素的值。LinearFilter是預設值,傳回距離指定的紋理坐标最近的四個紋理元素的權重平均值
minFilter LinearFilter 縮小濾鏡--NearestFilter傳回與指定紋理坐标(在曼哈頓距離之内)最接近的紋理元素的值。NearestMipmapNearestFilter選擇與被紋理化像素的尺寸最比對的mipmap, 并以NearestFilter(最靠近像素中心的紋理元素)為标準來生成紋理值。NearestMipmapLinearFilter選擇與被紋理化像素的尺寸最接近的兩個mipmap, 并以NearestFilter為标準來從每個mipmap中生成紋理值。最終的紋理值是這兩個值的權重平均值。LinearFilter是預設值,傳回距離指定的紋理坐标最近的四個紋理元素的權重平均值。LinearMipmapNearestFilter選擇與被紋理化像素的尺寸最比對的mipmap, 并以LinearFilter(最靠近像素中心的四個紋理元素的權重平均值)為标準來生成紋理值。LinearMipmapLinearFilter選擇與被紋理化像素的尺寸最接近的兩個mipmap, 并以LinearFilter為标準來從每個mipmap中生成紋理值。最終的紋理值是這兩個值的權重平均值。
format RGBAFormat AlphaFormat 丢棄紅、綠、藍分量,僅讀取Alpha分量。RedFormat丢棄綠色和藍色分量,隻讀取紅色分量RedIntegerFormat丢棄綠色和藍色分量,隻讀取紅色分量。texel被讀取為整數而不是浮點。(隻能與WebGL 2呈現上下文一起使用)。RGFormat丢棄alpha和blue元件并讀取紅色和綠色元件。(隻能與WebGL 2呈現上下文一起使用)。RGIntegerFormat丢棄alpha和blue元件并讀取紅色和綠色元件。texel被讀取為整數而不是浮點。(隻能與WebGL 2呈現上下文一起使用)。RGBFormat 丢棄Alpha分量,僅讀取紅、綠、藍分量。RGBIntegerFormat丢棄alpha元件并讀取紅色、綠色和藍色元件。(隻能與WebGL 2呈現上下文一起使用)。RGBAFormat将讀取紅、綠、藍和Alpha分量。RGBAIntegerFormat讀取紅色、綠色、藍色和alpha分量。texel被讀取為整數而不是浮點。(隻能與WebGL 2呈現上下文一起使用)。LuminanceFormat 将每個元素作為單獨的亮度分量來讀取。 将其轉換為範圍限制在[0,1]區間的浮點數,然後通過将亮度值放入紅、綠、藍通道,并将1.0賦給Alpha通道,來組裝成一個RGBA元素。LuminanceAlphaFormat 将每個元素同時作為亮度分量和Alpha分量來讀取。 和上面LuminanceFormat的處理過程是一緻的,除了Alpha分量具有除了1.0以外的值。RGBEFormat 與 RGBAFormat 是相同的。DepthFormat将每個元素作為單獨的深度值來讀取,将其轉換為範圍限制在[0,1]區間的浮點數。 它是DepthTexture的預設值。DepthStencilFormat将每個元素同時作為一對深度值和模闆值來讀取。 其中的深度分量解釋為DepthFormat。 模闆分量基于深度+模闆的内部格式來進行解釋。
type UnsignedByteType THREE.UnsignedByteType,THREE.ByteType,THREE.ShortType,THREE.UnsignedShortType,THREE.IntType,THREE.UnsignedIntType,THREE.FloatType,THREE.HalfFloatType,THREE.UnsignedShort4444Type,THREE.UnsignedShort5551Type,THREE.UnsignedShort565Type,THREE.UnsignedInt248Type。這些常量用于紋理的type屬性,這些屬性必須與正确的格式相對應。詳情請檢視下方。
anisotropy Texture.anisotropy 沿着軸,通過具有最高紋素密度的像素的樣本數。 預設情況下,這個值為1。設定一個較高的值将會産生比基本的mipmap更清晰的效果,代價是需要使用更多紋理樣本。 使用renderer.getMaxAnisotropy() 來查詢GPU中各向異性的最大有效值;這個值通常是2的幂。
encoding LinearEncoding THREE.LinearEncoding,THREE.sRGBEncoding,THREE.GammaEncoding,THREE.RGBEEncoding,THREE.LogLuvEncoding,THREE.RGBM7Encoding,THREE.RGBM16Encoding,THREE.RGBDEncoding,THREE.BasicDepthPacking,THREE.RGBADepthPacking。如果編碼類型在紋理已被一個材質使用之後發生了改變, 你需要來設定Material.needsUpdate為true來使得材質重新編譯。
depthBuffer true 深度緩沖器
stencilBuffer false 模具緩沖區

WebGLRenderTarget的屬性

屬性 描述
width 渲染目标寬度
height 渲染目标高度
scissor 渲染目标視口内的一個矩形區域,區域之外的片元将會被丢棄
scissorTest 表明是否激活了剪裁測試
viewport 渲染目标的視口
texture 紋理執行個體儲存這渲染的像素,用作進一步處理的輸入值
depthBuffer 渲染到深度緩沖區。預設true
stencilBuffer 渲染到模具緩沖區。預設false
depthTexture 如果設定,那麼場景的深度将會被渲染到慈紋理上。預設是null

WebGLRenderTarget的方法

方法 描述
setSize 設定渲染目标的大小
clone 建立一個渲染目标副本
copy 采用傳入的渲染目标的設定
dispose 發出一個處理事件

2 使用WebGLRenderTarget作為貼圖案例

1 做一個網格

首先做一個幾何體,這裡我們以THREE.Line為例

let pointArr = [];
let colorArr = [];
const points = GeometryUtils.hilbert2D(new THREE.Vector3( 0, 0, 0 ), 10, 3);
for(let i=0; i<points.length; i++) {
    pointArr.push(points[i].x, points[i].y, points[i].z);
    colorArr.push(Math.random(), Math.random(), Math.random());
}

const geometry = new THREE.BufferGeometry();
const positionAttribute = new THREE.Float32BufferAttribute( pointArr, 3 );
geometry.setAttribute( 'position', positionAttribute );
geometry.center();

const colorAttribute = new THREE.BufferAttribute( new Float32Array( colorArr ), 3 );
colorAttribute.setUsage( THREE.DynamicDrawUsage );
geometry.setAttribute( 'color', colorAttribute );                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

const material = new THREE.LineBasicMaterial( { vertexColors: true } );

line = new THREE.Line( geometry, material );
sceneRTT.add( line );      

這就做好了一個line,這裡說一下scene是我們的主場景,camera是拍攝主場景的相機,sceneRTT是renderTarget的場景,cameraRTT是rennderTarget的相機。GeometryUtils.hilbert2D是生成希爾伯特曲線的方法。

2. 建立render target

我們建立一個render target,裡面的參數不清楚的可以多次嘗試一下

target = new THREE.WebGLRenderTarget(200, 200, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat });
target.viewport = new THREE.Vector4(10,10,180,180);      

這裡我們設定視口起點從(10, 10)開始,寬高分别為180的矩形。

3. 建立渲染器和要貼圖的Mesh

接下來我們建立渲染器和要貼圖的Mesh

renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
this.$refs.box.appendChild(renderer.domElement);

let boxGeom = new THREE.BoxBufferGeometry(100, 100, 100);
let boxMate = new THREE.MeshBasicMaterial({map: target.texture});
let boxMesh = new THREE.Mesh(boxGeom, boxMate);
scene.add(boxMesh)      

直接調用target的Texture屬性來做材質的貼圖

4. 渲染

這裡要渲染render target的場景,這樣調用target.texture才能傳回一個正經的貼圖,同時我們讓這個貼圖随時間變換,最後渲染主場景,代碼如下。

onst colorAttribute = line.geometry.getAttribute( 'color' );
const l = colorAttribute.count;
for(let i=0; i<l; i++) {
    const h = ( ( offset + i ) % l ) / l * 20;
    color.setHSL(h, 0.8, 0.5);
    colorAttribute.setX( i, color.r );
    colorAttribute.setY( i, color.g );
    colorAttribute.setZ( i, color.b );
}

colorAttribute.needsUpdate = true;


offset -= 0.2;

renderer.setRenderTarget( target );
renderer.setClearColor(0xffddff);
renderer.clear();
renderer.render( sceneTT, cameraTT );

renderer.setRenderTarget( null );

renderer.setClearColor(0x000000);
renderer.render( scene, camera );
this.globalID = requestAnimationFrame(this.render);      

這樣就可以把render target作為貼圖使用了。

轉載請注明位址:郭先生的部落格

繼續閱讀