Force a sprite object to always be in front of sky

2019-07-29 23:00发布

I currently have a custom shader draw a gradient on a skydome and would like to have a sun/moon in front of the skydome (from users perspective). The easiest way to do this is to have sprites for the sun and moon but the problem that arises is that the sprites get lodged within the skydome (sprite is partway in front and partway in back of the skydome). I have attempted to solve this with polygonoffset, but that doesn't seem to work on sprite objects.

So my question is, how can I setup a sun/moon on top of skydome without having to modify my custom skydome shader to add sun/moon texture with the gradient (which could end up being very difficult)?

Below is the code for my sky shader for the skydome.

new THREE.ShaderMaterial({
    uniforms: {
        glow: {
            type: "t",
            value: THREE.ImageUtils.loadTexture(DEFAULT_PATH+"glow2.png")
        },
        color: {
            type: "t",
            value: THREE.ImageUtils.loadTexture(DEFAULT_PATH+"sky2.png")
        },
        lightDir: {
            type: "v3",
            value: self.lightPos
        }
    },
    vertexShader: [
        "varying vec3 vWorldPosition;",
        "varying vec3 vPosition;",
        "void main() {",
            "vec4 worldPosition = modelMatrix * vec4(position, 1.0);",
            "vWorldPosition = worldPosition.xyz;",
            "vPosition = position;",
            "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
        "}"
    ].join("\n"),
    fragmentShader: [
        "uniform sampler2D glow;",
        "uniform sampler2D color;",
        "uniform vec3 lightDir;",
        "varying vec3 vWorldPosition;",
        "varying vec3 vPosition;",
        "void main() {",
            "vec3 V = normalize(vWorldPosition.xzy);",
            "vec3 L = normalize(lightDir.xzy);",
            "float vl = dot(V, L);",
            "vec4 Kc = texture2D(color, vec2((L.y + 1.0) / 2.0, V.y));",
            "vec4 Kg = texture2D(glow,  vec2((L.y + 1.0) / 2.0, vl));",
            "gl_FragColor = vec4(Kc.rgb + Kg.rgb * Kg.a / 2.0, Kc.a);",
        "}",
    ].join("\n")
});

1条回答
Evening l夕情丶
2楼-- · 2019-07-29 23:24

Make sure your skydome is drawn before any other object and disable the depthWrite / depthTest flags on the material (depthWrite being the important thing here):

yourmaterial = new THREE.ShaderMaterial({...});
yourmaterial.depthWrite = false;
yourmaterial.depthTest = false;
skydome.renderDepth = 1e20;

where skydome is the mesh on which you have applied yourmaterial.

查看更多
登录 后发表回答