Unity SRP自定义渲染管线学习1.2:初步绘制

news2024/11/17 16:50:39

绘制物体

绘制物体,包括不透明的物体,透明物体,再加上之前的天空盒
Camera

void DrawVisibleGeometry()
    {
        //我们需要将不透明物体和透明物体分开绘制
        //如果我们直接先绘制所有的物体,然后再绘制天空盒,我们就会看到对于透明的物体,如果其对于相机视线后面没有不透明的物体的话,就会被天空球给遮挡住
        //我们的透明shader没有写入深度缓冲,绘制天空盒时,在这个片元上如果没有不透明的物体写入过深度的话,天空盒的绘制就会直接覆盖掉
        //所以我们的绘制顺序是先不透明物体,再绘制天空盒,最后绘制透明物体
        //先进行不透明物体的绘制
        var sortingSettings = new SortingSettings(camera) //相机的透明排序取决于使用的是正交还是基于距离的排序
        {
            // 不给定排序规则的话,绘制排序是随机混乱的
            // 这个排序是从前往后的,因为对于后面的不透明物体,当检测到其的深度大于缓冲区的深度时,说明被挡住了,可以直接丢弃不绘制
            // 而如果从后往前的话,就会需要不断的覆盖绘制,性能不如从前往后
            criteria = SortingCriteria.CommonOpaque,
        };
        var drawSettings = new DrawingSettings(unlitShaderTagId, sortingSettings);  //DrawingSettings主要用于对物体的渲染顺序和使用哪个Shader Pass
        var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);  //FilteringSettings主要决定哪些物体渲染,哪些不渲染根据LayerMask,RenderQueue,sortingLayer等
        //在Cull中我们得到了cullingResults,因此我们知道了哪些物体是需要绘制的
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
        context.DrawSkybox(camera);  //添加绘制Skybox的命令
        // 再进行透明物体的绘制
        // 这个绘制顺序是从后往前的,与不透明的绘制顺序是相反的
        // 不透明的物体并不写入深度缓冲,因此从前往后并没有性能更优
        // 而且透明物体之间需要进行混合,从后往前才能得到正确的混合
        // 但事实上并不能完全保证正确,因为排序是基于整个物体的位置的,但是对于复杂的大型物体间,可能会有部分穿插,有部分在前,有部分在后,这样子就会得到错误的效果
        sortingSettings.criteria = SortingCriteria.CommonTransparent;
        drawSettings.sortingSettings = sortingSettings;
        filteringSettings.renderQueueRange = RenderQueueRange.transparent;
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
    }


    //使用Unity默认的一些Shader绘制出使用了不支持的Shader的物体
    partial void DrawUnsupportedShaders()  //如果不改成分部方法的定义和实现声明,打包就会出错,因为这部分代码是仅在编辑器下使用的
    {
        if (errorMaterial == null)
        {
            errorMaterial = new Material(Shader.Find("Hidden/InternalErrorShader"));
        }
        //我们将不支持的Shader用Unity默认的设置直接绘制出来
        //没有设置好Shader的属性之前,绘制出来的物体是黑色的
        var drawSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera))
        {
            overrideMaterial = errorMaterial,  //使用内置错误材质来绘制所有不支持的Shader的物体
        }
        ;
        for (int i = 1; i < legacyShaderTagIds.Length; i++)
        {
            drawSettings.SetShaderPassName(i, legacyShaderTagIds[i]);
        }
        var filteringSettings = FilteringSettings.defaultValue;
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
    }

没有对绘制排序前
在这里插入图片描述

排序后
在这里插入图片描述

将不透明物体和透明物体分开渲染
在这里插入图片描述

先用默认Shader渲染不支持的Shader
在这里插入图片描述

用内置的错误材质在编辑器下绘制
在这里插入图片描述

分部代码,让代码更清晰,且可以让Editor代码不会出现打包错误
在这里插入图片描述

