user1214513
user1214513

Reputation: 273

Problems loading shaders from external file in ThreeJS

This has been asked before (2 years ago) and in several places both in ThreeJS github and SO. But still many (including me) are having problems with this. This is what I got now (which is part of a larger system):

function dataLoader()
{
    this.data_count = 0;
    this.data_array = new Array();
}

function loadFile( file, loader ){
    var FileObject = new Object();
    FileObject.data  = "";
    FileObject.ready = false;
    FileObject.id    = loader.data_count;
    loader.data_array[loader.data_count] = false;
    $.ajax({
        type: "GET",
        url: file,
        dataType: "text"
    }).done( function( msg ) {
        FileObject.data = msg;
        FileObject.ready = true;
        loader.data_array[FileObject.id] = true;
    });
    loader.data_count += 1;
    return FileObject;
}

And then I do this:

var loader = new dataLoader();
var SkyVertexShader = loadFile( "Shaders/sky.frag", loader );
var SkyFragmentShader = loadFile( "Shaders/sky.vertex", loader );

And then I create material like this:

var skyMat = new THREE.ShaderMaterial( { vertexShader: SkyVertexShader.data, fragmentShader: SkyFragmentShader.data, uniforms: uniforms, side: THREE.BackSide } );

Shaders in sky.frag and sky.vertex are plain text without any tags or anything. When I debug I can see that SkyFragmentShader.data and SkyVertexShader.data are both correctly set. Shaders are the ones from webgl_lights_hemisphere example. But when I load I get this error:

ERROR: 0:37: 'modelMatrix' : undeclared identifier
ERROR: 0:37: 'position' : undeclared identifier 
ERROR: 0:37: 'constructor' : not enough data provided for construction 
ERROR: 0:38: 'assign' : l-value required "vWorldPosition" (can't modify a varying) ERROR: 0:40: 'gl_Position' : undeclared identifier 
ERROR: 0:40: 'projectionMatrix' : undeclared identifier 
ERROR: 0:40: 'modelViewMatrix' : undeclared identifier 
ERROR: 0:40: 'constructor' : not enough data provided for construction 
ERROR: 0:40: 'assign' : cannot convert from '4-component vector of float' to 'float' �

But it works when I just do this (so like in the examples):

var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
var vertexShader = document.getElementById( 'vertexShader' ).textContent;
var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } );

This last part of course works only when having the shaders in HTML. So even though the content is virtually identical between the .textContent method and the Ajax GET method (just some tabs and newlines) it shows syntax errors about undefined variables. So what could cause this?

Upvotes: 3

Views: 3953

Answers (3)

Felix Turner
Felix Turner

Reputation: 1463

This is a nice lightweight external shader loader: https://github.com/codecruzer/webgl-shader-loader-js

Upvotes: 2

user1214513
user1214513

Reputation: 273

Ok I figured it out. I was loading them in reverse order which made vertex shader the first one and fragment the second one. That made the ThreeJS added code in the wrong position and that trew errors. It sadly made me debug for so long because the errors seemed generic, but its possible to get the full generated shader text via Firebug which helped a lot. But thanks gaitat, it did make me look closer at loading.

Upvotes: 2

gaitat
gaitat

Reputation: 12632

If you are referring to this post https://github.com/mrdoob/three.js/issues/283 (which is two years old) you are not exactly following their solution. Have you tried setting "async: false," to your ajax request in order to have a synchronous request because you might be trying to execute the shaders before they have actually loaded.

Upvotes: 0

Related Questions