Three.js ThreeJS FBO粒子照明和阴影

Three.js ThreeJS FBO粒子照明和阴影,three.js,glsl,lighting,particle-system,fbo,Three.js,Glsl,Lighting,Particle System,Fbo,更新:我决定根据ScieCode的建议,从这个链接实施一个简单的照明解决方案。这是链接页面的第一部分。结果可以在本文底部的图片中看到。 链接页面也包含关于如何在ThreeJS中使用自定义着色器材质投射阴影的信息,但我觉得它更适合网格和基本粒子系统。我正在使用FBO粒子系统。 我有一个使用FBO的粒子系统。它是使用ThreeJS中的着色器材质构建的。这些粒子变成了高耸的积云。如何将照明和阴影应用于这些粒子,就像它们是一个实体网格一样 下面是将粒子渲染到屏幕的最后一组着色器: 老实说,我甚至不完全理

更新:我决定根据ScieCode的建议,从这个链接实施一个简单的照明解决方案。这是链接页面的第一部分。结果可以在本文底部的图片中看到。

链接页面也包含关于如何在ThreeJS中使用自定义着色器材质投射阴影的信息,但我觉得它更适合网格和基本粒子系统。我正在使用FBO粒子系统。

我有一个使用FBO的粒子系统。它是使用ThreeJS中的着色器材质构建的。这些粒子变成了高耸的积云。如何将照明和阴影应用于这些粒子,就像它们是一个实体网格一样

下面是将粒子渲染到屏幕的最后一组着色器:

老实说,我甚至不完全理解顶点着色器是如何输出位置的。我找到了这个示例代码,并将其用于我正在做的工作。我了解它的大部分,但顶点着色器的尾部对我来说是模糊的

顶点:

precision highp float;

attribute vec2 id;
attribute vec3 p_color;
attribute float p_size;

uniform vec2 dimensions;
uniform float size;

uniform sampler2D infoTexture;
uniform sampler2D originalTexture;
uniform sampler2D positionTexture;
uniform sampler2D previousPositionTexture;
uniform sampler2D velocityTexture;

varying vec2 vUv;
varying float life;
varying vec2 vSpeed;
varying float vSize;

float modI(float a,float b) {
    float m=a-floor((a+0.5)/b)*b;
    return floor(m+0.5);
}

const float PI = 3.14159265359;

void main() {

    float size_modifier = 1. * p_size;

    float ptr = id.x;
    float u = modI( ptr, dimensions.x ) / dimensions.x;
    float v = ( ptr / dimensions.x ) / dimensions.y;
    vec2 puv = vec2( u, v );

    vec4 velocity = texture2D( velocityTexture, puv );
    // vSpeed = .1 * ( projectionMatrix * modelViewMatrix * vec4( velocity.xyz, 1. ) ).xy;

    vec4 i = texture2D( infoTexture, puv );

    vec4 prev_pos = texture2D( previousPositionTexture, puv );
    vec4 origin_pos = texture2D( originalTexture, puv );

    vec4 c = texture2D( positionTexture, puv );
    vec3 p = c.xyz;
    vUv = uv;
    float life_time = 1000.;
    life = 1. - ( c.a / life_time );
    // if( c.a == 0. ) life = 0.;

    if( velocity.a != 1. ){

        size_modifier = .0;

    }

    vec4 modified = modelViewMatrix * vec4( p, 1. );
    // float a = -atan( vSpeed.y, vSpeed.x ) - .5 * PI;
    // float l = clamp( length( vSpeed ), .5, 4. );
    // mat2 rot = mat2( cos( a ), -sin( a ), sin( a ), cos( a ) );

    // modified.xyz += size * i.x * 10. * vec3( rot * position.xy, 0. );
    // modified.xyz += size * size_modifier * i.x * 10. * vec3( rot * position.xy, 0. );
    modified.xyz += size * size_modifier * i.x * 10. * vec3( position.xy, 0. );
    gl_Position = projectionMatrix * modified;

}
片段:

precision highp float;

varying float vSize;
varying vec2 vUv;
varying float life;
varying vec2 vSpeed;
varying vec3 p_color_f;

uniform float useTriangles;

const vec2 barycenter = vec2( .5, .6666 );

