Vulkan开发实战详解 学习笔记 - vulkan三角形

程序入口模块——main

xcb 窗口 框架

/* 管线布置创作,创作和描述符设置布局数 */
#define NUM_DESCRIPTOR_SETS 1
/* 等待命令缓冲区填充的时间上限 纳秒*/
#define FENCE_TIMEOUT 100000000
#include <cassert>
#include <cstdlib>
#include <xcb/xcb.h>
#include <iostream>
/*xcb窗体信息对象*/
struct WindowInfo {
#define APP_NAME_STR_LEN 80
	char name[APP_NAME_STR_LEN];//窗体标题栏
	xcb_window_t xcb_window;//windows窗体句柄
	xcb_connection_t *xcb_connection;
	int width, height;
};


xcb_window_t xcb_window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
xcb_connection_t *xcb_connection;
xcb_screen_t *screen;

bool quit=false;

void init_connection(struct WindowInfo &info) {

	const xcb_setup_t *setup;
	xcb_screen_iterator_t iter;
	int scr;

	const char *display_envar = getenv("DISPLAY");
	if (display_envar == nullptr || display_envar[0] == '\0') {
		printf("Environment variable DISPLAY requires a valid value.\nExiting ...\n");
		fflush(stdout);
		exit(1);
	}

	xcb_connection = xcb_connect(nullptr, &scr);
	if (xcb_connection_has_error(xcb_connection) > 0) {
		printf(
				"Cannot find a compatible Vulkan installable client driver "
				"(ICD).\nExiting ...\n");
		fflush(stdout);
		exit(1);
	}

	setup = xcb_get_setup(xcb_connection);
	iter = xcb_setup_roots_iterator(setup);
	while (scr-- > 0) xcb_screen_next(&iter);

	screen = iter.data;

}

void handle_xcb_event(const xcb_generic_event_t *event) {
	uint8_t event_code = event->response_type & 0x7f;
	switch (event_code) {
		case XCB_EXPOSE:
			// TODO: Resize window
			break;
		case XCB_CLIENT_MESSAGE:
			break;
		case XCB_KEY_RELEASE: {
			const xcb_key_release_event_t *key = (const xcb_key_release_event_t *)event;

			switch (key->detail) {
				case 0x9:  // Escape
					break;
			}
		} break;

		default:
			break;
	}
}

void run_xcb() {
	xcb_flush(xcb_connection);

	while (!quit) {
		xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection);

		while (event) {
			handle_xcb_event(event);
			free(event);
			event = xcb_poll_for_event(xcb_connection);
		}

	}

}

void create_xcb_window(struct WindowInfo &info, int32_t default_width, int32_t default_height) {
	uint32_t value_mask, value_list[32];

	info.width = default_width;
	info.height = default_height;

	assert(info.width > 0);
	assert(info.height > 0);

	xcb_window = xcb_generate_id(xcb_connection);


	value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
	value_list[0] = screen->black_pixel;
	value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;

	xcb_create_window(xcb_connection, XCB_COPY_FROM_PARENT, xcb_window, screen->root, 0, 0, info.width, info.height, 0,
					  XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list);

	/* Magic code that will send notification when window is destroyed */
	xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection, 1, 12, "WM_PROTOCOLS");
	xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection, cookie, 0);

	xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(xcb_connection, 0, 16, "WM_DELETE_WINDOW");
	atom_wm_delete_window = xcb_intern_atom_reply(xcb_connection, cookie2, 0);

	xcb_change_property(xcb_connection, XCB_PROP_MODE_REPLACE, xcb_window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom);

	free(reply);

	xcb_map_window(xcb_connection, xcb_window);

	// Force the x/y coordinates to 100,100 results are identical in
	// consecutive
	// runs
	const uint32_t coords[] = {100, 100};
	xcb_configure_window(xcb_connection, xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);

	info.xcb_window = xcb_window;
	info.xcb_connection = xcb_connection;
}

void destroy_xcb_window(){
	xcb_destroy_window(xcb_connection, xcb_window);
	xcb_disconnect(xcb_connection);
	free(atom_wm_delete_window);
	quit = true;
}

struct WindowInfo info;

int main(int argc, char **argv) 
{

	init_connection(info);
	create_xcb_window(info, 1366, 768);
	run_xcb();

	return 0;
}

执行

xz@xiaqiu:~/study/vulkan/vulkan/xcb$ 
xz@xiaqiu:~/study/vulkan/vulkan/xcb$ g++ -o window window.cpp -lxcb
xz@xiaqiu:~/study/vulkan/vulkan/xcb$ ./window 

在这里插入图片描述

表1-1  常用的Vulkan基本类型

名称Vulkan类型说明
实例VkInstance用于存储Vulkan程序相关状态的软件结构,可以在逻辑上区分不同的Vulkan应用程序或者同一应用程序内部不同的Vulkan上下文
物理设备VkPhysicalDevice对系统中GPU硬件的抽象,每个GPU对应于一个物理设备。另外,每个实例下可以有多个物理设备
设备VkDevice基于物理设备创建的逻辑设备,本质上是存储信息的软件结构,其中主要保留了与对应物理设备相关的资源。每个物理设备可以对应多个逻辑设备
命令池VkCommandPool服务于高效分配命令缓冲
命令缓冲VkCommandBuffer用于记录组成绘制或计算任务的各个命令,在命令池中分配。若执行的是不变的绘制命令,可以对记录了命令的命令缓冲进行重用
命令缓冲启动信息VkCommandBufferBeginInfo携带了命令缓冲启动时必要信息的对象
命令缓冲提交信息VkSubmitInfo携带了命令缓冲提交给队列执行时必要信息的对象,包括需要等待的信号量数量、等待的信号量列表、命令缓冲数量、命令缓冲列表、触发的信号量数量、触发的信号量列表等
队列家族属性VkQueueFamilyProperties携带了特定家族属性信息的软件结构,包括家族中的数量、能力标志等。每一个家族中可能含有多个能力相近的,常用的家族主要有支持图形任务和计算任务的两大类
队列VkQueue功能为接收提交的任务,将任务按序由所属GPU硬件依次执行
格式VkFormat个枚举类型,包含了Vulkan开发中用到的各种内存组织格式,如VK_FORMAT_R8G8B8A8_UNORM就表示支持RGBA四个色彩通道,每个通道8个数据比特
图像VkImage设备内存的一种使用模式,这种模式下对应的内存用于存储像素数据。其中存储的像素数据可能是来自于纹理图也可能是来自于绘制任务的结果等
图像视图VkImageView配合对象使用,其中携带了对应对象的类型、格式、色彩通道交换设置等方面的信息
交换链VkSwapchainKHR将画面呈现到特定目标平台(如Windows、Android、Linux等)窗体或表面的机制,通过它可以提供多个用于呈现的图像。这些与目标平台相关,可以看作目标平台呈现用KHR表面的抽象接口。持续换帧呈现时交替使用其中的多个执行,避免用户看到绘制过程中的画面引起画面撕裂。一般情况下,交换链中至少有两个用于呈现的,有些设备中数量会更多
帧缓冲VkFrameBuffer为绘制服务,其中可以包含颜色附件用于记录一帧画面中各个像素的颜色值)、深度附件(用于记录一帧画面中各个像素的深度值)、模板附件(用于记录一帧画面中各个像素的模板值)等
缓冲VkBuffer设备内存的一种使用模式,这种模式下对应的内存用于存储各种数据。比如:绘制用顶点信息数据、绘制用一致变量数据等
缓冲描述信息VkDescriptorBufferInfo携带了描述缓冲信息的结构体,包含对应缓冲、内存偏移量、范围等
渲染通道VkRenderPass其中包含了一次绘制任务需要的多方面信息,诸如颜色附件、深度附件情况,子通道列表、子通道相互依赖信息等,用于向驱动描述绘制工作的结构、过程。一般来说,每个渲染通道从开始到结束将产生一帧完成的画面
清除内容VkClearValue包含了每次绘制前清除帧缓冲所用数据的相关值,主要有清除用颜色值、深度值、模板值等
渲染通道启动信息VkRenderPassBeginInfo携带了启动渲染通道时所需的信息,包括对应的渲染通道、渲染区域的位置及尺寸、绘制前的清除数据值等
渲染子通道描述VkSubpassDescription一个渲染通道由多个子通道组成,至少需要一个子通道。每个子通道用一个VkSubpassDescription实例描述,其中包含了此子通道的输入附件、颜色附件、深度附件等方面的信息
描述集布局VkDescriptorSetLayout服务于描述集,给出布局接口。通俗讲就是给出着色器中包含了哪些一致变量、分别是什么类型、绑定编号是什么、对应于哪个管线阶段(比如顶点着色器、片元着色器)等
描述集VkDescriptorSet通过布局接口将所需资源和着色器连接起来,帮助着色器读入并理解资源中的数据,比如着色器中的采样器类型、一致变量缓冲等
写入描述集VkWriteDescriptorSet用于绘制前更新着色器所需的一致变量等
描述集池VkDescriptorPool用于高效地分配描述集
管线布局VkPipelineLayout描述管线整体布局,包括有哪些推送常量、有哪些描述集等
管线VkPipeline包含了执行指定绘制工作对应管线的各方面信息,诸如管线布局、顶点数据输入情况、图元组装设置、光栅化设置、混合设置、视口与剪裁设置、深度及模板测试设置、多重采样设置等
着色器阶段创建信息VkPipelineShaderStageCreateInfo携带了单个着色器阶段信息的对象,包括着色器的SPIR-V模块、着色器主方法名称、着色器对应阶段(比如顶点着色器、片元着色器、几何着色器、曲面细分着色器)等
顶点输入绑定描述VkVertexInputBindingDescription用于描述管线的顶点数据输入情况,包括绑定点编号、数据输入频率(比如每顶点一套数据)、数据间隔等
顶点输入属性描述VkVertexInputAttributeDescription描述顶点输入的某项数据信息(比如顶点位置、顶点颜色),包括绑定点编号、位置编号、数据格式、偏移量等
管线缓冲VkPipelineCache为高效地创建管线提供支持
格式属性VkFormatProperties用于存储指定格式类型(比如VK_FORMAT_D16_UNORM)的格式属性,包括线性瓦片特性标志、最优化瓦片特性标志、缓冲特性标志等
物理设备内存属性VkPhysicalDeviceMemoryProperties用于存储获取的基于指定GPU的设备内存属性,包括内存类型数量、内存类型列表、内存堆数量、内存堆列表等
设备内存VkDeviceMemory设备内存的逻辑抽象,前面提到的缓冲(VkBuffer)、图像(VkImage)都需要绑定设备内存才能正常工作
信号量VkSemaphore用于一个设备(GPU)内部相同或不同队列并发执行任务时的同步工作,一般与方法VkQueueSubmit配合使用,以确保通过VkQueueSubmit方法提交的任务在指定未触发前阻塞直至触发后才执行。要特别注意的是,若有多个提交的任务同时等待同一个触发,则此的触发仅仅会被一个等待的任务接收到,其他等待的任务还将继续等待。这里的“同步”指的是并发执行任务时解决冲突的一种策略,有兴趣的读者可以进一步查阅相关资料
栅栏VkFence用于主机和设备之间的同步,通俗地讲就是用于CPU和GPU并发执行任务时的同步
KHR表面VkSurfaceKHR此类对象服务于帧画面的呈现
KHR表面能力VkSurfaceCapabilitiesKHR携带了用于呈现画面的表面相关呈现能力的信息,比如画面尺寸范围、交换链中的图像数量、是否支持屏幕变换等
呈现信息VkPresentInfoKHR携带了执行呈现时所需的一些信息,包括需要等待的信号量数量、信号量列表、交换链的数量、交换链列表、此次呈现的图像在交换链中的索引等

