Skip to content

Commit 2a166cb

Browse files
author
Thayer J Andrews
committed
CCEffectLighting - Specular lighting additions
Address the issues with specular mentioned in my previous commit. Properties have been added for controlling the shininess and specular color. Setting shininess to zero or specular color to black disables the specular calculations in the shader.
1 parent 50fc1cb commit 2a166cb

File tree

2 files changed

+80
-20
lines changed

2 files changed

+80
-20
lines changed

cocos2d/CCEffectLighting.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@
1919
/// @name Accessing Effect Attributes
2020
/// -----------------------------------------------------------------------
2121

22+
/**
23+
* The specular color of the affected node. This color is combined with the light's
24+
* color and the effect's shininess value to determine the color of specular highlights
25+
* that appear when lighting shiny surfaces.
26+
*/
27+
@property (nonatomic, strong) CCColor* specularColor;
28+
29+
/**
30+
* The shininess of the affected node. This value controls the tightness of specular
31+
* highlights. 0 results in no specular contribution to the lighting equations and
32+
* increasing values result in tighter highlights.
33+
*/
34+
@property (nonatomic, assign) float shininess;
2235

2336
/// -----------------------------------------------------------------------
2437
/// @name Initializing a CCEffectLighting object

cocos2d/CCEffectLighting.m

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,24 @@
1717
#import "CCEffect_Private.h"
1818
#import "CCSprite_Private.h"
1919

20-
static const NSUInteger CCEffectLightingMaxLightCount = 16;
20+
typedef struct _CCLightKey
21+
{
22+
NSUInteger pointLightMask;
23+
NSUInteger directionalLightMask;
24+
25+
} CCLightKey;
26+
27+
static CCLightKey CCLightKeyMake(NSArray *lights);
28+
static BOOL CCLightKeyCompare(CCLightKey a, CCLightKey b);
29+
30+
2131

2232
@interface CCEffectLighting ()
2333

2434
@property (nonatomic, strong) NSMutableArray *lights;
25-
@property (nonatomic, assign) NSUInteger lightKey;
35+
@property (nonatomic, assign) CCLightKey lightKey;
36+
@property (nonatomic, readonly) BOOL hasSpecular;
37+
@property (nonatomic, assign) BOOL previousHasSpecular;
2638

2739
@end
2840

@@ -48,7 +60,12 @@ -(id)initWithLights:(NSArray *)lights
4860
{
4961
_lights = [[NSMutableArray alloc] init];
5062
}
51-
_lightKey = 0;
63+
64+
_specularColor = [CCColor whiteColor];
65+
_shininess = 5.0f;
66+
67+
_lightKey = CCLightKeyMake(nil);
68+
_previousHasSpecular = NO;
5269
}
5370
return self;
5471
}
@@ -77,7 +94,7 @@ -(void)removeAllLights
7794
}
7895

7996

80-
+(NSMutableArray *)buildFragmentFunctionsWithLights:(NSArray*)lights
97+
+(NSMutableArray *)buildFragmentFunctionsWithLights:(NSArray*)lights andSpecular:(BOOL)hasSpecular
8198
{
8299
CCEffectFunctionInput *input = [[CCEffectFunctionInput alloc] initWithType:@"vec4" name:@"inputValue" initialSnippet:CCEffectDefaultInitialInputSnippet snippet:CCEffectDefaultInputSnippet];
83100

@@ -94,7 +111,7 @@ +(NSMutableArray *)buildFragmentFunctionsWithLights:(NSArray*)lights
94111

95112
vec4 lightColor;
96113
vec4 diffuseLightColor = u_globalAmbientColor;
97-
vec4 specularLightColor = vec4(0,0,0,1);
114+
vec4 specularLightColor = vec4(0,0,0,0);
98115

99116
vec3 tangentSpaceLightDir;
100117
vec3 halfAngleDir;
@@ -123,11 +140,19 @@ +(NSMutableArray *)buildFragmentFunctionsWithLights:(NSArray*)lights
123140
[effectBody appendString:@"diffuseTerm = max(0.0, dot(tangentSpaceNormal, tangentSpaceLightDir));\n"];
124141
[effectBody appendString:@"diffuseLightColor += lightColor * diffuseTerm;\n"];
125142

126-
[effectBody appendString:@"halfAngleDir = (2.0 * dot(tangentSpaceLightDir, tangentSpaceNormal) * tangentSpaceNormal - tangentSpaceLightDir);\n"];
127-
[effectBody appendString:@"specularTerm = max(0.0, dot(halfAngleDir, vec3(0,0,1))) * step(0.0, diffuseTerm);\n"];
128-
[effectBody appendString:@"specularLightColor += lightColor * pow(specularTerm, 10.0);\n"];
143+
if (hasSpecular)
144+
{
145+
[effectBody appendString:@"halfAngleDir = (2.0 * dot(tangentSpaceLightDir, tangentSpaceNormal) * tangentSpaceNormal - tangentSpaceLightDir);\n"];
146+
[effectBody appendString:@"specularTerm = max(0.0, dot(halfAngleDir, vec3(0,0,1))) * step(0.0, diffuseTerm);\n"];
147+
[effectBody appendString:@"specularLightColor += lightColor * pow(specularTerm, u_specularExponent);\n"];
148+
}
129149
}
130-
[effectBody appendString:@"return diffuseLightColor * inputValue + specularLightColor;\n"];
150+
[effectBody appendString:@"vec4 resultColor = diffuseLightColor * inputValue;\n"];
151+
if (hasSpecular)
152+
{
153+
[effectBody appendString:@"resultColor += specularLightColor * u_specularColor;\n"];
154+
}
155+
[effectBody appendString:@"return vec4(resultColor.xyz, inputValue.a);\n"];
131156