绘制Gizmos

    partial void DrawGizmos()
    {
        if (Handles.ShouldRenderGizmos())  //获取Gizmos是否开启
        {
            context.DrawGizmos(camera, GizmoSubset.PreImageEffects);
            context.DrawGizmos(camera, GizmoSubset.PostImageEffects);
        }
    }

绘制Gizmos前
在这里插入图片描述
绘制Gizmos后
在这里插入图片描述

UI

如果是Overlay的UI,则不受我们的管线影响
在这里插入图片描述
改成ScreenCamera或者WorldSpaceCamera后
在这里插入图片描述
但是Scene中没有UI
在这里插入图片描述

添加绘制Scene视图的代码后

    partial void PrepareForSceneWindow()
    {
        if (camera.cameraType == CameraType.SceneView)
        {
            //绘制Scene视图中的UI
            ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
        }
    }

在这里插入图片描述

多相机

添加新的相机
在这里插入图片描述

两个相机的绘制在FrameDebuger中都混在了一起
在这里插入图片描述
我们对每个相机单独进行Sample

   partial void PrepareBuffer()
    {
        //我们将Buffer的名称修改为相机名称,这样子就可以在FrameDebuger中看到相机对应的渲染在自己的组中,查看会比较清晰
        Profiler.BeginSample("Editor Only");  //这里会产生GC,会混下我们性能分析,所以直接标明是Editor Only
        buffer.name = SampleName = camera.name;
        Profiler.EndSample();
    }

在这里插入图片描述
有多余的GC
在这里插入图片描述
在这里插入图片描述
把Editor下的GC单独分开
在这里插入图片描述

相机的ClearFlags

根据相机的ClearFlags的设置去调用buffer.ClearRenderTarget,主要就是决定是否清除颜色缓冲,深度缓冲
在这里插入图片描述

var flags = camera.clearFlags;
        //ClearRenderTarget需要在SetupCameraProperties之后进行Execute,不然Clear的方式会变成Draw GL(可以在FrameDebuger中看到)
        //Draw GL是使用Hidden/InternalClear Shader绘制了一个全屏的Quad来达到清除的效果,这种方式不是性能最好的
        //ClearRenderTarget需要在BeginSample之前,不然FrameDebuger中会被多一次嵌套在"Render Camera"中
        buffer.ClearRenderTarget(
            flags != CameraClearFlags.Nothing,
            flags == CameraClearFlags.Color,   //为什么可以不用管Skybox时的清理颜色缓冲?因为当选择Skybox时,会清理深度缓冲,且需要绘制Skybox,没有深度缓冲此时一定会覆盖掉之前的颜色,相当于清理了颜色缓冲
            flags == CameraClearFlags.Color ? camera.backgroundColor.linear : Color.clear  //我们用的是线性空间,所以当要使用背景颜色时,需要将其转化为线性空间的颜色
        );

Solid Color
在这里插入图片描述
Don’t Clear
在这里插入图片描述
改变Viewport后的Skybox
在这里插入图片描述
改变Viewport后的SolidColor
在这里插入图片描述
改变Viewport后的Depth Only
在这里插入图片描述
改变Viewport后的Don’t Clear
在这里插入图片描述
没有改变Viewport之前是直接用Clear的方式
在这里插入图片描述
改变Viewport后,由于需要将清理的范围限定在Viewport中,并非整个屏幕,因此使用Shader绘制的方式清理,将范围限定
在这里插入图片描述

参考

本文主要学习自:https://catlikecoding.com/unity/tutorials/custom-srp/custom-render-pipeline/
catlikecoding是大神的博客,里面有很多教程,膜拜大神,感恩大神。

具体代码

CustomRenderPipeline.cs

using UnityEngine;
using UnityEngine.Rendering;
public class CustomRenderPipeline : RenderPipeline
{
    CameraRenderer cameraRenderer = new CameraRenderer();
    //每一帧渲染调用
    protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        foreach(var camera in cameras)
        {
            cameraRenderer.Render(context, camera);
        }
    }
}

CustomRenderPipelineAsset.cs

