跟着cherno手搓游戏引擎【21】shaderLibrary(shader管理类)

news2024/10/5 17:18:48

前置:

ytpch.h:

#pragma once
#include<iostream>
#include<memory>
#include<utility>
#include<algorithm>
#include<functional>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<sstream>
#include<array>
#ifdef YT_PLATFORM_WINDOWS
#include<Windows.h>
#endif // YT_PLATFORM_WINDOWS


创建glsl文件:

 

Texture.glsl:

		#type vertex
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		layout(location = 1) in vec2 a_TexCoord;

		uniform mat4 u_ViewProjection;
		uniform mat4 u_Transform;
		
		out vec2 v_TexCoord;
		out vec3 v_Position;

		void main(){
		v_TexCoord=a_TexCoord;
		v_Position=a_Position;
		gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
		}

		#type fragment
		#version 330 core
		layout(location = 0) out vec4 color;
		in vec3 v_Position;
		in vec2 v_TexCoord;
		uniform sampler2D u_Texture ;
		void main(){
		color = texture(u_Texture, v_TexCoord);	
		}
		

抽象:

Shader.h:

#pragma once
#include <string>
#include"YOTO/Core.h"
namespace YOTO {

	class Shader {

	public:
		virtual~Shader()=default;
		virtual void Bind()const=0;
		virtual void UnBind()const=0;

		virtual const std::string& GetName()const = 0;

		static Ref<Shader> Create(const std::string& filepath);
		static Ref<Shader> Create(const std::string&name, const std::string& vertexSrc, const std::string& fragmentSrc);

	};
	class ShaderLibrary {
	public:
		void Add(const Ref<Shader>& shader);
		void Add(const std::string &name,const Ref<Shader>& shader);
		Ref<Shader> Load(const std::string filepath);
		Ref<Shader> Load(const std::string &name,const std::string filepath);
		Ref<Shader> Get(const std::string& name);
		bool Exists(const std::string& name);
	private:
		std::unordered_map<std::string,Ref<Shader>> m_Shaders;

	};
}

Shader.cpp:

#include "ytpch.h"
#include "Shader.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLShader.h"
namespace YOTO {
	Ref<Shader> Shader::Create(const std::string& filepath)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Shader:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return std::make_shared <OpenGLShader>(filepath);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}
	Ref<Shader> Shader::Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Shader:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return std::make_shared <OpenGLShader>(name,vertexSrc, fragmentSrc);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}
	void ShaderLibrary::Add(const Ref<Shader>& shader)
	{
		auto& name = shader->GetName();
		Add(name, shader);
	}
	void ShaderLibrary::Add(const std::string& name, const Ref<Shader>& shader)
	{
	
		YT_CORE_ASSERT(!Exists(name), "ShaderLibrary:shader已经存在了")
			m_Shaders[name] = shader;
	}
	Ref<Shader> ShaderLibrary::Load(const std::string filepath)
	{
		auto shader = Shader::Create(filepath);
		Add(shader);
		return shader;
	}
	Ref<Shader> ShaderLibrary::Load(const std::string& name, const std::string filepath)
	{
		auto shader = Shader::Create(filepath);
		Add(shader);
		return shader;
	}
	Ref<Shader> ShaderLibrary::Get(const std::string& name)
	{YT_CORE_ASSERT(Exists(name),"ShaderLibrary:未找到shader")
		return m_Shaders[name];
	}
	bool ShaderLibrary::Exists(const std::string& name)
	{
		return m_Shaders.find(name)!=m_Shaders.end();
	}
}

实现:

OpenGLShader.h:

#pragma once
#include <string>
#include "YOTO/Renderer/Shader.h"
#include <glm/glm.hpp>
typedef unsigned int GLenum;
namespace YOTO {

	class OpenGLShader:public Shader {

	public:
		OpenGLShader(const std::string& filepath);
		OpenGLShader(const std::string &name,const std::string& vertexSrc, const std::string& fragmentSrc);
		~OpenGLShader();
		void Bind()const override;
		void UnBind()const override;
		virtual const std::string& GetName()const override { return m_Name; }
		void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);
		void UploadUniformMat3(const std::string& name, const glm::mat3& matrix);