MyVulkanManager:包含一些静态函数和方法

class MyVulkanManager
{
public:
	//窗口辅助结构体
	static struct WindowInfo info;
	//vulkan绘制的循环标志
	static bool loopDrawFlag;
	static std::vector<const char *> instanceExtensionNames;//需要使用的实例扩展名称列表
	static VkInstance instance;//Vulkan实例
	static uint32_t gpuCount;//物理设备数量
	static  std::vector<VkPhysicalDevice> gpus;	//物理设备列表
	static uint32_t queueFamilyCount;//物理设备对应的队列家族数量
	static std::vector<VkQueueFamilyProperties> queueFamilyprops;//物理设备对应的队列家族属性列表
	static uint32_t queueGraphicsFamilyIndex;//支持图形工作的队列家族索引
	static VkQueue queueGraphics;//支持图形工作的队列
	static uint32_t queuePresentFamilyIndex;//支持显示工作的队列家族索引
	static std::vector<const char *> deviceExtensionNames;	//所需的设备扩展名称列表
	static VkDevice device;	//逻辑设备
	static VkCommandPool cmdPool;//命令池
	static VkCommandBuffer cmdBuffer;//命令缓冲
	static VkCommandBufferBeginInfo cmd_buf_info;//命令缓冲启动信息
	static VkCommandBuffer cmd_bufs[1];	//供提交执行的命令缓冲数组
	static VkSubmitInfo submit_info[1];	//命令缓冲提交执行信息数组
	static uint32_t screenWidth;//屏幕宽度
	static uint32_t screenHeight;//屏幕高度
	static VkSurfaceKHR surface;//KHR表面
	static std::vector<VkFormat> formats;//KHR表面支持的格式
	static VkSurfaceCapabilitiesKHR surfCapabilities;//表面的能力
	static uint32_t presentModeCount;//显示模式数量
	static std::vector<VkPresentModeKHR> presentModes;//显示模式列表
	static VkExtent2D swapchainExtent;//交换链尺寸
	static VkSwapchainKHR swapChain;//交换链
	static uint32_t swapchainImageCount;//交换链中的图像数量
	static std::vector<VkImage> swapchainImages;//交换链中的图像列表
	static std::vector<VkImageView> swapchainImageViews;//交换链对应的的图像视图列表
	static VkFormat depthFormat;//深度图像格式
	static VkFormatProperties depthFormatProps;	//物理设备支持的深度格式属性
	static VkImage depthImage;//深度缓冲图像
	static VkPhysicalDeviceMemoryProperties memoryroperties;//物理设备内存属性
	static VkDeviceMemory memDepth;	//深度缓冲图像对应的内存
	static VkImageView depthImageView;//深度缓冲图像视图
	static VkSemaphore imageAcquiredSemaphore;//渲染目标图像获取完成信号量
	static uint32_t currentBuffer;//从交换链中获取的当前渲染用图像对应的缓冲编号
	static VkRenderPass renderPass;//渲染通道
	static VkClearValue clear_values[2];//渲染通道用清除帧缓冲深度、颜色附件的数据
	static VkRenderPassBeginInfo rp_begin;//渲染通道启动信息
	static VkFence taskFinishFence;//等待任务完毕的栅栏
	static VkPresentInfoKHR present;//呈现信息
	static VkFramebuffer* framebuffers;//帧缓冲序列首指针
	static ShaderQueueSuit_Common* sqsCL;//着色器管线指针
	static DrawableObjectCommonLight* triForDraw;//绘制用三色三角形物体对象指针
	//三角形旋转角度
	static float xAngle;
	static float yAngle;
	static float zAngle;

	//一般来说,完整的Vulkan图形应用程序包含创建Vulkan实例、获取物理设备列表创建逻辑设备、创建命令缓冲、创建渲染通道、创建帧缓冲、创建绘制用的物体、初始化渲染管线、创建栅栏和初始化呈现信息、初始化基本变换矩阵、摄像机矩阵和投影矩阵、执行绘制、销毁相关对象等模块,具体内容如下。
	static void init_vulkan_instance();//创建Vulkan实例
	static void enumerate_vulkan_phy_devices();//初始化物理设备
	static void create_vulkan_devices();//创建逻辑设备
	static void create_vulkan_CommandBuffer();//创建命令缓冲
	static void create_vulkan_swapChain();//初始化交换链
	static void create_vulkan_DepthBuffer();//创建深度缓冲相关
	static void create_render_pass();//创建渲染通道
	static void init_queue();//获取设备中支持图形工作的队列
	static void create_frame_buffer();//创建帧缓冲
	static void createDrawableObject();//创建绘制用物体
	static void drawObject();//执行场景中的物体绘制
	static void doVulkan();//启动线程执行Vulkan任务
	static void initPipeline();//初始化管线
	static void createFence();//创建栅栏
	static void initPresentInfo();//初始化显示信息
	static void initMatrix();//初始化矩阵
	static void flushUniformBuffer();//将一致变量数据送入缓冲
	static void flushTexToDesSet();//将纹理等数据与描述集关联
	static void destroyFence();//销毁栅栏
	static void destroyPipeline();//销毁管线
	static void destroyDrawableObject();//销毁绘制用物体
	static void destroy_frame_buffer();//销毁帧缓冲
	static void destroy_render_pass();//销毁渲染通道
	static void destroy_vulkan_DepthBuffer();//销毁深度缓冲相关
	static void destroy_vulkan_swapChain();//销毁交换链
	static void destroy_vulkan_CommandBuffer();//销毁命令缓冲
	static void destroy_vulkan_devices();//销毁逻辑设备
	static void destroy_vulkan_instance();//销毁实例
};

