GLTF создает экземпляры
Я новичок в THREEJS, в прошлом я использовал AFRAME, CESIUM, XEOGL и BABYLONJS, но в итоге из-за нехватки памяти и производительности я понял, что лучшим продуктом для создания CAD-визуализатора является THREEJS.
BABYLONJS занимает больше 4 минут, чтобы загрузить большой файл GLTF (400 МБ), тогда как THREEJS занимает всего 30 секунд. Память, занятая BABYLONJS, в 4 раза больше используемой THREEJS.
Я знаю, что все еще есть некоторые проблемы, связанные с возможностью создания экземпляров (GPU) из загруженного файла GLTF в THREEJS, но мне нужно только изменять положение и поворот в каждом экземпляре, не нужно ничего анимировать.
Я пытался с GLTF1.0 и GLTF2.0, и проблема та же. Когда я загружаю модель GLTF, я получаю сцену.
Из этой сцены я пытаюсь получить буферную геометрию из массива children, но когда я пытаюсь создать экземпляр, он не работает.
Мои объекты статичны (без анимации вообще).
Есть ли способ создать экземпляр Object3D или из его буферной геометрии?
В BABYLONJS очень просто создавать экземпляры из загруженного файла GLTF.
Мне действительно нужно использовать экземпляры для хранения оперативной памяти и использовать графический процессор вместо ресурсов процессора.
Моя сцена должна загружать много раз одни и те же объекты, чтобы составить сцену.
Большое спасибо заранее за вашу поддержку.
Некоторые проблемы, которые я вижу при использовании загрузчика GLFT: 1. Вы должны идентифицировать все object3D, которые содержат правильную геометрию. В этом примере в строке 335: var geo = data.scene.children[0].children[0].children[0].children[0].geometry 2.- Пример объединения не работает. это не работает ни в оригинальном примере. 3.- Кажется, что создание экземпляров вообще не улучшает производительность: - 10000 объектов, мультиматериалы -> 4FPS - 10000 объектов, одиночные материалы -> 4FPS - 10000 объектов, экземпляры -> 4FPS - 10000 объектов, объединены -> Нет работает 4.- Когда выбран экземпляр, геометрии не отображаются должным образом.
Вот мой код на примере 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>
3 ответа
Похоже, ваш вопрос в первую очередь, как сделать инстансинг в three.js? После того, как вы загрузили модель, не имеет значения, какой формат вы использовали для ее создания.
В таком случае, вы, вероятно, просто захотите проверить примеры создания экземпляров three.js или использовать один из помощников, таких как трехэкземплярная сетка.
Вторая ссылка показывает, как действовать после того, как вы взяли геометрию из вашей модели:
// 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 );
Через некоторое время я выяснил, почему использование инстансированных буферных геометрий не работает с буферными геометриями, найденными в моих файлах GLTF.
Проблема заключается в том, что формат GLTF использует индексированные буферные геометрии, и обходной путь очень прост, просто преобразуйте их с помощью метода toNonIndexed().
Проблема исправлена.
С наилучшими пожеланиями
Да, я основал пример экземпляра gpu: https://threejs.org/examples/?q=insta.
Когда вы загружаете файл GLTF, вы действительно получаете сцену с одним / несколькими объектами 3D. Эти объекты object3D не имеют геометрии, но имеют буферную геометрию.
Я попытался адаптировать этот пример для загрузки модели GLTF вместо модели JSON.
Мне удалось создать экземпляры, сделав клон буферной геометрии, но ограничивающая рамка не сгенерирована должным образом, я не знаю почему.
Пожалуйста, попробуйте изменить этот пример и попробуйте модель GLTF, вы увидите.
Кстати, я не знаю почему, но если я пытаюсь использовать конструктор THREE.InstancedMesh, он говорит, что это не допустимый конструктор. Я использую r87.
Другая проблема, которую я вижу в примерах, состоит в том, что объединение не работает. Он говорит, что matrix.applyToVector3Array был удален, и я не знаю альтернативы.
С наилучшими пожеланиями и большое спасибо за вашу поддержку.