2021年05月04日 - WebVR・Three.js
Three.jsでオフスクリーンレンダリング

オフスクリーンレンダリングが使えるようになると、表現の幅が広がります。そこで「シェーダで画像エフェクト」に続き、Three.jsでオフスクリーンレンダリングを試しました。※Three.jsはr128を使用しています。
Three.jsでオフスクリーンレンダリング
オフスクリーンレンダリングは、スクリーンではなくメモリ上にレンダリングした結果を、そのままテクスチャとして使用する手法です。
● トーラスを生成
まずは、TorusGeometryを使用してトーラスを生成します。マテリアルはライティングを必要としないMeshNormalMaterialを使用します。
const geometry = new THREE.TorusGeometry(2.5,1,32,100); const material = new THREE.MeshNormalMaterial(); const torus = new THREE.Mesh(geometry,material); scene.add(torus);
● オフスクリーンレンダリング
トーラスを生成して、オフスクリーンレンダリング用のシーンに追加します。次にスクリーン用の平面にレンダーターゲットオブジェクトのテクスチャを設定して、レンダリングします。
//オフスクリーンレンダリング用のシーン
const sceneRTT = new THREE.Scene();
//オフスクリーンレンダリング用のカメラ
const cameraRTT = new THREE.PerspectiveCamera(50,1,1,50);
cameraRTT.position.set(0,0,11);
//レンダーターゲットオブジェクト
const renderTarget = new THREE.WebGLRenderTarget(1024,1024);
//トーラス
const geometry = new THREE.TorusGeometry(2.5,1,32,100);
const material = new THREE.MeshNormalMaterial();
const torus = new THREE.Mesh(geometry,material);
sceneRTT.add(torus);
//スクリーン用の平面
const planeGeometry = new THREE.PlaneGeometry(4,4,2,2);
const planeMaterial = new THREE.MeshPhongMaterial({
color:0xFFFFFF,
//テクスチャを設定
map:renderTarget.texture,
});
const plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
function rendering(){
requestAnimationFrame(rendering);
//オフスクリーンレンダリング
renderer.setClearColor(0x115558,1.0);
renderer.setRenderTarget(renderTarget);
renderer.render(sceneRTT,cameraRTT);
renderer.setRenderTarget(null);
//レンダリング
renderer.setClearColor(0x000000,1.0);
renderer.render(scene,camera);
}
● script.js
必要なライブラリを読み込みます。
<script src="js/preloadjs.min.js"></script> <script src="js/TweenMax.min.js"></script> <script src="js/script.js" type="module"></script>
完成したscript.jsになります。
//===============================================================
// Import Library
//===============================================================
import * as THREE from './lib/three_jsm/three.module.js';
import { OrbitControls } from './lib/three_jsm/OrbitControls.js';
import { scene, camera, container, renderer } from './lib/basescene.js';
//===============================================================
// Init
//===============================================================
window.addEventListener('load',function(){
init();
});
let orbitControls;
let torus;
let sceneRTT,cameraRTT,renderTarget;
let time = 0;
function init(){
setLoading();
}
function setLoading(){
TweenMax.to('.loader',0.1,{opacity:1});
TweenMax.to('#loader_wrapper',1,{
opacity:0,
delay:1,
onComplete: function(){
document.getElementById('loader_wrapper').style.display = 'none';
TweenMax.to('.loader',0,{opacity:0});
}
});
threeWorld();
setLight();
setControll();
rendering();
}
//===============================================================
// Create World
//===============================================================
function threeWorld(){
renderer.outputEncoding = THREE.sRGBEncoding;
sceneRTT = new THREE.Scene();
cameraRTT = new THREE.PerspectiveCamera(50,1,1,50);
cameraRTT.position.set(0,0,11);
renderTarget = new THREE.WebGLRenderTarget(1024,1024);
const geometry = new THREE.TorusGeometry(2.5,1,32,100);
const material = new THREE.MeshNormalMaterial();
torus = new THREE.Mesh(geometry,material);
sceneRTT.add(torus);
const planeGeometry = new THREE.PlaneGeometry(4,4,2,2);
const planeMaterial = new THREE.MeshPhongMaterial({
color:0xFFFFFF,
shininess:70,
reflectivity:1,
map:renderTarget.texture,
side:THREE.DoubleSide
});
const plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
}
function setLight(){
const ambientlight = new THREE.AmbientLight(0x333333,0.1);
scene.add(ambientlight);
const pointLight = new THREE.PointLight(0XFFFFFF,4,3.7,1);
pointLight.position.set(0,0,3);
scene.add(pointLight);
const pointLightHelper = new THREE.PointLightHelper(pointLight,0.3);
scene.add(pointLightHelper);
}
function setControll(){
document.addEventListener('touchmove',function(e){e.preventDefault();},{passive:false});
orbitControls = new OrbitControls(camera,renderer.domElement);
orbitControls.enableDamping = true;
orbitControls.dampingFactor = 0.5;
}
function rendering(){
requestAnimationFrame(rendering);
if(orbitControls){
orbitControls.update();
}
time++;
torus.rotation.x = time * 0.25 * Math.PI / 180;
torus.rotation.y = time * 0.5 * Math.PI / 180;
renderer.setClearColor(0x115558,1.0);
renderer.setRenderTarget(renderTarget);
renderer.render(sceneRTT,cameraRTT);
renderer.setRenderTarget(null);
renderer.setClearColor(0x000000,1.0);
renderer.render(scene,camera);
}
● basescene.js
sceneやcameraなど基本的な設定を管理するbasescene.jsです。
//===============================================================
// Import Library
//===============================================================
import * as THREE from './three_jsm/three.module.js';
//===============================================================
// Base scene
//===============================================================
let scene,camera,container,renderer;
init();
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,1,100);
camera.position.set(0,0,10);
scene.add(camera);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.setClearColor(new THREE.Color(0x000000));
container = document.querySelector('#canvas_vr');
container.appendChild(renderer.domElement);
window.addEventListener('resize',function(){
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
},false);
}
export { scene, camera, container, renderer }
完成したデモになります。Three.jsでオフスクリーンレンダリングを試しました。