using UnityEngine;
using UnityEngine.Rendering;  //需要使用UnityEngine.Rendering命名空间
//用于存储自定义渲染管线的设置
[CreateAssetMenu(menuName = "Rendering/Custom Render Pipeline")]
public class CustomRenderPipelineAsset : RenderPipelineAsset  //需要继承自RenderPipelineAsset
{
    protected override RenderPipeline CreatePipeline()
    {
        return new CustomRenderPipeline();
    }
}

CameraRenderer.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
//用于进行单个相机的画面渲染
public partial class CameraRenderer
{
    static ShaderTagId unlitShaderTagId = new ShaderTagId("SRPDefaultUnlit");
    ScriptableRenderContext context;
    Camera camera;
    CullingResults cullingResults;
    const string bufferName = "Render Camera";
    CommandBuffer buffer = new CommandBuffer
    {  //创建实例时可以这样直接初始化
        name = bufferName,
    };
    public void Render(ScriptableRenderContext context, Camera camera)
    {
        this.context = context;
        this.camera = camera;
        PrepareBuffer();
        PrepareForSceneWindow();
        if (!Cull())
            return;
        Setup();
        DrawVisibleGeometry();
        DrawUnsupportedShaders();
        DrawGizmos();
        Submit();
    }
    bool Cull()
    {
        //返回值表示cullingParameters是否有效,比如当相机viewport rectangle宽高被设置为0,0,无效的裁剪平面设置等
        //因此返回值能代表这个相机是否需要绘制
        if (camera.TryGetCullingParameters(out var cullingParameters))
        {
            //我们会发现在这里,对ScriptableCullingParameters的操作基本都是out和ref,这是因为ScriptableCullingParameters比较大,这样子可以优化
            cullingResults = context.Cull(ref cullingParameters);
            return true;
        }
        return false;
    }
    void Setup()
    {
        //将相机的属性设置到绘制命令中,比如相机的位置和旋转,透视还是正交投影等,这会决定视图矩阵和投影矩阵
        //就是Shader中所使用的unity_MatrixVP, View Matrix, Projection Matrix
        //我们可以在FrameDebuger中的ShaderProperties中看到unity_MatrixVP
        //如果我们不进行这项设置,unity_MatrixVP都是一样的,所以当我们旋转相机时,相机看到的东西不会发生变化
        context.SetupCameraProperties(camera);
        var flags = camera.clearFlags;
        //ClearRenderTarget需要在SetupCameraProperties之后进行Execute,不然Clear的方式会变成Draw GL(可以在FrameDebuger中看到)
        //Draw GL是使用Hidden/InternalClear Shader绘制了一个全屏的Quad来达到清除的效果,这种方式不是性能最好的
        //ClearRenderTarget需要在BeginSample之前,不然FrameDebuger中会被多一次嵌套在"Render Camera"中
        buffer.ClearRenderTarget(
            flags != CameraClearFlags.Nothing,
            flags == CameraClearFlags.Color,   //我们的Skybox是在最后绘制的
            flags == CameraClearFlags.Color ? camera.backgroundColor.linear : Color.clear  //我们用的是线性空间,所以当要使用背景颜色时,需要将其转化为线性空间的颜色
        );
        buffer.BeginSample(SampleName);
        ExecuteBuffer();  //Execute后,Buffer中的命令才会加入到context中
    }
    void DrawVisibleGeometry()
    {
        //我们需要将不透明物体和透明物体分开绘制
        //如果我们直接先绘制所有的物体,然后再绘制天空盒,我们就会看到对于透明的物体,如果其对于相机视线后面没有不透明的物体的话,就会被天空球给遮挡住
        //我们的透明shader没有写入深度缓冲,绘制天空盒时,在这个片元上如果没有不透明的物体写入过深度的话,天空盒的绘制就会直接覆盖掉
        //所以我们的绘制顺序是先不透明物体,再绘制天空盒,最后绘制透明物体
        //先进行不透明物体的绘制
        var sortingSettings = new SortingSettings(camera) //相机的透明排序取决于使用的是正交还是基于距离的排序
        {
            // 不给定排序规则的话,绘制排序是随机混乱的
            // 这个排序是从前往后的,因为对于后面的不透明物体,当检测到其的深度大于缓冲区的深度时,说明被挡住了,可以直接丢弃不绘制
            // 而如果从后往前的话,就会需要不断的覆盖绘制,性能不如从前往后
            criteria = SortingCriteria.CommonOpaque,
        };
        var drawSettings = new DrawingSettings(unlitShaderTagId, sortingSettings);  //DrawingSettings主要用于对物体的渲染顺序和使用哪个Shader Pass
        var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);  //FilteringSettings主要决定哪些物体渲染,哪些不渲染根据LayerMask,RenderQueue,sortingLayer等
        //在Cull中我们得到了cullingResults,因此我们知道了哪些物体是需要绘制的
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
        context.DrawSkybox(camera);  //添加绘制Skybox的命令
        // 再进行透明物体的绘制
        // 这个绘制顺序是从后往前的,与不透明的绘制顺序是相反的
        // 不透明的物体并不写入深度缓冲,因此从前往后并没有性能更优
        // 而且透明物体之间需要进行混合,从后往前才能得到正确的混合
        // 但事实上并不能完全保证正确,因为排序是基于整个物体的位置的,但是对于复杂的大型物体间,可能会有部分穿插,有部分在前,有部分在后,这样子就会得到错误的效果
        sortingSettings.criteria = SortingCriteria.CommonTransparent;
        drawSettings.sortingSettings = sortingSettings;
        filteringSettings.renderQueueRange = RenderQueueRange.transparent;
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
    }
    void Submit()
    {
        buffer.EndSample(SampleName);
        ExecuteBuffer();
        context.Submit();  //提交绘制命令,进行绘制
    }
    void ExecuteBuffer()
    {
        context.ExecuteCommandBuffer(buffer);
        buffer.Clear();
    }
}