		void UploadUniformFloat4(const std::string& name, const glm::vec4& values);
		void UploadUniformFloat3(const std::string& name, const glm::vec3& values);
		void UploadUniformFloat2(const std::string& name, const glm::vec2& values);
		void UploadUniformFloat(const std::string& name, float values);

		void UploadUniformInt(const std::string& name, int values);
	private:
		std::string ReadFile(const std::string filepath);
		std::unordered_map<GLenum,std::string> PreProcess(const std::string& source);
		void Compile(const std::unordered_map<GLenum, std::string>& shaderSources);
	private:
		uint32_t m_RendererID;
		std::string m_Name;
	}
	;
} 

OpenGLShader.cpp:

#include "ytpch.h"
#include "OpenGLShader.h"

#include <glad/glad.h>
#include <YOTO/Log.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {
	static GLenum ShaderTypeFromString(const std::string& type) {
		if (type == "vertex") {
			return GL_VERTEX_SHADER;
		}
		if (type == "fragment" || type == "pixel") {
			return GL_FRAGMENT_SHADER;
		}
		YT_CORE_ASSERT(false, "不知道的shader类型");
		return 0;
	}
	
	OpenGLShader::OpenGLShader(const std::string& filepath)
	{
		std::string source = ReadFile(filepath);
		YT_CORE_ASSERT(source.size(), "GLSL读取的字符串为空");
		auto shaderSources = PreProcess(source);
		Compile(shaderSources);


		auto lastSlash = filepath.find_last_of("/\\");
		lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1;
		auto lastDot = filepath.rfind('.');
		auto count = lastDot == std::string::npos ? filepath.size() - lastSlash : lastDot - lastSlash;
		m_Name=filepath.substr(lastSlash, count);
	}
	OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
	:m_Name(name){
		std::unordered_map<GLenum, std::string >sources;
		sources[GL_VERTEX_SHADER] = vertexSrc;
		sources[GL_FRAGMENT_SHADER] = fragmentSrc;
		Compile(sources);
	}
	OpenGLShader::~OpenGLShader()
	{
		glDeleteProgram(m_RendererID);
	}

	std::string OpenGLShader::ReadFile(const std::string filepath)
	{
		std::string result;
		std::ifstream in(filepath, std::ios::in | std::ios::binary);
		if (in) {
			in.seekg(0, std::ios::end);			// 将指针放在最后面
			result.resize(in.tellg());			// 初始化string的大小, in.tellg()返回位置
			in.seekg(0, std::ios::beg);			// in指回头部
			in.read(&result[0], result.size());	// in读入放在result指向的内存中
		}
		else {
			YT_CORE_ERROR("不能打开文件:{0}", filepath);
		}
		return result;
	}
	std::unordered_map<GLenum, std::string> OpenGLShader::PreProcess(const std::string& source)
	{
		std::unordered_map<GLenum, std::string> shaderSources;

		std::string typeToken = "#type";
		size_t typeTokenLen = typeToken.size();
		size_t findCurPos = source.find(typeToken, 0);
		size_t findNextPos = findCurPos;
		while (findNextPos != std::string::npos) {
			size_t curlineEndPos = source.find_first_of("\r\n", findCurPos);///r/n写错为/r/n
			YT_CORE_ASSERT(curlineEndPos != std::string::npos, "解析shader失败");
			size_t begin = findCurPos + typeTokenLen + 1;

			std::string type = source.substr(begin, curlineEndPos - begin);// 获取到是vertex还是fragment
			YT_CORE_ASSERT(ShaderTypeFromString(type), "无效的shader的类型	");

			size_t nextLinePos = source.find_first_not_of("\r\n", curlineEndPos);
			findNextPos = source.find(typeToken, nextLinePos);
			// 获取到具体的shader代码
			shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, findNextPos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));

			findCurPos = findNextPos;
		}
		return shaderSources;
		/*
			用find,而不是find_firtst_of,因为
			find返回完全匹配的字符串的的位置;
			find_first_of返回被查匹配字符串中某个字符的第一次出现位置。

			std::string::npos是一个非常大的数
			source.substr(0, source.size() + 10000)截取到从头到末尾,不会报错
		*/
	}

	void OpenGLShader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources)
	{
		GLuint program = glCreateProgram();
		YT_CORE_ASSERT(shaderSources.size()<=2,"OpenGLShader:shader只支持两种!")
		std::array<GLenum,2>glShaderIDs;
		int glShaderIDIndex=0;
		for (auto& kv : shaderSources) {
			GLenum type = kv.first;
			const std::string& source = kv.second;
			// Create an empty vertex shader handle
			GLuint shader = glCreateShader(type);
			// Send the vertex shader source code to GL
			// Note that std::string's .c_str is NULL character terminated.
			const GLchar* sourceCStr = source.c_str();
			glShaderSource(shader, 1, &sourceCStr, 0);
			// Compile the vertex shader
			glCompileShader(shader);
			GLint isCompiled = 0;
			glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
			if (isCompiled == GL_FALSE)
			{
				GLint maxLength = 0;
				glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
				// The maxLength includes the NULL character
				std::vector<GLchar> infoLog(maxLength);
				glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
				// We don't need the shader anymore.
				glDeleteShader(shader);
				// Use the infoLog as you see fit.
				// In this simple program, we'll just leave
				YT_CORE_ERROR("{0} ", infoLog.data());
				YT_CORE_ASSERT(false, "shader 编译失败!");
				break;
			}
			// Attach our shaders to our program
			glAttachShader(program, shader);
			glShaderIDs[glShaderIDIndex++]=shader;
		}

		// Link our program
		glLinkProgram(program);
		// Note the different functions here: glGetProgram* instead of glGetShader*.
		GLint isLinked = 0;
		glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);
		if (isLinked == GL_FALSE)
		{
			GLint maxLength = 0;
			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
			// The maxLength includes the NULL character
			std::vector<GLchar> infoLog(maxLength);
			glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
			// We don't need the program anymore.
			glDeleteProgram(program);
			// Don't leak shaders either.
			for (auto id : glShaderIDs) {
				glDeleteShader(id);
			}
			// Use the infoLog as you see fit.
			// In this simple program, we'll just leave
			YT_CORE_ERROR("{0} ", infoLog.data());
			YT_CORE_ASSERT(false, "shader link failure!");
			return;
		}
		// Always detach shaders after a successful link.
		for (auto id : glShaderIDs) {
			glDetachShader(program, id);
		}
		m_RendererID = program;

	}

	void OpenGLShader::Bind() const
	{
		glUseProgram(m_RendererID);
	}
	void OpenGLShader::UnBind() const
	{
		glUseProgram(0);
	}
	void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniformMatrix4fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix));

	}
	void OpenGLShader::UploadUniformMat3(const std::string& name, const glm::mat3& matrix)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniformMatrix3fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix)); 
	}
	void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform4f(loacation, values.x, values.y, values.z, values.w);

	}
	void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform3f(loacation, values.x, values.y, values.z);
	}
	void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform2f(loacation, values.x, values.y);
	}
	void OpenGLShader::UploadUniformFloat(const std::string& name, float values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform1f(loacation, values);
	}
	void OpenGLShader::UploadUniformInt(const std::string& name, int values)
	{
		GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());
		glUniform1i(loacation, values);
	}
	
}

