轻量封装WebGPU渲染系统示例<42>- vsm阴影实现过程(源码)

news2025/1/23 23:17:10

前向实时渲染vsm阴影实现的主要步骤:

        1. 编码深度数据,存到一个rtt中。

        2. 纵向和横向执行遮挡信息blur filter sampling, 存到对应的rtt中。

        3. 将上一步的结果(rtt)应用到可接收阴影的材质中。

具体代码情况文章最后附上的实现源码。

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/BaseVSMShadowTest.ts

当前示例运行效果:

主要的WGSL Shader代码:

编码深度:

struct VertexOutput {
	@builtin(position) Position: vec4<f32>,
	@location(0) projPos: vec4<f32>,
	@location(1) objPos: vec4<f32>
}
@vertex
fn vertMain(
    @location(0) position: vec3<f32>
) -> VertexOutput {
    let objPos = vec4(position.xyz, 1.0);
    let wpos = objMat * objPos;
    var output: VertexOutput;
    let projPos = projMat * viewMat * wpos;
    output.Position = projPos;
    output.projPos = projPos;
    output.objPos = objPos;
    return output;
}

const PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)
const UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)

const PackFactors = vec3<f32>(256. * 256. * 256., 256. * 256., 256.);
const UnpackFactors = UnpackDownscale / vec4<f32>(PackFactors, 1.0);

const ShiftRight8 = 1. / 256.;

fn packDepthToRGBA(v: f32) -> vec4<f32> {
    var r = vec4<f32>(fract(v * PackFactors), v);
    let v3 = r.yzw - (r.xyz * ShiftRight8);
    r = vec4<f32>(v3.x, v3);
    return r * PackUpscale;
}

@fragment
fn fragMain(
    @location(0) projPos: vec4<f32>,
    @location(1) objPos: vec4<f32>
) -> @location(0) vec4<f32> {
    let fragCoordZ = 0.5 * projPos[2] / projPos[3] + 0.5;
    var color4 = packDepthToRGBA( fragCoordZ );
    return color4;
}

纵向和横向执行遮挡信息blur filter sampling:

struct VertexOutput {
	@builtin(position) Position: vec4<f32>,
	@location(0) uv: vec2<f32>
}
@vertex
fn vertMain(
    @location(0) position: vec3<f32>,
    @location(1) uv: vec2<f32>
) -> VertexOutput {
    var output: VertexOutput;
    output.Position = vec4(position.xyz, 1.0);
    output.uv = uv;
    return output;
}


const PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)
const UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)

const PackFactors = vec3<f32>(256. * 256. * 256., 256. * 256., 256.);
const UnpackFactors = UnpackDownscale / vec4<f32>(PackFactors, 1.0);

const ShiftRight8 = 1. / 256.;

fn packDepthToRGBA(v: f32) -> vec4<f32> {
    var r = vec4<f32>(fract(v * PackFactors), v);
    let v3 = r.yzw - (r.xyz * ShiftRight8);
    return vec4<f32>(v3.x, v3) * PackUpscale;
}


fn unpackRGBAToDepth( v: vec4<f32> ) -> f32 {
    return dot( v, UnpackFactors );
}

fn pack2HalfToRGBA( v: vec2<f32> ) -> vec4<f32> {
    let r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));
    return vec4<f32>( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);
}
fn unpackRGBATo2Half( v: vec4<f32> ) -> vec2<f32> {
    return vec2<f32>( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );
}

const SAMPLE_RATE = 0.25;
const HALF_SAMPLE_RATE = 0.125;
@fragment
fn fragMain(
    @location(0) uv: vec2<f32>,
) -> @location(0) vec4<f32> {
    
    var mean = 0.0;
    var squared_mean = 0.0;
    
    let resolution = viewParam.zw;
    let fragCoord = resolution * uv;
    
    let radius = param[3];
    let c4 = textureSample(shadowDepthTexture, shadowDepthSampler, uv);
    var depth = unpackRGBAToDepth( c4 );

    for ( var i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {

        #ifdef USE_HORIZONAL_PASS

            let distribution = unpackRGBATo2Half( textureSample(shadowDepthTexture, shadowDepthSampler, ( fragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );
            mean += distribution.x;
            squared_mean += distribution.y * distribution.y + distribution.x * distribution.x;

        #else

            depth = unpackRGBAToDepth( textureSample(shadowDepthTexture, shadowDepthSampler, ( fragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );
            mean += depth;
            squared_mean += depth * depth;

        #endif

    }

    mean = mean * HALF_SAMPLE_RATE;
    squared_mean = squared_mean * HALF_SAMPLE_RATE;

    let std_dev = sqrt( squared_mean - mean * mean );

    var color4 = pack2HalfToRGBA( vec2<f32>( mean, std_dev ) );

    return color4;
}

应用到可接收阴影的材质中(示例用法):


struct VertexOutput {
	@builtin(position) Position: vec4<f32>,
	@location(0) uv: vec2<f32>,
	@location(1) worldNormal: vec3<f32>,
	@location(2) svPos: vec4<f32>
}
@vertex
fn vertMain(
    @location(0) position: vec3<f32>,
    @location(1) uv: vec2<f32>,
    @location(2) normal: vec3<f32>
) -> VertexOutput {
    let objPos = vec4(position.xyz, 1.0);
    let wpos = objMat * objPos;
    var output: VertexOutput;
    let projPos = projMat * viewMat * wpos;
    output.Position = projPos;
    // output.normal = normal;
    let invMat33 = inverseM33(m44ToM33(objMat));
    output.uv = uv;
    output.worldNormal = normalize(normal * invMat33);
    output.svPos = shadowMatrix * wpos;
    return output;
}

fn pack2HalfToRGBA( v: vec2<f32> ) -> vec4<f32> {
	let r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));
	return vec4<f32>( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);
}
fn unpackRGBATo2Half( v: vec4<f32> ) -> vec2<f32> {
	return vec2<f32>( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );
}

fn texture2DDistribution( uv: vec2<f32> ) -> vec2<f32> {
    let v4 = textureSample(shadowDepthTexture, shadowDepthSampler, uv );
    return unpackRGBATo2Half( v4 );

}
fn VSMShadow (uv: vec2<f32>, compare: f32 ) -> f32 {

    var occlusion = 1.0;

    let distribution = texture2DDistribution( uv );

    let hard_shadow = step( compare , distribution.x ); // Hard Shadow

    if (hard_shadow != 1.0 ) {

        let distance = compare - distribution.x ;
        let variance = max( 0.00000, distribution.y * distribution.y );
        var softness_probability = variance / (variance + distance * distance ); // Chebeyshevs inequality
        softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); // 0.3 reduces light bleed
        occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );

    }
    return occlusion;

}
fn getVSMShadow( shadowMapSize: vec2<f32>, shadowBias: f32, shadowRadius: f32, shadowCoordP: vec4<f32> ) -> f32 {

    var shadowCoord = vec4<f32>(shadowCoordP.xyz / vec3<f32>(shadowCoordP.w), shadowCoordP.z + shadowBias);
   
    let inFrustumVec = vec4<bool> ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
    let inFrustum = all( inFrustumVec );

    let frustumTestVec = vec2<bool>( inFrustum, shadowCoord.z <= 1.0 );
    var shadow = VSMShadow( shadowCoord.xy, shadowCoord.z );
    if ( !all( frustumTestVec ) ) {
        shadow = 1.0;
    }
    return shadow;
}

@fragment
fn fragMain(
    @location(0) uv: vec2<f32>,
    @location(1) worldNormal: vec3<f32>,
    @location(2) svPos: vec4<f32>
) -> @location(0) vec4<f32> {
    var color = vec4<f32>(1.0);
    var shadow = getVSMShadow(params[1].xy, params[0].x, params[0].z, svPos );
    let shadowIntensity = 1.0 - params[0].w;
    shadow = clamp(shadow, 0.0, 1.0) * (1.0 - shadowIntensity) + shadowIntensity;
    var f = clamp(dot(worldNormal, params[2].xyz),0.0,1.0);
    if(f > 0.0001) {
        f = min(shadow,clamp(f, shadowIntensity,1.0));
    }else {
        f = shadowIntensity;
    }
    var color4 = vec4<f32>(color.xyz * vec3(f * 0.9 + 0.1), 1.0);
    return color4;
}

此示例基于此渲染系统实现,当前示例TypeScript源码如下:

export class BaseVSMShadowTest {
	private mRscene = new RendererScene();
	private mShadowCamera: Camera;
	private mDebug = false;
	initialize(): void {

		this.mRscene.initialize({
			canvasWith: 512,
			canvasHeight: 512,
			rpassparam: { multisampleEnabled: true }
		});
		this.initScene();
		this.initEvent();
	}

	private mEntities: Entity3D[] = [];
	private initScene(): void {

		let rc = this.mRscene;

		this.buildShadowCam();

		let sph = new SphereEntity({
			radius: 80,
			transform: {
				position: [-230.0, 100.0, -200.0]
			}
		});
		this.mEntities.push(sph);
		rc.addEntity(sph);

		let box = new BoxEntity({
			minPos: [-30, -30, -30],
			maxPos: [130, 230, 80],
			transform: {
				position: [160.0, 100.0, -210.0],
				rotation: [50, 130, 80]
			}
		});
		this.mEntities.push(box);
		rc.addEntity(box);

		let torus = new TorusEntity({
			transform: {
				position: [160.0, 100.0, 210.0],
				rotation: [50, 30, 80]
			}
		});
		this.mEntities.push(torus);
		rc.addEntity(torus);
		if (!this.mDebug) {
			this.applyShadow();
		}

	}
	private mShadowDepthRTT = { uuid: "rtt-shadow-depth", rttTexture: {}, shdVarName: 'shadowDepth' };
	private mOccVRTT = { uuid: "rtt--occV", rttTexture: {}, shdVarName: 'shadowDepth' };
	private mOccHRTT = { uuid: "rtt--occH", rttTexture: {}, shdVarName: 'shadowDepth' };
	private applyShadowDepthRTT(): void {

		let rc = this.mRscene;

		// rtt texture proxy descriptor
		let rttTex = this.mShadowDepthRTT;
		// define a rtt pass color colorAttachment0
		let colorAttachments = [
			{
				texture: rttTex,
				// green clear background color
				clearValue: { r: 1, g: 1, b: 1, a: 1.0 },
				loadOp: "clear",
				storeOp: "store"
			}
		];
		// create a separate rtt rendering pass
		let rPass = rc.createRTTPass({ colorAttachments });
		rPass.node.camera = this.mShadowCamera;

		let extent = [-0.5, -0.5, 0.8, 0.8];

		const shadowDepthShdSrc = {
			shaderSrc: { code: shadowDepthWGSL, uuid: "shadowDepthShdSrc" }
		};
		let material = this.createDepthMaterial(shadowDepthShdSrc);
		let es = this.createDepthEntities([material], false);
		for (let i = 0; i < es.length; ++i) {
			rPass.addEntity(es[i]);
		}

		// 显示渲染结果
		extent = [-0.95, -0.95, 0.4, 0.4];
		let entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: rttTex }] });
		rc.addEntity(entity);
	}
	private applyBuildDepthOccVRTT(): void {
		let rc = this.mRscene;

		// rtt texture proxy descriptor
		let rttTex = this.mOccVRTT;
		// define a rtt pass color colorAttachment0
		let colorAttachments = [
			{
				texture: rttTex,
				// green clear background color
				clearValue: { r: 1, g: 1, b: 1, a: 1.0 },
				loadOp: "clear",
				storeOp: "store"
			}
		];
		// create a separate rtt rendering pass
		let rPass = rc.createRTTPass({ colorAttachments });
		let material = new ShadowOccBlurMaterial();

		let ppt = material.property;
		ppt.setShadowRadius(this.mShadowRadius);
		ppt.setViewSize(this.mShadowMapW, this.mShadowMapH);

		material.addTextures([this.mShadowDepthRTT]);
		let extent = [-1, -1, 2, 2];
		let rttEntity = new FixScreenPlaneEntity({ extent, materials: [material] });
		rPass.addEntity(rttEntity);

		// 显示渲染结果
		extent = [-0.5, -0.95, 0.4, 0.4];
		let entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: rttTex }] });
		rc.addEntity(entity);
	}

	private applyBuildDepthOccHRTT(): void {
		let rc = this.mRscene;

		// rtt texture proxy descriptor
		let rttTex = this.mOccHRTT;
		// define a rtt pass color colorAttachment0
		let colorAttachments = [
			{
				texture: rttTex,
				// green clear background color
				clearValue: { r: 1, g: 1, b: 1, a: 1.0 },
				loadOp: "clear",
				storeOp: "store"
			}
		];
		// create a separate rtt rendering pass
		let rPass = rc.createRTTPass({ colorAttachments });
		let material = new ShadowOccBlurMaterial();
		let ppt = material.property;
		ppt.setShadowRadius(this.mShadowRadius);
		ppt.setViewSize(this.mShadowMapW, this.mShadowMapH);
		material.property.toHorizonalBlur();
		material.addTextures([this.mOccVRTT]);
		let extent = [-1, -1, 2, 2];
		let rttEntity = new FixScreenPlaneEntity({ extent, materials: [material] });
		rPass.addEntity(rttEntity);

		// 显示渲染结果
		extent = [-0.05, -0.95, 0.4, 0.4];
		let entity = new FixScreenPlaneEntity({ extent, flipY: true, textures: [{ diffuse: rttTex }] });
		rc.addEntity(entity);
	}
	private createDepthMaterial(shaderSrc: WGRShderSrcType, faceCullMode = "none"): WGMaterial {

		let pipelineDefParam = {
			depthWriteEnabled: true,
			faceCullMode,
			blendModes: [] as string[]
		};

		const material = new WGMaterial({
			shadinguuid: "shadow-depth_material",
			shaderSrc,
			pipelineDefParam
		});

		return material;
	}
	private createDepthEntities(materials: WGMaterial[], flag = false): Entity3D[] {

		const rc = this.mRscene;

		let entities = [];
		let ls = this.mEntities;
		let tot = ls.length;
		for (let i = 0; i < tot; ++i) {
			let et = ls[i];
			let entity = new Entity3D({ transform: et.transform });
			entity.materials = materials;
			entity.geometry = et.geometry;
			entities.push(entity);
			if (flag) {
				rc.addEntity(entity);
			}
		}
		return entities;
	}
	private mShadowBias = -0.0005;
	private mShadowRadius = 2.0;
	private mShadowMapW = 512;
	private mShadowMapH = 512;
	private mShadowViewW = 1300;
	private mShadowViewH = 1300;
	private buildShadowCam(): void {

		const cam = new Camera({
			eye: [600.0, 800.0, -600.0],
			near: 0.1,
			far: 1900,
			perspective: false,
			viewWidth: this.mShadowViewW,
			viewHeight: this.mShadowViewH
		});
		cam.update();
		this.mShadowCamera = cam;
		const rsc = this.mRscene;
		let frameColors = [[1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 1.0]];
		let boxFrame = new BoundsFrameEntity({ vertices8: cam.frustum.vertices, frameColors });
		rsc.addEntity(boxFrame);
	}
	private initEvent(): void {
		const rc = this.mRscene;
		rc.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDown);
		new MouseInteraction().initialize(rc, 0, false).setAutoRunning(true);
	}
	private mFlag = -1;
	private buildShadowReceiveEntity(): void {

		let cam = this.mShadowCamera;
		let transMatrix = new Matrix4();
		transMatrix.setScaleXYZ(0.5, -0.5, 0.5);
		transMatrix.setTranslationXYZ(0.5, 0.5, 0.5);
		let shadowMat = new Matrix4();
		shadowMat.copyFrom(cam.viewProjMatrix);
		shadowMat.append(transMatrix);

		let material = new ShadowReceiveMaterial();
		let ppt = material.property;

		ppt.setShadowRadius(this.mShadowRadius);
		ppt.setShadowBias(this.mShadowBias);
		ppt.setShadowSize(this.mShadowMapW, this.mShadowMapH);
		ppt.setShadowMatrix(shadowMat);
		ppt.setDirec(cam.nv);

		material.addTextures([this.mOccHRTT]);

		const rc = this.mRscene;
		let plane = new PlaneEntity({
			axisType: 1,
			extent: [-600, -600, 1200, 1200],
			transform: {
				position: [0, -1, 0]
			},
			materials: [material]
		});
		rc.addEntity(plane);
	}
	private applyShadow(): void {

		this.applyShadowDepthRTT();
		this.applyBuildDepthOccVRTT();
		this.applyBuildDepthOccHRTT();
		this.buildShadowReceiveEntity();
	}
	private mouseDown = (evt: MouseEvent): void => {
		this.mFlag++;
		if (this.mDebug) {
			if (this.mFlag == 0) {
				this.applyShadowDepthRTT();
			} else if (this.mFlag == 1) {
				this.applyBuildDepthOccVRTT();
			} else if (this.mFlag == 2) {
				this.applyBuildDepthOccHRTT();
			} else if (this.mFlag == 3) {
				this.buildShadowReceiveEntity();
			}
		}
	};
	run(): void {
		this.mRscene.run();
	}
}

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

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

