如何在DX中重复我的纹理

时间:2013-07-15 13:29:58

标签: directx texture-mapping

在three.js 3d库中有一个方便的功能,您可以将采样器设置为重复模式并将repeat属性设置为您喜欢的某些值,例如,(3,5)表示此纹理将水平重复3次和垂直5次。但现在我正在使用DirectX,我找不到一些解决这个问题的好方法。请注意,顶点的UV坐标仍然在0到1的范围内,我不想更改我的HLSL代码,因为我想要一个可编程的解决方案,非常感谢!

编辑:假设我已经有了一个立方体模型。并且其顶点的纹理坐标在0和1之间。如果我使用环绕模式或钳位模式对纹理进行采样,那么现在一切正常。但是我想在其中一个面上重复一个纹理,我首先需要改为换行模式。那是我已经知道了。然后我必须编辑我的模型,使纹理坐标范围为0-3。如果我不改变模型怎么办?到目前为止,我提出了一种方法:我需要在像素着色器中添加一个变量来表示地图重复的次数,我将在采样时将此因子乘以坐标。我觉得这不是一个优雅的解决方案......

2 个答案:

答案 0 :(得分:1)

您基本上想要像这样创建一个采样器状态:

ID3D11SamplerState* m_sampleState;
3D11_SAMPLER_DESC samplerDesc;
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

// Create the texture sampler state.
result = ifDEVICE->ifDX11->getD3DDevice()->CreateSamplerState(&samplerDesc, &m_sampleState);

当您设置着色器常量时,请调用:

ifDEVICE->ifDX11->getD3DDeviceContext()->PSSetSamplers(0, 1, &m_sampleState);

然后您可以像这样编写像素着色器:

Texture2D Texture;
SamplerState SampleType;

...

float4 main(PixelInputType input) : SV_TARGET
{
    float4 textureColor = shaderTexture.Sample(SampleType, input.uv);
    ...
}

希望有帮助...

答案 1 :(得分:1)

由于您已编辑了问题,因此您的问题还有另一个答案:

根据我的理解,你有一张像uv一样的脸:

0,1         1,1
 -------------
 |           |
 |           |
 |           |
 -------------
0,0         1,0

但是希望纹理重复3次(例如)而不是1次。 (不改变原始模型)

此处有多种解决方案:

您可以在更新缓冲区时执行此操作(如果这样做):

    D3D11_MAPPED_SUBRESOURCE resource;

    HRESULT hResult = D3DDeviceContext->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
    if(hResult != S_OK) return false;

    YourVertexFormat *ptr=(YourVertexFormat*)resource.pData;
    for(int i=0;i<vertexCount;i++)
    {
        ptr[i] = vertices[i];
        ptr[i].uv.x *= multiplyX; //in your case 3
        ptr[i].uv.y *= multiplyY; //in your case 5 
    }
    D3DDeviceContext->Unmap(vertexBuffer, 0);

但是如果你不需要更新缓冲区,我不会推荐它,因为它非常慢。

更快的方法是使用顶点着色器:

cbuffer MatrixBuffer
{
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
};

struct VertexInputType
{
    float4 position : POSITION0;
    float2 uv : TEXCOORD0;
    // ...
};

struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 uv : TEXCOORD0;
    // ...
};

PixelInputType main(VertexInputType input)
{
    input.position.w = 1.0f;

    PixelInputType output;
    output.position = mul(input.position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

    This is what you basicly need:
    output.uv = input.uv * 3; // 3x3

    Or more advanced:
    output.uv = float2(input.u * 3, input.v * 5);

    // ...

    return output;
}

我会推荐使用顶点着色器解决方案,因为它很快并且在directx中你无论如何都使用顶点着色器,因此它不像缓冲区更新解决方案那么昂贵......

希望有助于解决您的问题:)