2020年07月09日

RawShaderMaterial

Three.jsでシェーダ(GLSL)入門」で、Three.jsのShaderMaterialでシェーダを使用する方法を調べましたが、RawShaderMaterialについて調べてみました。※Three.jsはr117を使用しています。

RawShaderMaterial

● RawShaderMaterialについて

RawShaderMaterialは、大量のオブジェクトをインスタンスを使用して効率的にレンダリングを行う、インスタンシングの使用を想定しています。またShaderMaterialでは、modelViewMatrixやprojectionMatrix、positionやnormalなどは、シェーダプログラム内ですでに定義されていて、GLSLで宣言する必要はありませんが、RawShaderMaterialではGLSLで明示的に宣言する必要があります。

● ShaderMaterialからRawShaderMaterialへ変更

Three.jsでシェーダ(GLSL)入門」で制作した三角形ポリゴンを、ShaderMaterialからRawShaderMaterialへ変更します。ShaderMaterialからRawShaderMaterialへの変更は難しくありません。modelViewMatrixなどの宣言を追加する他、精度の指定を追加します。

const vertexShader =`
	//精度の指定を追加
	precision mediump float;

	//modelViewMatrixの宣言を追加
	uniform mat4 modelViewMatrix;

	//projectionMatrixの宣言を追加
	uniform mat4 projectionMatrix;

	//positionの宣言を追加
	attribute vec3 position;
	attribute vec3 color;
	attribute vec3 displacement;
	varying vec3 vColor;

	void main(){
		vColor = color;
		vec3 vv = position + displacement;
		gl_Position = projectionMatrix * modelViewMatrix * vec4(vv,1.0);
	}
`;

const fragmentShader =`
	//精度の指定を追加
	precision mediump float;
	uniform float step;
	varying vec3 vColor;

	void main(){
		float r = vColor.r + cos(step/50.0);
		float g = vColor.g + cos(step/60.0);
		float b = vColor.b + cos(step/70.0);
		gl_FragColor = vec4(r,g,b,1.0);
	}
`;

//RawShaderMaterialに変更
const material = new THREE.RawShaderMaterial({
	vertexShader:vertexShader,
	fragmentShader:fragmentShader,
	uniforms:uniforms,
	side:THREE.DoubleSide,
});

● script.js

ShaderMaterialからRawShaderMaterialへ変更した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, renderer } from './lib/basescene.js';

//===============================================================
// Init
//===============================================================
window.addEventListener('load',function(){
   init();
});

let orbitControls;
let triangle;
let uniforms;
let step = 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(){
	const gridHelper = new THREE.GridHelper(50,50);
	scene.add(gridHelper);
	renderer.outputEncoding = THREE.sRGBEncoding;

	const vertexShader =`
		precision mediump float;
		uniform mat4 modelViewMatrix;
		uniform mat4 projectionMatrix;
		attribute vec3 position;
		attribute vec3 color;
		attribute vec3 displacement;
		varying vec3 vColor;

		void main(){
			vColor = color;
			vec3 vv = position + displacement;
			gl_Position = projectionMatrix * modelViewMatrix * vec4(vv,1.0);
		}
	`;

	const fragmentShader =`
		precision mediump float;
		uniform float step;
		varying vec3 vColor;

		void main(){
			float r = vColor.r + cos(step/50.0);
			float g = vColor.g + cos(step/60.0);
			float b = vColor.b + cos(step/70.0);
			gl_FragColor = vec4(r,g,b,1.0);
		}
	`;

	const positions = new Float32Array([
		2.5,0.0,0.0,
		0,5.0,0.0,
		-2.5,0.0,0.0,
		]);
	const colors = new Float32Array([
		1.0,0.0,0.0,
		0.0,0.0,1.0,
		0.0,1.0,0.0,
		]);
	const displacement = new Float32Array(3*3);

	const geometry = new THREE.BufferGeometry();
	geometry.setAttribute('position',new THREE.BufferAttribute(positions,3));
	geometry.setAttribute('color',new THREE.BufferAttribute(colors,3));
	geometry.setAttribute('displacement',new THREE.BufferAttribute(displacement,3));

	uniforms = {
		step:{type:'f',value:1.0}
	};

	const material = new THREE.RawShaderMaterial({
		vertexShader:vertexShader,
		fragmentShader:fragmentShader,
		uniforms:uniforms,
		side:THREE.DoubleSide,
	});
	triangle = new THREE.Mesh(geometry,material);
	scene.add(triangle);
}

function setLight(){
	const ambientlight = new THREE.AmbientLight(0xFFFFFF);
	scene.add(ambientlight);
}

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();
	}

	step ++;
	uniforms.step.value = step;

	triangle.geometry.attributes.displacement.array[0] = 1.25 * Math.sin(step/50);
	triangle.geometry.attributes.displacement.array[4] = 1.25 * Math.sin(step/60);
	triangle.geometry.attributes.displacement.array[6] = -1.25 * Math.sin(step/70);
	triangle.geometry.attributes.displacement.needsUpdate = true;

	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,renderer;

init();

function init(){
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,0.1,1000);
	camera.position.set(0,1,20);
	scene.add(camera);

	renderer = new THREE.WebGLRenderer({antialias:true});
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setSize(window.innerWidth,window.innerHeight);

	const 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, renderer }

完成したデモになります。「Three.jsでシェーダ(GLSL)入門」で制作した三角形ポリゴンを、ShaderMaterialからRawShaderMaterialへ変更しました。

  • このエントリーをはてなブックマークに追加

関連記事

前の記事へ

BufferGeometryで頂点アニメーション

次の記事へ

立方体にシェーダを設定