相关文章

Azure Machine Learning - 使用 Python 进行语义排名

在 Azure AI 搜索中&#xff0c;语义排名是查询端功能&#xff0c;它使用 Microsoft AI 对搜索结果重新评分&#xff0c;将具有更多语义相关性的结果移动到列表顶部。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&am…

基于单片机的多功能视力保护器(论文+源码)

1.系统设计 多功能视力保护器在设计过程中能够对用户阅读过程中的各项数据信息进行控制&#xff0c;整体设计分为亮种模式&#xff0c;分别是自动模式&#xff0c;手动模式。在自动模式的控制下&#xff0c;当单片机检测当前光照不强且有人时就开启LED灯&#xff0c;并且会根据…

实现跨平台高手必修的课程,玩转Flutter动态化的解决的一些精华部分总结

Flutter作为一种快速、可靠的跨平台移动应用开发框架&#xff0c;在动态化方面也有很多令人兴奋的特性。本文将总结Flutter动态化的一些精华部分&#xff0c;帮助开发者更好地利用这些功能。 正文&#xff1a; 在实现跨平台高手必修的课程中&#xff0c;Flutter动态化是一个不…

kubernetes七层负载Ingress搭建(K8S1.23.5)

首先附上K8S版本及Ingress版本对照 Ingress介绍 NotePort&#xff1a;该方式的缺点是会占用很多集群机器的端口&#xff0c;当集群服务变多时&#xff0c;这个缺点就愈发的明显(srevice变多&#xff0c;需要的端口就需要多) LoadBalancer&#xff1a;该方式的缺点是每个servi…

