user4124520
user4124520

Reputation:

THREE.JS, dynamically shader couldn't compile

I'm trying to use particles for showing the falling snow in 3D scene. I don't want to create shaders in HTML page, because my project doesn't allow to add specific scripts and many additional scripts are loading dynamically, not including in HTML page as <script src=''>.

I'm getting the next errors ( short: http://pastebin.com/KqiZze49, full: http://pastebin.com/LZHhCnuh):

THREE.WebGLShader: Shader couldn't compile. three.min.js:592(anonymous function) 
three.min.js:592(anonymous function) three.min.js:588initMaterial three.min.js:566z
three.min.js:488renderBuffer three.min.js:544v three.min.js:483render 
three.min.js:556Rekod3DBuildings.Engine.renderScene rekod3d-new.js:668
(anonymous function) new-index.html:71
THREE.WebGLShader: gl.getShaderInfoLog() ERROR: 0:68: 'gl_FragColor' : undeclared identifier
ERROR: 0:68: 'assign' :  cannot convert from '4-component vector of float' to 'float'
ERROR: 0:68: 'gl_PointCoord' : undeclared identifier
ERROR: 0:68: 'texture2D' : no matching overloaded function found

You can tell me "Man, look at console, you've got all errors in console, just google." But, the strange thing is that, if to use the same shaders, which are generating dynamically in JavaScript, but use as prepared part in HTML page, there're no errors, and the result is:

enter image description here

And as you can in screenshot above, if shaders are included in HTML page, there is no error. Of course, logically you want to tell, that it's obviously I'm creating shaders not correctly in JavaScript, but there are also some strange things, let's look:

1). How am I generating shaders in JavaScript?

http://pastebin.com/HncUKMUL

Rekod3DBuildings.Engine.prototype.createVertexShaderForSnowParticles = function( scriptId ) {
    if ( typeof scriptId === 'string' ) {
        var script = document.createElement( 'script' );
        script.id = scriptId;
        script.type = 'x-shader/x-vertex';
        script.textContent = '\
                attribute float size;\
                attribute float time;\
                attribute vec3 customColor;\
                uniform float globalTime;\
                varying vec3 vColor;\
                varying float fAlpha;\
                \
                void main() {\
                    vColor = customColor;\
                    vec3 pos = position;\
                    float localTime = time + globalTime;\
                    float modTime = mod( localTime, 1.0 );\
                    float accTime = modTime * modTime;\
                    pos.x += cos( modTime * 8.0 + ( position.z ) ) * 70.0;\
                    pos.z += sin( modTime * 6.0 + ( position.x ) ) * 100.0;\
                    fAlpha = ( pos.z ) / 1800.0;\
                    vec3 animated = vec3( pos.x, pos.y * accTime, pos.z );\
                    vec4 mvPosition = modelViewMatrix * vec4( animated, 1.0 );\
                    gl_PointSize = min( 150.0, size * ( 150.0 / length( mvPosition.xyz ) ) );\
                    gl_Position = projectionMatrix * mvPosition;\
                }';
        document.head.appendChild( script );        
        return script;
    }
    else
        console.error( 'Script id for the vertex shader isn\'t a type of `string`.' );
};
Rekod3DBuildings.Engine.prototype.createFragmentShaderForSnowParticles = function( scriptId ) {
    if ( typeof scriptId === 'string' ) {
        var script = document.createElement( 'script' );
        script.id = scriptId;
        script.type = 'x-shader/x-fragment';
        script.textContent = '\
                uniform vec3 color;\
                uniform sampler2D texture;\
                varying vec3 vColor;\
                varying float fAlpha;\
                \
                void main() {\
                    gl_FragColor = vec4( color * vColor, fAlpha );\
                    gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );\
                }';
        document.head.appendChild( script );        
        return script;
    }
    else
        console.error( 'Script id for the fragment shader isn\'t a type of `string`.' );
};

2). After creating them, let's check are they added?

Look at the screenshot, the shaders are successfully added:

enter image description here

