Skip to content

Instantly share code, notes, and snippets.

@Samsy
Created April 30, 2020 10:56
Show Gist options
  • Save Samsy/bf0b2b84316ff44fa758539b60554ca1 to your computer and use it in GitHub Desktop.
Save Samsy/bf0b2b84316ff44fa758539b60554ca1 to your computer and use it in GitHub Desktop.
instancer batcher
import {
InstancedBufferGeometry,
InstancedBufferAttribute,
BufferAttribute,
Vector3,
Object3D,
Sphere,
DynamicDrawUsage
} from 'three'
import {
MAX_INSTANCE,
BLOCK_SCALE
} from 'constants'
import Scene from 'scene'
import Camera from 'camera'
let temp1 = new Vector3()
import Shared from 'shared'
const AWAY = 1000000
export default class GeometryInstancer extends InstancedBufferGeometry {
constructor( geometry ) {
super()
geometry.computeBoundingSphere()
this.sphere = geometry.boundingSphere
this.sphere.center.x *= BLOCK_SCALE
this.sphere.center.y *= BLOCK_SCALE
this.sphere.center.z *= BLOCK_SCALE
this.sphere.radius *= BLOCK_SCALE
this.tempSphere = new Sphere()
this.INSTANCED = true
if ( geometry.index ){
this.setIndex( new BufferAttribute( geometry.index.array, 1 ) )
}
if( geometry.attributes.position ){
this.addAttribute( 'position', new BufferAttribute( geometry.attributes.position.array, 3))
}
if( geometry.attributes.uv ){
this.addAttribute( 'uv', new BufferAttribute( geometry.attributes.uv.array, 2))
}
let i = 0
let offsets = []
this.fixedOffset = []
while(i < MAX_INSTANCE) {
offsets.push(AWAY, AWAY, AWAY, AWAY )
this.fixedOffset.push([AWAY, AWAY, AWAY, 0])
i++
}
this.addAttribute( 'offset', new InstancedBufferAttribute( new Float32Array( offsets ), 4, false, 1 ) )
this.attributes.offset.setUsage(DynamicDrawUsage)
this.maxInstancedCount = 0
this._currentInstanceCount = -1
this._closestDistance = AWAY
geometry.dispose()
geometry = null
}
update(){
this.sort()
}
sort(){
// store
if ( this.offsetSorted == null ){
this.offsetSorted = []
let c = 0
while( c < MAX_INSTANCE ) {
this.offsetSorted[c] = {_distance : AWAY, _index: c, ACTIVE : false }
c++
}
}
let gg = 0
while( gg < this.offsetSorted.length ){
this.offsetSorted[gg] = {_distance : AWAY, _index: gg, ACTIVE : false }
gg++
}
// 1 object no need
let g = 0
let instanceCount = 0
while( g < this.offsetSorted.length ){
if(this.fixedOffset[g][0] != AWAY){
temp1.set(
this.fixedOffset[g][0],
this.fixedOffset[g][1],
this.fixedOffset[g][2]
)
this.offsetSorted[g]._index = g
this.offsetSorted[g]._distance = temp1.distanceTo(Camera.current.position)
this.tempSphere.copy(this.sphere)
this.tempSphere.center.add(temp1)
let contains = Camera.frustum.intersectsSphere(this.tempSphere)
if(contains == false){
this.offsetSorted[g]._distance = AWAY * 10
}
else{
this.offsetSorted[g].ACTIVE = true
instanceCount++
}
}
g++
}
this._closestDistance = AWAY
this.offsetSorted.sort((a, b) => {
if( a.ACTIVE && a._distance < this._closestDistance){
this._closestDistance = a._distance
}
if( b.ACTIVE && b._distance < this._closestDistance){
this._closestDistance = b._distance
}
if(b.ACTIVE == false){
return -1
}
if(a.ACTIVE == false){
return 1
}
if (a._distance > b._distance) {
return -1
}
if (a._distance < b._distance) {
return 1
}
return 0
})
let m = 0
let currentIndex = null
while( m < this.offsetSorted.length ){
currentIndex = this.offsetSorted[m]._index
this.attributes.offset.array[m * 4] = this.fixedOffset[currentIndex][0]
this.attributes.offset.array[m * 4 + 1] = this.fixedOffset[currentIndex][1]
this.attributes.offset.array[m * 4 + 2] = this.fixedOffset[currentIndex][2]
this.attributes.offset.array[m * 4 + 3] = this.fixedOffset[currentIndex][3]
m++
}
this.attributes.offset.needsUpdate = true
this.maxInstancedCount = instanceCount
}
addInstance(){
if(this.maxInstancedCount + 1 <= MAX_INSTANCE ){
this.maxInstancedCount += 1
this._currentInstanceCount += 1
}
else {
console.log('over max instance')
}
}
setRotation( index, rotation ){
if(this.INSTANCED){
this.fixedOffset[ index ][3] = rotation
this.sort()
}
else {
this.attributes.offset.array[index * 4 + 3 ] = rotation
this.attributes.offset.needsUpdate = true
}
}
setPosition( index , val ){
if(this.INSTANCED){
this.fixedOffset[ index ][0] = val[0]
this.fixedOffset[ index ][1] = val[1]
this.fixedOffset[ index ][2] = val[2]
this.sort()
}
else{
this.attributes.offset.array[index * 4 ] = val[0]
this.attributes.offset.array[index * 4 + 1 ] = val[1]
this.attributes.offset.array[index * 4 + 2 ] = val[2]
this.attributes.offset.needsUpdate = true
}
}
remove( index ){
this.fixedOffset[ index ][0] = AWAY
this.fixedOffset[ index ][1] = AWAY
this.fixedOffset[ index ][2] = AWAY
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment