Drawing a triangle/Setup/Base code

文章介绍了如何构建一个基础的Vulkan应用,包括设置通用结构,初始化Vulkan,管理资源,以及集成GLFW来创建窗口。强调了Vulkan对象的生命周期管理和GLFW在禁用OpenGL上下文创建、窗口创建及事件处理的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

General structure

Resource management

Integrating GLFW


General structure

在上一章中,您创建了一个具有所有正确配置的Vulkan项目,并使用示例代码对其进行了测试。在本章中,我们将从以下代码开始:

#include <vulkan/vulkan.h>

#include <iostream>
#include <stdexcept>
#include <cstdlib>

class HelloTriangleApplication {
public:
    void run() {
        initVulkan();
        mainLoop();
        cleanup();
    }

private:
    void initVulkan() {

    }

    void mainLoop() {

    }

    void cleanup() {

    }
};

int main() {
    HelloTriangleApplication app;

    try {
        app.run();
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

我们首先包含了LunarG SDK中的Vulkan标头,它提供了函数、结构和枚举。stdexcept和iostream标头用于报告和传播错误。cstdlib标头提供EXIT_SUCCESS和EXIT_FAILURE宏。

程序本身被封装到一个类中,我们将在其中存储Vulkan对象作为私有类成员,并添加函数来初始化每个对象,这将从initVulkan函数调用。一切准备就绪后,我们进入主循环开始渲染帧。我们将填充mainLoop函数,以包含一个循环,该循环将迭代直到窗口立即关闭。一旦窗口关闭并且mainLoop返回,我们将确保释放清理函数中使用的资源。

如果在执行过程中发生任何类型的致命错误,那么我们将抛出一个std::runtime_error异常和一条描述性消息,该消息将传播回主函数并打印到命令提示符。为了处理各种标准异常类型,我们捕捉了更一般的std::exception。我们将很快处理的一个错误示例是发现某个必需的扩展不受支持。

大致上,本章之后的每一章都将添加一个从initVulkan调用的新函数,以及一个或多个新Vulkan对象到需要在清理结束时释放的私有类成员。

Resource management

就像分配给malloc的每个内存块都需要调用释放一样,我们创建的每个Vulkan对象都需要在不再需要时显式销毁。在C++中,可以使用RAII或<memory>头中提供的智能指针执行自动资源管理。然而,在本教程中,我选择了明确Vulkan对象的分配和释放。毕竟,Vulkan的优势是明确每一个操作以避免错误,所以明确对象的生命周期以了解API的工作原理是很好的。

遵循本教程后,您可以通过编写C++类来实现自动资源管理,这些C++类在构造函数中获取Vulkan对象,并在析构函数中释放它们,或者根据所有权要求,为std::unique_ptr或std::shared_ptr提供自定义删除器。RAII是大型Vulkan项目的推荐模式,但出于学习目的,了解幕后情况总是很好的。

Vulkan对象要么直接使用vkCreateXXX等函数创建,要么通过另一个具有vkAllocateXXX等函数的对象分配。确保某个对象不再在任何地方使用后,您需要使用对应的vkDestroyXXX和vkFreeXXX销毁它。对于不同类型的对象,这些函数的参数通常有所不同,但它们都共享一个参数:pAllocator。这是一个可选参数,允许您为自定义内存分配器指定回调。我们将在教程中忽略此参数,并始终传递nullptr作为参数。

Integrating GLFW

如果你想将Vulkan用于屏幕外渲染,那么它在不创建窗口的情况下工作得非常好,但实际显示一些东西会让你兴奋得多!首先将#include<vulkan/vulkan.h>行替换为

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

这样,GLFW将包含自己的定义并自动加载Vulkan标头。添加initWindow函数,并在其他调用之前从run函数添加对它的调用。我们将使用该函数初始化GLFW并创建一个窗口。

void run() {
    initWindow();
    initVulkan();
    mainLoop();
    cleanup();
}

private:
    void initWindow() {

    }

initWindow中的第一个调用应该是glfwInit(),它初始化GLFW库。因为GLFW最初设计用于创建OpenGL上下文,所以我们需要告诉它不要在后续调用中创建OpenGL上下文:

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

因为处理调整大小的窗口需要特别小心,我们稍后将对此进行研究,所以现在使用另一个窗口提示调用禁用它:

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

现在剩下的就是创建实际的窗口。添加GLFWwindow*窗口;私有类成员,以存储对它的引用,并使用以下命令初始化窗口:

window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr);

前三个参数指定窗口的宽度、高度和标题。第四个参数允许您选择指定要打开窗口的监视器,最后一个参数仅与OpenGL相关。

使用常量而不是硬编码的宽度和高度数字是一个好主意,因为我们将在将来多次引用这些值。我在HelloTriangleApplication类定义上方添加了以下行:

const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;

并将窗口创建调用替换为

window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

您现在应该有一个initWindow函数,它看起来像这样:

void initWindow() {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}

要保持应用程序运行,直到出现错误或窗口关闭,我们需要向mainLoop函数添加一个事件循环,如下所示:

void mainLoop() {
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }
}

