How to read custom data from framebuffer - graphics

for the past few days I've been trying to implement mouse picking in my vulkan game engine and part of that is reading data from framebuffers. Now I can successfully read RGBA data. But what I need is to read specific attachment containing id of the entity.
Here is what my fragment shader looks like:
#version 450 core
struct VertexInput
{
vec4 Color;
vec2 TexCoord;
float TilingFactor;
};
// Inputs
layout(location = 0) in VertexInput Input;
layout(location = 3) in flat uint in_TexIndex;
layout(location = 4) in flat int in_EntityID;
layout(binding = 1) uniform sampler2D u_Samplers[10];
// Outputs
layout(location = 0) out vec4 o_Color;
layout(location = 1) out int o_EntityID; // <-- This is what I need
void main()
{
o_EntityID = in_EntityID;
o_Color = Input.Color * texture(u_Samplers[in_TexIndex], Input.TexCoord * Input.TilingFactor);
}
And get this warning
Validation layer: Validation Warning: [ UNASSIGNED-CoreValidation-Shader-OutputNotConsumed ] Object 0: handle = 0x5dbcf90000000065, type = VK_OBJECT_TYPE_SHADER_MODULE; | MessageID = 0x609a13b | fragment shader writes to output location 1 with no matching attachment
which is understandable.
I know I need to add attachment into my framebuffer object but I am not sure which one or how should I approach this problem. Any ideas? Thanks :)

Related

pixi.js: how to draw outline of container while keeping its content transparent

I have a container with several graphics containing circles. I would like to only render this container's outline, without the graphics themselves.
I managed to draw the outlines using OutlineFilter, and I managed to make the container transparent using AlphaFilter, but not both at the same time, no matter in which order I added the filters.
That is technically not possible like you intend to do it. One shader (pixi.js filter) doesn't know about the previous shader, such as where the outline was painted or what is the original texture alpha.
Alternatively you can create a new filter with a new shader that achieves that effect. I'm basing this on the OutlineFilter:
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform vec2 thickness;
uniform vec4 outlineColor;
uniform vec4 filterClamp;
const float DOUBLE_PI = 3.14159265358979323846264 * 2.;
void main(void) {
vec4 ownColor = texture2D(uSampler, vTextureCoord);
vec4 curColor;
float maxAlpha = 0.;
vec2 displaced;
for (float angle = 0.; angle <= DOUBLE_PI; angle += 0.1) {
displaced.x = vTextureCoord.x + thickness.x * cos(angle);
displaced.y = vTextureCoord.y + thickness.y * sin(angle);
curColor = texture2D(uSampler, clamp(displaced, filterClamp.xy, filterClamp.zw));
maxAlpha = max(maxAlpha, curColor.a);
}
float resultAlpha = maxAlpha * step(ownColor.a, 0.0) > 0. ? 1. : 0.0;
gl_FragColor = vec4(outlineColor.rgb * resultAlpha, resultAlpha);
}
Example result as in the pixi-filters demos:

Compute Shader Corrupting Vertex Buffer