PathData.cpp 主要是访问着色器的代码

#ifndef PathData_H
#define PathData_H
#define VertShaderPath  "../shaders/vertshadertext.vert.inc";
#define FragShaderPath  "../shaders/fragshadertext.frag.inc";
#endif
	std::vector<unsigned int> vtx_spv = 
	{
		#include VertShaderPath
	};
	std::vector<unsigned int> frag_spv = 
	{
		#include FragShaderPath
	};

,Vulkan没有指定官方的着色器编程语言,而是采用SPIR-V二进制中间格式来进行表示。但对于开发人员来说,不大可能直接使用SPIR-V进行开发,一般都需要基于某种着色器编程语言开发着色器然后再编译为SPIR-V格式。本书案例中的着色器都选用了GLSL着色器编程语言进行开发,这对于熟悉或了解一些OpenGL的开发人员来说应该是最好的选择了。

1.首先介绍的是顶点着色器,其每顶点执行一次。本节案例的顶点着色器主要包括计算顶点的最终绘制位置以及将顶点颜色传递给片元着色器,具体代码如下。

//第1行给定了所用GLSL(OpenGL Shading Language——OpenGL着色语言)的版本,不同版本GLSL支持的特性和功能不尽相同。
#version 400
//开启了GL_ARB_separate_shader_objects和GL_ARB_shading_language_420pack扩展,在Vulkan中如果想使用着色器进行开发,一般需要开启这两个扩展。
#extension GL_ARB_separate_shader_objects : enable//启动GL_ARB_separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//启动GL_ARB_shading_language_420pack
//声明了一致块myBufferVals,其中包含用于接收总变换矩阵数据的成员mvp,同时指定了此一致块的绑定点编号为0。
layout (std140,set = 0, binding = 0) uniform bufferVals 
{//一致块
    mat4 mvp;//总变换矩阵
} myBufferVals;
layout (location = 0) in vec3 pos;//传入的物体坐标系顶点位置
layout (location = 1) in vec3 color;//传入的顶点颜色
layout (location = 0) out vec3 vcolor;//传到片元着色器的顶点颜色
//定义了输出接口块gl_PerVertex,其中包含内建输出变量gl_Position,此内建变量负责接收最终的顶点位置并传递到渲染管线进行后继处理。
out gl_PerVertex 
{//输出的接口块
	vec4 gl_Position;//顶点最终位置
};
void main() 
{//主函数
    //为顶点着色器的主方法,首先将最终变换矩阵与物体坐标系下的顶点坐标相乘,得到顶点最终位置,然后将计算得到的顶点最终位置传递给内建变量gl_Position。最后,将传入到顶点着色器的顶点颜色数据传递给片元着色器。
    gl_Position = myBufferVals.mvp * vec4(pos,1.0);//计算最终顶点位置
    vcolor=color;//传递顶点颜色给片元着色器
}

片元着色器

