Threejs自定义着色器 - 花屏(Threejs Custom Shader - Screen

2019-08-02 10:27发布

因此,要实现使用Threejs和布兰登卓尼的tilemap的方法(tilemap的发现这里 ),我使用的是THREE.Plane几何每一层,并涂抹面部与下面的自定义着色器:

顶点着色器:

var tilemapVS = [
    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform vec2 mapSize;",
    "uniform vec2 inverseTileTextureSize;",
    "uniform float inverseTileSize;",

    "void main(void) {",
    "    pixelCoord = (uv * mapSize);",
    "    texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;",
    "    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    "}"
].join("\n");

片段着色器:

var tilemapFS = [
    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform sampler2D tiles;",
    "uniform sampler2D sprites;",

    "uniform vec2 inverseTileTextureSize;",
    "uniform vec2 inverseSpriteTextureSize;",
    "uniform float tileSize;",
    "uniform int repeatTiles;",

    "void main(void) {",
    "    vec4 tile = texture2D(tiles, texCoord);", //load this pixel of the tilemap
    "    if(tile.x == 1.0 && tile.y == 1.0) { discard; }", //discard if R is 255 and G is 255
    "    vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;", //generate the offset in the tileset this pixel represents
    "    vec2 spriteCoord = mod(pixelCoord, tileSize);",
    "    vec4 texture = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);",
    "    gl_FragColor = texture;",
    "}"
].join("\n");

每个纹理设置,如:

//Setup Tilemap
this.tilemap.magFilter = THREE.NearestFilter;
this.tilemap.minFilter = THREE.NearestMipMapNearestFilter;
//tilemap.flipY = false;
if(this.repeat) {
    this.tilemap.wrapS = this.tilemap.wrapT = THREE.RepeatWrapping;
} else {
    this.tilemap.wrapS = this.tilemap.wrapT = THREE.ClampToEdgeWrapping;
}

//Setup Tileset
this.tileset.wrapS = this.tileset.wrapT = THREE.ClampToEdgeWrapping;
this.tileset.flipY = false;
if(this.filtered) {
    this.tileset.magFilter = THREE.LinearFilter;
    this.tileset.minFilter = THREE.LinearMipMapLinearFilter;
} else {
    this.tileset.magFilter = THREE.NearestFilter;
    this.tileset.minFilter = THREE.NearestMipMapNearestFilter;
}

和制服:

//setup shader uniforms
this._uniforms = {
    mapSize: { type: 'v2', value: new THREE.Vector2(this.tilemap.image.width * this.tileSize, this.tilemap.image.height * this.tileSize) },
    inverseSpriteTextureSize: { type: 'v2', value: new THREE.Vector2(1/this.tileset.image.width, 1/this.tileset.image.height) },
    tileSize: { type: 'f', value: this.tileSize },
    inverseTileSize: { type: 'f', value: 1/this.tileSize },

    tiles: { type: 't', value: this.tilemap },
    sprites: { type: 't', value: this.tileset },

    inverseTileTextureSize: { type: 'v2', value: new THREE.Vector2(1/this.tilemap.image.width, 1/this.tilemap.image.height) },
    repeatTiles: { type: 'i', value: this.repeat ? 1 : 0 }
};

而实际的几何形状和网格:

//create the shader material
this._material = new THREE.ShaderMaterial({
    uniforms: this._uniforms,
    vertexShader: tilemapVS,
    fragmentShader: tilemapFS,
    transparent: false
});

this._plane = new THREE.PlaneGeometry(
    this.tilemap.image.width * this.tileSize * this.tileScale,
    this.tilemap.image.height * this.tileSize * this.tileScale
);

this._mesh = new THREE.Mesh(this._plane, this._material);
this._mesh.z = this.zIndex;

this.tileSize16this.tileScale4 。 我遇到的问题是,围绕着16×16瓦的边缘,我得到一些撕裂:

奇怪的是,沿y轴移动时它不发生的时间,只有sparatically(但是在我的Linux机器的问题是糟糕得多和效果x轴为好)。

这几乎就像当我的顶点着色器放置在16×16瓦是关闭的量小; 但我不知道是什么原因造成的。 任何帮助表示赞赏,谢谢!

编辑

这里是撕裂的一个更好的形象,它是在草地地区更加明显:

正如你可以看到它是沿着16×16瓦的边缘(因为它们是由比例4 )。

Answer 1:

您使用的是mipmapped质地和你的纹理坐标是在瓷砖的边缘不连续的:

"    vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;", //generate the offset in the tileset this pixel represents
"    vec2 spriteCoord = mod(pixelCoord, tileSize);",
"    vec4 texture = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);",

地板和MOD功能意味着纹理坐标突然两个像素之间的跳跃(如你打算,以获得不同的瓦)。

然而,纹理查找使用像素之间的坐标的变化,以确定哪些纹理贴图级别使用,所以在瓷砖边缘它跳起来用更小的贴图,有一个间断,因为这是一个不同的纹理贴图比像素的其余部分。

这一轮的最快方法是不使用的贴图例如之一:

texture.minFilter = THREE.LinearFilter;
texture.minFilter = THREE.NearestFilter;

否则,如果你需要的贴图,您需要第三个参数偏差传递到的Texture2D。 设置此为0.0通常,然后当你在标题边缘将其设置为你想穿越回了来抵消这种影响的贴图数量的负数。

例如-11.0将带您从最低的单个像素纹理贴图11个的贴图到0的fullsized质地2048×2048处。 准确值需要根据变焦图像尺寸纹理大小等一些计算



Answer 2:

我怀疑,你得到这些问题是由于导致错误与精灵UV贴图相机位置。 基本上,你是显示从精灵的精灵表,你都应该被渲染邻近的精灵。

这条线,特别是:`VEC2 spriteOffset =地板(tile.xy * 256.0)* tileSize;”

看起来它可能会造成偏差的问题。 你可以通过做出来填补你的精灵具有色泽鲜艳,并查看是否弹出一个更好的检查。



文章来源: Threejs Custom Shader - Screen Tearing