调用:

SandboxApp.cpp:

#include<YOTO.h>
#include "imgui/imgui.h"
#include<stdio.h>
#include <glm/gtc/matrix_transform.hpp>
#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>

class ExampleLayer:public YOTO::Layer
{
public:
	ExampleLayer()
	:Layer("Example"),  m_Camera(-2.0f, 2.0f, -2.0f, 2.0f), m_CameraPosition(0){
		uint32_t indices[3] = { 0,1,2 };
		float vertices[3 * 7] = {
			-0.5f,-0.5f,0.0f, 0.8f,0.2f,0.8f,1.0f,
			0.5f,-0.5f,0.0f,  0.2f,0.3f,0.8f,1.0f,
			0.0f,0.5f,0.0f,   0.8f,0.8f,0.2f,1.0f,
		};

		m_VertexArray.reset(YOTO::VertexArray::Create());


		YOTO::Ref<YOTO::VertexBuffer> m_VertexBuffer;
		m_VertexBuffer.reset(YOTO::VertexBuffer::Create(vertices, sizeof(vertices)));

		{
			YOTO::BufferLayout setlayout = {

	{YOTO::ShaderDataType::Float3,"a_Position"},
		{YOTO::ShaderDataType::Float4,"a_Color"}
			};
			m_VertexBuffer->SetLayout(setlayout);

		}

		m_VertexArray->AddVertexBuffer(m_VertexBuffer);


		YOTO::Ref<YOTO::IndexBuffer>m_IndexBuffer;
		m_IndexBuffer.reset(YOTO::IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t)));

		m_VertexArray->AddIndexBuffer(m_IndexBuffer);

		std::string vertexSource = R"(
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		layout(location = 1) in vec4 a_Color;
		uniform mat4 u_ViewProjection;
		uniform mat4 u_Transform;
		out vec3 v_Position;
		out vec4 v_Color;
		void main(){
		v_Position=a_Position;
		v_Color=a_Color;
		gl_Position =u_ViewProjection *u_Transform* vec4( a_Position,1.0);
		}
		)";
		//绘制颜色
		std::string fragmentSource = R"(
		#version 330 core
		layout(location = 0) out vec4 color;
		in vec3 v_Position;
		in vec4 v_Color;
		void main(){
		color=vec4(v_Color);
		}
		)";
		m_Shader=(YOTO::Shader::Create("VertexPosColor", vertexSource, fragmentSource));

		///测试/

		m_SquareVA.reset(YOTO::VertexArray::Create());

		float squareVertices[5 * 4] = {
			-0.5f,-0.5f,0.0f, 0.0f,0.0f,
			0.5f,-0.5f,0.0f,  1.0f,0.0f,
			0.5f,0.5f,0.0f,   1.0f,1.0f,
			-0.5f,0.5f,0.0f,  0.0f,1.0f,
		};
		YOTO::Ref<YOTO::VertexBuffer> squareVB;
		squareVB.reset(YOTO::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
		squareVB->SetLayout({
			{YOTO::ShaderDataType::Float3,"a_Position"},
				{YOTO::ShaderDataType::Float2,"a_TexCoord"}
			});
		m_SquareVA->AddVertexBuffer(squareVB);
		uint32_t squareIndices[6] = { 0,1,2,2,3,0 };
		YOTO::Ref<YOTO::IndexBuffer> squareIB;

		squareIB.reset((YOTO::IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t))));

		m_SquareVA->AddIndexBuffer(squareIB);

		//测试:
		std::string BlueShaderVertexSource = R"(
		#version 330 core
		layout(location = 0) in vec3 a_Position;
		uniform mat4 u_ViewProjection;
		uniform mat4 u_Transform;

		out vec3 v_Position;
		void main(){
		v_Position=a_Position;
		gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
		}
		)";
		//绘制颜色
		std::string BlueShaderFragmentSource = R"(
		#version 330 core
		layout(location = 0) out vec4 color;

		in vec3 v_Position;
		uniform vec3 u_Color;
		void main(){
		color=vec4(u_Color,1.0);
		}
		)";
		m_BlueShader=(YOTO::Shader::Create("FlatColor", BlueShaderVertexSource, BlueShaderFragmentSource));

	auto textureShader=	m_ShaderLibrary.Load("assets/shaders/Texture.glsl");
		m_Texture=YOTO::Texture2D::Create("assets/textures/Checkerboard.png");
		m_ChernoLogo= YOTO::Texture2D::Create("assets/textures/ChernoLogo.png");
		std::dynamic_pointer_cast<YOTO::OpenGLShader>(textureShader)->Bind();
		std::dynamic_pointer_cast<YOTO::OpenGLShader>(textureShader)->UploadUniformInt("u_Texture", 0);
	}
	void OnImGuiRender() override {
		ImGui::Begin("设置");
		ImGui::ColorEdit3("正方形颜色", glm::value_ptr(m_SquareColor));
		ImGui::End();
	}
	void OnUpdate(YOTO::Timestep ts)override {
		//YT_CLIENT_TRACE("delta time {0}s ({1}ms)", ts.GetSeconds(), ts.GetMilliseconds());
	

		if (YOTO::Input::IsKeyPressed(YT_KEY_LEFT)) {
			m_CameraPosition.x -= m_CameraMoveSpeed* ts;
		}
		else if (YOTO::Input::IsKeyPressed(YT_KEY_RIGHT)) {
			m_CameraPosition.x += m_CameraMoveSpeed * ts;
		}
		if (YOTO::Input::IsKeyPressed(YT_KEY_DOWN)) {
			m_CameraPosition.y -= m_CameraMoveSpeed * ts;
		}
		else if (YOTO::Input::IsKeyPressed(YT_KEY_UP)) {
			m_CameraPosition.y += m_CameraMoveSpeed * ts;
		}
		if (YOTO::Input::IsKeyPressed(YT_KEY_A)) {
			m_CameraRotation += m_CameraRotationSpeed * ts;
		}else if (YOTO::Input::IsKeyPressed(YT_KEY_D)) {
			m_CameraRotation -= m_CameraRotationSpeed * ts;
		}

		YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
		YOTO::RenderCommand::Clear();
		m_Camera.SetPosition(m_CameraPosition);
		m_Camera.SetRotation(m_CameraRotation);
		YOTO::Renderer::BeginScene(m_Camera);
		{
			static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f)); 
			glm::vec4  redColor(0.8f, 0.3f, 0.3f, 1.0f);
			glm::vec4  blueColor(0.2f, 0.3f, 0.8f, 1.0f);

	/*		YOTO::MaterialRef material = new YOTO::MaterialRef(m_FlatColorShader);
			YOTO::MaterialInstaceRef mi = new YOTO::MaterialInstaceRef(material);
			mi.setValue("u_Color",redColor);
			mi.setTexture("u_AlbedoMap", texture);
			squreMesh->SetMaterial(mi);*/

			std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->Bind();
			std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->UploadUniformFloat3("u_Color",m_SquareColor);
			for (int y = 0; y < 20; y++) {
				for (int x = 0; x <20; x++)
				{

					glm::vec3 pos(x * 0.105f,y* 0.105f, 0.0);
					glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * scale;
					/*if (x % 2 == 0) {
						m_BlueShader->UploadUniformFloat4("u_Color", redColor);
					}
					else {
						m_BlueShader->UploadUniformFloat4("u_Color", blueColor);
					}*/
		

					YOTO::Renderer::Submit(m_BlueShader, m_SquareVA, transform);
				}
			}
			
			auto textureShader = m_ShaderLibrary.Get("Texture");
			m_Texture->Bind();
			YOTO::Renderer::Submit(textureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
			m_ChernoLogo->Bind();
			YOTO::Renderer::Submit(textureShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));

			//YOTO::Renderer::Submit(m_Shader, m_VertexArray);


			YOTO::Renderer::EndScene();
		}

	}
	void OnEvent(YOTO::Event& event)override {
		/*if (event.GetEventType() == YOTO::EventType::KeyPressed) {
		YOTO:: KeyPressedEvent& e = (YOTO::KeyPressedEvent&)event;
		YT_CLIENT_TRACE("ExampleLayer:{0}",(char)e.GetKeyCode());
		if (e.GetKeyCode()==YT_KEY_TAB) {
			YT_CLIENT_INFO("ExampleLayerOnEvent:TAB按下了");
		}}*/
		//YT_CLIENT_TRACE("SandBoxApp:测试event{0}", event);




	}


