Skip to content

Sampling Textures & Buffers

Adam Gorski edited this page Nov 12, 2021 · 7 revisions

Setting up the sampler

Before you can start sampling textures you will need to assign these values via your shaders SetValue() method. The shader will take care of casting it to a sampler1D/2D/Cube when you execute the shader:

Shader myShader = ...;

GLTexture myTexture = ...;
GLCubemap myCubemap = ...;
GLBuffer myBuffer = ...;

myShader.SetValue("cobbleTexture", myTexture);
myShader.SetValue("skybox", myCubemap);
myShader.SetValue("random_vectors", myBuffer);

Sampling Textures

To read from a texture you can use the texture() function. Obviously you will need a uniform for that:

out byte4 FragColor;
in vec2 uv_data;
uniform vec2 textureSize;
uniform sampler2D myTexture;

void main()
{
	FragColor = texture(myTexture, uv_data * textureSize);
}

WARNING: texture() reads the EXACT texture coordinates. It is NOT normalized to 0-1

This just means that a 800x600 texture will return the w:800 and h:600 pixel when doing texture(myTexture, vec2(799, 599);

WARNING: texture() outputs 32bpp ARGB integers in byte4 format.

This just means that calling texture without any templates will return a byte4 type

Sampling non-32bpp ARGB textures:

To read from textures that contain a stride of vec3, vec2 or float, you will need to use templates:

out byte4 FragColor;
in vec2 uv_data;
uniform vec2 textureSize;
uniform sampler2D myTexture;

void main()
{
	vec3 data = texture<vec3>(myTexture, uv_data * textureSize);
	FragColor = byte4(data.x, data.y, data.z);
}

This becomes quite useful when shadow mapping:

float shadow_coord = texture<float>(myTexture, uv_data * textureSize);
ShadowCheck(shadow_coord);

You can also just T result = *(T*)&data; if the type sizes are identical, but that is not very convenient.

Sampling cubemaps

Sampling a cubemap is done the same way you would do it in OpenGL:

out byte4 FragColor;
in vec3 norm_data;
in vec3 frag_pos;
uniform samplerCube skybox;
uniform vec3 camera_Pos;

void main()
{
	vec3 I = frag_pos - camera_Pos;
	vec3 R = reflect(I, norm_data);
	FragColor = texture(skybox, R);
}

Sampling 1 dimensional buffers

You can sample one dimensional buffers just by using texture again but with a sampler1D. Without any <T> template the return type will be a float. Note that the stride multiplication is done automatically.

[...]
uniform sampler1D ssao_kernel;
void main()
{
	for (int i = 0; i < kernel_size; i++){
		vec3 ssao_pos = texture<vec3>(ssao_kernel, i);
		//OR the slower method (3x more calls and bound checks)
		vec3 ssao_pos  = vec3(texture(ssao_kernel, i * 3 + 0), texture(ssao_kernel, i * 3 + 1), texture(ssao_kernel, i * 3 + 2));

		[...]
	}
}

Writing to buffers

You can write to a 2D texture too by using the textureWrite method:

[...]
uniform sampler2D targetTexture;

void main()
{
	textureWrite<float>(targetTexture, int2(x, y), 10.0f);
}

Extra textureNEAREST and textureBILINEAR methods.

You can use these methods to force the shader to use bilinear or nearest interpolation methods. The texture method uses these methods after it determines which sampling mode to use:

out byte4 FragColor;
in vec2 uv_data;
uniform vec2 textureSize;
uniform sampler2D myTexture;

void main()
{
	FragColor = textureNEAREST(myTexture, int2(10, 20));
	//OR
	FragColor = textureBILINEAR(myTexture, uv_data * textureSize);
}
Note that textureNEAREST forces you to use int2(x,y)
Clone this wiki locally