Browse Source

Merge pull request #13140 from Mugen87/dev4

WebGLProgram: Introduce loop unrolling via pragma
Mr.doob 7 years ago
parent
commit
e306903efd

+ 23 - 0
docs/api/materials/ShaderMaterial.html

@@ -44,6 +44,29 @@
 				If you don't want the [page:WebGLProgram] to add anything to your shader code, you can use
 				[page:RawShaderMaterial] instead of this class.
 			</li>
+			<li>
+				You can use the directive #pragma unroll_loop in order to unroll a *for* loop in GLSL by the shader preprocessor.
+				The directive has to be placed right above the loop. The loop formatting has to correspond to a defined standard.
+				<ul>
+					<li>
+						The loop has to be [link:https://en.wikipedia.org/wiki/Normalized_loop normalized].
+					</li>
+					<li>
+						The loop variable has to be *i*.
+					</li>
+					<li>
+						The loop has to use a certain whitespace formatting.
+					</li>
+				</ul>
+				<code>
+		#pragma unroll_loop
+		for ( int i = 0; i < 10; i ++ ) {
+
+			// ...
+
+		}
+				</code>
+			</li>
 		</ul>
 		</div>
 

+ 13 - 6
src/renderers/shaders/ShaderChunk/clipping_planes_fragment.glsl

@@ -1,22 +1,29 @@
 #if NUM_CLIPPING_PLANES > 0
 
-	for ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {
+	vec4 plane;
 
-		vec4 plane = clippingPlanes[ i ];
+	#pragma unroll_loop
+	for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {
+
+		plane = clippingPlanes[ i ];
 		if ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;
 
 	}
-		
+
 	#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES
 
 		bool clipped = true;
-		for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {
-			vec4 plane = clippingPlanes[ i ];
+
+		#pragma unroll_loop
+		for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {
+
+			plane = clippingPlanes[ i ];
 			clipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;
+
 		}
 
 		if ( clipped ) discard;
-	
+
 	#endif
 
 #endif

+ 4 - 0
src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl

@@ -22,6 +22,7 @@ vec3 directLightColor_Diffuse;
 
 #if NUM_POINT_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 
 		getPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );
@@ -43,6 +44,7 @@ vec3 directLightColor_Diffuse;
 
 #if NUM_SPOT_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
 
 		getSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );
@@ -75,6 +77,7 @@ vec3 directLightColor_Diffuse;
 
 #if NUM_DIR_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
 
 		getDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );
@@ -96,6 +99,7 @@ vec3 directLightColor_Diffuse;
 
 #if NUM_HEMI_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {
 
 		vLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );

+ 5 - 0
src/renderers/shaders/ShaderChunk/lights_template.glsl

@@ -25,6 +25,7 @@ IncidentLight directLight;
 
 	PointLight pointLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 
 		pointLight = pointLights[ i ];
@@ -45,6 +46,7 @@ IncidentLight directLight;
 
 	SpotLight spotLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
 
 		spotLight = spotLights[ i ];
@@ -65,6 +67,7 @@ IncidentLight directLight;
 
 	DirectionalLight directionalLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
 
 		directionalLight = directionalLights[ i ];
@@ -85,6 +88,7 @@ IncidentLight directLight;
 
 	RectAreaLight rectAreaLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {
 
 		rectAreaLight = rectAreaLights[ i ];
@@ -114,6 +118,7 @@ IncidentLight directLight;
 
 	#if ( NUM_HEMI_LIGHTS > 0 )
 
+		#pragma unroll_loop
 		for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {
 
 			irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );

+ 3 - 0
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl

@@ -2,6 +2,7 @@
 
 	#if NUM_DIR_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
 
 		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
@@ -12,6 +13,7 @@
 
 	#if NUM_SPOT_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
 
 		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
@@ -22,6 +24,7 @@
 
 	#if NUM_POINT_LIGHTS > 0
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 
 		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;

+ 3 - 0
src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl

@@ -8,6 +8,7 @@ float getShadowMask() {
 
 	DirectionalLight directionalLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
 
 		directionalLight = directionalLights[ i ];
@@ -21,6 +22,7 @@ float getShadowMask() {
 
 	SpotLight spotLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
 
 		spotLight = spotLights[ i ];
@@ -34,6 +36,7 @@ float getShadowMask() {
 
 	PointLight pointLight;
 
+	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 
 		pointLight = pointLights[ i ];

+ 13 - 12
src/renderers/webgl/WebGLProgram.js

@@ -150,6 +150,14 @@ function replaceLightNums( string, parameters ) {
 
 }
 
+function replaceClippingPlaneNums( string, parameters ) {
+
+	return string
+		.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
+		.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
+
+}
+
 function parseIncludes( string ) {
 
 	var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;
@@ -174,7 +182,7 @@ function parseIncludes( string ) {
 
 function unrollLoops( string ) {
 
-	var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
+	var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
 
 	function replace( match, start, end, snippet ) {
 
@@ -358,8 +366,6 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
 			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
 			parameters.flipSided ? '#define FLIP_SIDED' : '',
 
-			'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
-
 			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
 			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
 
@@ -462,9 +468,6 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
 			parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
 			parameters.flipSided ? '#define FLIP_SIDED' : '',
 
-			'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
-			'#define UNION_CLIPPING_PLANES ' + ( parameters.numClippingPlanes - parameters.numClipIntersection ),
-
 			parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
 			parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
 
@@ -502,16 +505,14 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
 
 	vertexShader = parseIncludes( vertexShader );
 	vertexShader = replaceLightNums( vertexShader, parameters );
+	vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
 
 	fragmentShader = parseIncludes( fragmentShader );
 	fragmentShader = replaceLightNums( fragmentShader, parameters );
+	fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
 
-	if ( ! material.isShaderMaterial ) {
-
-		vertexShader = unrollLoops( vertexShader );
-		fragmentShader = unrollLoops( fragmentShader );
-
-	}
+	vertexShader = unrollLoops( vertexShader );
+	fragmentShader = unrollLoops( fragmentShader );
 
 	var vertexGlsl = prefixVertex + vertexShader;
 	var fragmentGlsl = prefixFragment + fragmentShader;