这段代码应该是不言自明的。它循环并检查事件,如按下X按钮,直到用户关闭窗口。这也是我们稍后将调用函数来渲染单个帧的循环。

一旦窗口关闭,我们需要通过销毁它并终止GLFW本身来清理资源。这将是我们的第一个清理代码:

void cleanup() {
    glfwDestroyWindow(window);

    glfwTerminate();
}

当您现在运行程序时,应该会看到一个名为Vulkan的窗口出现,直到关闭窗口终止应用程序。现在我们有了Vulkan应用程序的框架,让我们创建第一个Vulkan对象!

### 绘制凯蒂猫的思路 使用 Python 的 Turtle 庿可以实现复杂的图形绘制,包括卡通形象如凯蒂猫。以下是绘制凯蒂猫的主要步骤说明: 1. **初始化环境** 使用 `turtle` 模块设置画布颜色、大小以及标题等基础参数[^2]。 2. **创建海龟对象** 调用 `turtle.Turtle()` 方法创建一个海龟对象,并为其设定初始状态,比如移动到合适的位置以便开始绘制。 3. **绘制头部** 头部可以通过圆弧或者椭圆完成。利用 `circle(radius, extent)` 函数绘制部分圆周来构成脸部轮廓[^4]。 4. **绘制耳朵** 耳朵通常也是两个对称的小半圆或三角形结构,在适当角度下放置于头顶两侧。 5. **添加面部特征** 面部细节包括眼睛、鼻子和嘴巴。这些都可以通过组合基本几何形状(如点、线段、小圆圈)来构建。 6. **装饰与优化** 可以为图像增添更多个性化元素,例如蝴蝶结或其他配饰;还可以调整颜色填充使画面更加生动有趣[^3]。 7. **保存作品并退出程序** 完成所有绘图操作之后记得调用相应命令关闭窗口显示最终成果。 下面给出一段简化版示例代码用于演示如何用Python-Turtle库大致勾勒出Hello Kitty的形象: ```python import turtle as t def draw_circle(size): """Draw a filled circle.""" t.begin_fill() t.circle(size) t.end_fill() # Set up screen and pen. screen = t.Screen() screen.setup(width=800, height=600) screen.title("Drawing Hello Kitty with Python Turtle") pen = t.Turtle() pen.speed('fastest') pen.penup() # Draw face outline - white big circle. pen.color("#FFFFFF", "#FFFFFF") # White color for the face. pen.goto(0, -150) draw_circle(150) # Left ear - black small circle on top-left side of head. pen.color("#000000", "#000000") # Black color for ears. pen.goto(-90, 180) draw_circle(40) # Right ear - same size but mirrored position relative to centerline. pen.goto(90, 180) draw_circle(40) # Add bow (simple red triangle). pen.color("#FF1493", "#FF1493") # Pinkish-red shade chosen here arbitrarily. pen.goto(60, 160) pen.pendown() for _ in range(3): pen.forward(50); pen.right(120) pen.penup() # Simple eyes represented by two smaller circles each colored differently. eyes_positions = [(-50, 50), (50, 50)] eye_colors = ["#000000","#FFFFFF"] for pos,color in zip(eyes_positions, eye_colors[::-1]): pen.color(color, color) pen.goto(*pos) draw_circle(20) # Nose defined simply via another tiny unfilled oval shape at base point between both eyeballs' centers. nose_position=(0,-20) pen.setheading(-90) # Point downwards before drawing vertical ellipse segment representing nose bridge slightly curved upwards towards tip end near mouth area later below this section code block continues... pen.width(5) pen.pencolor('#000000') pen.pendown(); pen.circle(25,.6,None); pen.penup(); t.done() ``` 此脚本仅提供了一个非常基础版本的凯蒂猫外观表示方式,实际应用当中可以根据个人喜好进一步美化和完善设计样式直至满意为止!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值