private:
	YOTO::ShaderLibrary m_ShaderLibrary;
	YOTO::Ref<YOTO::Shader> m_Shader;
	YOTO::Ref<YOTO::VertexArray> m_VertexArray;


	YOTO::Ref<YOTO::Shader> m_BlueShader;
	YOTO::Ref<YOTO::VertexArray> m_SquareVA;
	
	YOTO::Ref<YOTO::Texture2D> m_Texture,m_ChernoLogo;

	YOTO::OrthographicCamera m_Camera;
	glm::vec3 m_CameraPosition;
	float m_CameraMoveSpeed = 5.0f;

	float m_CameraRotation = 0;
	float m_CameraRotationSpeed = 180.0f;

	glm::vec3 m_SquareColor = { 0.2f,0.3f,0.7f };

};


class Sandbox:public YOTO::Application
{
public:
	Sandbox(){
		PushLayer(new ExampleLayer());
		//PushLayer(new YOTO::ImGuiLayer());
	}
	~Sandbox() {

	}

private:

};

YOTO::Application* YOTO::CreateApplication() {
	printf("helloworld");
	return new Sandbox();
}

测试:

cool! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1436274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot 过滤器Filter的过滤链 多个过滤器优先级

SpringBoot 过滤器Filter 拦截请求 生命周期 什么是过滤链&#xff1f; 指的是有多个过滤器形成的过滤链&#xff0c;一个项目中可以存在多个过滤器。 优先级 根据字母排序&#xff0c;如XFilter和AFilter&#xff0c;那么按照顺序应该先到AFilter过滤器当中