void main() {

    // render circles
    float d = smoothstep( .5, .55, 1. - 2. * length( vUv - barycenter ) );
    if( d <= 0. ) discard;

    vec3 frag_c = vec3( p_color_f );

    gl_FragColor = vec4( frag_c, 1.);

}
基本照明效果:


即使这样,风暴也增加了很多深度。

我们不太清楚你希望阴影或灯光表现如何。如果你能说得更清楚,我很乐意编辑这个回复,以最好地回答你的问题

话虽如此,在您的案例中,有两种资源是可行的:

  • Edan Kwan关于自定义着色器/粒子的阴影。它有点过时了,但大部分仍然有效,应该能让你对你试图解决的问题有一个合理的理解
  • 由于一些GLSL ShaderChunk在制作Edan的帖子后发生了变化,我建议你看看我制作的这个,当时我正在尝试一些听起来与你要求的类似的东西

为了模拟正确的照明,需要导入
light\u pars
ShaderChunks及其所有依赖项。使用该选项,可以访问每个粒子顶点位置上的灯光强度。你可以用你认为合适的任何方式使用这些信息。

我已经看到你的回答是一个很大的帮助!我将研究这些链接,我理解你关于着色器块的意思。至于行为,我只想让粒子系统像网格一样被照亮,所以如果有一列粒子,就会有黑暗面和光明面。我添加了上一组着色器,它们实际上将粒子放置到屏幕上。当我将着色器块添加到这些着色器时,它们停止工作,这并不奇怪。没有错误,但粒子不再渲染到屏幕上。如果您正确地包含ShaderChunk,它们应该中断代码并显示错误,或者正常工作。为了知道如何正确使用着色器,您需要在源代码中分析它们,没有关于它们的文档。我能说什么?控制台中没有错误代码或警告,我的粒子不会渲染到屏幕上。在将“标准”着色器块注入使用FBO渲染粒子的着色器后,我认为他们不会这样做。更新了我的帖子,以反映我是如何将块添加到着色器中的..嗯,用于照明。。您可以自行计算照明,只需将一个均匀的灯光位置绑定到粒子着色器,为每个粒子定义一个法向量,然后计算点积以获得有多少灯光接触到该粒子“曲面”。如果光线随时间移动,请记住在每一帧更新此一致性。这些是
UniformLibs
,而不是
ShaderChunks
,它们表示绑定到着色器的额外一致性,它们包含
ShaderChunks
使用的信息。块是在GLSL着色器本身内部导入的代码片段,以便于实现常见内容。您可以在着色器中使用
#include
导入这些内容。好吧,我忘记了,但对于我的例子(FBO粒子),我将只使用简单的照明,如图中所示。我会让它工作的。如果我使用的是Mesh,我肯定会选择你在最初的回复中建议的路线,我会清理所有这些,并将你的回复标记为答案,因为它实际上就是我所问问题的答案。有什么方法可以让我私下和你谈谈进一步的发展吗?@sciecode可能是最简单的方法。请随便打电话给我。
particleMaterial = new THREE.ShaderMaterial( {
    uniforms: THREE.UniformsUtils.merge([
        THREE.UniformsLib.shadowmap,
        THREE.UniformsLib.lights,
        THREE.UniformsLib.ambient,
        {
            size: { type: 'f', value: 1 },
            useTriangles: { type: 'f', value: 0 },
            originalTexture: { type: 't', value: texture },
            infoTexture: { type: 't', value: texture2 },
            positionTexture: { type: 't', value: positionSim.fbos[ 0 ] },
            previousPositionTexture: { type: 't', value: positionSim.fbos[ 1 ] },
            velocityTexture: { type: 't', value: velocitySim.fbos[ 1 ] },
            dimensions: { type: 'v2', value: dimensions },
            cameraPosition: { type: 'v3', value: new THREE.Vector3() },
            prevModelViewMatrix: { type: 'm4', value: new THREE.Matrix4() },
            prevProjectionMatrix: { type: 'm4', value: new THREE.Matrix4() }
        } ]),
    vertexShader: document.getElementById( 'particle-vs' ).textContent,
    fragmentShader: document.getElementById( 'particle-fs' ).textContent,
    transparent: false,
    side: THREE.DoubleSide,
    depthTest: true,
    depthWrite: true,
    lights: true
    // blending: THREE.NoBlending
} );