人工智能学习5(特征抽取)

编译环境&#xff1a;PyCharm 文章目录 编译环境&#xff1a;PyCharm 特征抽取无监督特征抽取(之PCA)代码实现鸢尾花数据集无监督特征抽取 有监督特征抽取(之LDA)代码实现,生成自己的数据集并进行有监督特征抽取(LDA)生成自己的数据集PCA降维和LDA降维对比 代码实现LDA降维对鸢…

mysql服务日志打印,时区不对的问题

查资料发现 原来日志的时区和服务器的时区不是一个参数控制的 log_timestamps 单独控制日志的时区 show global variables like log_timestamps;看到默认的是UTC&#xff0c;只需要修改为和系统一致就行 #数据库中直接修改 set global log_timestampsSYSTEM;#配置文件my.cn…

NacosSync 用户手册

手册目标 理解 NacosSync 组件启动 NacosSync 服务通过一个简单的例子&#xff0c;演示如何将注册到 Zookeeper 的 Dubbo 客户端迁移到 Nacos。 介绍 NacosSync是一个支持多种注册中心的同步组件,基于Spring boot开发框架,数据层采用Spring Data JPA,遵循了标准的JPA访问规范…

面试题:MySQL为什么选择B+树作为索引结构

文章目录 前言二、平衡二叉树(AVL)&#xff1a;旋转耗时三、红黑树&#xff1a;树太高四、B树&#xff1a;为磁盘而生五、B树六、感受B树的威力七、总结 前言 在MySQL中&#xff0c;无论是Innodb还是MyIsam&#xff0c;都使用了B树作索引结构(这里不考虑hash等其他索引)。本文…