Source-code, which is preparing particles ( http://pastebin.com/HgLHJWFu ):

Rekod3DBuildings.Engine.prototype.setSnowParticles = function() {
    var map = THREE.ImageUtils.loadTexture( 'images/textures/snowflake.png' );

    var attributes = {
        size:        { type: 'f', value: [] },
        customColor: { type: 'c', value: [] },
        time:        { type: 'f', value: [] },
    };

    this.snowUniforms = {
        color:      { type: "c", value: new THREE.Color( 0x777777 ) },
        texture:    { type: "t", value: 0, texture: map },
        globalTime: { type: "f", value: 0.0 },
    };

    var shaderMaterial = new THREE.ShaderMaterial( {
        uniforms:       this.snowUniforms,
        attributes:     attributes,
        vertexShader:   document.getElementById( 'fragmentshader-airplane' ).textContent,
        fragmentShader: document.getElementById( 'vertexshader-airplane' ).textContent,
        blending:       THREE.AdditiveBlending,
        depthTest:      false,
        transparent:    true,
    });

    var geometry = new THREE.Geometry();

    for ( var i = 0; i < 10000; i++ )
        geometry.vertices.push( new THREE.Vector3( Math.random() * 18000 - 1500, -5000, Math.random() * 18000 ) );

    var particles = new THREE.PointCloud( geometry, shaderMaterial );
    particles.position.x = -5000; 
    particles.position.y = 5000;
    particles.position.z = -5000;

    var vertices = particles.geometry.vertices;
    var values_size = attributes.size.value;
    var values_color = attributes.customColor.value;
    var values_time = attributes.time.value;

    for( var v = 0; v < vertices.length; v++ ) {
        values_size[ v ] = 50 + Math.random() * 80;
        values_color[ v ] = new THREE.Color( 0xffffff );
        values_time[ v ] = Math.random();
    }

    this.scene.add( particles );
};

So, what's wrong?

Please, help me with a piece of advice.

Upvotes: 1

Views: 4666

Answers (2)

Paul-Jan
Paul-Jan

Reputation: 17278

Reading the code fragment in your screenshot, you are loading the fragment shader text into the vertex shader and vice versa, hence the error about gl_FragColor from the shader compiler. I'm pretty sure reversing those will help a great deal. :-)

Upvotes: 2

vals
vals

Reputation: 64254

Do you really need to go thru the DOM ?

I can dynamically create shaders this way

THREE.SlicedBoxGeometry.prototype.GetVertexShader = function()  {
    var r = "";

    r+= "uniform vec4 uClipPlane1;              \n";
    r+= "uniform vec4 uClipPlane2;              \n";
    r+= "uniform vec4 uClipPlane3;              \n";
    r+= "varying vec3 vPos;                     \n";


    r+= "void main()                                                \n";
    r+= "{                                                  \n";
    r+= "   vec3 newPosition = position;                            \n";

    r+= "   if (position.x == " + this.width_half.toFixed(2) + " ) {            \n";
    r+= "       newPosition.x = - uClipPlane1.w / uClipPlane1.x;        \n";
    r+= "   }                                                   \n";
    r+= "   if (position.y == " + this.height_half.toFixed(2) + ") {            \n";
    r+= "       newPosition.y = - uClipPlane2.w / uClipPlane2.y;        \n";
    r+= "   }                                                   \n";
    r+= "   if (position.z == " + this.depth_half.toFixed(2) + ") {         \n";
    r+= "       newPosition.z = - uClipPlane3.w / uClipPlane3.z;        \n";
    r+= "   }                                                   \n";
    r+= "   gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );\n";
    r+= "   vPos = newPosition; \n";
    r+= "}\n";

    return r;
}

May be not the better way to do it, but it works ...

The only reason to put a shader in the DOM is directly as in

<script type="something-not-javascript" id="someId">
shader code goes here
</script>

You can then retrieve it with

var shaderSource = document.getElementById("someId").text

You put it in the DOM because then you can edit it without having to surround each line with quotes etc...

Otherwise though if you're going to put it in JavaScript then either the format above or something like this also works

THREE.SlicedBoxGeometry.prototype.GetVertexShader = function()  {
  return [  
    "uniform vec4 uClipPlane1;              ",
    "uniform vec4 uClipPlane2;              ",
    "uniform vec4 uClipPlane3;              ",
    "varying vec3 vPos;                     ",
    "",
    "",
    "void main()                                                ",
    "{                                                  ",
    "   vec3 newPosition = position;                            ",

    "   if (position.x == " + this.width_half.toFixed(2) + " ) {            ",
    "       newPosition.x = - uClipPlane1.w / uClipPlane1.x;        ",
    "   }                                                   ",
    "   if (position.y == " + this.height_half.toFixed(2) + ") {            ",
    "       newPosition.y = - uClipPlane2.w / uClipPlane2.y;        ",
    "   }                                                   ",
    "   if (position.z == " + this.depth_half.toFixed(2) + ") {         ",
    "       newPosition.z = - uClipPlane3.w / uClipPlane3.z;        ",
    "   }                                                   ",
    "   gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );",
    "   vPos = newPosition; ",
    "}",
  ].join("¥n");
};

Upvotes: 0

Related Questions