2024/02/06

画出TCP三次握手和四次挥手的示意图 三次握手 四次挥手 并且总结TCP和UDP的区别 TCP: TCP提供面向连接的&#xff0c;可靠的数据传输服务传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复 TCP会给每个数据包编上编号&#xff0c;该编号称之为序列号每个序…

2、6作业

TCP和UDP的区别 TCP和UDP都是通信协议 TCP提供有连接的&#xff0c;稳定的&#xff0c;无误码无失真无乱序无丢失的通信 UDP提供无连接的&#xff0c;尽力的&#xff0c;可能误码可能乱序&#xff0c;可能丢失的通信 TCP每发一个数据包就需要对方回应一个应答包&#xff0c…

Linux进程信号处理:深入理解与应用(3)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;its 6pm but I miss u already.—bbbluelee 0:01━━━━━━️&#x1f49f;──────── 3:18 &#x1f504; ◀️…

编译原理与技术(三)——语法分析(二)自顶向下-递归下降

一、语法分析的两种方法 自顶向下&#xff08;Top-down&#xff09;&#xff1a; 针对输入串&#xff0c;从文法的开始符号出发&#xff0c;尝试根据产生式规则推导&#xff08;derive&#xff09;出该输入串。 从根部开始构造语法树。 自底向上&#xff08;Bottom-up&#…