132157
CCEffectFunction* fragmentFunction = [[CCEffectFunction alloc] initWithName:@"lightingEffectFrag" body:effectBody inputs:@[input] returnType:@"vec4"];
133158
return [NSMutableArray arrayWithObject:fragmentFunction];
@@ -210,6 +235,8 @@ -(void)buildRenderPasses
210235
}
211236

212237
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_globalAmbientColor"]] = [NSValue valueWithGLKVector4:globalAmbientColor];
238+
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_specularExponent"]] = [NSNumber numberWithFloat:weakSelf.shininess];
239+
pass.shaderUniforms[weakSelf.uniformTranslationTable[@"u_specularColor"]] = [NSValue valueWithGLKVector4:weakSelf.specularColor.glkVector4];
213240

214241
} copy]];
215242

@@ -220,10 +247,12 @@ - (CCEffectPrepareStatus)prepareForRendering
220247
{
221248
CCEffectPrepareStatus result = CCEffectPrepareNothingToDo;
222249

223-
NSUInteger newLightKey = [CCEffectLighting computeLightKey:_lights];
224-
if (newLightKey != _lightKey)
250+
CCLightKey newLightKey = CCLightKeyMake(_lights);
251+
if (!CCLightKeyCompare(newLightKey, _lightKey) ||
252+
(_previousHasSpecular != self.hasSpecular))
225253
{
226254
_lightKey = newLightKey;
255+
_previousHasSpecular = self.hasSpecular;
227256

228257
NSMutableArray *fragUniforms = [[NSMutableArray alloc] initWithArray:@[[CCEffectUniform uniform:@"vec4" name:@"u_globalAmbientColor" value:[NSValue valueWithGLKVector4:GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f)]]]];
229258
NSMutableArray *vertUniforms = [[NSMutableArray alloc] initWithArray:@[[CCEffectUniform uniform:@"mat4" name:@"u_ndcToTangentSpace" value:[NSValue valueWithGLKMatrix4:GLKMatrix4Identity]]]];
@@ -244,7 +273,13 @@ - (CCEffectPrepareStatus)prepareForRendering
244273
[varyings addObject:[CCEffectVarying varying:@"vec4" name:[NSString stringWithFormat:@"v_tangentSpaceLightDir%lu", (unsigned long)lightIndex]]];
245274
}
246275

247-
NSMutableArray *fragFunctions = [CCEffectLighting buildFragmentFunctionsWithLights:_lights];
276+
if (self.hasSpecular)
277+
{
278+
[fragUniforms addObject:[CCEffectUniform uniform:@"float" name:@"u_specularExponent" value:[NSNumber numberWithFloat:5.0f]]];
279+
[fragUniforms addObject:[CCEffectUniform uniform:@"vec4" name:@"u_specularColor" value:[NSValue valueWithGLKVector4:GLKVector4Make(1.0f, 1.0f, 1.0f, 1.0f)]]];
280+
}
281+
282+
NSMutableArray *fragFunctions = [CCEffectLighting buildFragmentFunctionsWithLights:_lights andSpecular:self.hasSpecular];
248283
NSMutableArray *vertFunctions = [CCEffectLighting buildVertexFunctionsWithLights:_lights];
249284

250285
[self buildEffectWithFragmentFunction:fragFunctions vertexFunctions:vertFunctions fragmentUniforms:fragUniforms vertexUniforms:vertUniforms varyings:varyings firstInStack:YES];
@@ -254,26 +289,38 @@ - (CCEffectPrepareStatus)prepareForRendering
254289
return result;
255290
}
256291

257-
+(NSUInteger)computeLightKey:(NSArray*)lights
292+
- (BOOL)hasSpecular
293+
{
294+
return (!ccc4FEqual(_specularColor.ccColor4f, ccc4f(0.0f, 0.0f, 0.0f, 0.0f)) && (_shininess > 0.0f));
295+
}
296+
297+
@end
298+
299+
CCLightKey CCLightKeyMake(NSArray *lights)
258300
{
259-
static const NSUInteger CCEffectLightingPointOffset = 0;
260-
static const NSUInteger CCEffectLightingDirectionalOffset = CCEffectLightingMaxLightCount;
261-
262-
NSUInteger lightKey = 0;
301+
CCLightKey lightKey;
302+
lightKey.pointLightMask = 0;
303+
lightKey.directionalLightMask = 0;
304+
263305
for (NSUInteger lightIndex = 0; lightIndex < lights.count; lightIndex++)
264306
{
265307
CCLightNode *light = lights[lightIndex];
266308
if (light.type == CCLightPoint)
267309
{
268-
lightKey |= (1 << (lightIndex + CCEffectLightingPointOffset));
310+
lightKey.pointLightMask |= (1 << lightIndex);
269311
}
270312
else if (light.type == CCLightDirectional)
271313
{
272-
lightKey |= (1 << (lightIndex + CCEffectLightingDirectionalOffset));
314+
lightKey.directionalLightMask |= (1 << lightIndex);
273315
}
274316
}
275317
return lightKey;
276318
}
277319

278-
@end
320+
BOOL CCLightKeyCompare(CCLightKey a, CCLightKey b)
321+
{
322+
return (((a.pointLightMask) == (b.pointLightMask)) &&
323+
((a.directionalLightMask) == (b.directionalLightMask)));
324+
}
325+
279326

0 commit comments

Comments
 (0)