视频生成的发展史及其原理解析:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0

前言 考虑到文生视频开始爆发&#xff0c;比如11月份就是文生视频最火爆的一个月 11月3日&#xff0c;Runway的Gen-2发布里程碑式更新&#xff0c;支持4K超逼真的清晰度作品(runway是Stable Diffusion最早版本的开发商&#xff0c;Stability AI则开发的SD后续版本)11月16日&a…

wordpress安装之Linux解压缩安装

本次教程是为了让大家少走弯路&#xff0c;可以更直观的去认识我们不懂的知识面。 首先我们安装解压缩的软件 命令如下&#xff1a; yum install -y unzip 上一篇我们讲到传输文件了 这篇我们把传输过来的压缩包解压并进行安装。follow me&#xff01; 我们输入命令 unzi…

Spring Cloud NetFlix

文章目录 Spring Cloud1 介绍2 Eureka&#xff08;服务注册与发现&#xff09;2.1 介绍2.2 服务注册与发现示例2.2.1 Eureka Server&#xff1a;springcloud-eureka2.2.2 Eureka Client&#xff1a;springcloud-provider2.2.3 Eureka Client&#xff1a;springcloud-consumer 2…

前端可滚动分类商品List列表 可用于电商分类列表

前端可滚动分类商品List列表 可用于电商分类列表 引言 在电商应用中&#xff0c;一个高效、用户友好的分类列表是提高用户体验和转化率的关键。本文将探讨如何使用xg-list-item、uni-grid和xg-tab等组件创建一个可滚动的分类商品列表&#xff0c;并处理相关的用户交互事件&…

