Twitter
2021年04月24日 - Three.js・WebVR

RawShaderMaterialにライトを設定

平面にシェーダを設定」に続き「three.jsのShaderMaterialでシーン内のライトを使用する」を参考に、RawShaderMaterialにライトを設定しました。※Three.jsはr127を使用しています。

RawShaderMaterialにライトを設定

● PointLightを設置

PlaneGeometryにRawShaderMaterialを設定したものにPointLightを設置します。

//ポイントライト
const pointLight = new THREE.PointLight(0XFFFFFF,1,5,1);
pointLight.position.set(0,0,2.5);
scene.add(pointLight);

//ヘルパー
const pointLightHelper = new THREE.PointLightHelper(pointLight,1);
scene.add(pointLightHelper);

● RawShaderMaterialを修正

uniformsにGLSLで使用する拡散色と放射色を追加して、RawShaderMaterialのライトプロパティをtrueにし、ライト情報をGLSLに送信します。

const uniforms = {
	time:{type:'f',value:0.0},

	//拡散色
	diffuse:{type:'c',value:new THREE.Color(0xFFFFFF)},

	//放射色
	emissive:{type:'c',value:new THREE.Color(0x000000)}
};
const geometry = new THREE.PlaneGeometry(10,10,2,2);
const material = new THREE.RawShaderMaterial({
	vertexShader:vertexShader,
	fragmentShader:fragmentShader,

	//ライト情報
	uniforms:THREE.UniformsUtils.merge([
		THREE.UniformsLib.lights,
		uniforms,
	]),

	//ライトプロパティ
	lights:true,
	side:THREE.DoubleSide,
});
plane = new THREE.Mesh(geometry,material);
scene.add(plane);

● glsl.js

script.jsとbasescene.jsは、上記以外は「平面にシェーダを設定」と同じです。

const vertexShader =`
	precision mediump float;

	attribute vec3 position;

    //normalの宣言
    attribute vec3 normal;
    attribute vec2 uv;

	uniform mat4 projectionMatrix;
	uniform mat4 modelViewMatrix;

	//normalMatrixの宣言
	uniform mat3 normalMatrix;

	varying vec2 vUv;
	varying vec3 vViewPosition;
	varying vec3 vNormal;

	void main(void){
		vUv = uv;

		//フラグメントシェーダにnormalを転送
		vNormal = normalMatrix * normal;
		vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);

		//フラグメントシェーダにmvPositionを転送
		vViewPosition = mvPosition.xyz;
		gl_Position = projectionMatrix * mvPosition;
	}
`;

const fragmentShader =`
	precision mediump float;

	uniform float time;

	//拡散色
	uniform vec3 diffuse;

	//放射色
	uniform vec3 emissive;
	uniform mat4 viewMatrix;

	varying vec2 vUv;
	varying vec3 vViewPosition;
	varying vec3 vNormal;

	//Three.jsのShaderChunk読み込み
	#include <common>
	#include <bsdfs>
	#include <lights_pars_begin>

    void main(void){
		vec3 mvPosition = vViewPosition;
  		vec3 transformedNormal = vNormal;

		//ランバート・シェーディング
		GeometricContext geometry;
		geometry.position = mvPosition.xyz;
		geometry.normal = normalize(transformedNormal);
		geometry.viewDir = (normalize(-mvPosition.xyz));
		vec3 lightFront = vec3(0.0);
		vec3 indirectFront = vec3(0.0);
		IncidentLight directLight;
		float dotNL;
		vec3 directLightColor_Diffuse;

		//ポイントライト
		#if NUM_POINT_LIGHTS > 0
		#pragma unroll_loop_start
		for (int i = 0; i < NUM_POINT_LIGHTS; i++) {
			getPointDirectLightIrradiance(pointLights[ i ], geometry, directLight);
			dotNL = dot(geometry.normal, directLight.direction);
			directLightColor_Diffuse = PI * directLight.color;
			lightFront += saturate(dotNL) * directLightColor_Diffuse;
		}
		#pragma unroll_loop_end
		#endif

		//スポットライト
		#if NUM_SPOT_LIGHTS > 0
		#pragma unroll_loop_start
		for (int i = 0; i < NUM_SPOT_LIGHTS; i++) {
			getSpotDirectLightIrradiance(spotLights[ i ], geometry, directLight);
			dotNL = dot(geometry.normal, directLight.direction);
			directLightColor_Diffuse = PI * directLight.color;
			lightFront += saturate(dotNL) * directLightColor_Diffuse;
		}
		#pragma unroll_loop_end
		#endif

		//ディレクショナルライト
		#if NUM_DIR_LIGHTS > 0
		#pragma unroll_loop_start
			for (int i = 0; i < NUM_DIR_LIGHTS; i++) {
			getDirectionalDirectLightIrradiance(directionalLights[ i ], geometry, directLight);
			dotNL = dot(geometry.normal, directLight.direction);
			directLightColor_Diffuse = PI * directLight.color;
			lightFront += saturate(dotNL) * directLightColor_Diffuse;
		}
		#pragma unroll_loop_end
		#endif

		//へミスフィアライト
		#if NUM_HEMI_LIGHTS > 0
		#pragma unroll_loop_start
		for (int i = 0; i < NUM_HEMI_LIGHTS; i++) {
			indirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );
		}
		#pragma unroll_loop_end
		#endif

		vec4 diffuseColor = vec4(diffuse, 1.0);
		ReflectedLight reflectedLight = ReflectedLight(vec3(0.0),vec3(0.0),vec3(0.0),vec3(0.0));
		vec3 totalEmissiveRadiance = emissive;
		reflectedLight.indirectDiffuse = getAmbientLightIrradiance(ambientLightColor);
		reflectedLight.indirectDiffuse += indirectFront;
		reflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert(diffuseColor.rgb);
		reflectedLight.directDiffuse = lightFront;
		reflectedLight.directDiffuse *= BRDF_Diffuse_Lambert(diffuseColor.rgb);
		vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;

	    //ドットアニメーション
	    vec2 p = (vUv * 2.0 - 1.0);

	    p.x -= time * 0.00075;
	    p *= 8.0;
	    p = mod(p,3.0)-1.0;
	    float l = length(p);
	    l = step(0.0,1.0-l);

	    gl_FragColor = vec4(vec3(l,l,0.0) * outgoingLight,diffuseColor.a);
	}
`;

export { vertexShader, fragmentShader };

完成したデモになります。RawShaderMaterialにライトを設定しました。

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

関連記事

前の記事へ

平面にシェーダを設定

次の記事へ

PlaneGeometryをシェーダで波形アニメーション