未验证 提交 99970ca6 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #17505 from mrdoob/instancing

Implemented THREE.InstancedMesh
......@@ -47,6 +47,7 @@ var files = {
"webgl_geometry_text_shapes",
"webgl_geometry_text_stroke",
"webgl_helpers",
"webgl_instancing",
"webgl_interactive_buffergeometry",
"webgl_interactive_cubes",
"webgl_interactive_cubes_gpu",
......
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - instancing</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<script type="module">
import * as THREE from '../build/three.module.js';
import Stats from './jsm/libs/stats.module.js';
var camera, scene, renderer, stats;
var mesh;
var amount = 12;
var count = Math.pow( amount, 3 );
var dummy = new THREE.Object3D();
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 10, 10, 10 );
camera.lookAt( 0, 0, 0 );
scene = new THREE.Scene();
var material = new THREE.MeshNormalMaterial();
// check overdraw
// var material = new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.1, transparent: true } );
var loader = new THREE.BufferGeometryLoader();
loader.load( 'models/json/suzanne_buffergeometry.json', function ( geometry ) {
geometry.computeVertexNormals();
geometry.scale( 0.5, 0.5, 0.5 );
mesh = new THREE.InstancedMesh( geometry, material, count );
scene.add( mesh );
} );
//
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
stats = new Stats();
document.body.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
if ( mesh ) {
var time = Date.now() * 0.001;
mesh.rotation.x = Math.sin( time / 4 );
mesh.rotation.y = Math.sin( time / 2 );
var i = 0;
for ( var x = 0; x < amount; x ++ ) {
for ( var y = 0; y < amount; y ++ ) {
for ( var z = 0; z < amount; z ++ ) {
dummy.position.set( 6 - x, 6 - y, 6 - z );
dummy.rotation.y = ( Math.sin( x / 4 + time ) + Math.sin( y / 4 + time ) + Math.sin( z / 4 + time ) );
dummy.rotation.z = dummy.rotation.y * 2;
dummy.updateMatrix();
mesh.setMatrixAt( i ++, dummy.matrix );
}
}
}
mesh.instanceMatrix.needsUpdate = true;
}
renderer.render( scene, camera );
}
</script>
</body>
</html>
......@@ -18,6 +18,7 @@ export { SkinnedMesh } from './objects/SkinnedMesh.js';
export { Skeleton } from './objects/Skeleton.js';
export { Bone } from './objects/Bone.js';
export { Mesh } from './objects/Mesh.js';
export { InstancedMesh } from './objects/InstancedMesh.js';
export { LineSegments } from './objects/LineSegments.js';
export { LineLoop } from './objects/LineLoop.js';
export { Line } from './objects/Line.js';
......
/**
* @author mrdoob / http://mrdoob.com/
*/
import { BufferAttribute } from '../core/BufferAttribute.js';
import { Mesh } from './Mesh.js';
function InstancedMesh( geometry, material, count ) {
Mesh.call( this, geometry, material );
this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
}
InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
constructor: InstancedMesh,
isInstancedMesh: true,
raycast: function () {},
setMatrixAt: function ( index, matrix ) {
matrix.toArray( this.instanceMatrix.array, index * 16 );
},
updateMorphTargets: function () {}
} );
export { InstancedMesh };
......@@ -258,7 +258,7 @@ function WebGLRenderer( parameters ) {
capabilities = new WebGLCapabilities( _gl, extensions, parameters );
if ( ! capabilities.isWebGL2 ) {
if ( capabilities.isWebGL2 === false ) {
extensions.get( 'WEBGL_depth_texture' );
extensions.get( 'OES_texture_float' );
......@@ -283,7 +283,7 @@ function WebGLRenderer( parameters ) {
textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
attributes = new WebGLAttributes( _gl );
geometries = new WebGLGeometries( _gl, attributes, info );
objects = new WebGLObjects( geometries, info );
objects = new WebGLObjects( _gl, geometries, attributes, info );
morphtargets = new WebGLMorphtargets( _gl );
programCache = new WebGLPrograms( _this, extensions, capabilities );
renderLists = new WebGLRenderLists();
......@@ -765,7 +765,7 @@ function WebGLRenderer( parameters ) {
if ( updateBuffers ) {
setupVertexAttributes( material, program, geometry );
setupVertexAttributes( object, geometry, material, program );
if ( index !== null ) {
......@@ -831,7 +831,6 @@ function WebGLRenderer( parameters ) {
}
} else if ( object.isLine ) {
var lineWidth = material.linewidth;
......@@ -864,13 +863,13 @@ function WebGLRenderer( parameters ) {
}
if ( geometry && geometry.isInstancedBufferGeometry ) {
if ( object.isInstancedMesh ) {
if ( geometry.maxInstancedCount > 0 ) {
renderer.renderInstances( geometry, drawStart, drawCount, object.instanceMatrix.count );
renderer.renderInstances( geometry, drawStart, drawCount );
} else if ( geometry.isInstancedBufferGeometry ) {
}
renderer.renderInstances( geometry, drawStart, drawCount, geometry.maxInstancedCount );
} else {
......@@ -880,16 +879,11 @@ function WebGLRenderer( parameters ) {
};
function setupVertexAttributes( material, program, geometry ) {
if ( geometry && geometry.isInstancedBufferGeometry && ! capabilities.isWebGL2 ) {
function setupVertexAttributes( object, geometry, material, program ) {
if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {
if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
return;
}
if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
}
......@@ -972,6 +966,29 @@ function WebGLRenderer( parameters ) {
}
} else if ( name === 'instanceMatrix' ) {
var attribute = attributes.get( object.instanceMatrix );
// TODO Attribute may not be available on context restore
if ( attribute === undefined ) continue;
var buffer = attribute.buffer;
var type = attribute.type;
state.enableAttributeAndDivisor( programAttribute + 0, 1 );
state.enableAttributeAndDivisor( programAttribute + 1, 1 );
state.enableAttributeAndDivisor( programAttribute + 2, 1 );
state.enableAttributeAndDivisor( programAttribute + 3, 1 );
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
_gl.vertexAttribPointer( programAttribute + 0, 4, type, false, 64, 0 );
_gl.vertexAttribPointer( programAttribute + 1, 4, type, false, 64, 16 );
_gl.vertexAttribPointer( programAttribute + 2, 4, type, false, 64, 32 );
_gl.vertexAttribPointer( programAttribute + 3, 4, type, false, 64, 48 );
} else if ( materialDefaultAttributeValues !== undefined ) {
var value = materialDefaultAttributeValues[ name ];
......
export default /* glsl */`
vec3 transformedNormal = normalMatrix * objectNormal;
vec3 transformedNormal = objectNormal;
#ifdef USE_INSTANCING
transformedNormal = mat3( instanceMatrix ) * transformedNormal;
#endif
transformedNormal = normalMatrix * transformedNormal;
#ifdef FLIP_SIDED
......
export default /* glsl */`
vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
vec4 mvPosition = vec4( transformed, 1.0 );
#ifdef USE_INSTANCING
mvPosition = instanceMatrix * mvPosition;
#endif
mvPosition = modelViewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;
`;
export default /* glsl */`
#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )
vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );
vec4 worldPosition = vec4( transformed, 1.0 );
#ifdef USE_INSTANCING
worldPosition = instanceMatrix * worldPosition;
#endif
worldPosition = modelMatrix * worldPosition;
#endif
`;
......@@ -20,7 +20,9 @@ function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
}
function renderInstances( geometry, start, count ) {
function renderInstances( geometry, start, count, primcount ) {
if ( primcount === 0 ) return;
var extension, methodName;
......@@ -43,9 +45,9 @@ function WebGLBufferRenderer( gl, extensions, info, capabilities ) {
}
extension[ methodName ]( mode, start, count, geometry.maxInstancedCount );
extension[ methodName ]( mode, start, count, primcount );
info.update( count, mode, geometry.maxInstancedCount );
info.update( count, mode, primcount );
}
......
......@@ -29,7 +29,9 @@ function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
}
function renderInstances( geometry, start, count ) {
function renderInstances( geometry, start, count, primcount ) {
if ( primcount === 0 ) return;
var extension, methodName;
......@@ -52,9 +54,9 @@ function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {
}
extension[ methodName ]( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );
extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
info.update( count, mode, geometry.maxInstancedCount );
info.update( count, mode, primcount );
}
......
......@@ -2,7 +2,7 @@
* @author mrdoob / http://mrdoob.com/
*/
function WebGLObjects( geometries, info ) {
function WebGLObjects( gl, geometries, attributes, info ) {
var updateList = {};
......@@ -29,6 +29,12 @@ function WebGLObjects( geometries, info ) {
}
if ( object.isInstancedMesh ) {
attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );
}
return buffergeometry;
}
......
......@@ -441,6 +441,7 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
customDefines,
parameters.instancing ? '#define USE_INSTANCING' : '',
parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
'#define GAMMA_FACTOR ' + gammaFactorDefine,
......@@ -511,6 +512,12 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters
].join( '\n' ),
'#ifdef USE_INSTANCING',
' attribute mat4 instanceMatrix;',
'#endif',
'attribute vec3 position;',
'attribute vec3 normal;',
'attribute vec2 uv;',
......
......@@ -28,7 +28,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
};
var parameterNames = [
"precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding",
"precision", "supportsVertexTextures", "instancing",
"map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding",
"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "tangentSpaceNormalMap", "clearcoatNormalMap", "displacementMap", "specularMap",
"roughnessMap", "metalnessMap", "gradientMap",
"alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp2",
......@@ -134,10 +135,14 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
var parameters = {
isWebGL2: capabilities.isWebGL2,
shaderID: shaderID,
precision: precision,
isWebGL2: capabilities.isWebGL2,
instancing: object.isInstancedMesh === true,
supportsVertexTextures: capabilities.vertexTextures,
outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
map: !! material.map,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册