#version 400 着色器版本号
#extension GL_ARB_separate_shader_objects : enable//启动GL_ARB_separate_shader_objects
#extension GL_ARB_shading_language_420pack : enable//启动GL_ARB_shading_language_420pack
//顶点着色器传入的顶点颜色数据以及输出到渲染管线的片元颜色值。
layout (location = 0) in vec3 vcolor;//顶点着色器传入的顶点颜色数据
layout (location = 0) out vec4 outColor;//输出到渲染管线的片元颜色值
void main() 
{
    //一个分量代表4个色彩通道(RGBA)中的A通道
   outColor=vec4(vcolor.rgb,1.0);//将顶点着色器传递过来的颜色值输出
}

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vulkan被称为OpenGL的接班人,性能果然是霸气外漏,更能够承载下一个时代的图形渲染编程。 GPU高性能渲染的课题进入了一个新的阶段,对于计算细节的控制,多核CPU多线程渲染以及高性能算法的灵活设计需求日益旺盛。图形程序员需要有更加强力且灵活的工具,来“解锁”我们自身的控制能力,OpenGL的较高度封装性以及单纯的状态机模式显然已经无法适应现代化图形渲染的强烈需求。为什么要学习Vulkan?正如前言所说,Vulkan已经成为了下一个时代的图形渲染主流API,早已经被各大商业引擎(Unreal Engine、Unity3D)所支持。那么我们的同学就有如下问题需要明晰:1 作为游戏程序员我们只学会了UE或者Unity3D,那么就只能作为一个普通的程序员,如果能够结合Vulkan学习对商用引擎理解更加深刻,就可以更好的发挥引擎威力甚至更改引擎的源代码,实现更多的可能,让你在各大公司之间都“蛇形走位,游刃有余” 2 作为自研引擎工作人员,你可能在工业软件领域从业、也有可能在影视渲染领域从业、也可能在其他的图形系统领域(军工、GIS、BIM)等领域,那么熟练的掌握Vulkan就可以针对自己公司的不同领域需求进行不同的引擎定制开发,从而获得牢不可破的地位,对于自身职业发展有着极大的优势! 总而言之,越早学习Vulkan,就越能与别人拉开差距,让Vulkan称为你升职加薪、壮大不可替代性的核武器! 课程简介:本课程详细讲解了Vulkan从小白到入门的基础理论+实践知识,对于每一个知识点都会带领学员通过代码来实现功能。其中涵盖了计算机图形学基础理论,计算机图形学数学推导,Vulkan基础系统设计理论,基础单元(实例,设备,交换链), 渲染管线,RenderPass, 指令与多线程, 顶点描述与实验, Uniform与描述符, 图像与采样, 深度与反走样,模型与摄像机等内容;课程中会对Vulkan复杂抽象的API进行一次包装层的封装,将相关的API都进行聚合与接口设计,作为游戏或者图形引擎来讲,这是至关重要的第一步。这一个封装步骤,也被称为API-Wrapper,经过包装后的类库,同学可以在此之上根据自己的具体需求进行扩展,从而得到最适合自己的类库内容。本课程为系列化课程,在铸造基石篇章之后,会继续使用本包装类库进行改良,并且实现Vulkan API下的各类效果以及高级特性的开发教学。 课程优势:1 本课程会从计算机图形学的基础渲染管线原理出发,带领0基础的同学对计算机图形学进行快速认知,且对必要的知识点进行筛选提炼,去掉冗余繁杂的教学内容,更加适合新手对Vulkan渲染体系入门了解。 2 本课程会对计算机图形学所涉及的数学知识及如何应用到渲染当中,进行深入的讲解,带领同学对每一行公式展开认识,从三维世界如何映射到二维的屏幕,在学习完毕后会有清晰的知识体系 3 本课程会带领同学认知每一个Vulkan的API,并且在代码当中插入详细的注释,同学们在学习的时候就可以参照源代码进行一系列尝试以及学后复习 4 本课程所设计的包装层,会带领同学一行一行代码实现,现场进行Debug,对于Vulkan常出现的一些问题进行深入探讨与现场纠正  学习所得:1 同学们在学习后可以完全了解从三维世界的抽象物体,如何一步步渲染称为一个屏幕上的像素点。2 同学们在学习后可以完全掌握基础的Vulkan图形API,并且了解Vulkan当中繁多的对象之间相互的联系,从而可以设计更好的图形程序3 同学们在跟随课程进行代码编写后,可以获得一个轻量级的Vulkan底层API封装库(Wrapper),从而可以在此之上封装上层的应用,得到自己的迷你Vulkan图形渲染引擎当然,在达到如上三点之后,如果可以更进一步学习Vulkan的进阶课程,同学们可以获得更好的职业发展,升职加薪之路会更加清晰,成为公司不可替代的强力工程师 本课程含有全套源代码,同学购买后,可以在课程附件当中下载 完全不懂图形学可以学习么?使用层面上来讲是没有问题的,老师在每个api讲解的时候,都会仔细分析api背后的原理,所以可以跟随下来的话,能够编程与原理相融,学会使用 数学不好可以学习么?学习图形类课程,最好能够入门级别的线性代数,具体说就是: 1 向量操作 2 矩阵乘法 3 矩阵的逆、转置 这几个点就足够 学习后对就业面试有什么作用?目前类似Vulkan的渲染知识是一切引擎的基础,只要能够跟随每一节课写代码做下来,游戏公司、工业软件公司等都是非常容易进去的,因为原理层面已经通晓,面试就会特别有优势。同学可以在简历上写熟悉VulkanAPI并且有代码经验,对于建立筛选以及面试都会有很大的帮助,对于薪资也会有大幅度提升
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值