I'm making a tutorial for computing tangents and bitangents in a WGPU (Vulkan GLSL) compute shader. I'm creating the vertex buffer on the CPU from a .obj I made in blender.
Here's the code for the compute shader.
#version 450
#define VERTICES_PER_TRIANGLE 3
layout(local_size_x = VERTICES_PER_TRIANGLE) in;
// Should match the struct in model.rs
struct ModelVertex {
vec3 position;
vec2 tex_coords;
vec3 normal;
vec3 tangent;
vec3 bitangent;
};
layout(std140, set=0, binding=0) buffer SrcVertexBuffer {
ModelVertex srcVertices[];
};
layout(std140, set=0, binding=1) buffer DstVertexBuffer {
ModelVertex dstVertices[];
};
layout(std140, set=0, binding=2) buffer IndexBuffer {
uint Indices[];
};
void main() {
uint index = gl_GlobalInvocationID.x;
// Grab the indices for the triangle
uint i0 = Indices[index];
uint i1 = Indices[index + 1];
uint i2 = Indices[index + 2];
// Grab the vertices for the triangle
ModelVertex v0 = srcVertices[i0];
ModelVertex v1 = srcVertices[i1];
ModelVertex v2 = srcVertices[i2];
// Grab the position and uv components of the vertices
vec3 pos0 = v0.position;
vec3 pos1 = v1.position;
vec3 pos2 = v2.position;
vec2 uv0 = v0.tex_coords;
vec2 uv1 = v1.tex_coords;
vec2 uv2 = v2.tex_coords;
// Calculate the edges of the triangle
vec3 delta_pos1 = pos1 - pos0;
vec3 delta_pos2 = pos2 - pos0;
// This will give us a direction to calculate the
// tangent and bitangent
vec2 delta_uv1 = uv1 - uv0;
vec2 delta_uv2 = uv2 - uv0;
// Solving the following system of equations will
// give us the tangent and bitangent.
// delta_pos1 = delta_uv1.x * T + delta_u.y * B
// delta_pos2 = delta_uv2.x * T + delta_uv2.y * B
// Luckily, the place I found this equation provided
// the solution!
float r = 1.0 / (delta_uv1.x * delta_uv2.y - delta_uv1.y * delta_uv2.x);
vec3 tangent = (delta_pos1 * delta_uv2.y - delta_pos2 * delta_uv1.y) * r;
vec3 bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * r;
// We'll use the same tangent/bitangent for each vertex in the triangle
dstVertices[i0].tangent = tangent;
dstVertices[i1].tangent = tangent;
dstVertices[i2].tangent = tangent;
dstVertices[i0].bitangent = bitangent;
dstVertices[i1].bitangent = bitangent;
dstVertices[i2].bitangent = bitangent;
}
This leads to an image like the following.
The problem occurs in the last six lines.
dstVertices[i0].tangent = tangent;
dstVertices[i1].tangent = tangent;
dstVertices[i2].tangent = tangent;
dstVertices[i0].bitangent = bitangent;
dstVertices[i1].bitangent = bitangent;
dstVertices[i2].bitangent = bitangent;
If I delete these lines, the output is fine (albeit the lightings all wrong due to the tangent and bitangent being a 0 vector).
Why is modifying the tangent and bitangent messing with the position of the vertices?
Here's the rest of the code for context. https://github.com/sotrh/learn-wgpu/tree/compute/code/intermediate/tutorial14-compute
EDIT:
Here's the code where I'm calling the compute shader.
let src_vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", m.name)),
contents: bytemuck::cast_slice(&vertices),
// UPDATED!
usage: wgpu::BufferUsage::STORAGE,
});
let dst_vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", m.name)),
contents: bytemuck::cast_slice(&vertices),
// UPDATED!
usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::STORAGE,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", m.name)),
contents: bytemuck::cast_slice(&m.mesh.indices),
// UPDATED!
usage: wgpu::BufferUsage::INDEX | wgpu::BufferUsage::STORAGE,
});
let binding = BitangentComputeBinding {
dst_vertex_buffer,
src_vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
};
// Calculate the tangents and bitangents
let calc_bind_group = self.binder.create_bind_group(
&binding,
device,
Some("Mesh BindGroup")
);
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Tangent and Bitangent Calc"),
});
{
let mut pass = encoder.begin_compute_pass();
pass.set_pipeline(&self.pipeline);
pass.set_bind_group(0, &calc_bind_group, &[]);
pass.dispatch(binding.num_elements as u32 / 3, 1, 1);
}
queue.submit(std::iter::once(encoder.finish()));
device.poll(wgpu::Maintain::Wait);
The shader is supposed to loop through all the triangles in the mesh and compute the tangent and bitangent using the positon, and uv coordinates of the vertices of that triangle. I'm guessing that the vertices that are shared with multiple triangles are getting written to at the same time, causing this memory corruption.
I don't think it's a problem with shaders elsewhere, as I'm using the same model for the light, and the vertex shader responsible for that doesn't use the tangent and bitangent at all.
#version 450
layout(location=0) in vec3 a_position;
layout(location=0) out vec3 v_color;
layout(set=0, binding=0)
uniform Uniforms {
vec3 u_view_position;
mat4 u_view_proj;
};
layout(set=1, binding=0)
uniform Light {
vec3 u_position;
vec3 u_color;
};
// Let's keep our light smaller than our other objects
float scale = 0.25;
void main() {
vec3 v_position = a_position * scale + u_position;
gl_Position = u_view_proj * vec4(v_position, 1);
v_color = u_color;
}
Looking at the vertex data in Render Doc shows that they position data is getting messed up.
Also here's what the cubes look like if I set the tangent and bitangent to vec3(0, 1, 0).
My only guess is that storage buffers have a byte alignment rule that I'm unaware of. I know that's the case for uniform buffers, but I'm using storage buffers for my instancing code, and that doesn't seem to have any issues.
Turns out Vulkan style GLSL aligns to the largest field in the struct when using std430.
https://github.com/KhronosGroup/glslang/issues/264
In my case it's vec3. The vec2 tex_coord is throwing it off causing the shader to pull data from the wrong parts of the vertex buffer.
The fix was to change the struct in model_load.comp to specify the individual components instead.
struct ModelVertex {
float x; float y; float z;
float uv; float uw;
float nx; float ny; float nz;
float tx; float ty; float tz;
float bx; float by; float bz;
};
Now the base alignment is a float (4 bytes), and the shader reads the vertex buffer data properly.
I'm aware there's a packed layout, but shaderc doesn't allow me to use that for reasons beyond me. Honestly I think this is quite annoying, and cumbersome, but it works.
There's still a flaw in the result. There's some banding on the edge faces of the cube. My guess is that it's do a single vertex sharing multiple triangles, but that's another problem that I'll have to look into later.

Vec3 storage buffer not a valid layout despite the scalar qualifier

