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
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<base href="../../../" />
<script src="list.js"></script>
<script src="page.js"></script>
<link type="text/css" rel="stylesheet" href="page.css" />
</head>
<body>
<h1>如何更新场景([name])</h1>
<div>
<p>默认情况下,所有对象都会自动更新它们的矩阵(如果它们已添加到场景中)</p>
<code>
var object = new THREE.Object3D();
scene.add( object );
</code>
或者它们是已添加到场景中的另一个对象的子节点:
<code>
var object1 = new THREE.Object3D();
var object2 = new THREE.Object3D();
object1.add( object2 );
scene.add( object1 ); //object1 和 object2 会自动更新它们的矩阵
</code>
</div>
<p>但是,如果你知道对象将是静态的,则可以禁用此选项并在需要时手动更新转换矩阵。</p>
<code>
object.matrixAutoUpdate = false;
object.updateMatrix();
</code>
<h2>几何形状(Geometries)</h2>
<div>
<h3>[page:BufferGeometry]</h3>
<div>
<p>
BufferGeometries 将信息(例如顶点位置,面索引,法线,颜色,uv和任何自定义属性)存储在[page:BufferAttribute buffers] —— 也就是,
[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays typed arrays].
这使得它们通常比标准Geometries更快,缺点是更难用。
</p>
<p>
关于更新BufferGeometries,最重要的是理解你不能调整 buffers 大小(这种操作开销很大,相当于创建了个新的geometry)。
但你可以更新 buffers的内容。
</p>
<p>
这意味着如果你知道BufferGeometry的一个属性会增长,比如顶点的数量,
你必须预先分配足够大的buffer来容纳可能创建的任何新顶点。
当然,这也意味着BufferGeometry将有一个最大大小 —— 无法创建一个可以高效地无限扩展的BufferGeometry。
</p>
<p>
我们以在渲染时扩展的line来示例。我们将分配可容纳500个顶点的空间但起初仅绘制2个,使用
在500个顶点的缓冲区中,但首先只使用 [page:BufferGeometry.drawRange]。
</p>
<code>
var MAX_POINTS = 500;
// geometry
var geometry = new THREE.BufferGeometry();
// attributes
var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
// draw range
var drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );
// material
var material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
// line
var line = new THREE.Line( geometry, material );
scene.add( line );
</code>
<p>
然后我们随机增加顶点到line中,以这样的一种方式:
</p>
<code>
var positions = line.geometry.attributes.position.array;
var x, y, z, index;
x = y = z = index = 0;
for ( var i = 0, l = MAX_POINTS; i < l; i ++ ) {
positions[ index ++ ] = x;
positions[ index ++ ] = y;
positions[ index ++ ] = z;
x += ( Math.random() - 0.5 ) * 30;
y += ( Math.random() - 0.5 ) * 30;
z += ( Math.random() - 0.5 ) * 30;
}
</code>
<p>
如果要更改第一次渲染后渲染的<em>点数</em>,执行以下操作:
</p>
<code>
line.geometry.setDrawRange( 0, newValue );
</code>
<p>
如果要在第一次渲染后更改position数值,则需要像这样设置needsUpdate标志:
</p>
<code>
line.geometry.attributes.position.needsUpdate = true; // 需要加在第一次渲染之后
</code>
<p>
<a href="http://jsfiddle.net/w67tzfhx/">这个fiddle</a>展示了一个你可以参考的运动的line。
</p>
<h3>例子:</h3>
[example:webgl_custom_attributes WebGL / custom / attributes]<br />
[example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / custom / attributes / particles]
</div>
<h3>[page:Geometry]</h3>
<div>
<p>
以下标志控制各种geometry属性的更新。仅对于需要更新的属性设置标志,因为更新成本很高。
一旦buffers改变,这些标志位会自动重置为false。如果你想要持续更新buffers,你需要保持这些设置为true。
请注意这仅适用于[page:Geometry]而不是[page:BufferGeometry]。
</p>
<code>
var geometry = new THREE.Geometry();
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
geometry.morphTargetsNeedUpdate = true;
geometry.uvsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.tangentsNeedUpdate = true;
</code>
<p>
在早于[link:https://github.com/mrdoob/three.js/releases/tag/r66 r66]的版本中,meshes
需要额外设定 <em>dynamic</em> 标志为true (为了维持内部的 typed arrays):
</p>
<code>
//removed after r66
geometry.dynamic = true;
</code>
<h3>例子:</h3>
[example:webgl_geometry_dynamic WebGL / geometry / dynamic]<br />
</div>
</div>
<h2>材质(Materials)</h2>
<div>
<p>所有uniforms值都可以自由改变(比如 colors, textures, opacity 等等),这些数值在每帧都发给shader。</p>
<p>GL状态相关参数也可以随时改变(depthTest, blending, polygonOffset 等)。</p>
<p>在运行时无法轻松更改以下属性(一旦material被渲染了一次):</p>
<ul>
<li>uniforms的数量和类型</li>
<li>是否存在
<ul>
<li>texture</li>
<li>fog</li>
<li>vertex colors</li>
<li>skinning</li>
<li>morphing</li>
<li>shadow map</li>
<li>alpha test</li>
</ul>
</li>
</ul>
<p>这些变化需要建立新的shader程序。你需要设置</p>
<code>material.needsUpdate = true</code>
<p>请记住,这可能会非常缓慢并导致帧率的波动。(特别是在Windows上,因为shader编译在directx中比opengl慢)。</p>
<p>为了获得更流畅的体验,您可以通过“虚拟”值(如零强度光,白色纹理或零密度雾)在一定程度上模拟这些功能的变化。</p>
<p>您可以自由更改用于几何块的材质,但是无法更改对象如何划分为块(根据面材料)。</p>
<h3>如果你需要在运行时使用不同的材料配置:</h3>
<p>如果材料/块的数量很少,您可以事先预先划分物体(例如,人的头发/脸部/身体/上衣/裤子,汽车的前部/侧面/顶部/玻璃/轮胎/内部)。</p>
<p>如果数量很大(例如,每个面可能有所不同),请考虑不同的解决方案,例如使用属性/纹理来驱动不同的每个面部外观。</p>
<h3>例子:</h3>
[example:webgl_materials_cars WebGL / materials / cars]<br />
[example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
</div>
<h2>纹理(Textures)</h2>
<div>
<p>如果更改了图像,画布,视频和数据纹理,则需要设置以下标志:</p>
<code>
texture.needsUpdate = true;
</code>
<p>渲染对象就会自动更新。</p>
<h3>例子:</h3>
[example:webgl_materials_video WebGL / materials / video]<br />
[example:webgl_rtt WebGL / rtt]
</div>
<h2>相机(Cameras)</h2>
<div>
<p>相机的位置和目标会自动更新。 如果你需要改变</p>
<ul>
<li>
fov
</li>
<li>
aspect
</li>
<li>
near
</li>
<li>
far
</li>
</ul>
<p>
那么你需要重新计算投影矩阵:
</p>
<code>
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
</code>
</div>
</body>
</html>
|