-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathwebgl_materials_grass.html
215 lines (185 loc) · 8.64 KB
/
webgl_materials_grass.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
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - materials - grass</title>
<meta charset="utf-8">
<!--
如果没有设置viewport的width的话,网页很可能会超出手机屏幕宽度,具体多宽,要看浏览器定义的默认宽度是多少
user-scalable=no,规定了用户不能缩放网页,但有些浏览器对该项支持不是很好,故需要设置minimum-scale和maximum-scale相同来限制用户缩放
-->
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background:#000;
color:#fff;
padding:0;
margin:0;
font-family:georgia;
text-align:center;
overflow:hidden;
}
#testCanvas {
position:absolute;
background: white;
}
</style>
</head>
<body>
<script src="../build/three.js"></script>
<!--
检测支持(canvas,webgl,workers,fileApi)
-->
<script src="js/Detector.js"></script>
<canvas id="testCanvas" width="100px" height="100px">Your browser can not support canvas</canvas>
<script>
//如果不支持webgl,则会在当前的父布局上添加一个不支持的提示信息DIV
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var camera, scene, renderer;
init();
animate();
function init() {
/*
透视相机
PerspectiveCamera(fov, aspect, near, far)
fov(视场):从相机位置能够看到的部分场景。推荐默认值45
aspect(长宽比):渲染结果输出区域的横向长度和纵向长度的比值。推荐默认值window.innerWidth/window.innerHeight
near(近面):定义从距离相机多近的地方开始渲染场景。推荐默认值0.1
far(远面):定义相机可以从它所处的位置看多远。默认值1000
*/
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
//定义相机的位置,有如下两种方式。如果不设置的话,相机位置为默认的Vector3{x:0,y:0,z:0}
camera.position.set( 0, 75, 100 );
//camera.position.y = 75;
//camera.position.z = 100;
scene = new THREE.Scene();
/*
这个类是另一种创建几何体对象的方式,它将所有的数据包括顶点位置,法线,面,颜色,uv和其它的自定义属性存在缓冲区,
这样可以减少GPU的负荷,BufferGeometry同样也比Geometry对象复杂,增加了使用的难度,这里的属性都是存放在数组中,
比如顶点位置不是Vector3对象,颜色也不是color对象,而是数组.需要访问这些属性,需要从属性缓冲区中读原始数据.
其纹理图与 PlaneGeometry 完全一样
*/
var geometry = new THREE.PlaneBufferGeometry( 100, 100 );
//画布材质
var texture = new THREE.CanvasTexture( generateTexture() );
//绘制用于测试的材质
var testCanvas = document.getElementById("testCanvas");
//在画布上绘制图片时,绘制宽高默认为画图片的宽高
//testCanvas.getContext("2d").drawImage(texture.image,0,0,texture.image.width,texture.image.height);
testCanvas.getContext("2d").drawImage(texture.image,0,0);
for ( var i = 0; i < 15; i ++ ) {
var material;
if(i == 0) {
//底层要铺一层纯色当背景,不然由于transparet,会看到renderer的clearColor
material = new THREE.MeshBasicMaterial( {color: 0x003300 });
} else {
material = new THREE.MeshBasicMaterial( {
//亮度逐渐增大
color: new THREE.Color().setHSL( 0.3, 0.75, ( i / 15 ) * 0.4 + 0.1 ),
//没有map的话,就是一层层的绿色矩形叠在一起
map: texture,
//这两句我也不知道有什么用
//depthTest: false,
//depthWrite: false,
transparent: true
} );
}
//console.log(material.color.getHexString());
var mesh = new THREE.Mesh( geometry, material );
mesh.name = "mesh" + i;
mesh.position.y = i * 0.25;
//mesh.position.y = i * 3.25;
//初始的平面在XY面上,要绕着X轴按右手螺旋定则旋转到XZ平面上
mesh.rotation.x = - Math.PI / 2;
//if(i%5==0)
scene.add( mesh );
}
//将场景的子元素倒序排列
scene.children.reverse();
renderer = new THREE.WebGLRenderer();
//设置渲染器的"清除色"和"透明度"
renderer.setClearColor( 0xff3300 );
//设置屏幕像素比,与Android上的DIP相仿,作用是在所有设备上的显示效果都相近
renderer.setPixelRatio( window.devicePixelRatio );
//设置待渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
//将渲染器的DOM元素(即Canvas)添加到HTML中
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
//更新透视相机的宽高比。如果宽高比不对,那么正方形可能就不是正方形了
camera.aspect = window.innerWidth / window.innerHeight;
//更新透视相机的投影矩阵
camera.updateProjectionMatrix();
//重新设置渲染场景的大小
renderer.setSize( window.innerWidth, window.innerHeight );
}
function generateTexture() {
var canvas = document.createElement( 'canvas' );
//canvas的宽和高没有固定要求,可以随意
canvas.width = 512;
canvas.height = 512;
var context = canvas.getContext( '2d' );
for ( var i = 0; i < 20000; i ++ ) {
//HSL即是代表色相(Hue),饱和度(Saturation),明度(Lightness)三个通道的颜色
context.fillStyle = 'hsl(0,0%,' + ( Math.random() * 50 + 50 ) + '%)';
//设置路径开始
context.beginPath();
/*
在画布上圈出一个圆形或扇形的路径
context.arc(x,y,r,sAngle,eAngle,counterclockwise);
x: 圆的中心的X坐标。
y: 圆的中心的Y坐标。
r: 圆的半径。
sAngle: 起始角,以弧度计(三点钟方向为0度)
eAngle: 结束角,以弧度计。
counterclockwise: 规定应该逆时针还是顺时针绘图。False=顺时针,true=逆时针。
*/
context.arc( Math.random() * canvas.width, Math.random() * canvas.height, Math.random() + 0.15, 0, Math.PI * 2, true );
//使用fillStyle填充圆或扇形
context.fill();
}
//设置全局透明度
//都已经绘制过了,所以这句话在这里并没有什么用
//context.globalAlpha = 0.075;
/*
globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上。
source-over: 默认。在目标图像上显示源图像。
source-atop: 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-in: 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
source-out: 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
destination-over: 在源图像上方显示目标图像。
destination-atop: 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in: 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
destination-out: 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
lighter: 显示源图像+目标图像。
copy: 显示源图像。忽略目标图像。
xor: 使用异或操作对源图像与目标图像进行组合。
*/
//都已经绘制过了,所以这句话在这里并没有什么用
//context.globalCompositeOperation = 'lighter';
return canvas;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//Date.now()获取时间戳(单位:毫秒),在JS中没有整除的概念,所以除出来一般都是浮点类型的
var time = Date.now() / 6000;
//照相机围绕着场景中央,在一个半径为80的圆周上循环运动
camera.position.x = 80 * Math.cos( time );
camera.position.z = 80 * Math.sin( time );
//相机注视着场景中央
camera.lookAt( scene.position );
for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
var mesh = scene.children[ i ];
//由于前面倒序排列过,因此在移动位置的时候底部基本是保持不变的
mesh.position.x = Math.sin( time * 4 ) * i * i * 0.005;
mesh.position.z = Math.cos( time * 6 ) * i * i * 0.005;
}
renderer.render( scene, camera );
}
</script>
</body>
</html>