当前位置: 首页 > news >正文

Playcanvas后处理-辉光bloom

(一)Bloom介绍

Bloom(辉光、光晕、泛光)是一种常见的摄像机后处理(PostProcessing)效果,用于再现真实世界相机的成像伪影。这种效果会产生从图像中明亮区域边界延伸的光条纹(或羽毛),从而产生一种极其明亮的光线压倒捕捉场景的相机的错觉。

辉光简单的说法,就是有些地方足够亮,看上去是溢出到周围的区域,下面是playcanvas官方提供的辉光效果对比图

图1 未使用辉光效果

图2 使用辉光效果

(二)Bloom实现原理

bloom的实现原理很简单:就是取camera获取图像的高亮部分,进行高斯模糊,并和原图进行合并就可以实现。

1. 提取较亮区域

通过阈值提取较亮区域的像素点

varying vec2 vUv0;uniform sampler2D uBaseTexture
uniform float uBloomThreshold;float luminance(vec4 color)
{return  0.2125 * color[0] + 0.7154 * color[1] + 0.0721 * color[2]; 
}void main(void)
{vec4 color = texture2D(uBaseTexture, vUv0);// 只保留亮度超过阈值亮度的像素点float val = clamp(luminance(color) - uBloomThreshold, 0.0, 1.0);gl_FragColor = color * val;//这是playcanvas官网提供提取亮度高于某个阈值的算法,但还不知道它的原理//gl_FragColor = clamp((color - uBloomThreshold) / (1.0 - uBloomThreshold), 0.0, 1.0);
}

2. 高斯模糊

接下来,就是如何得到模糊图uBloomTexture

一般模糊图像的算法,我们可以选择常见的高斯模糊,它可以减少图像噪声、降低细节层次

高斯模糊的实现原理,这里不做多赘述,这里提供2篇文章供参考。

原理参考:2D Shader学习——高斯模糊

shader实现参考:基于线性采样的高效高斯模糊实现(译)

参考第二篇文章,我们在JavaScript中,计算我们高斯卷积核的权重和位移

var SAMPLE_COUNT = 15;//高斯曲线
function computeGaussian(n, theta) {return ((1.0 / Math.sqrt(2 * Math.PI * theta)) * Math.exp(-(n * n) / (2 * theta * theta)));
}function calculateBlurValues(sampleWeights, sampleOffsets, dx, dy, blurAmount) {// Create temporary arrays for computing our filter settings.// The first sample always has a zero offset.sampleWeights[0] = computeGaussian(0, blurAmount);sampleOffsets[0] = 0;sampleOffsets[1] = 0;// Maintain a sum of all the weighting values.var totalWeights = sampleWeights[0];// Add pairs of additional sample taps, positioned// along a line in both directions from the center.var i, len;for (i = 0, len = Math.floor(SAMPLE_COUNT / 2); i < len; i++) {// Store weights for the positive and negative taps.var weight = computeGaussian(i + 1, blurAmount);sampleWeights[i * 2] = weight;sampleWeights[i * 2 + 1] = weight;totalWeights += weight * 2;var sampleOffset = i * 2 + 1.5;sampleOffsets[i * 4] = dx * sampleOffset;sampleOffsets[i * 4 + 1] = dy * sampleOffset;sampleOffsets[i * 4 + 2] = -dx * sampleOffset;sampleOffsets[i * 4 + 3] = -dy * sampleOffset;}// Normalize the list of sample weightings, so they will always sum to one.for (i = 0, len = sampleWeights.length; i < len; i++) {sampleWeights[i] /= totalWeights;}
}

