<h5 dir="auto">Description of the problem</h5>
<p dir="auto"><a href="https://jsfiddle.net/liyuanqiu/wkdgt8h7/5/" rel="nofollow">JSFiddle here</a></p>
<p dir="auto">I record the performance in Chrome when running this JSFiddle, it shows:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://cloud.githubusercontent.com/assets/24999464/26337944/05272af4-3faf-11e7-8e3f-362e38a151f1.png"><img src="https://cloud.githubusercontent.com/assets/24999464/26337944/05272af4-3faf-11e7-8e3f-362e38a151f1.png" alt="1024x1024" style="max-width: 100%;"></a><br>
The memory peak value getting higher and higher, but the valley value always keeps a low value.</p>
<p dir="auto">Then uncomment the two lines in line number 30 and 31:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="width = 1000;
height = 1100;"><pre class="notranslate"><code class="notranslate">width = 1000;
height = 1100;
</code></pre></div>
<p dir="auto">The canvas size is not power of two, and the memory usage increases rapidly</p>
<p dir="auto">the performance record shows:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://cloud.githubusercontent.com/assets/24999464/26337947/0bbb0e3a-3faf-11e7-9da3-ab832b9eaeb1.png"><img src="https://cloud.githubusercontent.com/assets/24999464/26337947/0bbb0e3a-3faf-11e7-9da3-ab832b9eaeb1.png" alt="1000x1100" style="max-width: 100%;"></a><br>
The memory peak value and valley value both getting higher and higher.</p>
<p dir="auto">I call the dispose method of material and texture explicitly, and remove the mesh from scene in every loop.</p>
<h5 dir="auto">Three.js version</h5>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Dev</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> r85</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> ...</li>
</ul>
<h5 dir="auto">Browser</h5>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Chrome</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Firefox</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Internet Explorer</li>
</ul>
<h5 dir="auto">OS</h5>
<ul class="contains-task-list">
<li>[] All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Windows</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> macOS</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Linux</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Android</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> iOS</li>
</ul>
<h5 dir="auto">Hardware Requirements (graphics card, VR Device, ...)</h5>
<p dir="auto">Right now the only way to tell the <em>RayCaster</em> to include an object or not is with setting layers, and it is limited to checking any one of the <em>RayCaster</em>'s layers is included in the objects layers.</p>
<p dir="auto">Because this check exists outside the object in a separate function, in order to override this behavior, you need to needlessly override the <em>RayCaster</em>'s <em>intersectObject</em> and <em>intersectObjects</em> functions, instead of just the outside <em>intersectObject</em> function.</p>
<p dir="auto"><strong>Possible Solutions:</strong></p>
<ol dir="auto">
<li>Move the outside <em>intersectObject</em> function into the <em>RayCaster</em> object so that only it needs to be extended. (Maybe also include a second function for just the <code class="notranslate">if ( object.layers.test( raycaster.layers ) ) {</code> part.)</li>
<li>Add some sort of specifiable test mode to the Layers object to allow for <em>all</em>, <em>exact</em>, and <em>none</em> alternative comparison modes to take advantage of the bit masking.</li>
<li>Allow passing in a custom test object/function into <em>intersectObject</em> and <em>intersectObjects</em>.</li>
</ol>
<p dir="auto"><strong>Example Current Override</strong><br>
It requires a lot of duplicate code to get the desired result.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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 &lt; 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 &amp; 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 &lt; l; i ++) {
            this._intersectObject(objects[i], intersects, recursive)
        }

        intersects.sort(ascSort)

        return intersects
    }
}"><pre class="notranslate"><code class="notranslate">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 &lt; 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 &amp; 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 &lt; l; i ++) {
            this._intersectObject(objects[i], intersects, recursive)
        }

        intersects.sort(ascSort)

        return intersects
    }
}
</code></pre></div>
<p dir="auto"><strong>Potential Override If More Extendable</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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 &amp; this.layers.mask) === this.layers.mask)
        }
    }
}"><pre class="notranslate"><code class="notranslate">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 &amp; this.layers.mask) === this.layers.mask)
        }
    }
}
</code></pre></div>