У меня проблема с тройкой и инстансингом. Кажется, что объекты неправильно обрезаны ближней плоскостью камеры.
Как вы заметите, я использую измененную версию THREE.JS благодаря Mugen87, которая включает в себя UNIFORM BLOCKS, очень интересную функцию, позволяющую использовать WEBGL2.
Я установил свой экземплярный объект Mesh с параметром frustumCulled = false, чтобы экземпляры вообще не обрезались, а это не так. Поведение можно очень легко наблюдать, просто увеличив масштаб | вне.
Вы поймете, что какой-то объект, который должен быть невидимым, внезапно появляется как видимый, и наоборот.
https://jsfiddle.net/uvrox3kb/2
<!DOCTYPE html>
<html lang="en">
<head><base href="./three.js/examples/" target="_blank">
<title>three.js webgl - scene animation</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
html, body {
height: 100%;
}
body {
background: #ffffff;
padding: 0;
margin: 0;
font-family: Monospace;
font-size: 13px;
overflow: hidden;
}
#info {
top: 0px;
width: 100%;
color: #000000;
margin: 6px 0px;
text-align: center;
}
#info a {
color: #000000;
}
#container {
width: 100%;
height: calc(100% - 80px);
}
.selectBox {
border: 1px solid #55aaff;
background-color: rgba(75, 160, 255, 0.3);
position: fixed;
}
</style>
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<script type="text/javascript" src="https://yume.human-interactive.org/examples/ubo/three.js"></script>
<!--<script type="text/javascript" src="/libs/three_v101.js"></script>-->
<script type="text/javascript" src="https://threejs.org/examples/js/utils/SceneUtils.js"></script>
<script type="text/javascript" src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="vertexShader1" type="x-shader/x-vertex">
#define USE_LOGDEPTHBUF
precision highp float;
in float visible;
in float selected;
in float pickable;
in float pn_UUID;
in vec4 lodInfo;
in vec3 mcol0;
in vec3 mcol1;
in vec3 mcol2;
in vec3 mcol3;
in vec3 nmcol0;
in vec3 nmcol1;
in vec3 nmcol2;
in vec3 position;
in vec3 normal;
in vec4 color;
uniform ViewData {
mat4 projectionMatrix;
mat4 viewMatrix;
};
//uniform mat4 modelMatrix;
//uniform mat3 normalMatrix;
out vec3 vPositionEye;
out vec3 vNormalEye;
out vec4 vColor;
#include <common>
#include <logdepthbuf_pars_vertex>
void main() {
mat3 normalMatrix = mat3(
vec3( nmcol0 ),
vec3( nmcol1 ),
vec3( nmcol2 )
);
mat4 matrix = mat4(
vec4( mcol0, 0 ),
vec4( mcol1, 0 ),
vec4( mcol2, 0 ),
vec4( mcol3, 1 )
);
vec4 tposition = matrix * vec4( position, 1.0 );
vec4 vertexPositionEye = viewMatrix * tposition;
vPositionEye = vertexPositionEye.xyz;
vNormalEye = normalMatrix * normal;
gl_Position = projectionMatrix * vertexPositionEye;
#ifdef PICKING
vColor = vec4( tposition.xyz, pn_UUID );
#else
if ( selected > 0.0 ) {
vColor = vec4( 1.0, 0.0, 0.0, 0.5 );
} else {
vColor = color;
}
#endif
#include <logdepthbuf_vertex>
}
</script>
<script id="fragmentShader1" type="x-shader/x-fragment">
precision highp float;
uniform LightingData {
vec3 position;
vec3 ambientColor;
vec3 diffuseColor;
vec3 specularColor;
float shininess;
} Light;
in vec4 vColor;
in vec3 vPositionEye;
in vec3 vNormalEye;
out vec4 fragColor;
void main() {
// a very basic lighting equation (Phong reflection model) for testing
#ifdef PICKING
fragColor = vColor;
# else
vec3 l = normalize( Light.position - vPositionEye );
vec3 n = normalize( vNormalEye );
vec3 e = - normalize( vPositionEye );
vec3 r = normalize( reflect( - l, n ) );
float diffuseLightWeighting = max( dot( n, l ), 0.0 );
float specularLightWeighting = max( dot( r, e ), 0.0 );
specularLightWeighting = pow( specularLightWeighting, Light.shininess );
vec3 lightWeighting = Light.ambientColor +
Light.diffuseColor * diffuseLightWeighting +
Light.specularColor * specularLightWeighting;
fragColor = vec4( vColor.rgba * vec4(lightWeighting.rgb, 1.0 ));
#endif
//fragColor = vColor;
}
</script>
<script>
// --------------------------------------------------------------------------------------------------------------------
// - Global vars:
// --------------------------------------------------------------------------------------------------------------------
var camera, scene, renderer, controls;
var clock;
var dummyVector = new THREE.Vector3();
var objectCount = 0;
var cameraUniformBlock, lightingUniformBlock;
var objects = [];
var selectionBox, helper;
var isSelecting = false;
var canvas_h, canvas_w, canvas_x_offset, canvas_t_offset;
var pickingScene, pickingRenderTarget;
var gl;
var mouse;
var material, pmaterial;
var mesh, pmesh;
// --------------------------------------------------------------------------------------------------------------------
// - Functions:
// --------------------------------------------------------------------------------------------------------------------
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() * 100 ;
position.y = Math.random() * 100 ;
position.z = Math.random() * 100 ;
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 = Math.random() * 100
matrix.compose( position, quaternion, scale );
};
}();
function makeInstanced( geo, instanceCount ) {
// geometry
//geometryList.push( geo );
geo.computeBoundingSphere();
geo.computeBoundingBox();
geometrySize = geo.boundingBox.getSize(dummyVector);
console.log("geometrySize:", geometrySize);
var sizeArray = [geometrySize.x, geometrySize.y, geometrySize.z].sort((a, b) => b - a);
var occlussionDistance = (sizeArray[0]+ sizeArray[1]) * 0.5 * 500;
//console.log("occlussionDistance:", occlussionDistance);
geometryCenter = geo.boundingBox.getCenter(dummyVector);
//console.log("geometryCenter:", geometryCenter);
var igeo = new THREE.InstancedBufferGeometry();
igeo.index = geo.index;
igeo.attributes.position = geo.attributes.position;
igeo.attributes.normal = geo.attributes.normal;
igeo.attributes.uv = geo.attributes.uv;
//geometryList.push( igeo );
igeo.userData = {
uuid2IdArray: []
}
// Instanced Attributes Definition:
// Visible:
var visible = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );
// Selected:
var selected = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );
var pickable = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1, true, 1 );
// Absolute Transformation Matrix:
var mcol0 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var mcol1 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var mcol2 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var mcol3 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var nmcol0 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var nmcol1 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
var nmcol2 = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 3 ), 3, true, 1 );
// Center and Occlussion Distance of object from camera position:
var lodInfo = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 4 ), 4,true, 1 );
// Scene Colors:
var colors = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 4 ), 4, true, 1 );
// UUID information
var pn_UUID = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 1 ), 1 ,true, 1 );
// Instanced Attributes Assignation:
var matrix = new THREE.Matrix4();
var me = matrix.elements;
console.log(instanceCount);
for ( var i=0; i < instanceCount; i ++ ) {
objectCount ++;
visible.array[i] = 1;
pickable.array[i] = 1;
selected.array[i] = 0;
randomizeMatrix( matrix );
var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
var nme = normalMatrix.elements;
var instanceCenter = geometryCenter.applyMatrix4(matrix);
//console.log("instanceCenter:", instanceCenter);
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 ] );
nmcol0.setXYZ( i, nme[ 0 ], nme[ 1 ], nme[ 2 ] );
nmcol1.setXYZ( i, nme[ 3 ], nme[ 4 ], nme[ 5 ] );
nmcol2.setXYZ( i, nme[ 6 ], nme[ 7 ], nme[ 8 ] );
lodInfo.array[i*4] = instanceCenter.x;
lodInfo.array[(i*4) + 1] = instanceCenter.y;
lodInfo.array[(i*4) + 2] = instanceCenter.z;
lodInfo.array[(i*4) + 3] = occlussionDistance;
colors.array[i*4] = Math.random();
colors.array[(i*4) + 1] = Math.random();
colors.array[(i*4) + 2] = Math.random();
colors.array[(i*4) + 3] = 1.0;
//colors.array[i*4] = 0.0;
//colors.array[(i*4) + 1] = 0.0;
//colors.array[(i*4) + 2] = 1.0;
//colors.array[(i*4) + 3] = 1.0;
igeo.userData.uuid2IdArray[objectCount] = i;
pn_UUID.array[i] = objectCount;
}
// Instanced Attributes addition:
igeo.addAttribute( 'visible', visible );
igeo.addAttribute( 'selected', selected );
igeo.addAttribute( 'pickable', pickable );
igeo.addAttribute( 'mcol0', mcol0 );
igeo.addAttribute( 'mcol1', mcol1 );
igeo.addAttribute( 'mcol2', mcol2 );
igeo.addAttribute( 'mcol3', mcol3 );
igeo.addAttribute( 'nmcol0', nmcol0 );
igeo.addAttribute( 'nmcol1', nmcol1 );
igeo.addAttribute( 'nmcol2', nmcol2 );
igeo.addAttribute( 'lodInfo', lodInfo );
igeo.addAttribute( 'color', colors );
igeo.addAttribute( 'pn_UUID', pn_UUID );
// mesh
mesh = new THREE.Mesh( igeo, material );
mesh.frustumCulled = false;
console.log(mesh);
scene.add( mesh );
}
function init() {
var container = document.getElementById( 'container' );
mouse = new THREE.Vector2();
var rect = container.getBoundingClientRect();
canvas_w = rect.width;
canvas_h = rect.height;
canvas_x_offset = rect.left;
canvas_y_offset = rect.top;
camera = new THREE.PerspectiveCamera( 90, canvas_w / canvas_h, 1, 1e27 );
scene = new THREE.Scene();
clock = new THREE.Clock();
// geometry
//var geometry1 = new THREE.TorusBufferGeometry();
var geometry1 = new THREE.BoxBufferGeometry( 1, 1, 1 );
//var geometry2 = new THREE.TorusKnotBufferGeometry();
cameraUniformBlock = new THREE.UniformBlock();
cameraUniformBlock.setName( 'ViewData' );
cameraUniformBlock.add( { value: camera.projectionMatrix } ); // projection matrix
cameraUniformBlock.add( { value: camera.matrixWorldInverse } ); // view matrix
lightingUniformBlock = new THREE.UniformBlock();
lightingUniformBlock.setName( 'LightingData' );
lightingUniformBlock.add( { value: new THREE.Vector3( 0, 0, 0 ) } ); // light position
lightingUniformBlock.add( { value: new THREE.Color( 0x333333 ) } ); // ambient color
lightingUniformBlock.add( { value: new THREE.Color( 0xaaaaaa ) } ); // diffuse color
lightingUniformBlock.add( { value: new THREE.Color( 0xcccccc ) } ); // specular color
lightingUniformBlock.add( { value: 64 } ); // shininess
// materials
material = new THREE.RawShaderMaterial( {
uniformBlocks: [ cameraUniformBlock, lightingUniformBlock ],
vertexShader: "#version 300 es\n" + document.getElementById( 'vertexShader1' ).textContent,
fragmentShader: "#version 300 es\n" + document.getElementById( 'fragmentShader1' ).textContent,
transparent: true,
side: THREE.DoubleSide,
clipping: true,
clipShadows: false
} );
console.log(material);
makeInstanced( geometry1, 100 );
var canvas = document.createElement( 'canvas' );
gl = canvas.getContext( 'webgl2' );
renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true, canvas: canvas, context: gl } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
material.uniformBlocks.dynamic= true;
material.uniformBlocks[1].dynamic= true;
material.uniformBlocks[1].uniforms[0].dynamic = true;
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
camera.position.set( 0, 0, 250 );
camera.lookAt( scene.position );
container.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 render(){
renderer.render( scene, camera );
material.uniformBlocks[1].uniforms[0].value = camera.position;
}
// --------------------------------------------------------------------------------------------------------------------
// - Start of Body:
// --------------------------------------------------------------------------------------------------------------------
init();
render();
</script>
</body>
</html>
Чтобы воспроизвести проблему, просто увеличьте | и вы увидите, что видимость не работает должным образом:
Вот пример только увеличения:
С наилучшими пожеланиями
Любая подсказка?