Issue 1:
Description of the problem

JSFiddle here

I record the performance in Chrome when running this JSFiddle, it shows:

The memory peak value getting higher and higher, but the valley value always keeps a low value.

Then uncomment the two lines in line number 30 and 31:

width = 1000;
height = 1100;

The canvas size is not power of two, and the memory usage increases rapidly

the performance record shows:

The memory peak value and valley value both getting higher and higher.

I call the dispose method of material and texture explicitly, and remove the mesh from scene in every loop.

Three.js version

Dev

r85

...

Browser

All of them

Chrome

Firefox

Internet Explorer

OS

[] All of them

Windows

macOS

Linux

Android

iOS

Hardware Requirements (graphics card, VR Device, ...)

Issue 2:
Right now the only way to tell the RayCaster to include an object or not is with setting layers, and it is limited to checking any one of the RayCaster's layers is included in the objects layers.

Because this check exists outside the object in a separate function, in order to override this behavior, you need to needlessly override the RayCaster's intersectObject and intersectObjects functions, instead of just the outside intersectObject function.

Possible Solutions:

Move the outside intersectObject function into the RayCaster object so that only it needs to be extended. (Maybe also include a second function for just the if ( object.layers.test( raycaster.layers ) ) { part.)

Add some sort of specifiable test mode to the Layers object to allow for all, exact, and none alternative comparison modes to take advantage of the bit masking.

Allow passing in a custom test object/function into intersectObject and intersectObjects.

Example Current Override

It requires a lot of duplicate code to get the desired result.

import {
RayCaster as ThreeRayCaster
} from 'three'

function ascSort(a, b) {
return (a.distance - b.distance)
}

export default class extends ThreeRayCaster {
constructor (origin, direction, near, far) {
super(origin, direction, near, far)

this._testMode = 'all'
}

get testMode () { return this._testMode }
set testMode (value) { this._testMode = value }

_intersectObject (object, intersects, recursive) {
if (this._test(object)) {
object.raycast(this, intersects)
}

if (recursive === true) {
const children = object.children

for (let i = 0, l = children.length; i < l; ++i) {
this._intersectObject(children[i], intersects, true)
}
}
}

_test (object) {
switch (this.testMode) {
case 'any':
return object.layers.test(this.layers)
case 'none':
return !object.layers.test(this.layers)
case 'exact':
return (object.layers.mask === this.layers.mask)
case 'all':
default:
return ((object.layers.mask & this.layers.mask) === this.layers.mask)
}
}

intersectObject (object, recursive, optionalTarget) {
const intersects = optionalTarget || []

this._intersectObject(object, intersects, recursive)

intersects.sort(ascSort)

return intersects
},

intersectObjects (objects, recursive, optionalTarget) {
const intersects = optionalTarget || []

for (let i = 0, l = objects.length; i < l; i ++) {
this._intersectObject(objects[i], intersects, recursive)
}

intersects.sort(ascSort)

return intersects
}
}

Potential Override If More Extendable

import {
RayCaster as ThreeRayCaster
} from 'three'

export default class extends ThreeRayCaster {
constructor (origin, direction, near, far) {
super(origin, direction, near, far)

this._testMode = 'all'
}

get testMode () { return this._testMode }
set testMode (value) { this._testMode = value }

_test (object) {
switch (this.testMode) {
case 'any':
return object.layers.test(this.layers)
case 'none':
return !object.layers.test(this.layers)
case 'exact':
return (object.layers.mask === this.layers.mask)
case 'all':
default:
return ((object.layers.mask & this.layers.mask) === this.layers.mask)
}
}
}