3
\$\begingroup\$

Imagine that we have a vertex structure that looks like this:

struct Vertex
{
    XMFLOAT3 position;
    XMFLOAT4 color;
};

The vertex shader looks like this:

cbuffer MatrixBuffer
{
    matrix world;
    matrix view;
    matrix projection;
};

struct VertexInput
{
    float4 position : POSITION;
    float4 color    : COLOR;
};

struct PixelInput
{
    float4 position : SV_POSITION;
    float4 color    : COLOR;
};

PixelInput main(VertexInput input)
{
    PixelInput output;

    input.position.w = 1.0f;

    output.position = mul(input.position,  world);
    output.position = mul(output.position, view);
    output.position = mul(output.position, projection);

    output.color = input.color;

    return output;
}

And the pixel shader looks like this:

struct PixelInput
{
    float4 position : SV_POSITION;
    float4 color    : COLOR;
};

float4 main(PixelInput input) : SV_TARGET
{
    return input.color;
}

Now let's create a quad consisting of 2 triangles and the vertices A, B, C and D:

// Vertex A.
vertices[0].position = XMFLOAT3(-1.0f,  1.0f,  0.0f);
vertices[0].color    = XMFLOAT4( 0.5f,  0.5f,  0.5f,  1.0f);

// Vertex B.
vertices[1].position = XMFLOAT3( 1.0f,  1.0f,  0.0f);
vertices[1].color    = XMFLOAT4( 0.5f,  0.5f,  0.5f,  1.0f);

// Vertex C.
vertices[2].position = XMFLOAT3(-1.0f, -1.0f,  0.0f);
vertices[2].color    = XMFLOAT4( 0.5f,  0.5f,  0.5f,  1.0f);

// Vertex D.
vertices[3].position = XMFLOAT3( 1.0f, -1.0f,  0.0f);
vertices[3].color    = XMFLOAT4( 0.5f,  0.5f,  0.5f,  1.0f);

// 1st triangle.
indices[0] = 0; // Vertex A.
indices[1] = 3; // Vertex D.
indices[2] = 2; // Vertex C.

// 2nd triangle.
indices[3] = 0; // Vertex A.
indices[4] = 1; // Vertex B.
indices[5] = 3; // Vertex D.

This will result in a grey quad as shown in the image below. I've outlined the edges in red color to better illustrate the triangles:

Now imagine that we’d want our quad to have a different color in vertex A:

// Vertex A.
vertices[0].position = XMFLOAT3(-1.0f, 1.0f, 0.0f);
vertices[0].color    = XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f);

That works as expected since there’s now an interpolation between the black color in vertex A and the grey color in vertices B, C and D. Let’s revert the previus changes and instead change the color of vertex C:

// Vertex C.
vertices[2].position = XMFLOAT3(-1.0f, -1.0f, 0.0f);
vertices[2].color    = XMFLOAT4( 0.0f,  0.0f, 0.0f, 1.0f);

As you can see, the interpolation is only done half of the way across the first triangle and not across the entire quad. This is because there's no edge between vertex C and vertex B.

Which brings us to my question:

I want the interpolation to go across the entire quad and not only across the triangle. So regardless of which vertex we decide to change the color of, the color interpolation should always go across the entire quad. Is there any efficient way of achieving this without adding more vertices and triangles?

An illustration of what I'm trying to achieve is shown in the image below:


Background

This is just a very brief explanation of the problems background in case that would make it easier for you to understand the problems roots and maybe help you with finding a better solution to the problem.

I'm trying to texture a terrain mesh in DirectX11. It's working, but I'm a bit unsatisfied with the result. When changing the terrain texture of a single vertex, the interpolation with the other vertices results in a hexagon shape instead of a squared shape:

As the red arrows illustrate, I'd like the texture to be interpolated all the way into the corners of the quads.

\$\endgroup\$
2
\$\begingroup\$

You need per-fragment color interpolation rather than per vertex color interpolation. If you write the interpolation yourself in the fragment shader, you can make it work any way you'd like.

Unfortunately, I don't know Direct X or HLSL, but here's what it would look like in glsl. I imagine it's similar in HLSL. (Also, this is off the top of my head, untested.) Here I'm assuming that your texture coordinates go from 0-1 in both directions.

uniform vec2 chosenCornerCoord;

void main()
{
    vec2 diff = gl_TexCoord[0].xy - chosenCornerCoord;
    float dist = sqrt(dot(diff, diff));
    gl_FragColor = vec4(dist, dist, dist, 1.0);
}

This will actually give you a euclidean distance from the chosen corner which will result in a rounded falloff. You could use a manhattan (taxi) metric for the more square falloff you're seeing in your example.

In the above, gl_TexCoord[0] is the texture coordinate for the current fragment. chosenCornerCoord is the texture coordinate of the corner you want to measure the distance from. (Again, assuming texture coords from 0 to 1.)

\$\endgroup\$
  • \$\begingroup\$ Would you like to provide an example of how this could be done? \$\endgroup\$ – fighting_falcon93 Sep 15 '17 at 14:53
  • \$\begingroup\$ Sure. I don't know DirectX at all, so it will have to be in glsl. I'll try to add one shortly. \$\endgroup\$ – user1118321 Sep 15 '17 at 15:28
  • \$\begingroup\$ I've added one. Let me know if it makes sense. \$\endgroup\$ – user1118321 Sep 15 '17 at 15:59
  • \$\begingroup\$ I'm wondering about the chosenCornerCoord. Do you manually set a value to it before the draw call or does that mean something else in GLSL? Because if I'm not mistaken, setting it manually will cause problems when you have a large grid of multiple quads, or? \$\endgroup\$ – fighting_falcon93 Sep 15 '17 at 22:56
  • \$\begingroup\$ Yes, you need to manually set it before executing the shader. What sorts of problems are you anticipating? I suppose you could make it an attribute of the vertex shader, so long as you set the same value for all 4 corners of each quad. Then it will vary across the quad, but since all values are the same, all fragments will get the same value. \$\endgroup\$ – user1118321 Sep 16 '17 at 0:56
0
\$\begingroup\$

Probably not the thing you want to hear, but have you considered using a reference blend texture rather than what you are constrained by at the moment via the current interpolation constrained by geometry.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.