なにかお手伝いできることがあればご連絡ください。
お問い合わせはこちらから
※Googleフォームが表示されます
前回オフスクリーンレンダリングについて書きました。
今回は、オフスクリーンレンダリングを利用して、ポストプロセスをやってみたいと思います。
ポストプロセスを簡単に言うと、作成済みのシーンに対して、あとから何か処理を行うことです。
今回は以下のような2つのシーンを掛け合せてみようと思います。
まずはベースとなるシーンをオフスクリーンレンダリングして、その情報をテクスチャとしてシェーダーに情報を送ります。 この時点では何も表示されません。
const baseVert = require('./../shader/base.vert');
const baseFrag = require('./../shader/base.frag');
var theta = 0;
// ベースの描画処理(renderTarget への描画用)
baseScene = new THREE.Scene();
//ベースの描画処理用カメラ
baseCamera = new THREE.PerspectiveCamera(50, windowWidth / windowHeight, 0.1, 1000);
baseCamera.position.z = 20;
//ベース用のマテリアルとジオメトリ
var baseGeometry = new THREE.BoxGeometry(5, 5, 5);
var baseMaterial = new THREE.ShaderMaterial({
vertexShader: baseVert,
fragmentShader: baseFrag
});
var baseMesh = new THREE.Mesh(baseGeometry, baseMaterial);
baseScene.add(baseMesh);
//オフスクリーンレンダリング用
renderTarget = new THREE.WebGLRenderTarget(windowWidth, windowHeight, {
magFilter: THREE.NearestFilter,
minFilter: THREE.NearestFilter,
wrapS: THREE.ClampToEdgeWrapping,
wrapT: THREE.ClampToEdgeWrapping
});
render();
function render() {
theta += 0.01;
baseMesh.rotation.set(theta,theta,0);
//オフスクリーンレンダリング
renderer.setClearColor(new THREE.Color(0xffffff), 1.0);
renderer.render(baseScene, baseCamera, renderTarget);
requestAnimationFrame(render);
}
varying vec3 vNormal;
void main() {
vNormal = normalMatrix * normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
precision mediump float;
varying vec3 vNormal;
void main(){
gl_FragColor = vec4(vec3(vNormal),1.0) ;
}
ポストプロセスは通常画面全体に対して適応します。 その為、画面全体を覆うポリゴンを作成します。
const postVert = require('./../shader/post.vert');
const postFrag = require('./../shader/post.frag');
var clock = new THREE.Clock();
var time = 0.0;
//ポストプロセス用
postScene = new THREE.Scene();
postCamera = new THREE.PerspectiveCamera(60, windowWidth / windowHeight, 0.1, 1000);
postCamera.position.z = 20;
//ポストプロセス用ジオメトリ、マテリアル
var postGeometry = new THREE.Geometry();
postGeometry.vertices = [
new THREE.Vector3(-1.0 * aspect, 1.0, 0.0),
new THREE.Vector3(1.0 * aspect, 1.0, 0.0),
new THREE.Vector3(-1.0 * aspect, -1.0, 0.0),
new THREE.Vector3(1.0 * aspect, -1.0, 0.0)
];
postGeometry.faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(1, 2, 3)
];
var postUniforms = {
'uTex': {
type: 't',
//ベース用シーンをテクスチャとして渡す
value: renderTarget
},
'uTime': {
type: 'f',
value: time
}
};
var postMaterial = new THREE.ShaderMaterial({
uniforms: postUniforms,
vertexShader: postVert,
fragmentShader: postFrag
});
var postMesh = new THREE.Mesh(postGeometry, postMaterial);
postScene.add(postMesh);
render();
function render() {
//画面にレンダリング
renderer.setClearColor(new THREE.Color(0x000000), 1.0);
renderer.render(postScene, postCamera);
requestAnimationFrame(render);
}
varying vec2 vUv;
void main() {
gl_Position = vec4( position, 1.0 );
//uv座標はpositionをそのまま使う。中央の座標の(0.0,0.0)にする為 +1.0) * 0.5する
vUv = (position.xy + 1.0) * 0.5;
}
precision mediump float;
varying vec2 vUv;
uniform float uTime;
//ベースシーンのレンダリング結果
uniform sampler2D uTex;
float rnd(vec2 n){
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
void main(){
float n = rnd(gl_FragCoord.st + mod(uTime, 10.0)) * 0.5 + 0.7;
gl_FragColor = texture2D(uTex, vUv) * vec4(vec3(n),1.0);
}
両方合わせると以下のようになります。
const baseVert = require('./../shader/base.vert');
const baseFrag = require('./../shader/base.frag');
const postVert = require('./../shader/post.vert');
const postFrag = require('./../shader/post.frag');
window.onload = function () {
var renderer;
var postCamera, postScene;
var baseCamera, baseScene;
var renderTarget;
var theta = 0;
var clock = new THREE.Clock();
var time = 0.0;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var aspect = windowWidth / windowHeight;
// rendererの作成
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor('#CCC');
// canvasをbodyに追加
document.body.appendChild(renderer.domElement);
// canvasをリサイズ
renderer.setSize(windowWidth, windowHeight);
// ベースの描画処理(renderTarget への描画用)
baseScene = new THREE.Scene();
//ベースの描画処理用カメラ
baseCamera = new THREE.PerspectiveCamera(50, windowWidth / windowHeight, 0.1, 1000);
baseCamera.position.z = 20;
var baseUniforms = {
'uResolution': {
type: 'v2',
value: new THREE.Vector2(windowWidth, windowHeight)
}
};
//ベース用のマテリアルとジオメトリ
var baseGeometry = new THREE.BoxGeometry(5, 5, 5);
var baseMaterial = new THREE.ShaderMaterial({
uniforms: baseUniforms,
vertexShader: baseVert,
fragmentShader: baseFrag
});
var baseMesh = new THREE.Mesh(baseGeometry, baseMaterial);
baseScene.add(baseMesh);
//オフスクリーンレンダリング用
renderTarget = new THREE.WebGLRenderTarget(windowWidth, windowHeight, {
magFilter: THREE.NearestFilter,
minFilter: THREE.NearestFilter,
wrapS: THREE.ClampToEdgeWrapping,
wrapT: THREE.ClampToEdgeWrapping
});
//ポストプロセス用
postScene = new THREE.Scene();
postCamera = new THREE.PerspectiveCamera(60, windowWidth / windowHeight, 0.1, 1000);
postCamera.position.z = 20;
//ポストプロセス用ジオメトリ、マテリアル
var postGeometry = new THREE.Geometry();
postGeometry.vertices = [
new THREE.Vector3(-1.0 * aspect, 1.0, 0.0),
new THREE.Vector3(1.0 * aspect, 1.0, 0.0),
new THREE.Vector3(-1.0 * aspect, -1.0, 0.0),
new THREE.Vector3(1.0 * aspect, -1.0, 0.0)
];
postGeometry.faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(1, 2, 3)
];
var postUniforms = {
'uTex': {
type: 't',
value: renderTarget
},
'uTime': {
type: 'f',
value: time
}
};
var postMaterial = new THREE.ShaderMaterial({
uniforms: postUniforms,
vertexShader: postVert,
fragmentShader: postFrag
});
var postMesh = new THREE.Mesh(postGeometry, postMaterial);
postScene.add(postMesh);
render();
function render() {
theta += 0.01;
baseMesh.rotation.set(theta, theta, 0);
time = clock.getElapsedTime();
postMaterial.uniforms.uTime.value = time;
//オフスクリーンレンダリング
renderer.setClearColor(new THREE.Color(0xffffff), 1.0);
renderer.render(baseScene, baseCamera, renderTarget);
//画面にレンダリング
renderer.setClearColor(new THREE.Color(0x000000), 1.0);
renderer.render(postScene, postCamera);
requestAnimationFrame(render);
}
};
See the Pen wpKZEd by nogson (@satofaction) on CodePen.
なにかお手伝いできることがあればご連絡ください。
※Googleフォームが表示されます