1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
</copyright> */
/* UBERSHADER */
/*
The ubershader function takes a JSON definition object and creates a jshader
that supports all or a subset of ubershader features. The ubershader currently
supports up to four per-pixel lights, optional diffuse, normal, specular, and
environment map textures. Lights can be directional, point, or spot lights. The
resulting shader is very much optimized based on the given use case, so if the
configuration changes, such as by adding a light, removing a texture, or even
changing the type of a light) then the shader needs to be rebuilt and recompiled
to reflect those changes.
*/
ubershader = function(def) {
var r = new XMLHttpRequest();
r.open('GET', "assets/shaders/ub_vshader.glsl", false);
r.send(null);
if (r.status == 200) {
vshader = r.responseText;
}
r.open('GET', "assets/shaders/ub_fshader.glsl", false);
r.send(null);
if (r.status == 200) {
fshader = r.responseText;
}
var preproc = "";
// var paramBlock = {};
// paramBlock['u_uvMatrix'] = { 'type': 'mat4' };
if (typeof def.material != 'undefined') {
preproc += '#define MATERIAL\n';
}
if (typeof def.lighting != 'undefined') {
preproc += '#define LIGHTING\n';
preproc += '#define SPECULAR\n';
for (i = 0; i < 4; ++i) {
var light = def.lighting['light' + i];
var t;
if (typeof light != 'undefined') {
switch (light.type) {
case 'directional': t = 0; break;
case 'point': t = 1; break;
case 'spot': t = 2; break;
}
preproc += '#define LIGHT_' + i + ' ' + t + '\n';
preproc += '#define LIGHT_' + i + '_SPECULAR\n';
}
}
}
if (typeof def.diffuseMap != 'undefined') {
preproc += '#define DIFFUSE_MAP\n';
}
if (typeof def.normalMap != 'undefined') {
preproc += '#define NORMAL_MAP\n';
}
if (typeof def.specularMap != 'undefined') {
preproc += '#define SPECULAR_MAP\n';
}
if (typeof def.environmentMap != 'undefined') {
preproc += '#define ENVIRONMENT_MAP\n';
}
// prefix preprocessor settings
vshader = preproc + vshader;
fshader = preproc + fshader;
// build output jshader
uberJShader = new jshader();
uberJShader.def = {
'shaders': {
'defaultVShader': vshader,
'defaultFShader': fshader
},
'techniques': {
'defaultTechnique': [{
'vshader': 'defaultVShader',
'fshader': 'defaultFShader',
'attributes': {
'a_pos': { 'type': 'vec3' },
'a_normal': { 'type': 'vec3' },
'a_texcoord': { 'type': 'vec2' }
},
'params': {
specularColor : 'u_specularColor',
},
'states': {
'depthEnable': true,
'blendEnable': false,
'culling': true,
'cullFace': "FRONT"
}
}]
}
}
// initialize the jshader
uberJShader.init();
// initialize shader parameters
var technique = uberJShader.defaultTechnique;
if (typeof def.material != 'undefined') {
technique.u_ambientColor.set(def.material.ambientColor);
technique.u_diffuseColor.set(def.material.diffuseColor);
if (technique.u_specularColor)
technique.u_specularColor.set(def.material.specularColor);
if (technique.u_specularPower)
technique.u_specularPower.set([def.material.specularPower]);
}
if (typeof def.lighting != 'undefined') {
for (i = 0; i < 4; ++i) {
var light = def.lighting["light" + i];
if (typeof light != "undefined") {
if (light.type == 'directional') {
paramBlock['u_light' + i + 'Dir'] = { 'type': 'vec3' };
technique['u_light' + i + 'Dir'].set(light['direction'] || [0, 0, 1]);
}
else if (light.type == 'spot') {
paramBlock['u_light' + i + 'Spot'] = { 'type': 'vec2' };
technique['u_light' + i + 'Position'].set(light['position'] || [0, 0, 0]);
var deg2Rad = Math.PI / 180;
technique['u_light' + i + 'Spot'].set([Math.cos((light['spotInnerCutoff'] || 45.0) * deg2Rad),
Math.cos((light['spotOuterCutoff'] || 90.0) * deg2Rad)]);
technique['u_light' + i + 'Atten'].set(light['attenuation'] || [1, 0, 0]);
} else {
technique['u_light' + i + 'Position'].set(light['position'] || [0, 0, 0]);
technique['u_light' + i + 'Atten'].set(light['attenuation'] || [1, 0, 0]);
}
technique['u_light' + i + 'Color'].set(light['diffuseColor'] || [1, 1, 1, 1]);
technique['u_light' + i + 'Specular'].set(light['specularColor'] || [1, 1, 1, 1]);
}
}
}
if (technique.u_uvMatrix)
technique.u_uvMatrix.set(def.uvTransform || mat4.identity());
renderer = g_Engine.getContext().renderer;
if (technique.s_diffuseMap && typeof def.diffuseMap != 'undefined') {
technique.s_diffuseMap.set(renderer.getTextureByName(def.diffuseMap.texture, def.diffuseMap.wrap, def.diffuseMap.mips));
}
if (technique.s_normalMap && typeof def.normalMap != 'undefined') {
technique.s_normalMap.set(renderer.getTextureByName(def.normalMap.texture, def.normalMap.wrap, def.normalMap.mips));
}
if (technique.s_specMap && typeof def.specularMap != 'undefined') {
technique.s_specMap.set(renderer.getTextureByName(def.specularMap.texture, def.specularMap.wrap));
}
if (technique.s_envMap && typeof def.environmentMap != 'undefined') {
technique.s_envMap.set(renderer.getTextureByName(def.environmentMap.texture, def.environmentMap.wrap));
}
if (technique.u_envReflection) {
technique.u_envReflection.set([def.environmentMap.envReflection || 1.0]);
}
return uberJShader;
}
|