I've just read this mozilla WebGL tutorial and came upon a question
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context
I'm wondering why an array of positions for a simple square should be
const positions = [
-1.0, 1.0, // 1 - top left
1.0, 1.0, // 2 - top right
-1.0, -1.0, // 3 - bottom left
1.0, -1.0, // 4 - bottom right
];
instead of
const positions = [
-1.0, 1.0, // 1 - top left
1.0, 1.0, // 2 - top right
1.0, -1.0, // 4 - bottom right
-1.0, -1.0, // 3 - bottom left
];
which would make more sense to me.
In the first case (the correct one), it seems that the lines drawing the square from vertex to vertex should cross, but obviously it doesn't work that way.
They're using TRIANGLE_STRIP indexing in that example:
Draws a series of triangles (three-sided polygons) using vertices v0,
v1, v2, then v2, v1, v3 (note the order), then v2, v3, v4, and so on.
The ordering is to ensure that the triangles are all drawn with the
same orientation so that the strip can correctly form part of a
surface.
Wikipedia - Triangle strip
Related
I am totally new to tessellation and relatively new to Metal API, and have been referring to this sample code https://developer.apple.com/library/archive/samplecode/MetalBasicTessellation/Introduction/Intro.html
I realise the max tessellation factor on iOS is 16, which is very low for my use case compared to 64 on OSX.
I suppose i'll need to apply tessellation on a quad that has been sub-divided to 4 by 4 smaller sections to begin with, so that after tessellation it will end up into something like one with a tessellation factor of 64?
So, i've changed the input control points to something like this
static const float controlPointPositionsQuad[] = {
-0.8, 0.8, 0.0, 1.0, // upper-left
0.0, 0.8, 0.0, 1.0, // upper-mid
0.0, 0.0, 0.0, 1.0, // mid-mid
-0.8, 0.0, 0.0, 1.0, // mid-left
-0.8, 0.0, 0.0, 1.0, // mid-left
0.0, 0.0, 0.0, 1.0, // mid-mid
0.0, -0.8, 0.0, 1.0, // lower-mid
-0.8, -0.8, 0.0, 1.0, // lower-left
0.0, 0.8, 0.0, 1.0, // upper-mid
0.8, 0.8, 0.0, 1.0, // upper-right
0.8, 0.0, 0.0, 1.0, // mid-right
0.0, 0.0, 0.0, 1.0, // mid-mid
0.0, 0.0, 0.0, 1.0, // mid-mid
0.8, 0.0, 0.0, 1.0, // mid-right
0.8, -0.8, 0.0, 1.0, // lower-right
0.0, -0.8, 0.0, 1.0, // lower-mid
};
and for the drawPatches i changed it to 16 instead of 4.
But the result is that it is only showing only the first 4 points (top left).
if i change the vertex layout stride to this:
vertexDescriptor.layouts[0].stride = 16*sizeof(float);
it is still showing the same.
I don't really know what i'm doing but what i'm going for is similar to tessellating a 3d mesh, but for my case is just a quad with subdivisions.
I am unable to find any tutorial / code samples that teach about this using Metal API.
Can someone please point me to the right direction? thanks!
Here are a few things to check:
Ensure that your tessellation factor compute kernel is generating inside/edge factors for all patches by dispatching a compute grid of the appropriate size.
When dispatching threadgroups to execute your tessellation factor kernel, use 1D threadgroup counts and sizes (such that the total thread count is the number of patches, and the heights of both sizes passed to the dispatch method are 1).
When drawing patches, the first parameter (numberOfPatchControlPoints) should equal the number of control points in each patch (3 for triangles; 4 for quads), and the third parameter should be the number of patches to draw.
kernel vec4 custom(__sample s1, __sample s2) {
if(s1.a == 0.0)
return s2;
if(s2.a == 0.0)
return s1;
vec4 res;
float temp = 1.0 - s2.a;
res.rgb = s2.rgb * s2.aaa + s1.rgb * (temp, temp, temp);
res.a = 1.0;
return res;
}
I am trying to merge 2 images, but have artifacts in bounds, where due to aliasing the pixels have less than 1 alpha. Is there any suggestions what I am doing wrong :/ For example the cheeks have some kind of bound, which doesn't appear if I place one over the other via UIImageViews
OpenGL ES uses post-multiplied alpha, which means that channels are blended independently, but which is inaccurate for a lot of blending operations.
Imagine blending a source fragment [1.0, 0.0, 0.0, 0.5] (red, half transparent) on to a destination framebuffer [0.0, 0.0, 1.0, 0.0] (blue, fully transparent). You would logically expect "half transparent red" as the original destination color is not visible due to the 0.0 alpha value. However, because the channels are blended independently you would end up with the final RGB color being purple [0.5, 0.0, 0.5].
The fast way to fix this is by propagating the color values out into the transparent region, so that the opaque pink color extends out in to the feather region where you start to fade it out.
A better way to fix this is using pre-multipled alpha, but that starts to have side-effects (loss of precision in texel storage, and you need a different blend equation).
I'm drawing a set of triangles filled with plain color to off-screen texture.
My problem is that I get too big triangles in a result image, it looks like this:
My vertex coordinates are in pixels. (I simply generate them as a random float in (0, outTexture.width/height)). I do not multiply them by any projection in my vertex function (maybe that is my mistake?)
So my question is how does vertex coordinates correlate with pixel coordinate?
The solution was to make ortho projection and pass it as a uniform.
Here is the code that worked for me:
func makeOrthographicMatrix(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) -> [Float] {
let ral = right + left
let rsl = right - left
let tab = top + bottom
let tsb = top - bottom
let fan = far + near
let fsn = far - near
return [2.0 / rsl, 0.0, 0.0, 0.0,
0.0, 2.0 / tsb, 0.0, 0.0,
0.0, 0.0, -2.0 / fsn, 0.0,
-ral / rsl, -tab / tsb, -fan / fsn, 1.0]
}
And I called that like so :
var projection = makeOrthographicMatrix(0.0, right: Float(inTexture.width), bottom: 0.0, top: Float(inTexture.height), near: -1.0, far: 1.0)
This minimal Metal shader pair renders a simple interpolated gradient onto the screen (when provided with a vertex quad/triangle) based on the vertices' color attributes:
#include <metal_stdlib>
using namespace metal;
typedef struct {
float4 position [[position]];
float4 color;
} vertex_t;
vertex vertex_t vertex_function(const device vertex_t *vertices [[buffer(0)]], uint vid [[vertex_id]]) {
return vertices[vid];
}
fragment half4 fragment_function(vertex_t interpolated [[stage_in]]) {
return half4(interpolated.color);
}
…with the following vertices:
{
// x, y, z, w, r, g, b, a
1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0
}
So far so good. It renders the well-known gradient triangle/quad.
The one you find in pretty much every single GPU HelloWorld tutorial.
I however need to have a fragment shader that instead of taking the interpolated vertex color computes a color based on the fragments position on screen.
It receives a screen-filling quad of vertices and then uses only the fragment shader to calculate the actual colors.
From my understanding the position of a vertex is a float4 with the first three elements being the 3d vector and the 4th element set to 1.0.
So—I thought—it should be easy to modify the above to have it simply reinterpret the vertex' position as a color in the fragment shader, right?
#include <metal_stdlib>
using namespace metal;
typedef struct {
float4 position [[position]];
} vertex_t;
vertex vertex_t vertex_function(const device vertex_t *vertices [[buffer(0)]], uint vid [[vertex_id]]) {
return vertices[vid];
}
fragment half4 fragment_function(vertex_t interpolated [[stage_in]]) {
float4 color = interpolated.position;
color += 1.0; // move from range -1..1 to 0..2
color *= 0.5; // scale from range 0..2 to 0..1
return half4(color);
}
…with the following vertices:
{
// x, y, z, w,
1.0, -1.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 0.0, 1.0,
-1.0, 1.0, 0.0, 1.0,
}
I was quite surprised however to find a uniformly colored (yellow) screen being rendered, instead of a gradient going from red=0.0 to red=1.0 in x-axis and green=0.0 to green=1.0 in x-axis:
(expected render output vs. actual render output)
The interpolated.position appears to be yielding the same value for each fragment.
What am I doing wrong here?
Ps: (While this dummy fragment logic could have easily been accomplished using vertex interpolation, my actual fragment logic cannot.)
The interpolated.position appears to be yielding the same value for
each fragment.
No, the values are just very large. The variable with the [[position]] qualifier, in the fragment shader, is in pixel coordinates. Divide by the render target dimensions, and you'll see what you want, except for having to invert the green value, because Metal's convention is to define the upper-left as the origin for this, not the bottom-left.
I am very new to WebGL and I have a question about the order of vertices. When creating a cube, the vertices will look like this:
var vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
Can I rearrange the order of these vertices into any order I want, or do they have to be in a certain order?
Order of the vertices depends on the triangle culling paramaters and order in which the triangles are drawn.
Vertices that make up a triangle can be ordered in the right-hand or left-hand manner. Orientation of the triangle than describes the wait the normal of the triangle is pointing at. Read more here.
Depending on the option you select for the gl.cullface( option ), you have different culling of the triangles. So, that affects the vertices order.
Another important aspect to look after is order of the triangles/primitives that are drawn. You may have different requirements in your application, so may need to pre-order triangles that weer to be drawn, so that could also affect the order of the vertices. One such example is drawing transparent primitives. There are many issues with blending transparent primitives so need to take care. For more insightful direct example, read this.
Hope this helps you understand how the order of the vertices may or may not be important.