-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathwebgl_lights_hemisphere.html
322 lines (258 loc) · 9.89 KB
/
webgl_lights_hemisphere.html
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - lights - hemisphere light</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: #fff;
color: #111;
margin: 0px;
overflow: hidden;
font-family: Monospace;
font-size: 13px;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 5px;
text-align: center;
}
#status {
position: absolute;
top: 25px;
width: 100%;
text-align: center;
color: purple;
font-size: 18px;
font-weight: bold;
}
/*
未访问 a:link {color:blue;}
已访问 a:visited {color:blue;}
鼠标悬停 a:hover {color:red;}
鼠标按下 a:active {color:yellow;}
*/
a {
color: #0080ff;
text-decoration: none;
}
a:hover {
color: #f00;
}
/*
任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。
为了简化font-size的换算,需要在css中的body选择器中声明 font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。
em会继承父级元素的字体大小。
*/
#footer { width: 100%; margin: 2em auto; text-align: center; position: absolute; bottom: 0 }
strong { color: red }
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="http://threejs.org" target="_blank">three.js</a> - webgl hemisphere light example -
flamingo by <a href="http://mirada.com/">mirada</a> from <a href="http://ro.me">rome</a><br/>
</div>
<div id="status">
</div>
<div id="footer">
press <strong>h</strong> to toggle hemisphere light, <strong>d</strong> to toggle directional light
</div>
<script src="../build/three.js"></script>
<!--
检测支持(canvas,webgl,workers,fileApi)
-->
<script src="js/Detector.js"></script>
<!--
统计插件(FPS,渲染时间,chrome内存使用率),min表示js代码经过压缩
-->
<script src="js/libs/stats.min.js"></script>
<!--
GLSL顶点着色器
-->
<script type="x-shader/x-vertex" id="vertexShader">
/*
varying: 顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。
必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
*/
varying vec3 vWorldPosition;
void main() {
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vWorldPosition = worldPosition.xyz;
//gl_Position: 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<!--
GLSL片元着色器
-->
<script type="x-shader/x-fragment" id="fragmentShader">
/*
一致变量。在着色器执行期间一致变量的值是不变的。
与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。
一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
*/
uniform vec3 topColor;
uniform vec3 bottomColor;
uniform float offset;
uniform float exponent;
varying vec3 vWorldPosition;
void main() {
float h = normalize( vWorldPosition + offset ).y;
/*
gl_FragColor: 输出的颜色用于随后的像素操作
mix(color1, color2, r)是将color1和color2 两种颜色,按照bg = color1*(1-r)+r*color2的方式混合
*/
gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );
}
</script>
<script>
//如果不支持webgl,则会在当前的父布局上添加一个不支持的提示信息DIV
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var camera, scene, renderer, dirLight, hemiLight;
var mixers = [];
var stats;
//three.js定义的一种计时器,内部也是使用Date.now()来进行计时的
var clock = new THREE.Clock();
init();
animate();
function init() {
var container = document.getElementById( 'container' );
/*
透视相机
PerspectiveCamera(fov, aspect, near, far)
fov(视场):从相机位置能够看到的部分场景。推荐默认值45
aspect(长宽比):渲染结果输出区域的横向长度和纵向长度的比值。推荐默认值window.innerWidth/window.innerHeight
near(近面):定义从距离相机多近的地方开始渲染场景。推荐默认值0.1
far(远面):定义相机可以从它所处的位置看多远。默认值1000
*/
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.set( 0, 0, 250 );
scene = new THREE.Scene();
//添加雾化效果
//设置雾化浓度在near和far浓度渐变
scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
//设置场景中统一的雾化浓度
//scene.fog = new THREE.FogExp2(0xffffff, 0.015);
//设置雾的颜色,色相(Hue)、饱和度(Siguation)、明度(Lightness)
scene.fog.color.setHSL( 0.6, 0, 1 );
// LIGHTS
hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
hemiLight.color.setHSL( 0.6, 1, 0.6 );
hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
hemiLight.position.set( 0, 500, 0 );
scene.add( hemiLight );
//平行光
dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.color.setHSL( 0.1, 1, 0.95 );
dirLight.position.set( -1, 1.75, 1 );
dirLight.position.multiplyScalar( 50 );
scene.add( dirLight );
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
var d = 50;
dirLight.shadow.camera.left = -d;
dirLight.shadow.camera.right = d;
dirLight.shadow.camera.top = d;
dirLight.shadow.camera.bottom = -d;
dirLight.shadow.camera.far = 3500;
dirLight.shadow.bias = -0.0001;
// GROUND
var groundGeo = new THREE.PlaneBufferGeometry( 10000, 10000 );
var groundMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x050505 } );
groundMat.color.setHSL( 0.095, 1, 0.75 );
var ground = new THREE.Mesh( groundGeo, groundMat );
ground.rotation.x = -Math.PI/2;
ground.position.y = -33;
scene.add( ground );
ground.receiveShadow = true;
// SKYDOME
var vertexShader = document.getElementById( 'vertexShader' ).textContent;
var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
var uniforms = {
topColor: { value: new THREE.Color( 0x0077ff ) },
bottomColor: { value: new THREE.Color( 0xffffff ) },
offset: { value: 33 },
exponent: { value: 0.6 }
};
uniforms.topColor.value.copy( hemiLight.color );
scene.fog.color.copy( uniforms.bottomColor.value );
var skyGeo = new THREE.SphereGeometry( 4000, 32, 15 );
var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } );
var sky = new THREE.Mesh( skyGeo, skyMat );
scene.add( sky );
// MODEL
var loader = new THREE.JSONLoader();
loader.load( 'models/animated/flamingo.js', function( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );
var mesh = new THREE.Mesh( geometry, material );
var s = 0.35;
mesh.scale.set( s, s, s );
mesh.position.y = 15;
mesh.rotation.y = -1;
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
var mixer = new THREE.AnimationMixer( mesh );
mixer.clipAction( geometry.animations[ 0 ] ).setDuration( 1 ).play();
mixers.push( mixer );
} );
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( scene.fog.color );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMap.enabled = true;
renderer.shadowMap.renderReverseSided = false;
// STATS
stats = new Stats();
container.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keydown', onKeyDown, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onKeyDown ( event ) {
//keyCode是字母和数字键的键码值
switch ( event.keyCode ) {
case 72: // h
hemiLight.visible = !hemiLight.visible;
resetStatus();
break;
case 68: // d
dirLight.visible = !dirLight.visible;
resetStatus();
break;
}
}
function animate() {
requestAnimationFrame( animate );
render();
//这里可以在render前后使用stats.begin和stats.end,也可以在每次渲染的时候调用一次stats.update
stats.update();
}
function render() {
//获取两次getDelta()的时间差,单位:秒
var delta = clock.getDelta();
for ( var i = 0; i < mixers.length; i ++ ) {
mixers[ i ].update( delta );
}
renderer.render( scene, camera );
}
function resetStatus() {
document.getElementById("status").innerHTML = "hemiLight.visible = " + hemiLight.visible + ", dirLight.visible = " + dirLight.visible;
}
</script>
</body>
</html>