Vulkan学习--19.创建纹理图像视图和采样器

采样器:

在着色器中是可以直接访问图像数据,但当图像被作为纹理时,我们通常不这样做。通常我们使用采样器来访问纹理数据,采样器可以自动地对纹理数据进行过滤和变换处理.

采样器进行的过滤操作可以很好地处理纹理采样过密的问题。考虑一个被映射到一个几何图元上的纹理,每个纹素占据了多个片段。如果我们直接采样与片段最近的纹素作为片段颜色,可能就会得到下面第一幅图的效果:
在这里插入图片描述
如果使用线性插值组合 4 个最近的纹素,我们可以得到上面第二幅图的效果。当然,有时候我们可能会喜欢第一幅图的效果 (比如在编写类似我的世界这种游戏时),当通常来说我们更多的想要第二幅图的效果。采样器可以自动地为我们进行上面这样的纹理过滤。
与之相反的是纹理采样过疏的问题,这种情况发生在多个纹素被映射到一个片段时。这会造成幻影现象,如下面第一幅图:
在这里插入图片描述
上面第二幅图,我们可以看到远处的纹理已经变得模糊不清。解决这一问题的方法是使用采样器进行各向异性过滤。
除了上面这些过滤器,采样器还可以进行变换操作。变换操作发生在采样超出纹理图像实际范围的数据时,下面这些图像就是使用采样器的变换操作产生的:
在这里插入图片描述

    VkImageView textureImageView ;//纹理图像的图像视图对象
    VkSampler textureSampler ;//采样器对象

        //判断是否支持各向异性过滤
        VkPhysicalDeviceFeatures supportedFeatures ;
        vkGetPhysicalDeviceFeatures( device , &supportedFeatures );
        return indices.isComplete() && extensionsSupported &&
                swapChainAdequate && supportedFeatures.samplerAnisotropy;

        //指定应用程序使用的设备特性
        VkPhysicalDeviceFeatures deviceFeatures = {};
        //各向异性过滤实际上是一个非必需的设备特性,这里指定使用
        deviceFeatures.samplerAnisotropy = VK_TRUE;

    //创建纹理图像的图像视图对象
    void createTextureImageView(){
        textureImageView = createImageView(textureImage,
                                           VK_FORMAT_R8G8B8A8_UNORM);
    }
    //创建图像视图对象
    VkImageView createImageView(VkImage image , VkFormat format){
        //设置图像视图结构体相关信息
        VkImageViewCreateInfo viewInfo = {};
        viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        viewInfo.image = image;
        //viewType 和 format 成员变量用于指定图像数据的解释方式。
        //viewType用于指定图像被看作是一维纹理、二维纹理、三维纹理还是立方体贴图
        viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
        viewInfo.format = format;
        /**
        components 成员变量用于进行图像颜色通道的映射。
        比如,对于单色纹理,我们可以将所有颜色通道映射到红色通道。
        我们也可以直接将颜色通道的值映射为常数 0 或 1。在这里,我们只使用默认的映射

        createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;*/
        //subresourceRange用于指定图像的用途和图像的哪一部分可以被访问
        //在这里,我们的图像被用作渲染目标,并且没有细分级别,只存在一个图层
        viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        viewInfo.subresourceRange.baseMipLevel = 0;
        viewInfo.subresourceRange.levelCount = 1;
        viewInfo.subresourceRange.baseArrayLayer = 0;
        viewInfo.subresourceRange.layerCount = 1;
        VkImageView imageView;
        /**
        如果读者在编写 VR 一类的应用程序,可能会使用支持多个层次的交换链。
        这时,读者应该为每个图像创建多个图像视图,分别用来访问左眼和右眼两个不同的图层
          */
        //创建图像视图
        if(vkCreateImageView(device,&viewInfo,nullptr,
                             &imageView) != VK_SUCCESS){
            throw std::runtime_error("failed to create texture image view!");
        }
        return imageView;
        //有了图像视图,就可以将图像作为纹理使用,但作为渲染目标,还需要帧缓冲对象
    }
    //创建采样器对象
    void createTextureSampler(){
        //我们会在着色器中使用创建的采样器对象采样纹理数据
        VkSamplerCreateInfo samplerInfo = {};
        samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
        /**
        magFilter 和 minFilter 成员变量用于指定纹理需要放大和缩小时使用
        的插值方法。纹理放大会出现采样过密的问题,纹理缩小会出现采样过疏的问题
          */
        samplerInfo.magFilter = VK_FILTER_LINEAR;
        samplerInfo.minFilter = VK_FILTER_LINEAR;
        /**
        addressModeU、addressModeV 和 addressModeW 用于指定寻址模式。
        这里的 U、V、W 对应 X、Y 和 Z 轴。它们的值可以是下面这些:
        • VK_SAMPLER_ADDRESS_MODE_REPEAT:
            采样超出图像范围时重复纹理
        • VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
            采样超出图像范围时重复镜像后的纹理
        • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
            采样超出图像范围时使用距离最近的边界纹素
        • VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
            采样超出图像范围时使用镜像后距离最近的边界纹素
        • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:
            采样超出图像返回时返回设置的边界颜色

        在这里,我们的采样不会超出图像范围.

          */
        //VK_SAMPLER_ADDRESS_MODE_REPEAT 来实现平铺纹理的效果
        samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        /**
        anisotropyEnable 和 maxAnisotropy 成员变量和各向异性过滤相关。
        通常来说,只要性能允许,我们都会开启各向异性过滤。maxAnisotropy
        成员变量用于限定计算最终颜色使用的样本个数。maxAnisotropy 成员变
        量的值越小,采样的性能表现越好,但采样结果质量较低。目前为止,还
        没有图形硬件能够使用超过 16 个样本,同时即使可以使用超过 16 个样本,
        采样效果的增强也开始变得微乎其微。
          */
        samplerInfo.anisotropyEnable = VK_TRUE;
        samplerInfo.maxAnisotropy = 16;
        /**
        borderColor 成员变量用于指定使用 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
        寻址模式时采样超出图像范围时返回的边界颜色。边界颜色并非可以设置为任意颜色。
        它可以被设置为浮点或整型格式的黑色、白色或透明色
          */
        samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
        /**
        unnormalizedCoordinates 成员变量用于指定采样使用的坐标系统。将
        其设置为 VK_TRUE 时,采样使用的坐标范围为 [0, texWidth) 和 [0,
        texHeight)。将其设置为 VK_FALSE,采样使用的坐标范围在所有轴都是
        [0, 1)。通常使用 VK_FALSE 的情况更常见,这种情况下我们可以使用相
        同的纹理坐标采样不同分辨率的纹理
          */
        samplerInfo.unnormalizedCoordinates = VK_FALSE;
        /**
        通过 compareEnable 和 compareOp 成员变量,我们可以将样本和一
        个设定的值进行比较,然后将比较结果用于之后的过滤操作。通常我们在
        进行阴影贴图时会使用它
          */
        samplerInfo.compareEnable = VK_FALSE;
        samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
        /**
        mipmapMode、mipLodBias、minLod 和 maxLod 成员变量用于设置
        分级细化 (mipmap),它可以看作是过滤操作的一种
          */
        samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
        samplerInfo.mipLodBias = 0.0f;
        samplerInfo.minLod = 0.0f;
        samplerInfo.maxLod = 0.0f;
        /**
        需要注意,采样器对象并不引用特定的 VkImage 对象,它是一个用于
        访问纹理数据的接口。我们可以使用它来访问任意不同的图像,不管图像
        是一维的、二维的、还是三维的。这和一些旧的图形 API 将纹理图像和过
        滤设置绑定在一起进行采样是不同的
          */
        if(vkCreateSampler(device,&samplerInfo,nullptr,
                           &textureSampler) != VK_SUCCESS){
            throw std::runtime_error("failed to create texture sampler!");
        }
    }

        //清除采样器对象
        vkDestroySampler(device,textureSampler,nullptr);
        //清除纹理图像的图像视图对象,
        vkDestroyImageView ( device , textureImageView , nullptr ) ;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力减肥的小胖子5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值