三个js纹理边缘像素被拉伸

Three js texture edge pixels being stretched

我正在尝试在球体中显示纹理,其中球体充当遮罩。我的纹理已正确显示,但我无法理解如何删除被拉伸以填充球体的边缘像素。我希望它们是透明的。

这就是正在发生的事情

想法是图像以其默认方面显示,并且在鼠标悬停在球体上时会缩小以遮盖图像的一部分。球体稍后会被修改为其他东西,这只是为了测试,所以用二维形状做同样的事情不是一个选项。

这就是它的设置方式,没什么特别的,只是让您明白了。

    texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping
    texture.minFilter = THREE.LinearFilter

    // uniforms

    const uniforms = {
        texture: {value: texture},
        resolution: {type: 'vec2', value: new THREE.Vector2(window.innnerWidth, window.innerHeight)},
        offset: {type: 'vec2', value: new THREE.Vector2(offset.x, offset.y)},
        size: {type: 'vec2', value: new THREE.Vector2(width, height)},
        scroll: {value: 0}
    }

    // material

    const material = new THREE.ShaderMaterial({
        uniforms: uniforms,
        vertexShader: this.vertex,
        fragmentShader: this.fragment
    })

    const geometry = new THREE.SphereGeometry(5, 32, 32)
    this.mesh = new THREE.Mesh(geometry, material)

和我的片段着色器

    uniform sampler2D texture;
    uniform vec2 resolution;
    uniform vec2 offset;
    uniform vec2 size;

    void main() {

        vec2 uv = gl_FragCoord.xy / resolution * 2.0 - 1.0;
        uv = uv / 2.0 + 0.5;

        uv.x = (uv.x - offset.x) / size.x;
        uv.y = (uv.y - offset.y - scroll) / size.y + 1.0 ;

        gl_FragColor = texture2D(texture, uv);
    }

我知道 texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping 是默认行为,因此完全没用,我在文档中能找到的唯一其他替代方法是 RepeatWrappingMirroredRepeatWrapping,两者都不是我想。我也无法创建具有透明边缘的自定义纹理,因为图像将由客户端上传。

我该如何解决这个问题,我能否以某种方式检测我的着色器中的边界?

如果到视图中心的距离大于 1.0,则您必须遵守纵横比和 discard 片段。按纵横比缩放x分量,计算向量从中心到当前位置的length

vec2 p = gl_FragCoord.xy / resolution * 2.0 - 1.0;
p.x *= resolution.x / resolution.y;
if (length(p) > 1.0)
    discard;

请注意,discard 关键字可用于片段着色器中以放弃对当前片段的操作。此关键字导致片段被丢弃,并且不会更新任何缓冲区。


请注意,甚至可以在像素坐标中定义一个点和一个半径,并显示该点周围的圆形区域。
例如您可以通过当前鼠标位置更新中心点。 由于是在像素坐标系中计算的,所以不需要按纵横比缩放距离的x分量:

uniform vec2  center; // center of the circle in pixel coordinates
uniform float radius; // radius in pixel

void main()
{
   vec2 v = gl_FragCoord.xy - center.xy;
   if (length(v) > radius)
       discard;

   // [...]
}