双非本科准备秋招(18.1)—— 力扣二叉树

1、404. 左叶子之和 方法一&#xff1a; 可以在父节点判断一下&#xff0c;如果左子树不为null&#xff0c;并且左子树没有左右子树&#xff0c;说明这是个左叶子节点。 class Solution {public int sumOfLeftLeaves(TreeNode root) {if(root null) return 0;int LV sumOfL…

怎么把两段视频合成一个画面?教你4个合成方法

怎么把两段视频合成一个画面&#xff1f;在数字媒体时代&#xff0c;视频编辑已经成为一项必备技能。有时候&#xff0c;我们需要将两段或多段视频合并成一个画面&#xff0c;这在电影制作、自媒体内容创作、家庭相册制作等领域都有广泛应用。本文将为你介绍四种简单易行的方法…

挑战杯 python+opencv+机器学习车牌识别

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器学习的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&#xff0c;适…

PyTorch的10个基本张量操作

PyTorch是一个基于python的科学计算包。它的灵活性允许轻松集成新的数据类型和算法&#xff0c;并且框架也是高效和可扩展的&#xff0c;下面我们将介绍一些Pytorch的基本张量操作。 Tensors 张量Tensors是一个向量&#xff0c;矩阵或任何n维数组。这是深度学习的基本数据结构…

企业计算机服务器中了halo勒索病毒如何解密,halo勒索病毒数据恢复

对于众多的企业来说&#xff0c;数据是一个企业的发展的根基&#xff0c;通过数据可以更好地规划调整企业的发展方向&#xff0c;提高企业生产效率。但网络是一把双刃剑&#xff0c;网络技术的发展不仅会为企业带来极大便利&#xff0c;但也为企业数据安全带来严重威胁。近期&a…

谈谈BlueFS

