I have an image2DArray in my compute shaders with 7 slices.
I can write in it with the function imageStore without problem and also display these textures.
My problem comes with the initialization, I try to initialize my textures but I can't. Indeed, I make a loop for the initialization :
for(int i=0; i<N; i++){
imageStore( outputTexture , ivec3(texel, i), vec4(0));
}
When N = 7, nothing is displayed but when N < 7 everything works well and my textures initialized.
Is someone can explain me why I can't initialize correctly my image2DArray ?
Edit :
What I test to see that : try to write in all slices of the texture and display it. It works fine but data from the previous frame stay if I don't initialize the texture. So, I initialize all pixels of the slices to 0 but nothing display anymore if N=7.
Some code :
#version 430 compatibility
layout(rgba8) coherent uniform image2DArray outputTexture;
...
void main(){
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 outSize = imageSize( outputTexture ).xy;
if( texel.x >= outSize.x || texel.y >= outSize.y )
return;
initializeMeshSet( meshSet );
vec4 pWorld = texelFetch(gBuffer[0],texel,0);
pWorld /= pWorld.w;
vec4 nWorld = texelFetch(gBuffer[1],texel,0);
nWorld /= nWorld.w;
if( length(nWorld.xyz) < 0.1 ){
for(int i=0; i<4; i++){
imageStore( outputTexture , ivec3(texel, i), vec4(0));
}
return;
}
if(nbFrame == 0){
float value = treatment(texel, pWorld, nWorld.xyz, outSize.x);
imageStore( outputTexture, ivec3(texel, 0), vec4(vec3(value),1.0));
imageStore( outputTexture, ivec3(texel, 1), vec4(0.0,0.0,0.0, 1.0));
}
else if(nbFrame == 1){
float value = treatment2(texel, pWorld, nWorld.xyz, outSize.x);
vec3 previousValue = imageLoad(outputTexture, ivec3(texel, 1)).xyz * (nbFrame - 1);
value += previousValue;
value /= nbFrame;
imageStore( outputTexture, ivec3(texel, 1), vec4(vec3(value), 1.0));
}
}
Related
I want to iterate through an array of sampler2DShadow for a shadow map computation (multiple lights), and it looks like the sampler can be accessed only for a constant index. I only show the relevant code for clarity:
smooth in vec4 fShadowTexCoord[5];
uniform sampler2DShadow shadowMapTexSampler[5];
void main() {
for (uint i = 0u; i < 5u; i++) { // light 'i'
float shadowCoeff = 0.0f;
// this line does not work properly
vec2 scale = 2.0f / textureSize(shadowMapTexSampler[i], 0);
float bias = 0.006f;
for (int j = -1; j <= 1; j++)
for (int k = -1; k <= 1; k++)
shadowCoeff += texture(shadowMapTexSampler[i], vec3(fShadowTexCoord[i].xy + vec2(j, k) * scale, fShadowTexCoord[i].z - bias));
shadowCoeff /= 9.0f;
// ...........
}
}
The function 'texture' works as expected, but 'textureSize' function behaves like no texture is bound.
If I replace 'i' with a constant, it works fine, but I didn't found how to cast an 'uint' to a 'const uint' in GLSL.
sorry for the necro post, but this seems to be a limitation of GLSL prior to 4.60 or so?
I do something ugly like this:
#define PCF_LOOP(idx) \
else if (faceIdx == idx) \
{ \
for (int i=0; i<PCF_SAMPLES; i++) \
{ \
...
} \
}
if (false);
PCF_LOOP(0)
PCF_LOOP(1)
PCF_LOOP(2)
PCF_LOOP(3)
PCF_LOOP(4)
PCF_LOOP(5)
it's ugly and (probably) slow, but works even on ancient hw
This might be a trivial question.
I am curious about how glsl would synchronize when accessing texture data via a fragment shader.
Say I have a code like below in a fragment shader.
void main() {
vec3 texCoord = in_texCoord;
vec4 out_voxel_intensity = texture(image, vec3(texCoord.x , texCoord.y, texCoord.z));
out_voxel = float(out_voxel_intensity) ;
if(out_voxel <= threshold)
{
out_voxel = 0.0;
return;
}
for(int i = -int(kernalSize); i <= int(kernalSize);++i)
for(int j = -int(kernalSize); j <= int(kernalSize); ++j)
for(int k = -int(kernalSize); k <= int(kernalSize); ++k)
{
float x_o = texCoord.x + i / (imageSize.x);
float y_o = texCoord.y + j / (imageSize.y);
float z_o = texCoord.z + k / (imageSize.z);
if(x_o < 0.0 || x_o > 1.0
|| y_o < 0. || y_o > 1.0
|| z_o < 0. || z_o > 1.0)
continue;
if(float(texture(image, vec3(x_o, y_o, z_o))) <= threshold)
{
out_voxel = 0.0;
return;
}
}
}
as the code above access not only the current texture coordinate, but the values around it with the specified kernel size, how glsl takes care that no other parallel process access the same texture coordinates.
W.r.t that question, does the code above performs efficiently in a fragment shader given it access neighboring texture data or using openCL better?
Thanks
I have the following compute shader code for computing depth of field. However, very unusually, the loop executes just once, even if g_rayCount is 10. Please have a look in the main function raycastercs where the for loop lies.
//--------------------------------------------------------------------------------------
// Compute Shader
//-------------------------------------------------------------------------------------
SamplerState SSLinear
{
Filter = Min_Mag_Linear_Mip_Point;
AddressU = Border;
AddressV = Border;
AddressW = Border;
};
float3 CalculateDoF(uint seedIndex, uint2 fragPos)
{
;
}
[numthreads(RAYCASTER_THREAD_BLOCK_SIZE, RAYCASTER_THREAD_BLOCK_SIZE, 1)]
void RaycasterCS(in uint3 threadID: SV_GroupThreadID, in uint3 groupID: SV_GroupID, in uint3 dispatchThreadID :SV_DispatchThreadID)
{
uint2 fragPos = groupID.xy * RAYCASTER_THREAD_BLOCK_SIZE + threadID.xy;
float4 dstColor = g_texFinal[fragPos];
uint seedIndex = dispatchThreadID.x * dispatchThreadID.y;
float3 final = float3(0, 0, 0);
float color = 0;
[loop][allow_uav_condition]
for (int i = 0; i < g_rayCount; ++i);
{
float3 dof = CalculateDoF(seedIndex, fragPos);
final += dof;
}
final *= 1.0f / ((float) g_rayCount);
g_texFinalRW[fragPos] = float4(final, 1);
}
//--------------------------------------------------------------------------------------
technique10 Raycaster
{
pass RaycastDefault
{
SetVertexShader(NULL);
SetGeometryShader(NULL);
SetPixelShader(NULL);
SetComputeShader(CompileShader(cs_5_0, RaycasterCS()));
}
}
Remove the semicolon at the end of the for statement
for (int i = 0; i < g_rayCount; ++i) // removed semicolon
{
float3 dof = CalculateDoF(seedIndex, fragPos);
final += dof;
}
As I guess you know, the semicolon was just running an empty for loop, then the code in braces was thereafter executed just once.
I tried to implement something in glsl to do texture splatting, but the for loop is acting weird and gives different results for code that does exactly the same.
Code 1:
for(int i = 0; i < 5; ++i) {
if(i == 1) {
float fade = texture2D(alphaTextures[i], texCoord.st).r;
vec4 texCol = texture2D(textures[i], texCoord.ba);
texColor = mix(texColor, texCol, fade);
}
}
Code 2:
for(int i = 0; i < 6; ++i) {
if(i == 1) {
float fade = texture2D(alphaTextures[i], texCoord.st).r;
vec4 texCol = texture2D(textures[i], texCoord.ba);
texColor = mix(texColor, texCol, fade);
}
}
The if statement is just for testing purposes so that it should give the same result. The only difference is the loop condition. I really have no idea why only Code 1 gives the correct result. Here are two pictures:
Code1
Code2
The result should be like in picture 1.
According to this answer, you can't iterate over a sampler array. The index alphaTextures[i] is invalid, you can only use alphaTextures[1].
This changes in GLSL 4.00+ (OpenGL 4.0+), where you can have a variable index, but it cannot be from a shader input/derived value.
One reason could be that Graphic processors don't like branched texture fetches.
Try this instead:
for(int i = 0; i < 6; ++i) {
float fade = texture2D(alphaTextures[i], texCoord.st).r;
vec4 texCol = texture2D(textures[i], texCoord.ba);
if(i == 1) {
texColor = mix(texColor, texCol, fade);
}
}
(disclaimer) i am only guessing and this error is really weird.
I am using Ogre3D as the graphics engine.
I create a mesh manually which works fine, uvs are correct and are set to represent grid coordinates (for this example the grid is a 10 x 10)
I do nothing in the vertex program and have a very simple fragment program. I have included both programs plus the material file to explain.
My problem is, that even with filtering set to none the colours don't seem to come out the same as my original image (this is just a test image im using because I was having problems with creating the texture manually in ogre). It turns out that the problem is not my code in ogre but more likely something to do with either the material file or the fragment/vertex programs.
I have also included a screenshot of the output on the left and the original image on the right. The fragment shader also draws a simple grid over the top so I could make sure that uv coordinates were being passed across correctly. Which they seem to be.
Any insight would be much appreciated as I am really unsure what im doing wrong.
Material file:
// CG Vertex shader definition
vertex_program PlainTexture_VS cg
{
// Look in this source file for shader code
source GameObjStandard.cg
// Use this function for the vertex shader
entry_point main_plain_texture_vp
// Compile the shader to vs_1_1 format
profiles arbvp1
// This block saves us from manually setting parameters in code
default_params
{
// Ogre will put the worldviewproj into our 'worldViewProj' parameter for us.
param_named_auto worldViewProj worldviewproj_matrix
// Note that 'worldViewProj' is a parameter in the cg code.
}
}
// CG Pixel shader definition
fragment_program PlainTexture_PS cg
{
// Look in this source file for shader code
source GameObjStandard.cg
// Use this function for the pixel shader
entry_point main_plain_texture_fp
// Compile to ps_1_1 format
profiles arbfp1
}
material PlainTexture
{
// Material has one technique
technique
{
// This technique has one pass
pass
{
// Make this pass use the vertex shader defined above
vertex_program_ref PlainTexture_VS
{
}
// Make this pass use the pixel shader defined above
fragment_program_ref PlainTexture_PS
{
}
texture_unit 0
{
filtering none
// This pass will use this 2D texture as its input
texture test.png 2d
}
texture_unit 1
{
texture textureatlas.png 2d
tex_address_mode clamp
filtering none
}
}
}
}
CG File:
void main_plain_texture_vp(
// Vertex Inputs
float4 position : POSITION, // Vertex position in model space
float2 texCoord0 : TEXCOORD0, // Texture UV set 0
// Outputs
out float4 oPosition : POSITION, // Transformed vertex position
out float2 uv0 : TEXCOORD0, // UV0
// Model Level Inputs
uniform float4x4 worldViewProj)
{
// Calculate output position
oPosition = mul(worldViewProj, position);
// Simply copy the input vertex UV to the output
uv0 = texCoord0;
}
void main_plain_texture_fp(
// Pixel Inputs
float2 uv0 : TEXCOORD0, // UV interpolated for current pixel
// Outputs
out float4 color : COLOR, // Output color we want to write
// Model Level Inputs
uniform sampler2D Tex0: TEXUNIT0,
uniform sampler2D Tex1: TEXUNIT1) // Texture we're going to use
{
//get the index position by truncating the uv coordinates
float2 flooredIndexes = floor(uv0);
if((uv0.x > 0.9 && uv0.x < 1.1)
|| (uv0.x > 1.9 && uv0.x < 2.1)
|| (uv0.x > 2.9 && uv0.x < 3.1)
|| (uv0.x > 3.9 && uv0.x < 4.1)
|| (uv0.x > 4.9 && uv0.x < 5.1)
|| (uv0.x > 5.9 && uv0.x < 6.1)
|| (uv0.x > 6.9 && uv0.x < 7.1)
|| (uv0.x > 7.9 && uv0.x < 8.1)
|| (uv0.x > 8.9 && uv0.x < 9.1)) {
float4 color1 = {1.0,0,0,0};
color = color1;
} else if((uv0.y > 0.9 && uv0.y < 1.1)
|| (uv0.y > 1.9 && uv0.y < 2.1)
|| (uv0.y > 2.9 && uv0.y < 3.1)
|| (uv0.y > 3.9 && uv0.y < 4.1)
|| (uv0.y > 4.9 && uv0.y < 5.1)
|| (uv0.y > 5.9 && uv0.y < 6.1)
|| (uv0.y > 6.9 && uv0.y < 7.1)
|| (uv0.y > 7.9 && uv0.y < 8.1)
|| (uv0.y > 8.9 && uv0.y < 9.1)) {
float4 color1 = {1.0,0,0,0};
color = color1;
} else {
//get the colour of the index texture Tex0 at this floored coordinate
float4 indexColour = tex2D(Tex0, (1.0/10)*flooredIndexes);
color = indexColour;
}
}
Ok so its been a while since I found the solution to my problems unfortunately not been online so hope this helps anyone with similar issues.
When creating any texture you should always make textures a size in texels 2^n * 2^m where m and n are the width and height of the texture. This was my first mistake although I did not realise it at the time.
The reason I had not spotted this was because my main texture atlas was based on this principle and was a 1024 x 1024 texture. What I had not taken into account was the size of the texture I wasd creating as the texture index. Since my map was 10 x 10 I was creating a 10 x 10 texture for the indexes, this was I presume then being stretched somehow (not sure how it works in the backend) to be either 16 x 16 or 8 x 8, blending the texels together as it did it.
The first thing that gave me the clue was when I scaled my canvas in photoshop and found that the blended colours it was creating were the same as the ones I was getting on my ogre3d output.
Anyway moving on..
Once I had this figured out I was able to create the texture in Ogre and pass it across as follows
//Create index material
Ogre::TexturePtr indexTexture = Ogre::TextureManager::getSingleton().createManual("indexTexture","General",Ogre::TextureType::TEX_TYPE_2D, 16, 16, 0, Ogre::PixelFormat::PF_BYTE_BGRA, Ogre::TU_DEFAULT);
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = indexTexture->getBuffer();
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
Ogre::uint8 counter = 0;
for (size_t j = 0; j < 16; j++) {
for(size_t i = 0; i < 16; i++)
{
if(i==8 || i==7) {
*pDest++ = 3; // B
*pDest++ = 0; // G
*pDest++ = 0; // R
*pDest++ = 0; // A
} else {
*pDest++ = 1; // B
*pDest++ = 0; // G
*pDest++ = 0; // R
*pDest++ = 0; // A
}
counter++;
}
}
pixelBuffer->unlock();
So now I have a texture I can use as an index with some values I added in for testing, these values eventually will be populated at runtime by clicking on the tile.
Now to pass this texture across I had to pass it to the correct technique and pass in my material, this was done as follows:
Ogre::MaterialPtr material = Ogre::MaterialPtr(Ogre::MaterialManager::getSingleton().getByName("PlainTexture"));
float mapSize = 16;
float tas = 2;
material->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("mapSize",mapSize);
material->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("tas",tas);
material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("indexTexture");
This passes two values too, mapSize being the size of the map itself in tiles (assuming its a square) and tas being the texture atlas size (number of different texture squares across the width of the atlas).
To allow my material to understand what I just passed in I needed to modify my material file slightly as follows:
// CG Pixel shader definition
fragment_program PlainTexture_PS cg
{
source GameObjStandard.cg
entry_point main_plain_texture_fp
profiles arbfp1
default_params
{
param_named tas float
param_named
}
}
And my pass was redefined slightly too
pass
{
// Make this pass use the vertex shader defined above
vertex_program_ref PlainTexture_VS
{
}
// Make this pass use the pixel shader defined above
fragment_program_ref PlainTexture_PS
{
}
texture_unit 0
{
filtering none
}
texture_unit 1
{
texture textureatlas.png 2d
tex_address_mode clamp
filtering anisotropic
}
}
I then rewrote the cg texture fragment program to take into account the changes I had made.
void main_plain_texture_fp(
float2 uv0 : TEXCOORD0, // UV interpolated for current pixel
out float4 color : COLOR, // Output color we want to write
uniform float tas,
uniform float mapSize,
// Model Level Inputs
uniform sampler2D Tex0: TEXUNIT0,
uniform sampler2D Tex1: TEXUNIT1)
{
//get the index position by truncating the uv coordinates
float2 flooredIndexes = floor(uv0);
//get the colour of the index texture Tex0 at this floored coordinate
float4 indexColour = tex2D(Tex0, ((1.0/mapSize) * flooredIndexes)+(0.5/mapSize));
//calculate the uv offset required for texture atlas range = 0 - 255
float indexValue = (255 * indexColour.b) + (255 * indexColour.g) + (255 * indexColour.r);
//float indexValue = (tas * tas) - indexValue0;
if(indexValue < tas*tas) {
float row = floor(indexValue/tas);
float col = frac(indexValue/tas) * tas;
float uvFraction = 1.0/tas;
float uBase = col * uvFraction;
float vBase = 1 - ((tas - row) * uvFraction);
float uOffset = frac(uv0.x)/tas;
float vOffset = (frac(uv0.y))/tas;
float uNew = uBase + uOffset;
float vNew = vBase + vOffset;
float2 uvNew = {uNew, vNew};
if(frac(uv0.x) > 0.99 || frac(uv0.x) < 0.01) {
float4 color1 = {1,1,1,0};
color = (0.2*color1) + (0.8*tex2D(Tex1,uvNew));
} else if(frac(uv0.y) > 0.99 || frac(uv0.y) < 0.01) {
float4 color1 = {1,1,1,0};
color = (0.2*color1) + (0.8*tex2D(Tex1,uvNew));
} else {
color = tex2D(Tex1,uvNew);
}
} else {
float4 color2 = {0.0,0,0,0};
color = color2;
}
}
This calculates the correct texel needed from the texture atlas, it also overlays a faint grid over the top by combining 80% texel color and 20% white.
If the texture atlas does not have the index of the colour specified by the index texture then it just outputs black (This is mainly so its very easy to spot.
Below is an example of the output using a 2 x 2 texture atlas.