CameraRenderer.Editor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.Profiling;
using UnityEngine;
using UnityEngine.Rendering;
//用于进行单个相机的画面渲染
partial class CameraRenderer
{
    //为分部方法定义声明,这样子编译时如果没有找到实现声明的方法的话,就会剔除掉对这个方法的调用
    //使用这种方法可以比较好的避免Build出错,再来查错
    partial void PrepareBuffer();
    partial void PrepareForSceneWindow();
    partial void DrawUnsupportedShaders();
    partial void DrawGizmos();
#if UNITY_EDITOR
    string SampleName { get; set; }
    static Material errorMaterial; //用于绘制不支持的shader
    //Unity默认的所有的Shader Pass的Tag
    static ShaderTagId[] legacyShaderTagIds = {
        new ShaderTagId("Always"),
        new ShaderTagId("ForwardBase"),
        new ShaderTagId("PrepassBase"),
        new ShaderTagId("Vertex"),
        new ShaderTagId("VertexLMRGBM"),
        new ShaderTagId("VertexLM"),
    };
    partial void PrepareBuffer()
    {
        //我们将Buffer的名称修改为相机名称,这样子就可以在FrameDebuger中看到相机对应的渲染在自己的组中,查看会比较清晰
        Profiler.BeginSample("Editor Only");  //这里会产生GC,会混下我们性能分析,所以直接标明是Editor Only
        buffer.name = SampleName = camera.name;
        Profiler.EndSample();
    }
    partial void PrepareForSceneWindow()
    {
        if (camera.cameraType == CameraType.SceneView)
        {
            //绘制Scene视图中的UI
            ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
        }
    }
    //使用Unity默认的一些Shader绘制出使用了不支持的Shader的物体
    partial void DrawUnsupportedShaders()  //如果不改成分部方法的定义和实现声明,打包就会出错,因为这部分代码是仅在编辑器下使用的
    {
        if (errorMaterial == null)
        {
            errorMaterial = new Material(Shader.Find("Hidden/InternalErrorShader"));
        }
        //我们将不支持的Shader用Unity默认的设置直接绘制出来
        //没有设置好Shader的属性之前,绘制出来的物体是黑色的
        var drawSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera))
        {
            overrideMaterial = errorMaterial,  //使用内置错误材质来绘制所有不支持的Shader的物体
        }
        ;
        for (int i = 1; i < legacyShaderTagIds.Length; i++)
        {
            drawSettings.SetShaderPassName(i, legacyShaderTagIds[i]);
        }
        var filteringSettings = FilteringSettings.defaultValue;
        context.DrawRenderers(cullingResults, ref drawSettings, ref filteringSettings);
    }
    partial void DrawGizmos()
    {
        if (Handles.ShouldRenderGizmos())  //获取Gizmos是否开启
        {
            context.DrawGizmos(camera, GizmoSubset.PreImageEffects);
            context.DrawGizmos(camera, GizmoSubset.PostImageEffects);
        }
    }