Python容器——字典

Key——Value 键值对

canvas 轮廓路径提取效果

前言 微信公众号&#xff1a;前端不只是切图 轮廓 对内容做border效果&#xff0c;可以先看下代码运行的效果 内容是黑线构成的五角星&#xff0c;其轮廓就是红线的部分&#xff0c;本文主要介绍如何在canvas中实现这种效果 Marching Square 这里运用到的是marching square算法…

探索 Web API:SpeechSynthesis 与文本语言转换技术

一、引言 随着科技的不断发展&#xff0c;人机交互的方式也在不断演变。语音识别和合成技术在人工智能领域中具有重要地位&#xff0c;它们为残障人士和日常生活中的各种场景提供了便利。Web API 是 Web 应用程序接口的一种&#xff0c;允许开发者构建与浏览器和操作系统集成的…

Kubernetes(K8s)_16_CSI

Kubernetes&#xff08;K8s&#xff09;_16_CSI CSICSI实现CSI接口CSI插件 CSI CSI(Container Storage Interface): 实现容器存储的规范 本质: Dynamic Provisioning、Attach/Detach、Mount/Unmount等功能的抽象CSI功能通过3个gRPC暴露服务: IdentityServer、ControllerServe…

微信小程序组件与插件有啥区别?怎么用?

目录 一、微信小程序介绍 二、微信小程序组件 三、微信小程序插件 四、微信小程序组件与插件有啥区别 一、微信小程序介绍 微信小程序是一种基于微信平台的应用程序&#xff0c;它可以在微信客户端内直接运行&#xff0c;无需下载和安装。微信小程序具有轻量、便捷、跨平台…

RT-Thread ADC_DMA

看到这里&#xff0c;相信大家已经尝试过网上各类ADC_DMA传输的文章&#xff0c;且大多都并不能实现&#xff0c;因为在RT-Thread中并没有找到关于ADC的DMA接口&#xff0c;在官方例程中有关DMA的传输也只有一个串口接收的介绍&#xff0c;找遍全网怕也没能找到真正有用的消息。…

PyLMKit(5):基于网页知识库的检索增强生成RAG

基于网页知识库的检索增强生成RAG 0.项目信息 日期&#xff1a; 2023-12-2作者&#xff1a;小知课题: RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;是一种利用知识库检索的方法&#xff0c;提供与用户查询相关的内容&#xff0c;从而…

1 NLP分类之:FastText

0 数据 https://download.csdn.net/download/qq_28611929/88580520?spm1001.2014.3001.5503 数据集合&#xff1a;0 NLP: 数据获取与EDA-CSDN博客 词嵌入向量文件&#xff1a; embedding_SougouNews.npz 词典文件&#xff1a;vocab.pkl 1 模型 基于fastText做词向量嵌入…