在fragment shader中,对图像进行卷积模糊(注意:这里的shader只对水平或垂直一个方向卷积

#define SAMPLE_COUNT 15varying vec2 vUv0;uniform sampler2D uBloomTexture;
uniform vec2 uBlurOffsets[15];
uniform float uBlurWeights[15];void main(void)
{vec4 color = vec4(0.0);for (int i = 0; i < SAMPLE_COUNT; i++){color += texture2D(uBloomTexture, vUv0 + uBlurOffsets[i]) * uBlurWeights[i];}gl_FragColor = color;
}    

最后,我们需要进行2次方向的滤波处理

原理具体参考文章二中,如何将高斯滤波器分为水平方向和垂直方向的滤波器的原理

// Pass 2: draw from rendertarget 1 into rendertarget 2(垂直方向)
calculateBlurValues(this.sampleWeights, this.sampleOffsets, 1.0 / this.targets[1].width, 0, this.blurAmount);
scope.resolve("uBlurWeights[0]").setValue(this.sampleWeights);
scope.resolve("uBlurOffsets[0]").setValue(this.sampleOffsets);
scope.resolve("uBloomTexture").setValue(this.targets[0].colorBuffer);
this.drawQuad(this.targets[1], this.blurShader);// Pass 3: draw from rendertarget 2 back into rendertarget 1(水平方向)
calculateBlurValues(this.sampleWeights, this.sampleOffsets, 0, 1.0 / this.targets[0].height, this.blurAmount);
scope.resolve("uBlurWeights[0]").setValue(this.sampleWeights);
scope.resolve("uBlurOffsets[0]").setValue(this.sampleOffsets);
scope.resolve("uBloomTexture").setValue(this.targets[1].colorBuffer);
this.drawQuad(this.targets[0], this.blurShader);

3. 混合原图和模糊图

那我们最后的fragment shader就可以这样实现,原图+模糊图进行混合

varying vec2 vUv0;//bloom 强度
uniform float uBloomEffectIntensity;uniform sampler2D uBaseTexture;
uniform sampler2D uBloomTexture;void main(void)
{vec4 bloom = texture2D(uBloomTexture, vUv0) * uBloomEffectIntensity;vec4 base = texture2D(uBaseTexture, vUv0);//将原图变暗,防止两图叠加后,像素溢出1base *= (1.0 - clamp(bloom, 0.0, 1.0));//合并原图和模糊图,得到最终的bloom效果gl_FragColor = base + bloom;
}

(三)在playcanvas编辑器中使用

1. 创建脚本bloom.js

// --------------- POST EFFECT DEFINITION --------------- //
var SAMPLE_COUNT = 15;function computeGaussian(n, theta) {return ((1.0 / Math.sqrt(2 * Math.PI * theta)) * Math.exp(-(n * n) / (2 * theta * theta)));
}function calculateBlurValues(sampleWeights, sampleOffsets, dx, dy, blurAmount) {// Look up how many samples our gaussian blur effect supports.// Create temporary arrays for computing our filter settings.// The first sample always has a zero offset.sampleWeights[0] = computeGaussian(0, blurAmount);sampleOffsets[0] = 0;sampleOffsets[1] = 0;// Maintain a sum of all the weighting values.var totalWeights = sampleWeights[0];// Add pairs of additional sample taps, positioned// along a line in both directions from the center.var i, len;for (i = 0, len = Math.floor(SAMPLE_COUNT / 2); i < len; i++) {// Store weights for the positive and negative taps.var weight = computeGaussian(i + 1, blurAmount);sampleWeights[i * 2] = weight;sampleWeights[i * 2 + 1] = weight;totalWeights += weight * 2;// To get the maximum amount of blurring from a limited number of// pixel shader samples, we take advantage of the bilinear filtering// hardware inside the texture fetch unit. If we position our texture// coordinates exactly halfway between two texels, the filtering unit// will average them for us, giving two samples for the price of one.// This allows us to step in units of two texels per sample, rather// than just one at a time. The 1.5 offset kicks things off by// positioning us nicely in between two texels.var sampleOffset = i * 2 + 1.5;// Store texture coordinate offsets for the positive and negative taps.sampleOffsets[i * 4] = dx * sampleOffset;sampleOffsets[i * 4 + 1] = dy * sampleOffset;sampleOffsets[i * 4 + 2] = -dx * sampleOffset;sampleOffsets[i * 4 + 3] = -dy * sampleOffset;}// Normalize the list of sample weightings, so they will always sum to one.for (i = 0, len = sampleWeights.length; i < len; i++) {sampleWeights[i] /= totalWeights;}
}/*** @class* @name BloomEffect* @classdesc Implements the BloomEffect post processing effect.* @description Creates new instance of the post effect.* @augments PostEffect* @param {GraphicsDevice} graphicsDevice - The graphics device of the application.* @property {number} bloomThreshold Only pixels brighter then this threshold will be processed. Ranges from 0 to 1.* @property {number} blurAmount Controls the amount of blurring.* @property {number} bloomIntensity The intensity of the effect.*/
function BloomEffect(graphicsDevice) {pc.PostEffect.call(this, graphicsDevice);// Shadersvar attributes = {aPosition: pc.SEMANTIC_POSITION};// Pixel shader extracts the brighter areas of an image.// This is the first step in applying a bloom postprocess.var extractFrag = ["varying vec2 vUv0;","","uniform sampler2D uBaseTexture;","uniform float uBloomThreshold;","","float luminance(vec4 color)","{","    return  0.2125 * color[0] + 0.7154 * color[1] + 0.0721 * color[2]; ","}","","void main(void)","{",// Look up the original image color."    vec4 color = texture2D(uBaseTexture, vUv0);","",// Adjust it to keep only values brighter than the specified threshold."    float val = clamp(luminance(color) - uBloomThreshold, 0.0, 1.0);","    gl_FragColor = color * val;","}"].join("\n");// Pixel shader applies a one dimensional gaussian blur filter.// This is used twice by the bloom postprocess, first to// blur horizontally, and then again to blur vertically.var gaussianBlurFrag = ["#define SAMPLE_COUNT " + SAMPLE_COUNT,"","varying vec2 vUv0;","","uniform sampler2D uBloomTexture;","uniform vec2 uBlurOffsets[" + SAMPLE_COUNT + "];","uniform float uBlurWeights[" + SAMPLE_COUNT + "];","","void main(void)","{","    vec4 color = vec4(0.0);",// Combine a number of weighted image filter taps."    for (int i = 0; i < SAMPLE_COUNT; i++)","    {","        color += texture2D(uBloomTexture, vUv0 + uBlurOffsets[i]) * uBlurWeights[i];","    }","","    gl_FragColor = color;","}"].join("\n");// Pixel shader combines the bloom image with the original// scene, using tweakable intensity levels.// This is the final step in applying a bloom postprocess.var combineFrag = ["varying vec2 vUv0;","","uniform float uBloomEffectIntensity;","uniform sampler2D uBaseTexture;","uniform sampler2D uBloomTexture;","","void main(void)","{",// Look up the bloom and original base image colors."    vec4 bloom = texture2D(uBloomTexture, vUv0) * uBloomEffectIntensity;","    vec4 base = texture2D(uBaseTexture, vUv0);","",// Darken down the base image in areas where there is a lot of bloom,// to prevent things looking excessively burned-out."    base *= (1.0 - clamp(bloom, 0.0, 1.0));","",// Combine the two images."    gl_FragColor = base + bloom;","}"].join("\n");this.extractShader = pc.createShaderFromCode(graphicsDevice, pc.PostEffect.quadVertexShader, extractFrag, 'BloomExtractShader', attributes);this.blurShader = pc.createShaderFromCode(graphicsDevice, pc.PostEffect.quadVertexShader, gaussianBlurFrag, 'BloomBlurShader', attributes);this.combineShader = pc.createShaderFromCode(graphicsDevice, pc.PostEffect.quadVertexShader, combineFrag, 'BloomCombineShader', attributes);this.targets = [];// Effect defaultsthis.bloomThreshold = 0.25;this.blurAmount = 4;this.bloomIntensity = 1.25;// Uniformsthis.sampleWeights = new Float32Array(SAMPLE_COUNT);this.sampleOffsets = new Float32Array(SAMPLE_COUNT * 2);
}BloomEffect.prototype = Object.create(pc.PostEffect.prototype);
BloomEffect.prototype.constructor = BloomEffect;BloomEffect.prototype._destroy = function () {if (this.targets) {var i;for (i = 0; i < this.targets.length; i++) {this.targets[i].destroyTextureBuffers();this.targets[i].destroy();}}this.targets.length = 0;
};BloomEffect.prototype._resize = function (target) {var width = target.colorBuffer.width;var height = target.colorBuffer.height;if (width === this.width && height === this.height)return;this.width = width;this.height = height;this._destroy();// Render targetsvar i;for (i = 0; i < 2; i++) {var colorBuffer = new pc.Texture(this.device, {name: "Bloom Texture" + i,format: pc.PIXELFORMAT_RGBA8,width: width >> 1,height: height >> 1,mipmaps: false});colorBuffer.minFilter = pc.FILTER_LINEAR;colorBuffer.magFilter = pc.FILTER_LINEAR;colorBuffer.addressU = pc.ADDRESS_CLAMP_TO_EDGE;colorBuffer.addressV = pc.ADDRESS_CLAMP_TO_EDGE;colorBuffer.name = 'pe-bloom-' + i;var bloomTarget = new pc.RenderTarget({name: "Bloom Render Target " + i,colorBuffer: colorBuffer,depth: false});this.targets.push(bloomTarget);}
};Object.assign(BloomEffect.prototype, {render: function (inputTarget, outputTarget, rect) {this._resize(inputTarget);var device = this.device;var scope = device.scope;// Pass 1: draw the scene into rendertarget 1, using a// shader that extracts only the brightest parts of the image.scope.resolve("uBloomThreshold").setValue(this.bloomThreshold);scope.resolve("uBaseTexture").setValue(inputTarget.colorBuffer);this.drawQuad(this.targets[0], this.extractShader);// Pass 2: draw from rendertarget 1 into rendertarget 2,// using a shader to apply a horizontal gaussian blur filter.calculateBlurValues(this.sampleWeights, this.sampleOffsets, 1.0 / this.targets[1].width, 0, this.blurAmount);scope.resolve("uBlurWeights[0]").setValue(this.sampleWeights);scope.resolve("uBlurOffsets[0]").setValue(this.sampleOffsets);scope.resolve("uBloomTexture").setValue(this.targets[0].colorBuffer);this.drawQuad(this.targets[1], this.blurShader);// Pass 3: draw from rendertarget 2 back into rendertarget 1,// using a shader to apply a vertical gaussian blur filter.calculateBlurValues(this.sampleWeights, this.sampleOffsets, 0, 1.0 / this.targets[0].height, this.blurAmount);scope.resolve("uBlurWeights[0]").setValue(this.sampleWeights);scope.resolve("uBlurOffsets[0]").setValue(this.sampleOffsets);scope.resolve("uBloomTexture").setValue(this.targets[1].colorBuffer);this.drawQuad(this.targets[0], this.blurShader);// Pass 4: draw both rendertarget 1 and the original scene// image back into the main backbuffer, using a shader that// combines them to produce the final bloomed result.scope.resolve("uBloomEffectIntensity").setValue(this.bloomIntensity);scope.resolve("uBloomTexture").setValue(this.targets[0].colorBuffer);scope.resolve("uBaseTexture").setValue(inputTarget.colorBuffer);this.drawQuad(outputTarget, this.combineShader, rect);}
});// ----------------- SCRIPT DEFINITION ------------------ //
var Bloom = pc.createScript('bloom');Bloom.attributes.add('bloomIntensity', {type: 'number',default: 1,min: 0,title: 'Intensity'
});Bloom.attributes.add('bloomThreshold', {type: 'number',default: 0.25,min: 0,max: 1,title: 'Threshold'
});Bloom.attributes.add('blurAmount', {type: 'number',default: 4,min: 1,'title': 'Blur amount'
});Bloom.prototype.initialize = function () {this.effect = new BloomEffect(this.app.graphicsDevice);this.effect.bloomThreshold = this.bloomThreshold;this.effect.blurAmount = this.blurAmount;this.effect.bloomIntensity = this.bloomIntensity;var queue = this.entity.camera.postEffects;queue.addEffect(this.effect);this.on('attr', function (name, value) {this.effect[name] = value;}, this);this.on('state', function (enabled) {if (enabled) {queue.addEffect(this.effect);} else {queue.removeEffect(this.effect);}});this.on('destroy', function () {queue.removeEffect(this.effect);this.effect._destroy();});
};

2. 将脚本挂载在相机

相关文章:

Playcanvas后处理-辉光bloom

&#xff08;一&#xff09;Bloom介绍 Bloom&#xff08;辉光、光晕、泛光&#xff09;是一种常见的摄像机后处理&#xff08;PostProcessing&#xff09;效果&#xff0c;用于再现真实世界相机的成像伪影。这种效果会产生从图像中明亮区域边界延伸的光条纹&#xff08;或羽毛…...

GCC 学习

GCC Resource Center for GCC Internalshttps://www.cse.iitb.ac.in/grc/这是个不错资料网站&#xff0c;有兴趣的可以了解下...

2023数维杯数学建模C题完整版本

已经完成全部版本&#xff0c;获取请查看文末下方名片 摘要 随着人工智能在多个领域的快速发展&#xff0c;其在文本生成上的应用引起了广泛关注。本研究聚焦于辨识人工智能&#xff08;AI&#xff09;生成文本的基本规则&#xff0c;并探究AI文本的检测及其与人类文本的区分…...

快速解密PPT幻灯片密码,让PPT重见天日

最简单的办法解密、找回和去除PPT幻灯片密码&#xff0c;具体步骤如下&#xff1a;1.百度搜索【密码帝官网】&#xff0c;2.点击“立即开始”在用户中心上传要解密的文件稍等片刻&#xff0c;就能找回密码。不用下载软件&#xff0c;手机电脑都可用。而且还支持Word、Excel、PD…...

十六、RabbitMQ快速入门

目录 一、在centos上下载MQ镜像 二、安装运行容器 三、登录进入MQ 1、添加一个新的用户 2、新建虚拟机 3、 为用户分配权限 四、RabbitMQ的基本概念 RabbitMQ中的几个概念: 五、常见消息模型 六、简单的消息生产与消费 1、消费者类 2、生产者类 3、基本消息队列的消…...

C#WPF用户控件及自定义控件实例

本文演示C#WPF自定义控件实例 用户控件(UserControl)和自定义控件(CustomControl)都是对UI控件的一种封装方式,目的都是实现封装后控件的重用。 只不过各自封装的实现方式和使用的场景上存在差异。 1 基于UserControl 创建 创建控件最简单一个方法就是基于UserControl …...

大模型的语言能力

NLP作为一个领域为基础模型开辟了道路。虽然这些模型在标准基准测试中占据主导地位&#xff0c;但这些模型目前获得的能力与那些将语言描述为人类交流和思维的复杂系统的能力之间存在明显的差距。针对这一点&#xff0c;我们强调语言变异的全部范围&#xff08;例如&#xff0c…...

直播岗位认知篇

一、直播岗位概述 直播岗位&#xff0c;也称为直播主播或直播运营&#xff0c;是指在互联网直播平台上进行直播活动的工作岗位。该岗位的主要职责是通过直播形式&#xff0c;向观众展示自己的才艺、分享生活、销售产品或服务&#xff0c;并引导观众互动和参与。直播主播需要具…...

后端技术知识点内容-全部内容-面试宝典-后端面试知识点

文章目录 -2 flink-1 linux of viewlinux查看占用cup最高的10个进程的命令&#xff1b; 〇、分布式锁 & 分布式事务0-1分布式锁--包含CAP理论模型概述分布式锁&#xff1a;分布式锁应该具备哪些条件&#xff1a;分布式锁的业务场景&#xff1a; 分布式锁的实现方式有&#…...

3.ubuntu20.04环境的ros搭建

ros搭建比较简单&#xff0c;主要步骤如下&#xff1a; 1.配置ros软件源&#xff1a; sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list 2.配置密钥 sudo apt-key adv --keyser…...

米诺地尔行业分析:预计2029年将达到14亿美元

米诺地尔市场规模庞大&#xff0c;不仅包括消费品市场和服务行业&#xff0c;还涵盖了创新科技领域。随着经济的发展和市场需求的不断增长&#xff0c;米诺地尔市场的规模将继续扩大&#xff0c;各行各业都将面临更多机遇和挑战。 随着社会经济发展和城市化进程的推进&#xff…...

在Spring Boot中使用Thymeleaf开发Web页面

引言&#xff1a; 为啥写这篇文章呢&#xff1f;我明明就没怎么用过这个Thymeleaf进行web开发&#xff0c;用JSP也行&#xff0c;三剑客也行&#xff0c;或者Vue&#xff0c;React&#xff0c;PHP等等&#xff0c;不好吗&#xff1f; 那我为啥写这篇博客呢&#xff1f;这个写了…...

2023年亚太杯数学建模思路 - 案例:感知机原理剖析及实现

文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其…...

linux高级篇基础理论五(用户安全,口令设置,JR暴力破解用户密码,NMAP端口扫描)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…...

鸿蒙原生应用/元服务开发-AGC分发如何配置版本信息(上)

1.配置HarmonyOS应用的“发布国家或地区”。 2.设置是否为开放式测试版本。 注意&#xff1a;HarmonyOS应用开放式测试当前仅支持手机、平板、智能手表。如开发者想发布为开放式测试版本&#xff0c;选择“是”。正式发布的版本请选择“否”。 3.在“软件版本”下点击“软件包…...

探索Scrapy中间件:自定义Selenium中间件实例解析

简介 Scrapy是一个强大的Python爬虫框架&#xff0c;可用于从网站上抓取数据。本教程将指导你创建自己的Scrapy爬虫。其中&#xff0c;中间件是其重要特性之一&#xff0c;允许开发者在爬取过程中拦截和处理请求与响应&#xff0c;实现个性化的爬虫行为。 本篇博客将深入探讨…...

渗透测试--3.中间人攻击

渗透测试--3.中间人攻击 一 .中间人攻击arp欺骗DNS欺骗无线局域网漏洞利用使用 Ettercap 执行欺骗攻击arp欺骗实例1、首先查看欺骗之前靶机ip以及默认网关,2、查看kali的IP地址(192.168.76.134),MAC:000c294079903、使用Ettercap,将A主机和B主机加入到target中4、点击右上…...

nginx/html关闭网页缓存方法

【问题】 通常代理服务器默认是有缓存的&#xff0c;即用户访问网址的时候默认获取到的是缓存&#xff0c;只有刷新之后才能得到服务器端的最新文件 【解决】 以nginx为例&#xff0c;找到配置文件nginx.conf&#xff0c;找到http {}&#xff0c;在其花括号之内添加命令&…...

华为防火墙 Radius认证

实现的功能&#xff1a;本地内网用户上网时必须要进行Radius验证&#xff0c;通过后才能上网 前置工作请按这个配置&#xff1a;华为防火墙 DMZ 设置-CSDN博客 Windows 服务器安装 Radius 实现上网认证 拓扑图如下&#xff1a; 一、服务器配置 WinRadius 1、安装WinRadius …...

用spring发送http请求

在Spring中&#xff0c;你可以使用RestTemplate或WebClient来发送HTTP请求。下面分别给出使用这两个类的简单示例。 现在pom.xml中导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artif…...

赴日开发工程师是做什么的?

日本的软件开发岗位对技术要求和沟通能力都有较高的要求&#xff0c;赴日开发工程师主要负责软件设计、开发和测试&#xff0c;包括编写代码、测试代码和修复漏洞等工作。开发人员必须对软件架构、设计模式和业务逻辑有深入的理解&#xff0c;并能做出合适的技术决策。 当然&a…...

Wireshark的数据包它来啦!

通过Wireshark工具&#xff0c;可以轻松的看到网卡的数据信息。通过Wireshark显示的数据包内容信息&#xff0c;通常分七栏&#xff0c;介绍一下&#xff1a; 1No.&#xff1a; 数据包编号。 2.Time Time显示时间&#xff0c;以1号数据包发生开始计时。 3.Source Source显示内容…...

接口测试需要验证数据库么?

有的接口会返回很多数据&#xff0c;有的接口可能就返回一个状态码及success之类的消息&#xff0c;这些需要验证数据库么&#xff1f;现在在写一个测试框架&#xff0c;配置接口参数和预期返回值&#xff0c;生成xml文件管理用例&#xff0c;用一个比较方法对预期和返回作比较…...

配置 `PostgreSQL` 与 `Keepalived` 以实现高可用性

配置 PostgreSQL 与 Keepalived 以实现高可用性通常包括以下步骤&#xff1a; PostgreSQL 配置 安装 PostgreSQL&#xff1a;在两台服务器上安装相同版本的 PostgreSQL。 sudo yum install postgresql-server postgresql-contrib初始化数据库&#xff1a;在两台服务器上初始化…...

C++: int转换成LPCSTR

LPCSTR类型是指向字符常量的指针&#xff0c;因此需要将int类型转换为字符串类型&#xff0c;然后再将字符串类型转换为LPCSTR类型。 以下是一个示例代码&#xff1a; int num 123; char str[10]; sprintf(str, "%d", num); // 将int类型转换为字符串类型 LPCSTR …...

kettle官网和中文网地址

整理的kettle相关的网站地址&#xff1a; github 地址&#xff1a; https://github.com/pentaho/pentaho-kettle kettle下载目录&#xff1a; https://sourceforge/projects/pentaho/files/ kettle9.2下载地址&#xff1a; https://sourceforge/projects/pentaho/files/Penta…...

纽扣电池类产品上架亚马逊澳大利站认证标准要求AS/NZS 62368

纽扣电池一般来说常见的有充电的和不充电的两种&#xff0c; 充电的包括3.6V可充锂离子扣式电池(LIR系列)&#xff0c;3V可充锂离子扣式电池(ML或VL系列)&#xff1b;不充电的包括3V锂锰扣式电池(CR系列)及1.5V碱性锌锰扣式电池(LR及SR系列)。 澳大利亚*已经发布了经批准的《消…...

网站监控的重要性及实施策略

随着互联网的快速发展&#xff0c;网站已经成为企业和个人不可或缺的在线服务平台。然而&#xff0c;网站的安全性和稳定性一直是企业及个人非常关注的问题。一旦网站出现故障或者被攻击&#xff0c;将会给企业和个人带来严重的损失。因此&#xff0c;实施有效的网站监控策略对…...

亚马逊车灯外贸出口CE认证标准办理解析

车灯是车辆夜间行驶在道路照明的工具&#xff0c;也是发出各种车辆行驶信号的提示工具。车灯一般分为前照灯、尾灯、转向灯等。车灯出口欧盟需要办理CE认证。 CE认证是欧盟对进入欧洲市场的产品强制性的认证标志&#xff0c;是指符合欧盟安全、健康、环境保护等标准和要求的产…...

windows 查看防火墙设置命令使用方法

点击键盘上windows键&#xff0c;输入cmd&#xff0c;选择以管理员身份运行 输入下面命令查看使用说明 netsh advfirewall firewall add rule ? 发现显示不全&#xff0c;不方便看 可以输入下面命令&#xff0c;生成文件&#xff0c;方便查看 netsh advfirewall firewall ad…...