As far as I understand, the scalar layout qualifier in vulkan GLSL should allow a simple array of vec3 values to work, apparently with out any physical device features to be specified. I've tried with and with out specifying scalar layout features like so:
VkPhysicalDeviceScalarBlockLayoutFeatures layoutfeatures = {};
layoutfeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES;
layoutfeatures.scalarBlockLayout = VK_TRUE;
VkPhysicalDeviceFeatures2 features2 = {};
features2.features = m_required_features;
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features2.pNext = &layoutfeatures;
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_create_infos.size());
create_info.pQueueCreateInfos = queue_create_infos.data();
create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_names.size());
create_info.ppEnabledExtensionNames = enabled_extensions_names.data();
create_info.pEnabledFeatures = &features2 .features;
create_info.pNext = &features2 ;
create_info.flags = flags;
VkDevice device;
VUL_EXCEPT_RESULT(vkCreateDevice(physical_device, &create_info, pAllocator, &device));
but to no avail. I'm getting strange spec invalidation errors.
here's example code:
#version 450
#extension GL_EXT_scalar_block_layout: require
#define WORKGROUP_SIZE 128
layout (local_size_x = WORKGROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
layout(scalar, binding = 3) buffer MyBufferBlock{
vec3 example_array[];
};
void main(){
example_array[gl_GlobalInvocationID.x] = 0.0;
}
and I get the following SPIR-V validation error:
"example.exe"
ERROR : SPEC_INVALIDATION - Message ID Number 7060244, Message ID String UNASSIGNED-CoreValidation-Shader-InconsistentSpirv:
Validation Error: [ UNASSIGNED-CoreValidation-Shader-InconsistentSpirv ] Object 0: handle = 0x6543e40, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x6bbb14 | SPIR-V module not valid: Structure id 500 decorated as BufferBlock for variable in Uniform storage class must follow relaxed storage buffer layout rules: member 0 contains an array with stride 12 not satisfying alignment to 16
%MyBufferBlock = OpTypeStruct %_runtimearr_v3float
First I don't understand why it is trying to call out my buffer as a uniform? and obviuosly I'm still confused on how this is at all a spec violation.

Using 2D metaballs to draw an outline with a constant thickness

I'm apply the concept of metaballs to a game I'm making in order to show that the player has selected a few ships, like so http://prntscr.com/klgktf
However, my goal is to keep a constant thickness of this outline, and that's not what I'm getting with the current code.
I'm using a GLSL shader to do this, and I pass to the fragmentation shader a uniform array of positions for the ships (u_metaballs).
Vertex shader:
#version 120
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Fragmentation shader:
#version 120
uniform vec2 u_metaballs[128];
void main() {
float intensity = 0;
for(int i = 0; i < 128 && u_metaballs[i].x != 0; i++){
float r = length(u_metaballs[i] - gl_FragCoord.xy);
intensity += 1 / r;
}
gl_FragColor = vec4(0, 0, 0, 0);
if(intensity > .2 && intensity < .21)
gl_FragColor = vec4(.5, 1, .7, .2);
}
I've tried playing around with the intensity ranges, and even changing 1 / r to 10000 / (r ^ 4) which (although it makes no sense) helps a bit, though it does not fix the problem.
Any help or suggestions would be greatly appreciated.
after some more taught it is doable even in single pass ... you just compute the distance to nearest metaball and if less or equal to the boundary thickness render fragment otherwise discard it ... Here example (assuming single quad <-1,+1> is rendered covering whole screen):
Vertex:
// Vertex
varying vec2 pos; // fragment position in world space
void main()
{
pos=gl_Vertex.xy;
gl_Position=ftransform();
}
Fragment:
// Fragment
#version 120
varying vec2 pos;
const float r=0.3; // metabal radius
const float w=0.02; // border line thickness
uniform vec2 u_metaballs[5]=
{
vec2(-0.25,-0.25),
vec2(+0.25,-0.25),
vec2( 0.00,+0.05),
vec2(+0.30,+0.35),
vec2(-1000.1,-1000.1), // end of metaballs
};
void main()
{
int i;
float d;
// d = min distance to any metaball
for (d=r+r+w+w,i=0;u_metaballs[i].x>-1000.0;i++)
d=min(d,length(pos-u_metaballs[i].xy));
// if outside range ignore fragment
if ((d<r)||(d>r+w)) discard;
// otherwise render it
gl_FragColor=vec4(1.0,1.0,1.0,1.0);
}
Preview:

Edge shader using GLSL-ES

I'm trying to do an edge shader but I have places where the edges are not shown at all. The behaviour is shown in the following image.
As you see the way I look at the model, doesn't show edges, but the other places are very sharp and looks good.
here is my attempt
uniform mat4 projection_matrix;
varying vec3 normFrag;
void main()
{
vec4 pos_transformed = modelViewProjectionMatrix * vertex;
vec3 normalizedNormal = normalize(normal);
vec3 norm = mat3(normalMatrix)* normalizedNormal ;
norm.y *=projection_matrix[2][3];
norm.x *= projection_matrix[3][2];
//norm *=-1.0;
norm = normalize(norm);
pos_transformed.xy -= pos_transformed.z*norm.xy*0.005;
gl_Position = vec4(pos_transformed);
}

Resources