目录 前言数据结构标识一个文件文件系统的全局记录事务记录超级块 启动流程磁盘管理读写流程创建文件流程为文件写数据把数据下刷到磁盘读流程 参考资料 前言 BlueFS具体是个什么东西呢&#xff1f; 如上图&#xff0c;在Ceph里&#xff0c;使用BlueStore作为默认的存储引擎。…

LLM(大语言模型)——大模型简介

目录 概述 发展历程 大语言模型的概念 LLM的应用和影响 大模型的能力、特点 大模型的能力 涌现能力&#xff08;energent abilities&#xff09; 作为基座模型支持多元应用的能力 支持对话作为统一入口的能力 大模型的特点 常见大模型 闭源LLM&#xff08;未公开源…

datax离线同步oracle表到clickhouse实践1

时间&#xff1a;2024.01 目录1、安装启动 oracle19c 容器 2、rpm包安装clickhouse 3、datax安装 4、datax同步 目标库根据要同步的表&#xff0c;按照clickhouse建表规范建表 编写json文件 编写增量同步shell脚本&#xff0c;加入 crond 定时任务 1、安装启动 oracle19c 容器…

关于如何在Mac上安装Windows,看这篇文章就差不多了

启动转换(Boot Camp)助手可以让你在一些Mac电脑上安装Windows并引导到其中,就像在普通电脑上一样。现代苹果硅型号(M1、M2等)不支持启动转换助手,必须使用其他方法来运行Windows。 可以在M1或M2 Mac上使用启动转换助手吗 只有当Mac上有Intel(x86)处理器时,才能使用启…

Arcgis使用过程中常见问题解决方法

Arcgis无法连接数据库/数据库连接或创建失败解决方法 最近在使用arcgis过程中出现无法连接数据库或者是无法创建数据库。连接到数据库失败&#xff1b;无法创建新的数据库&#xff0c;权限被拒绝&#xff08;如下图&#xff09;。 出现这个原因是你所用的电脑系统文件dao360.…

生存类游戏《幻兽帕鲁》从部署服务器到开始体验全过程

SteamDB数据显示&#xff0c;《幻兽帕鲁》上线24小时内&#xff0c;在线人数峰值便突破200万&#xff0c;跻身Steam历史排行榜第二位。随着热度进一步发酵&#xff0c;《幻兽帕鲁》官方发布推文称&#xff0c;游戏发售不到6天&#xff0c;销量已经突破了 800万份。欢迎大家在阿…

香港公司员工遭遇2亿港币Deepfake诈骗; 阿里巴巴Qwen1.5震撼发布;通义千问App推新功能迎佳节

&#x1f989; AI新闻 &#x1f680; 香港公司员工遭遇2亿港币Deepfake诈骗 摘要&#xff1a;近日&#xff0c;香港一家英国跨国企业的员工被Deepfake技术仿造的视频诈骗&#xff0c;损失2亿港币。骗子通过伪造高管的面貌和声音&#xff0c;用视频会议的形式命令其转账&#…

双非本科准备秋招(17.1)—— 力扣二叉树

1、257. 二叉树的所有路径 要求返回根节点到叶子节点的所有路径&#xff0c;这里用前序遍历就好。 每次递归前&#xff0c;都让字符串s加上当前节点的值和“->”&#xff0c;然后判断是否为叶子节点&#xff0c;如果是的话&#xff0c;说明这条路径是一个答案&#xff0c;因…

基于springboot实现二次元商品购物系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现二次元商品购物系统演示 摘要 时代的变化速度实在超出人类的所料&#xff0c;21世纪&#xff0c;计算机已经发展到各行各业&#xff0c;各个地区&#xff0c;它的载体媒介-计算机&#xff0c;大众称之为的电脑&#xff0c;是一种特高速的科学仪器&#xff0…

python + 蒙特卡罗 = 股市神器! 能用到A股吗?

蒙特卡罗模拟作为一种在金融领域广泛应用的强大统计技术&#xff0c;能够对金融资产&#xff08;例如股票&#xff09;的行为进行模拟建模。在本文中&#xff0c;我们将深入探讨如何在Python编程环境中实现蒙特卡罗模拟&#xff0c;以预测股票市场未来可能出现的情况。我们将利…