#else
    const string SampleName = bufferName;
#endif
}

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

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

相关文章

nodejs+vue家庭食谱饮食方案管理系统网站python php java

本系统分为用户和管理员两个角色&#xff0c;其中用户可以注册登陆系统&#xff0c;查看美食食谱&#xff0c;一周健康食谱安排&#xff0c;查看美食食材&#xff0c;在线交流发布帖子&#xff1b;管理员可以对食谱分类&#xff0c;食谱信息&#xff0c;材料信息&#xff0c;美…

区块链技术2---BTC的数据结构

1&#xff1a;Hash pointers&#xff08;哈希指针&#xff09;和普通指针相比&#xff0c;哈希指针除了保存地址还保存哈希值2&#xff1a;Block chain区块链中的区块通过哈希指针相连&#xff0c;这里的哈希指针的哈希值是对前一个区块的整体取哈希值&#xff08;包括前一个区…

linux系统中使用QT实现摄像头功能的方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用QT中的Camera的功能和实现。 目录 第一&#xff1a;摄像头资源简介 第二&#xff1a;环境搭建要求 第三&#xff1a;代码编译实现要求 第一&#xff1a;摄像头资源简介 开发板上有一路“CSI”摄像头接口&#xf…

组件封装 - steps组件

首先, 我先来看看效果 steps 组件的封装和 tabs 组件还是相似的 都会去指定两个组件来完成(仿Element UI), 都会去使用 jsx 的语法 让其中一个组件去规定样式和排版, 另外一个组件去接收父组件传入的动态数据 但和面包屑组件还是有区别的(面包屑组件封装): 相同点都是使用两…

v-for 的“就地更新”策略

前言 我们平时使用v-for的时候通常都是加一个唯一标识key&#xff0c;因为不加的时候Vue会给我们发出警告。其实我们加上key的操作&#xff0c;就是为了避免它的“就地更新”策略。我们来看一下官网对“就地更新”的解释&#xff1a; 当 Vue 正在更新使用 v-for 渲染的元素列表…

jsp文化活动系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 文化活动系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统采用web模式开发&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数…

第4章 任务看门狗

任务看门狗 主任务死循环 在app_main任务中死循环 #include <stdio.h> #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h"const char *TAG "COUNTER";int count 0;void app_main(void) {wh…

[翻译]PG15新特性-加速WAL日志归档

PG15新特性-加速WAL日志归档PG15通过&#xff1a;一次扫描64个待归档的日志&#xff0c;将其放到一个数组中以供归档&#xff0c;当处理完这64个文件后&#xff0c;再进行下一次扫描。这样达到减少archive_status目录扫描次数提升性能的目的。WAL归档介绍PG15如何加速归档前&am…

C++ · 入门 · 05 | 内联函数

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a;《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a;《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…

SegFormer学习笔记(4)train续2

这次关注一下最关键的东西&#xff1a;用什么网络&#xff0c;用什么数据&#xff0c;预训练数据在哪里呢&#xff1f;为了方便&#xff0c;重新贴一下 train.pyimport torch import argparse import yaml import time import multiprocessing as mp from tabulate import tab…

JVM笔记——根据黑马jvm课程课件+自己总结

