You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
earthquake_3d_viewer_front/three/manual/en/how-to-update-things.html

277 lines
11 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title>How to update Things</title>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@threejs">
<meta name="twitter:title" content="Three.js How to update Things">
<meta property="og:image" content="https://threejs.org/files/share.png">
<link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
<link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="../resources/lesson.css">
<link rel="stylesheet" href="../resources/lang.css">
<script type="importmap">
{
"imports": {
"three": "../../build/three.module.js"
}
}
</script>
</head>
<body>
<div class="container">
<div class="lesson-title">
<h1>How to update Things</h1>
</div>
<div class="lesson">
<div class="lesson-main">
<div>
<p>All objects by default automatically update their matrices if they have been added to the scene with</p>
<pre class="prettyprint notranslate lang-js" translate="no">
const object = new THREE.Object3D();
scene.add( object );
</pre>
or if they are the child of another object that has been added to the scene:
<pre class="prettyprint notranslate lang-js" translate="no">
const object1 = new THREE.Object3D();
const object2 = new THREE.Object3D();
object1.add( object2 );
scene.add( object1 ); //object1 and object2 will automatically update their matrices
</pre>
</div>
<p>However, if you know the object will be static, you can disable this and update the transform matrix manually just when needed.</p>
<pre class="prettyprint notranslate lang-js" translate="no">
object.matrixAutoUpdate = false;
object.updateMatrix();
</pre>
<h2>BufferGeometry</h2>
<div>
<p>
BufferGeometries store information (such as vertex positions, face indices, normals, colors,
UVs, and any custom attributes) in attribute buffers - that is,
[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays typed arrays].
This makes them generally faster than standard Geometries, at the cost of being somewhat harder to
work with.
</p>
<p>
With regards to updating BufferGeometries, the most important thing to understand is that
you cannot resize buffers (this is very costly, basically the equivalent to creating a new geometry).
You can however update the content of buffers.
</p>
<p>
This means that if you know an attribute of your BufferGeometry will grow, say the number of vertices,
you must pre-allocate a buffer large enough to hold any new vertices that may be created. Of
course, this also means that there will be a maximum size for your BufferGeometry - there is
no way to create a BufferGeometry that can efficiently be extended indefinitely.
</p>
<p>
We'll use the example of a line that gets extended at render time. We'll allocate space
in the buffer for 500 vertices but draw only two at first, using `BufferGeometry.drawRange`.
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
const MAX_POINTS = 500;
// geometry
const geometry = new THREE.BufferGeometry();
// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // 3 floats (x, y and z) per point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
// draw range
const drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );
// material
const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
// line
const line = new THREE.Line( geometry, material );
scene.add( line );
</pre>
<p>
Next we'll randomly add points to the line using a pattern like:
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
const positionAttribute = line.geometry.getAttribute( 'position' );
let x = 0, y = 0, z = 0;
for ( let i = 0; i < positionAttribute.count; i ++ ) {
positionAttribute.setXYZ( i, x, y, z );
x += ( Math.random() - 0.5 ) * 30;
y += ( Math.random() - 0.5 ) * 30;
z += ( Math.random() - 0.5 ) * 30;
}
</pre>
<p>
If you want to change the <em>number of points</em> rendered after the first render, do this:
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
line.geometry.setDrawRange( 0, newValue );
</pre>
<p>
If you want to change the position data values after the first render, you need to
set the needsUpdate flag like so:
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
positionAttribute.needsUpdate = true; // required after the first render
</pre>
<p>
If you change the position data values after the initial render, you may need to recompute
bounding volumes so other features of the engine like view frustum culling or helpers properly work.
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
line.geometry.computeBoundingBox();
line.geometry.computeBoundingSphere();
</pre>
<p>
[link:https://jsfiddle.net/t4m85pLr/1/ Here is a fiddle] showing an animated line which you can adapt to your use case.
</p>
<h3>Examples</h3>
<p>
[example:webgl_custom_attributes WebGL / custom / attributes]<br />
[example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / custom / attributes / particles]
</p>
</div>
<h2>Materials</h2>
<div>
<p>All uniforms values can be changed freely (e.g. colors, textures, opacity, etc), values are sent to the shader every frame.</p>
<p>Also GLstate related parameters can change any time (depthTest, blending, polygonOffset, etc).</p>
<p>The following properties can't be easily changed at runtime (once the material is rendered at least once):</p>
<ul>
<li>numbers and types of uniforms</li>
<li>presence or not of
<ul>
<li>texture</li>
<li>fog</li>
<li>vertex colors</li>
<li>morphing</li>
<li>shadow map</li>
<li>alpha test</li>
<li>transparent</li>
</ul>
</li>
</ul>
<p>Changes in these require building of new shader program. You'll need to set</p>
<code>material.needsUpdate = true</code>
<p>Bear in mind this might be quite slow and induce jerkiness in framerate (especially on Windows, as shader compilation is slower in DirectX than OpenGL).</p>
<p>For smoother experience you can emulate changes in these features to some degree by having "dummy" values like zero intensity lights, white textures, or zero density fog.</p>
<p>You can freely change the material used for geometry chunks, however you cannot change how an object is divided into chunks (according to face materials). </p>
<h3>If you need to have different configurations of materials during runtime:</h3>
<p>If the number of materials / chunks is small, you could pre-divide the object beforehand (e.g. hair / face / body / upper clothes / trousers for a human, front / sides / top / glass / tire / interior for a car). </p>
<p>If the number is large (e.g. each face could be potentially different), consider a different solution, such as using attributes / textures to drive different per-face look.</p>
<h3>Examples</h3>
<p>
[example:webgl_materials_car WebGL / materials / car]<br />
[example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
</p>
</div>
<h2>Textures</h2>
<div>
<p>Image, canvas, video and data textures need to have the following flag set if they are changed:</p>
<code>
texture.needsUpdate = true;
</code>
<p>Render targets update automatically.</p>
<h3>Examples</h3>
<p>
[example:webgl_materials_video WebGL / materials / video]<br />
[example:webgl_rtt WebGL / rtt]
</p>
</div>
<h2>Cameras</h2>
<div>
<p>A camera's position and target is updated automatically. If you need to change</p>
<ul>
<li>
fov
</li>
<li>
aspect
</li>
<li>
near
</li>
<li>
far
</li>
</ul>
<p>
then you'll need to recompute the projection matrix:
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
</pre>
</div>
<h2>InstancedMesh</h2>
<div>
<p>
`InstancedMesh` is a class for conveniently access instanced rendering in `three.js`. Certain library features like view frustum culling or
ray casting rely on up-to-date bounding volumes (bounding sphere and bounding box). Because of the way how `InstancedMesh` works, the class
has its own `boundingBox` and `boundingSphere` properties that supersede the bounding volumes on geometry level.
</p>
<p>
Similar to geometries you have to recompute the bounding box and sphere whenever you change the underlying data. In context of `InstancedMesh`, that
happens when you transform instances via `setMatrixAt()`. You can use the same pattern like with geometries.
</p>
<pre class="prettyprint notranslate lang-js" translate="no">
instancedMesh.computeBoundingBox();
instancedMesh.computeBoundingSphere();
</pre>
</div>
<h2>SkinnedMesh</h2>
<div>
<p>
`SkinnedMesh` follows the same principles like `InstancedMesh` in context of bounding volumes. Meaning the class has its own version of
`boundingBox` and `boundingSphere` to correctly enclose animated meshes.
When calling `computeBoundingBox()` and `computeBoundingSphere()`, the class computes the respective bounding volumes based on the current
bone transformation (or in other words the current animation state).
</p>
</div>
</div>
</div>
</div>
<script src="../resources/prettify.js"></script>
<script src="../resources/lesson.js"></script>
</body></html>