Monday, November 5, 2018

xna - Something other than Vertex Welding with Texture Atlas?


What options (in C# with XNA) would there be for texture usage in a procedural generated 3D world made of cubes to increase performance? Yes, it's like Minecraft.


I've been doing a texture atlas and rendering faces individually (4 vertices per face), but I've also read in a couple places about using texture wrapping with two 1D atlases to merge adjacent faces with the same texture.


If two or more adjacent faces share the same image, it'd be quite easy to wrap in this way reducing vertices by a large amount. My problem with this is having too many textures, swapping too often, and many image related things like non-power of 2 images.


Is there a middle ground option between the 1D texture atlas trick and rendering 4 vertices per cube face?



This is a picture of what I have currently (in wireframe). 4 vertices per face seems extremely inefficient to me.


Current 4 vertices per face in wireframe



Answer



So I've really exceeded my time budget for this question, with my mega-answer. But here's an idea, which you can hopefully evaluate using the code I've provided in my other answer:


Basically, you have two texture coordinates per quad: One that is the same for all vertices of a given quad, to select the tile within the texture atlas. The second has coordinates that interpolate as normal for a fully-wrappable (not atlased) texture (so from 0..1 for a single tile, but extending beyond that for wrapping). You then combine those in a pixel shader to perform the wrapping.


This lets you do completely arbitrary wrapping - allowing 2D texture atlases and 2D merging of faces! Far better than the 1D atlas and 1D merging we were discussing before.


Here's a pixel-shader I threw together to do exactly that:


sampler TextureSampler : register(s0);

// Select the tile within a texture by its coordinates

// For a real implementation, you'd probably pass this in TEXCOORD1
float2 textureBase = float2(0, 0);

// The size, in texture coordinates, of a tile
float2 tileSize = float2(1.0 / 16.0, 1.0 / 16.0);

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
// Adjust the texture coordinate to map into a specific tile:
texCoord = frac(texCoord) * tileSize + textureBase;


return tex2D(TextureSampler, texCoord) * color;
}

technique TileMapRepeater
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}

}

It's tested working, although it gives seams if you don't use point-sampling. You might be able to get it to work with linear-sampling, but that's more effort and a lot more computationally expensive.


So the question would be: are extra pixel shader calculations and added vertex data worth the significant reduction in quads rendered? I'll leave it to you to figure that out :)


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...