JVM一、内存结构1、程序计数器&#xff08;PC Register&#xff09;2、虚拟机栈&#xff08;JVM Stacks&#xff09;3、本地方法栈&#xff08;Native Method Stacks&#xff09;4、堆&#xff08;Heap&#xff09;5、方法区&#xff08;Method Area&#xff09;6、直接内存二、…

【爬虫】第七部分 scrapy

【爬虫】第七部分 scrapy 文章目录【爬虫】第七部分 scrapy7. scrapy7.1 基本使用7.2 项目的文件结构7.3 response的方法和属性7.4 小案例7.5 scrapy 工作原理7.6 管道的使用7.7 多管道下载7.8 下载分页类型和get请求的使用7.9 下载多层级类型7.10 post请求的使用总结7. scrapy…

清华大学出版——C语言从入门到精通(第4版)

《C语言从入门到精通&#xff08;第4版&#xff09;》是清华大学出版社出版的图书&#xff0c;该书从初学者的角度出发&#xff0c;以通俗易懂的语言&#xff0c;丰富多彩的实例&#xff0c;详细介绍了使用C语言进行程序开发需要掌握的各方面知识。《C语言从入门到精通&#xf…

YOLO v8详解

回顾一下YOLOv5 Backbone&#xff1a;CSPDarkNet结构&#xff0c;主要结构思想的体现在C3模块&#xff0c;这里也是梯度分流的主要思想所在的地方&#xff1b;PAN-FPN&#xff1a;双流的FPN&#xff0c;但是量化还是有些需要图优化才可以达到最优的性能&#xff0c;比如cat前后…

VSCode 配置Go环境,弹出警告“golps”等插件要求下载但下载时超时、失去连接等 解决方案

1. 背景&#xff1a; 下载完GO环境和VSCode的GO配套插件后&#xff0c;试图运行hello world程序&#xff0c;此时VSCode弹出警告&#xff1a; 提示有几个go的工具没有下载&#xff0c;于是我点击install 下载&#xff1a; 》下载时报错&#xff0c;一般是出现超时timeout错误…

57 mac 中 SIGINFO 信号, jdk8 支持, 但是 jdk9 不支持?

前言 问题来自于文章 shell脚本 后台启动 程序1 “tail -f log“, ctrl c 导致程序1中断 中的测试用例 Test07Signal2ParentProcess, 可以看到 我当时标记了一个 "todo, not work in hostpostVM9" 然后 问题是这样的, 我同一台机器, 然后 jdk8 带上 SIGINFO 去执行…

【已解决】右键以某应用打开xx文件时,没有“默认”选项怎么办

问题解决方案简单来说详细操作解释问题 右键以某应用打开xx文件时&#xff0c;没有“默认”选项 解决方案 简单来说 在注册表&#xff1a;计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\找到要打开的文件后缀名&#xff0c;删除…

mybatis plus基本使用初体验01

我们都知道MyBatis是目前比较常用的持久层框架&#xff1b;这个框架的使用也是很简单的&#xff0c;我们在使用的时候&#xff0c;只需要关注mapper的接口层和对应的xml文件即可。 但是MyBatis作为一个半自动框架&#xff0c;是需要我们自己手动编写sql语句的&#xff0c;对于…

Linux系统软件安装

在Linux上部署各类软件MySQL数据库管理系统安装部署简介注意MySQL5.7版本在CentOS系统安装安装配置MySQL8.0版本在CentOS系统安装安装配置MySQL5.7版本在Ubuntu&#xff08;WSL环境&#xff09;系统安装安装MySQL8.0版本在Ubuntu&#xff08;WSL环境&#xff09;系统安装安装To…

Web服务统一身份认证协议设计与实现

单点登录(SSO)是目前比较流行的企业业务整合的解决方案之一,它的机制是在企业网络用户访问企业网站时作一次身份认证,随后就可以对所有被授权的网络资源进行无缝的访问,而不需要多次输入自己的认证信息.Web服务具有松散耦合、语言中立、平台无关性、开放性的特性,通过对集中单点…