Debug Notes

Three.js #14635 (Material instance)

test case:

test/html/greate-cd.html

About the Three Module Issue

Attention

This issue should no longer exists because all imports from packages/three/three.module.js are now directly from three package - not verified.

Note

It’s worth to have a note after days of debugging.

EffectComposer and its depending passes are not included in the threejs bundle. This makes x-visual have to import these modules via both by npm three/examples/ or by copying directly the source files.

As x-visual is using Mocha for test, the former method leads to another problem, (see the packages/README,) which makes the latter method the only plausible way - as to his knowledge limitation.

But the using threejs module source presented another issue, classes supposed to be the same class are not as expected when checking with “instanceof”.

There is a good example showing this issue.

In lib/sys/ext/finalcomposer.js, the system create a ShaderPass with a THREE.ShaderMaterial will makes ShaderPass failed to check the the instance.

There are similar issue like this question.

The code snippet causing the issue in lib/sys/ext/finalComposer.js/FinalComposer:

import * as THREE from 'three'
import {ShaderPass} from  '../../../packages/three/postprocessing/ShaderPass'
import {EffectComposer} from  '../../../packages/three/postprocessing/EffectComposer'

class FinalComposer extends XSys {
    effects(x) {
        var effects = x.composer;
        effects.renderToScreen = false;
        this.effectPass = effects;

        this.finalCompose = new EffectComposer( x.renderer );

        var finalPass = new ShaderPass(
            // Should from packages/three.module.js, instead of THREE.ShaderMaterial
            new THREE.ShaderMaterial( {
                uniforms: {
                    texScene: { value: null },
                    texEffects: { value: effects.renderTarget2.texture },
                },
                vertexShader: finalVert,
                fragmentShader: finalFrag,
            } ),
            "texScene");
        finalPass.renderToScreen = true;
        this.finalCompose.addPass( finalPass );
    }
}

The final composer sharing texture from effects composer (effects) rendering target is essential to the result.

Here is where the problem comes from:

The packages/three/postprocessing/ShaderPass constructor check the shader arguments with “insanceof ShaderMaterial” which is actually another class from ../three.module.js, leading to an unexpected result.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import {
	ShaderMaterial,
	UniformsUtils
} from "../three.module-MRTSupport.js"

import { Pass } from "../postprocessing/Pass.js";

var ShaderPass = function ( shader, textureID ) {

	Pass.call( this );

	this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse";

	if ( shader instanceof ShaderMaterial ) {

		this.uniforms = shader.uniforms;

		this.material = shader;

	} else if ( shader ) {

		this.uniforms = UniformsUtils.clone( shader.uniforms );

		this.material = new ShaderMaterial( {

			defines: Object.assign( {}, shader.defines ),
			uniforms: this.uniforms,
			vertexShader: shader.vertexShader,
			fragmentShader: shader.fragmentShader

		} );

	}

	this.fsQuad = new Pass.FullScreenQuad( this.material );

Texture Referenced Across Shaders

Texture must been provided in uniforms to be bound to sampler2D in shader. Otherwise the texture can be bound to a wrong sampler.

The left results from bug that without setting image (loaded as texture) to material uniforms, making shader using wrong texture binding.

../_images/007-cross-shader-tex.jpg

Hacking Three.js

Glsl Shader Source

THREE.Revision 110

ShaderId in renderers/webgl/WebGLPrograms.js,

In renderers/shaders/ShaderLib.js,

ShaderChunk packs all source grogram, like

Src: meshbasic_vert & meshbasic_frag.

And WebGLRenderer, the three.js renderer, using WebGLPrograms.acquireProgram() to get shader program.

Shader instance for LineBasicMaterial: