我是THREEJS的新手。过去,我使用过AFRAME,CESIUM,XEOGL和BABYLONJS。但最终,由于内存消耗和性能,我意识到制作CAD可视化工具的最佳产品是THREEJS。
BABYLONJS加载大型GLTF文件(400MB)花费了4分钟以上,而THREEJS仅花费30秒。 BABYLONJS占用的内存是THREEJS使用的内存的4倍。
[我知道仍然存在一些问题,无法从THREEJS中的已加载GLTF文件创建实例(GPU),但是我只需要更改每个实例的位置和旋转度,而无需设置任何动画。
我已经尝试使用GLTF1.0和GLTF2.0,并且问题相同。加载GLTF模型时,会得到一个场景。从这个场景中,我试图从children数组中获取buffergeometry。但是,当我尝试创建一个实例时,它无法正常工作。我的对象是静态的(根本没有动画)。
有什么方法可以创建Object3D的实例或从其缓冲几何中创建实例?
在BABYLONJS中,从加载的GLTF文件创建实例非常简单。我确实需要使用实例来节省RAM并使用GPU代替CPU资源。我的场景需要加载许多相同对象的副本以合成场景。
我使用GLFT加载程序看到一些问题:
var geo = data.scene.children[0].children[0].children[0].children[0].geometry
这里有使用Duck GLTF示例的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - interactive instances (gpu)</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 {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
.info {
position: absolute;
background-color: black;
opacity: 0.8;
color: white;
text-align: center;
top: 0px;
width: 100%;
}
.info a {
color: #00ffff;
}
#notSupported {
width: 50%;
margin: auto;
border: 2px red solid;
margin-top: 20px;
padding: 10px;
}
</style>
</head>
<body>
<div class="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - gpu picking of geometry instances
<div id="notSupported" style="display:none">Sorry your graphics card + browser does not support hardware instancing</div>
<br/><br/>
<div>This demo compares different methods of constructing and rendering many instances of a single geometry.</div>
<br/>
<div>
<div style="display:inline-block;">
<span>number of<br/>geometry instances</span>
<br/>
<select id="instanceCount">
<option>100</option>
<option>500</option>
<option selected>1000</option>
<option>2000</option>
<option>3000</option>
<option>5000</option>
<option>10000</option>
<option>20000</option>
<option>30000</option>
<option>50000</option>
<option>100000</option>
</select>
</div>
<div style="display:inline-block;">
<span>method of<br/>construction/rendering</span>
<br/>
<select id="method">
<option>instanced</option>
<option>merged</option>
<option selected>singleMaterial</option>
<option>multiMaterial</option>
</select>
</div>
<div style="display:inline-block;">
<span>render continuously<br/>(to get fps reading)</span>
<br/>
<input id="animate" type="checkbox" />
</div>
<div style="display:inline-block;">
<span>use override material<br/>(only effects singleMaterial method)</span>
<br/>
<input id="override" type="checkbox" checked/>
</div>
<div style="display:inline-block;">
<span>construct anew<br/>(to get additional timings)</span>
<br/>
<button id="construct" type="button">do it</button>
</div>
</div>
<br/>
<div>
<span>Materials: #<span id="materialCount"></span></span>
<span>Objects: #<span id="objectCount"></span></span>
<span>Drawcalls: #<span id="drawcalls"></span></span>
<span>Construction time: <span id="initTime"></span> ms</span>
</div>
</div>
<div id="container"></div>
<script src="../build/three.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/loaders/GLTF2Loader.js"></script>
<script id="vertMerged" type="x-shader/x-vertex">
#define SHADER_NAME vertMerged
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
#ifdef PICKING
attribute vec3 pickingColor;
#else
attribute vec3 color;
varying vec3 vPosition;
#endif
varying vec3 vColor;
void main() {
vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
#ifdef PICKING
vColor = pickingColor;
#else
vColor = color;
vPosition = positionEye;
#endif
gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
}
</script>
<script id="fragMerged" type="x-shader/x-fragment">
#define SHADER_NAME fragMerged
#extension GL_OES_standard_derivatives : enable
precision highp float;
varying vec3 vColor;
#ifndef PICKING
varying vec3 vPosition;
#endif
void main() {
#ifdef PICKING
gl_FragColor = vec4( vColor, 1.0 );
#else
vec3 fdx = dFdx( vPosition );
vec3 fdy = dFdy( vPosition );
vec3 normal = normalize( cross( fdx, fdy ) );
float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
gl_FragColor = vec4( diffuse * vColor, 1.0 );
#endif
}
</script>
<script id="vertInstanced" type="x-shader/x-vertex">
#define SHADER_NAME vertInstanced
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec3 mcol0;
attribute vec3 mcol1;
attribute vec3 mcol2;
attribute vec3 mcol3;
#ifdef PICKING
attribute vec3 pickingColor;
#else
attribute vec3 color;
varying vec3 vPosition;
#endif
varying vec3 vColor;
void main() {
mat4 matrix = mat4(
vec4( mcol0, 0 ),
vec4( mcol1, 0 ),
vec4( mcol2, 0 ),
vec4( mcol3, 1 )
);
vec3 positionEye = ( modelViewMatrix * matrix * vec4( position, 1.0 ) ).xyz;
#ifdef PICKING
vColor = pickingColor;
#else
vColor = color;
vPosition = positionEye;
#endif
gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
}
</script>
<script id="fragInstanced" type="x-shader/x-fragment">
#define SHADER_NAME fragInstanced
#extension GL_OES_standard_derivatives : enable
precision highp float;
varying vec3 vColor;
#ifndef PICKING
varying vec3 vPosition;
#endif
void main() {
#ifdef PICKING
gl_FragColor = vec4( vColor, 1.0 );
#else
vec3 fdx = dFdx( vPosition );
vec3 fdy = dFdy( vPosition );
vec3 normal = normalize( cross( fdx, fdy ) );
float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
gl_FragColor = vec4( diffuse * vColor, 1.0 );
#endif
}
</script>
<script id="vertMaterial" type="x-shader/x-vertex">
#define SHADER_NAME vertMaterial
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
#ifndef PICKING
varying vec3 vPosition;
#endif
void main() {
vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
#ifndef PICKING
vPosition = positionEye;
#endif
gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
}
</script>
<script id="fragMaterial" type="x-shader/x-fragment">
#define SHADER_NAME fragMaterial
#extension GL_OES_standard_derivatives : enable
precision highp float;
#ifdef PICKING
uniform vec3 pickingColor;
#else
uniform vec3 color;
varying vec3 vPosition;
#endif
void main() {
#ifdef PICKING
gl_FragColor = vec4( pickingColor, 1.0 );
#else
vec3 fdx = dFdx( vPosition );
vec3 fdy = dFdy( vPosition );
vec3 normal = normalize( cross( fdx, fdy ) );
float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
gl_FragColor = vec4( diffuse * color, 1.0 );
#endif
}
</script>
<script>
var container, stats;
var camera, controls, scene, renderer;
var pickingData, pickingRenderTarget, pickingScene;
var useOverrideMaterial = true;
var singleMaterial, singlePickingMaterial;
var highlightBox;
var materialList = [];
var geometryList = [];
var objectCount = 0;
var geometrySize;
var mouse = new THREE.Vector2();
var scale = 1.03;
var loader = new THREE.GLTF2Loader();
var pixelBuffer = new Uint8Array( 4 );
var instanceCount, method, doAnimate;
gui();
init();
initMesh();
if ( doAnimate ) animate();
function gui() {
var instanceCountElm = document.getElementById( 'instanceCount' );
instanceCount = parseInt( instanceCountElm.value );
instanceCountElm.addEventListener( "change", function() {
instanceCount = parseInt( instanceCountElm.value );
initMesh();
} );
var methodElm = document.getElementById( 'method' );
method = methodElm.value;
methodElm.addEventListener( "change", function() {
method = methodElm.value;
initMesh();
} );
var animateElm = document.getElementById( 'animate' );
doAnimate = animateElm.checked;
animateElm.addEventListener( "click", function() {
doAnimate = animateElm.checked;
animate();
} );
var overrideElm = document.getElementById( 'override' );
useOverrideMaterial = overrideElm.checked;
overrideElm.addEventListener( "click", function() {
useOverrideMaterial = overrideElm.checked;
initMesh();
} );
var constructElm = document.getElementById( 'construct' );
constructElm.addEventListener( "click", function() {
initMesh();
} );
}
function clean() {
THREE.Cache.clear();
materialList.forEach( function( m ) {
m.dispose();
} );
geometryList.forEach( function( g ) {
g.dispose();
} );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xffffff );
scene.add( camera );
scene.add( highlightBox );
pickingScene = new THREE.Scene();
pickingData = {};
materialList = [];
geometryList = [];
objectCount = 0;
singleMaterial = undefined;
singlePickingMaterial = undefined;
}
var randomizeMatrix = function() {
var position = new THREE.Vector3();
var rotation = new THREE.Euler();
var quaternion = new THREE.Quaternion();
var scale = new THREE.Vector3();
return function( matrix ) {
position.x = Math.random() * 40 - 20;
position.y = Math.random() * 40 - 20;
position.z = Math.random() * 40 - 20;
rotation.x = Math.random() * 2 * Math.PI;
rotation.y = Math.random() * 2 * Math.PI;
rotation.z = Math.random() * 2 * Math.PI;
quaternion.setFromEuler( rotation, false );
scale.x = scale.y = scale.z = 0.001;
matrix.compose( position, quaternion, scale );
};
}();
function initMesh() {
clean();
loader.load( 'models/gltf/Duck/glTF-Binary/Duck.glb', function ( data ) {
console.log(data);
var geo = data.scene.children[0].children[0].children[0].children[0].geometry
console.log("geo:");
console.log(geo);
geo.computeBoundingBox();
geometrySize = geo.boundingBox.getSize();
geometryList.push( geo );
var start = window.performance.now();
switch ( method ){
case "merged":
makeMerged( geo );
break;
case "instanced":
makeInstanced( geo );
break;
case "singleMaterial":
makeSingleMaterial( geo );
break;
case "multiMaterial":
makeMultiMaterial( geo );
break;
}
render();
var end = window.performance.now();
document.getElementById( 'materialCount' ).innerText = materialList.length;
document.getElementById( 'objectCount' ).innerText = objectCount;
document.getElementById( 'drawcalls' ).innerText = renderer.info.render.calls;
document.getElementById( 'initTime' ).innerText = ( end - start ).toFixed( 2 );
} );
}
function makeMultiMaterial( geo ) {
var vert = document.getElementById( 'vertMaterial' ).textContent;
var frag = document.getElementById( 'fragMaterial' ).textContent;
var material = new THREE.RawShaderMaterial( {
vertexShader: vert,
fragmentShader: frag,
uniforms: {
color: {
value: new THREE.Color()
}
}
} );
var pickingMaterial = new THREE.RawShaderMaterial( {
vertexShader: "#define PICKING\n" + vert,
fragmentShader: "#define PICKING\n" + frag,
uniforms: {
pickingColor: {
value: new THREE.Color()
}
}
} );
var matrix = new THREE.Matrix4();
for ( var i = 0; i < instanceCount; i ++ ) {
var object = new THREE.Mesh( geo, material );
objectCount ++;
randomizeMatrix( matrix );
object.applyMatrix( matrix );
var pickingObject = object.clone();
objectCount ++;
object.material = material.clone();
object.material.uniforms.color.value.setHex( Math.random() * 0xffffff );
materialList.push( object.material );
pickingObject.material = pickingMaterial.clone();
pickingObject.material.uniforms.pickingColor.value.setHex( i + 1 );
materialList.push( pickingObject.material );
pickingData[ i + 1 ] = object;
scene.add( object );
pickingScene.add( pickingObject );
}
material.dispose();
pickingMaterial.dispose();
}
function makeSingleMaterial( geo ) {
var vert = document.getElementById( 'vertMaterial' ).textContent;
var frag = document.getElementById( 'fragMaterial' ).textContent;
var material = new THREE.RawShaderMaterial( {
vertexShader: vert,
fragmentShader: frag,
uniforms: {
color: {
value: new THREE.Color()
}
}
} );
materialList.push( material );
var pickingMaterial = new THREE.RawShaderMaterial( {
vertexShader: "#define PICKING\n" + vert,
fragmentShader: "#define PICKING\n" + frag,
uniforms: {
pickingColor: {
value: new THREE.Color()
}
}
} );
materialList.push( pickingMaterial );
if ( useOverrideMaterial ) {
singleMaterial = material;
singlePickingMaterial = pickingMaterial;
}
var matrix = new THREE.Matrix4();
function onBeforeRender( renderer, scene, camera, geometry, material, group ){
var updateList = [];
var u = material.uniforms;
var d = this.userData;
if( u.pickingColor ){
u.pickingColor.value.setHex( d.pickingColor );
updateList.push( "pickingColor" );
}
if( u.color ){
u.color.value.setHex( d.color );
updateList.push( "color" );
}
if( updateList.length ){
var materialProperties = renderer.properties.get( material );
if( materialProperties.program ){
var gl = renderer.getContext();
var p = materialProperties.program;
gl.useProgram( p.program );
var pu = p.getUniforms();
updateList.forEach( function( name ){
pu.setValue( gl, name, u[ name ].value );
} );
}
}
}
for ( var i = 0; i < instanceCount; i ++ ) {
var object = new THREE.Mesh( geo, material );
objectCount ++;
randomizeMatrix( matrix );
object.applyMatrix( matrix );
var pickingObject;
if ( ! useOverrideMaterial ) {
pickingObject = object.clone();
objectCount ++;
}
object.material = material;
object.userData[ "color" ] = Math.random() * 0xffffff;
if ( useOverrideMaterial ) {
object.userData[ "pickingColor" ] = i + 1;
object.onBeforeRender = onBeforeRender;
}else {
pickingObject.material = pickingMaterial;
pickingObject.userData[ "pickingColor" ] = i + 1;
pickingObject.onBeforeRender = onBeforeRender;
}
pickingData[ i + 1 ] = object;
scene.add( object );
if ( ! useOverrideMaterial ) pickingScene.add( pickingObject );
}
}
function makeMerged( geo ) {
var vert = document.getElementById( 'vertMerged' ).textContent;
var frag = document.getElementById( 'fragMerged' ).textContent;
var material = new THREE.RawShaderMaterial( {
vertexShader: vert,
fragmentShader: frag
} );
materialList.push( material );
var pickingMaterial = new THREE.RawShaderMaterial( {
vertexShader: "#define PICKING\n" + vert,
fragmentShader: "#define PICKING\n" + frag
} );
materialList.push( pickingMaterial );
var bgeo = geo.clone();
geometryList.push( bgeo );
var mgeo = new THREE.BufferGeometry();
geometryList.push( mgeo );
var pos = bgeo.attributes.position;
var posLen = bgeo.attributes.position.count * 3;
var vertices = new THREE.BufferAttribute(
new Float32Array( instanceCount * posLen ), 3
);
var matrix = new THREE.Matrix4();
for ( var i = 0, ul = instanceCount; i < ul; i ++ ) {
randomizeMatrix( matrix );
var object = new THREE.Object3D();
objectCount ++;
object.applyMatrix( matrix );
pickingData[ i + 1 ] = object;
vertices.set( pos.array, i * posLen );
//matrix.applyToVector3Array( vertices.array, i * posLen, posLen )
}
mgeo.addAttribute( 'position', vertices );
var colCount = posLen / 3;
var colors = new THREE.BufferAttribute(
new Float32Array( instanceCount * colCount * 3 ), 3
);
var randCol = function() {
return Math.random();
};
for ( var i = 0, ul = instanceCount; i < ul; i ++ ) {
var r = randCol(), g = randCol(), b = randCol();
for ( var j = i * colCount, jl = ( i + 1 ) * colCount; j < jl; j ++ ) {
colors.setXYZ( j, r, g, b );
}
}
mgeo.addAttribute( 'color', colors );
var col = new THREE.Color();
var pickingColors = new THREE.BufferAttribute(
new Float32Array( instanceCount * colCount * 3 ), 3
);
for ( var i = 0, ul = instanceCount; i < ul; i ++ ) {
col.setHex( i + 1 );
for ( var j = i * colCount, jl = ( i + 1 ) * colCount; j < jl; j ++ ) {
pickingColors.setXYZ( j, col.r, col.g, col.b );
}
}
mgeo.addAttribute( 'pickingColor', pickingColors );
var mesh = new THREE.Mesh( mgeo, material );
scene.add( mesh );
var pickingMesh = new THREE.Mesh( mgeo, pickingMaterial );
pickingScene.add( pickingMesh );
}
function makeInstanced( geo ) {
var vert = document.getElementById( 'vertInstanced' ).textContent;
var frag = document.getElementById( 'fragInstanced' ).textContent;
var material = new THREE.RawShaderMaterial( {
vertexShader: vert,
fragmentShader: frag,
} );
materialList.push( material );
var pickingMaterial = new THREE.RawShaderMaterial( {
vertexShader: "#define PICKING\n" + vert,
fragmentShader: "#define PICKING\n" + frag
} );
materialList.push( pickingMaterial );
var bgeo = geo.clone();
geometryList.push( bgeo );
var igeo = new THREE.InstancedBufferGeometry();
geometryList.push( igeo );
var vertices = bgeo.attributes.position.clone();
igeo.addAttribute( 'position', vertices );
var mcol0 = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
var mcol1 = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
var mcol2 = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
var mcol3 = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
var matrix = new THREE.Matrix4();
var me = matrix.elements;
for ( var i = 0, ul = mcol0.count; i < ul; i ++ ) {
randomizeMatrix( matrix );
var object = new THREE.Object3D();
objectCount ++;
object.applyMatrix( matrix );
pickingData[ i + 1 ] = object;
mcol0.setXYZ( i, me[ 0 ], me[ 1 ], me[ 2 ] );
mcol1.setXYZ( i, me[ 4 ], me[ 5 ], me[ 6 ] );
mcol2.setXYZ( i, me[ 8 ], me[ 9 ], me[ 10 ] );
mcol3.setXYZ( i, me[ 12 ], me[ 13 ], me[ 14 ] );
}
igeo.addAttribute( 'mcol0', mcol0 );
igeo.addAttribute( 'mcol1', mcol1 );
igeo.addAttribute( 'mcol2', mcol2 );
igeo.addAttribute( 'mcol3', mcol3 );
var randCol = function() {
return Math.random();
};
var colors = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
for ( var i = 0, ul = colors.count; i < ul; i ++ ) {
colors.setXYZ( i, randCol(), randCol(), randCol() );
}
igeo.addAttribute( 'color', colors );
var col = new THREE.Color();
var pickingColors = new THREE.InstancedBufferAttribute(
new Float32Array( instanceCount * 3 ), 3, 1
);
for ( var i = 0, ul = pickingColors.count; i < ul; i ++ ) {
col.setHex( i + 1 );
pickingColors.setXYZ( i, col.r, col.g, col.b );
}
igeo.addAttribute( 'pickingColor', pickingColors );
var mesh = new THREE.Mesh( igeo, material );
scene.add( mesh );
var pickingMesh = new THREE.Mesh( igeo, pickingMaterial );
pickingScene.add( pickingMesh );
}
function init() {
camera = new THREE.PerspectiveCamera(
70, window.innerWidth / window.innerHeight, 1, 100
);
camera.position.z = 40;
pickingRenderTarget = new THREE.WebGLRenderTarget(
window.innerWidth, window.innerHeight
);
pickingRenderTarget.texture.generateMipmaps = false;
pickingRenderTarget.texture.minFilter = THREE.NearestFilter;
highlightBox = new THREE.Mesh(
new THREE.BoxGeometry( 1, 1, 1 ),
new THREE.MeshLambertMaterial( {
emissive: 0xffff00,
transparent: true,
opacity: 0.5,
side: THREE.FrontSide
} )
);
container = document.getElementById( "container" );
renderer = new THREE.WebGLRenderer( {
antialias: true,
alpha: true
} );
if ( renderer.extensions.get( 'ANGLE_instanced_arrays' ) === false ) {
document.getElementById( "notSupported" ).style.display = "";
return;
}
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
if ( renderer.extensions.get( 'ANGLE_instanced_arrays' ) === false ) {
throw 'ANGLE_instanced_arrays not supported';
}
controls = new THREE.TrackballControls(
camera, renderer.domElement
);
controls.staticMoving = true;
stats = new Stats();
container.appendChild( stats.dom );
renderer.domElement.addEventListener( 'mousemove', onMouseMove );
window.addEventListener( 'resize', onWindowResize, false );
}
//
function onMouseMove( e ) {
mouse.x = e.clientX;
mouse.y = e.clientY;
controls.update();
requestAnimationFrame( render );
}
function onWindowResize( event ) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
pickingRenderTarget.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
if ( doAnimate ) {
requestAnimationFrame( animate );
}
controls.update();
stats.update();
document.getElementById( 'materialCount' ).innerText = materialList.length;
document.getElementById( 'objectCount' ).innerText = objectCount;
document.getElementById( 'drawcalls' ).innerText = renderer.info.render.calls;
render();
}
function pick() {
highlightBox.visible = false;
if ( singlePickingMaterial ) {
scene.overrideMaterial = singlePickingMaterial;
renderer.render( scene, camera, pickingRenderTarget );
scene.overrideMaterial = null;
}else {
renderer.render( pickingScene, camera, pickingRenderTarget );
}
renderer.readRenderTargetPixels(
pickingRenderTarget,
mouse.x,
pickingRenderTarget.height - mouse.y,
1,
1,
pixelBuffer
);
var id =
( pixelBuffer[ 0 ] << 16 ) |
( pixelBuffer[ 1 ] << 8 ) |
( pixelBuffer[ 2 ] );
var object = pickingData[ id ];
if ( object ) {
if ( object.position && object.rotation && object.scale ) {
highlightBox.position.copy( object.position );
highlightBox.rotation.copy( object.rotation );
highlightBox.scale.copy( object.scale )
.multiply( geometrySize )
.multiplyScalar( scale );
highlightBox.visible = true;
}
} else {
highlightBox.visible = false;
}
}
function render() {
pick();
renderer.render( scene, camera );
}
</script>
</body>
</html>
似乎您的问题主要是,如何在Three.js中实例化?加载模型后,创建模型所用的格式并不重要。
在这种情况下,您可能只想签出three.js instancing examples或使用three-instanced-mesh之类的助手之一。
第二个链接显示了从模型中获取几何图形后如何进行:
// Assumes your model only contains one mesh.
var geometry;
model.traverse(function (node) => {
if (node.isMesh) {
geometry = node.geometry;
}
});
//material that the geometry will use
var material = new THREE.MeshPhongMaterial();
//the instance group
var cluster = new THREE.InstancedMesh(
geometry,
material,
10000, //instance count
false, //is it dynamic
false //does it have color
true, //uniform scale
);
var _v3 = new THREE.Vector3();
var _q = new THREE.Quaternion();
for ( var i ; i < 10000 ; i ++ ) {
cluster.setQuaternionAt( i , _q );
cluster.setPositionAt( i , v3.set( Math.random() , Math.random(), Math.random() ) );
cluster.setScaleAt( i , v3.set(1,1,1) );
}
scene.add( cluster );
是的,我基于gpu实例示例:https://threejs.org/examples/?q=insta#webgl_interactive_instances_gpu
当加载GLTF文件时,您确实会获得一个包含一个/多个object3d的场景。这些object3D对象不具有几何图形,而是具有缓冲几何图形。
我已尝试使此示例适应于加载GLTF模型而不是JSON模型。
我通过复制buffergeometry成功创建了实例,但是没有正确生成边界框,我不知道为什么。
[请尝试更改此示例,并尝试使用GLTF模型,]。>
顺便说一句,我不知道为什么,但是如果我尝试使用构造函数THREE.InstancedMesh,它说这不是有效的构造函数。我正在使用r87。
我在示例中看到的另一个问题是合并不起作用。它说matrix.applyToVector3Array已被删除,我不知道替代方法。
最诚挚的问候,非常感谢您的支持。
经过一段时间的调查,我发现了为什么使用instancedbuffergeometries无法与在GLTF文件中找到的buffergeometry一起使用的原因。