三。动态着色器无法编译。

时间:2022-06-16 03:47:22

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=''>.

我试着用粒子来显示3D场景中的雪花。我不想在HTML页面中创建着色器,因为我的项目不允许添加特定的脚本,很多附加的脚本都是动态加载的,不包括在HTML页面中作为

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

我得到了下一个错误(短:http://pastebin.com/KqiZze49,全文: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:

你可以告诉我,“伙计,看看控制台,你在控制台上都有错误,只是谷歌。”但奇怪的是,如果使用相同的着色器,它们在JavaScript中动态生成,但在HTML页面中作为准备部分使用,就不会出现错误,结果是:

三。动态着色器无法编译。

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:

正如您可以在上面的屏幕截图中看到的,如果在HTML页面中包含着色器,则没有错误。当然,逻辑上你想说的是,显然我在JavaScript中创建的着色器不正确,但也有一些奇怪的东西,让我们看看:

1). How am I generating shaders in JavaScript?

1)如何在JavaScript中生成着色器?

http://pastebin.com/HncUKMUL

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?

2)创建后,我们检查是否添加了?

Look at the screenshot, the shaders are successfully added:

看屏幕截图,成功添加了阴影:

三。动态着色器无法编译。

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

源代码,它正在准备粒子(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.

请帮我提个建议。

2 个解决方案

#1


2  

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. :-)

读取屏幕截图中的代码片段,将碎片着色文本加载到顶点着色器中,反之亦然,因此会出现来自着色器编译器的gl_FragColor错误。我很肯定扭转这些会有很大的帮助。:-)

#2


0  

Do you really need to go thru the DOM ?

你真的需要通过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

在DOM中放置着色器的唯一原因是直接在

<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...

你把它放到DOM中,因为这样你就可以编辑它而不需要用引号把每一行括起来……

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

否则,如果你要把它放到JavaScript上面的格式或者类似的东西也可以

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");
};

#1


2  

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. :-)

读取屏幕截图中的代码片段,将碎片着色文本加载到顶点着色器中,反之亦然,因此会出现来自着色器编译器的gl_FragColor错误。我很肯定扭转这些会有很大的帮助。:-)

#2


0  

Do you really need to go thru the DOM ?

你真的需要通过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

在DOM中放置着色器的唯一原因是直接在

<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...

你把它放到DOM中,因为这样你就可以编辑它而不需要用引号把每一行括起来……

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

否则,如果你要把它放到JavaScript上面的格式或者类似的东西也可以

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");
};