three.js使用ShaderMaterial实现聚光灯光源demo

文章目录

          • 顶点
          • 片元
          • 全部

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心:

顶点
varying vec3 vNormal;varying vec3 vViewPosition;void main() {vNormal = normalMatrix * normal;vNormal = normalize( vNormal );vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);gl_Position = projectionMatrix * modelViewPosition;vec3 transformed = vec3( position );vec4 mvPosition = vec4( transformed, 1.0 );mvPosition = modelViewMatrix * mvPosition;vViewPosition = - mvPosition.xyz;}
片元
 varying vec3 vNormal;               varying vec3 vViewPosition;uniform vec3 AmbientLight;uniform float roughness;#if NUM_SPOT_LIGHTS > 0struct SpotLight {vec3 position;vec3 direction;vec3 color;float distance;float decay;bool visible;float angle;float penumbra;float coneCos;float penumbraCos;};uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];#endif#include <common>float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {return smoothstep( coneCosine, penumbraCosine, angleCosine );}float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {// based upon Frostbite 3 Moving to Physically-based Rendering// page 32, equation 26: E[window1]// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdffloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );if ( cutoffDistance > 0.0 ) {distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );}return distanceFalloff;}void main() {gl_FragColor = vec4(vec3( 1,0,0 ) , 1. );#if NUM_SPOT_LIGHTS > 0#ifdef FLAT_SHADEDvec3 fdx = dFdx( vViewPosition );vec3 fdy = dFdy( vViewPosition );vec3 normal = normalize( cross( fdx, fdy ) );#elsevec3 normal =  vNormal ;normal = normalize( vNormal );#endifvec3 geometryPosition = - vViewPosition;vec3 geometryNormal = normal;vec3 geometryViewDir = normalize( vViewPosition );SpotLight spotLight;vec3 directSpecular = vec3(0.);vec3 diffuse = vec3(0.);for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {spotLight = spotLights[ i ];vec3 lVector = spotLight.position - geometryPosition;vec3 lightDirection = normalize( lVector );// 漫反射float diff = max(dot(normal, lightDirection), 0.0);// * spotLight.colorfloat angleCos = dot( lightDirection, spotLight.direction);float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );// if(angleCos > spotLight.coneCos){//     diffuse = vec3(1.);// }else {//     diffuse = vec3(0.);// }if(spotAttenuation > 0.0){float lightDistance = length( lVector );float attenuation = getDistanceAttenuation(lightDistance, spotLight.distance, spotLight.decay);diffuse += diff * spotLight.color * spotAttenuation * attenuation;}}// gl_FragColor = vec4( directSpecular , 1. );gl_FragColor = vec4( diffuse + AmbientLight , 1. );#endif}
全部
import * as THREE from "three";
import { ThreeHelper } from "@/src/ThreeHelper";
import { MethodBaseSceneSet, LoadGLTF } from "@/src/ThreeHelper/decorators";
import { MainScreen } from "./Canvas";
import type { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
import { Injectable } from "@/src/ThreeHelper/decorators/DI";
import type { GUI } from "dat.gui";
import { SpotLightMaterial } from "@/src/ThreeHelper/shader/material/SpotLight";
import { SpecularShaderMaterial } from "@/src/ThreeHelper/shader/material/Specular";@Injectable
// @ThreeHelper.useWebGPU
export class Main extends MainScreen {static instance: Main;// spotLight = new THREE.SpotLight(0xffffff, 100, 0, 1, 1, 2);spotLight = new THREE.SpotLight(0xffffff, 100, 0, 0.5, 1, 2);constructor(private helper: ThreeHelper) {super(helper);helper.main = this;this.init();Main.instance = this;}@MethodBaseSceneSet({addAxis: true,cameraPosition: new THREE.Vector3(-3, 2, 5),cameraTarget: new THREE.Vector3(0, 0, 0),useRoomLight: false,near: 0.1,far: 800,})init() {this.spotLight.position.set(0, 0, 2);// this.spotLight.target.position.set(0, 0, 0);this.helper.add(this.spotLight);// const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);// directionalLight.position.set(0, 0, 1);// const targetObject = new THREE.Object3D();// targetObject.position.set(0, 0, -1);// this.helper.scene.add(targetObject);// directionalLight.target = targetObject;// this.helper.scene.add(directionalLight);// const light = new THREE.AmbientLight(0x404040);// this.helper.scene.add(light);// {//     const light = new THREE.PointLight(0xffffff, 10, 100);//     light.position.set(0, 0, 3);//     this.helper.scene.add(light);// }{const object = this.helper.create.plane(12, 30);object.mesh.position.y = -1;object.mesh.position.z = -5;object.mesh.rotateX(Math.PI / -2);object.material(new SpotLightMaterial({scene: this.helper.scene,camera: this.helper.camera,roughness: 0,})// new THREE.MeshStandardMaterial({ roughness: 0, metalness: 0 }));// const phongMaterial = new THREE.MeshPhongMaterial();// object.material(phongMaterial);this.helper.add(object.mesh);}const object = this.helper.create.sphere(1, 64, 64);object.material(new SpotLightMaterial({scene: this.helper.scene,camera: this.helper.camera,roughness: 0,})// new THREE.MeshStandardMaterial({ roughness: 0, metalness: 0 }));this.helper.add(object.mesh);{const object = this.helper.create.box(0.3, 0.3, 0.3);object.mesh.position.y = -1;object.mesh.position.x = -1;object.mesh.position.z = -2;object.mesh.rotateY(Math.PI / 4);object.material(new SpotLightMaterial({scene: this.helper.scene,camera: this.helper.camera,roughness: 0,})// new THREE.MeshStandardMaterial({ roughness: 0, metalness: 0 }));this.helper.add(object.mesh);}// plane.material(//     new SpecularShaderMaterial({//         scene: this.helper.scene,//         camera: this.helper.camera,//         roughness: 0.,//     })// );// const phongMaterial = new THREE.MeshPhongMaterial();// object.material(phongMaterial);// phongMaterial.onBeforeCompile = (shader) => {//     shader.fragmentShader = shader.fragmentShader.replace(//         "vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",//         `//         vec3 outgoingLight = reflectedLight.directDiffuse;//         `//     );//     console.log(shader.fragmentShader);// };// plane.material(new THREE.MeshStandardMaterial({roughness:0,metalness:0}));// plane.material(new THREE.MeshBasicMaterial());}@LoadGLTF("/public/models/.glb")loadModel(gltf?: GLTF) {if (gltf) {this.helper.add(gltf.scene);}}@ThreeHelper.InjectAnimation(Main)animation() {// this.spotLight.target.rotation.x += 0.1}@ThreeHelper.AddGUI(Main)createEnvTexture(gui: GUI) {gui.add(this.spotLight, "visible").name("three.spotLight");const prev = this.spotLight.position.clone();const lightPosition = this.spotLight.position;const tempObj = new THREE.Object3D();this.helper.gui?.add({ v: 0 }, "v", -360, 360).onChange((v) => {lightPosition.copy(prev);tempObj.rotation.x = v * (Math.PI / 180);tempObj.updateMatrix();lightPosition.applyMatrix4(tempObj.matrix);// lightDirection.copy(lightPosition).multiplyScalar(-1).normalize();});gui.add(this.spotLight, "angle", 0, Math.PI / 3).onChange((val) => {this.spotLight.angle = val;});gui.add(this.spotLight, "penumbra", 0, 1).onChange((val) => {this.spotLight.penumbra = val;});gui.add(this.spotLight, "decay", 1, 4).onChange((val) => {this.spotLight.decay = val;});gui.add(this.spotLight, "intensity", 0, 100).onChange((val) => {this.spotLight.intensity = val;});gui.addFunction(() => {this.helper.scene.traverse((obj) => {const mesh = obj as THREE.Mesh<THREE.BufferGeometry, THREE.Material>;if (mesh.material) {if (mesh.material.type == "ShaderMaterial") {mesh.userData.material = mesh.material;mesh.material = new THREE.MeshPhongMaterial();} else {mesh.userData.material && (mesh.material = mesh.userData.material);}}});}, "Toggle Material");}
}
import * as THREE from "three";interface SpotLightUniforms {color: THREE.SpotLight["color"];intensity: THREE.SpotLight["intensity"];distance: THREE.SpotLight["distance"];decay: THREE.SpotLight["decay"];visible: THREE.SpotLight["visible"];position: THREE.SpotLight["position"];coneCos: number;penumbraCos: number;
}export class SpotLightMaterial extends THREE.ShaderMaterial {Lights: SpotLightUniforms[] = [];original: ConstructorParameters<typeof THREE.ShaderMaterial>[0];color = new THREE.Color(0xffffff);onBeforeRender(renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera): void {const Lights: SpotLightUniforms[] = [];const viewMatrix = camera.matrixWorldInverse;const vector3 = new THREE.Vector3();scene.traverse((obj) => {if (obj.type == "SpotLight") {const light = obj as THREE.SpotLight;const uniforms = {position: new THREE.Vector3(),direction: new THREE.Vector3(),color: light.color.clone().multiplyScalar(light.intensity),intensity: light.intensity,distance: light.distance,decay: light.decay,visible: light.visible,coneCos: Math.cos(light.angle),penumbraCos: Math.cos(light.angle * (1 - light.penumbra)),};uniforms.position.setFromMatrixPosition(light.matrixWorld);uniforms.position.applyMatrix4(viewMatrix);uniforms.direction.setFromMatrixPosition(light.matrixWorld);vector3.setFromMatrixPosition(light.target.matrixWorld);uniforms.direction.sub(vector3);uniforms.direction.transformDirection(viewMatrix);// console.log(uniforms.position)// console.log(uniforms.direction)Lights.push(uniforms);}});// this.fragmentShader = this.replaceLightNums(this.original!.fragmentShader!, {//     numPointLights: PointLights.length,// });this.uniforms.spotLights.value = Lights;}constructor(params?: ConstructorParameters<typeof THREE.ShaderMaterial>[0] & {scene: THREE.Scene;camera: THREE.PerspectiveCamera;roughness: number;AmbientLight?: THREE.Color;}) {const original = {uniforms: {spotLights: {value: [] as SpotLightUniforms[],},roughness: {value: params?.roughness,},AmbientLight: { value: params?.AmbientLight ?? new THREE.Color(0x000000) },},defines: {RECIPROCAL_PI: 1 / Math.PI,// 平直着色 关闭则 平滑着色FLAT_SHADED: false,},vertexShader: /* glsl */ `varying vec3 vNormal;varying vec3 vViewPosition;void main() {vNormal = normalMatrix * normal;vNormal = normalize( vNormal );vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);gl_Position = projectionMatrix * modelViewPosition;vec3 transformed = vec3( position );vec4 mvPosition = vec4( transformed, 1.0 );mvPosition = modelViewMatrix * mvPosition;vViewPosition = - mvPosition.xyz;}`,fragmentShader: /* glsl */ `varying vec3 vNormal;               varying vec3 vViewPosition;uniform vec3 AmbientLight;uniform float roughness;#if NUM_SPOT_LIGHTS > 0struct SpotLight {vec3 position;vec3 direction;vec3 color;float distance;float decay;bool visible;float angle;float penumbra;float coneCos;float penumbraCos;};uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];#endif#include <common>float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {return smoothstep( coneCosine, penumbraCosine, angleCosine );}float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {// based upon Frostbite 3 Moving to Physically-based Rendering// page 32, equation 26: E[window1]// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdffloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );if ( cutoffDistance > 0.0 ) {distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );}return distanceFalloff;}void main() {gl_FragColor = vec4(vec3( 1,0,0 ) , 1. );#if NUM_SPOT_LIGHTS > 0#ifdef FLAT_SHADEDvec3 fdx = dFdx( vViewPosition );vec3 fdy = dFdy( vViewPosition );vec3 normal = normalize( cross( fdx, fdy ) );#elsevec3 normal =  vNormal ;normal = normalize( vNormal );#endifvec3 geometryPosition = - vViewPosition;vec3 geometryNormal = normal;vec3 geometryViewDir = normalize( vViewPosition );SpotLight spotLight;vec3 directSpecular = vec3(0.);vec3 diffuse = vec3(0.);for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {spotLight = spotLights[ i ];vec3 lVector = spotLight.position - geometryPosition;vec3 lightDirection = normalize( lVector );// 漫反射float diff = max(dot(normal, lightDirection), 0.0);// * spotLight.colorfloat angleCos = dot( lightDirection, spotLight.direction);float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );// if(angleCos > spotLight.coneCos){//     diffuse = vec3(1.);// }else {//     diffuse = vec3(0.);// }if(spotAttenuation > 0.0){float lightDistance = length( lVector );float attenuation = getDistanceAttenuation(lightDistance, spotLight.distance, spotLight.decay);diffuse += diff * spotLight.color * spotAttenuation * attenuation;}}// gl_FragColor = vec4( directSpecular , 1. );gl_FragColor = vec4( diffuse + AmbientLight , 1. );#endif}`,};const SpotLights: SpotLightUniforms[] = [];const viewMatrix = params!.camera.matrixWorldInverse;const vector3 = new THREE.Vector3();params!.scene.traverse((obj) => {if (obj.type == "SpotLight") {const light = obj as THREE.SpotLight;const uniforms = {position: new THREE.Vector3(),direction: new THREE.Vector3(),color: light.color.clone().multiplyScalar(light.intensity),intensity: light.intensity,distance: light.distance,decay: light.decay,visible: light.visible,coneCos: Math.cos(light.angle),penumbraCos: Math.cos(light.angle * (1 - light.penumbra)),};console.log(uniforms.coneCos);console.log(uniforms.penumbraCos);uniforms.position.setFromMatrixPosition(light.matrixWorld);uniforms.position.applyMatrix4(viewMatrix);uniforms.direction.setFromMatrixPosition(light.matrixWorld);vector3.setFromMatrixPosition(light.target.matrixWorld);uniforms.direction.sub(vector3);uniforms.direction.transformDirection(viewMatrix);SpotLights.push(uniforms);}});const replaceLightNums = (string: string, parameters: { numSpotLights: number }) => {return string.replace(/NUM_SPOT_LIGHTS/g, "" + parameters.numSpotLights);};original.uniforms.spotLights = { value: SpotLights };original.fragmentShader = replaceLightNums(original!.fragmentShader!, {numSpotLights: SpotLights.length,});super(original);this.original = original;}
}

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

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

相关文章

【jvm】堆的内部结构

目录 1. 说明2. 年轻代&#xff08;Young Generation&#xff09;2.1 说明2.2 Eden区2.3 Survivor区 3. 老年代&#xff08;Old Generation&#xff09;3.1 说明3.2 对象存放3.3 垃圾回收 4. jdk7及之前5. jdk8及之后 1. 说明 1.JVM堆的内部结构主要包括年轻代&#xff08;You…

在线教育系统源码开发详解:网校培训平台搭建的核心技术

本篇文章&#xff0c;笔者将详细介绍在线教育系统源码的开发过程&#xff0c;重点聚焦网校培训平台搭建的核心技术&#xff0c;以期为有意从事在线教育行业的开发者提供实用的参考。 一、在线教育系统的构成 前端负责用户的交互体验&#xff0c;后端处理业务逻辑&#xff0c;…

DeepLearn-实现天气的识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 本次使用的数据集有晴天、雨天、多云和日出。 导入基本的包 包括读取文件、图像处理、科学计算和tensorflow的api包layers是层模块&#xff0c;提供了神经网络…

pycharm与anaconda下的pyside6的安装记录

一、打开anaconda虚拟环境的命令行窗口&#xff0c;pip install&#xff0c;加入清华源&#xff1a; pip install PySide6 -i https://pypi.tuna.tsinghua.edu.cn/simple 二、打开pycharm&#xff0c;在文件--设置--工具--外部工具中配置一下三项&#xff1a; 1、 QtDesigner…

Java常用任务调度

JAVA 任务调度技术 前言 在日常开发过程中&#xff0c;我们经常会遇到周期性执行某段代码的场景。比如定期同步订单&#xff0c;定期更新商品信息&#xff0c;定期发送消息等。这些重复执行的代码可以抽象为一个任务(Task)。 一个Task的特点如下&#xff1a; 包含需要执行的业…

将多个commit合并成一个commit并提交

0 Preface/foreword 1 压缩多个commit方法 1.1 git merge --squash 主分支&#xff1a;main 开发分支&#xff1a;test 当前在test分支提交了8个commits&#xff0c;功能已经开发完成&#xff0c;需要将test分支合并到main分支&#xff0c;但是不想在合并时候&#xff0c;看…

开源一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码

大家好&#xff0c;我是一颗甜苞谷&#xff0c;今天分享一款基于若依的wms仓库管理系统&#xff0c;支持lodop和网页打印入库单、出库单的源码。 前言 在当今快速发展的商业环境中&#xff0c;库存管理对于企业来说至关重要。然而&#xff0c;许多企业仍然依赖于传统的、手动…

【Rust】环境搭建

▒ 目录 ▒ &#x1f6eb; 导读需求 1️⃣ 安装Chocolatey安装依赖 2️⃣ 安装RustRover安装toolchain&#xff08;rustup、VS&#xff09;重启配置生效设置安装插件 &#x1f4d6; 参考资料 &#x1f6eb; 导读 需求 重装系统&#xff0c;记录下环境搭建遇到的问题。 1️⃣ …

安装Ubuntu系统

打开vmware&#xff0c;新建一个Ubuntu虚拟机&#xff0c;点击自定义&#xff0c;进入下一步 &#xff0c;选择Workstation 17.x后&#xff0c;点击下一步 选择稍后安装系统选项&#xff0c;进入选择客户机操作系统页面&#xff0c;客户机操作系统选择Linux&#xff0c;版本选…

rom定制系列------红米note8_miui14安卓13定制修改固件 带面具root权限 刷写以及界面预览

&#x1f49d;&#x1f49d;&#x1f49d;红米note8机型代码&#xff1a;ginkgo。高通芯片。此固件官方最终版为稳定版12.5.5安卓11的版本。目前很多工作室需要高安卓版本的固件来适应他们的软件。并且需要root权限。根据客户要求。修改固件为完全root。并且修改为可批量刷写的…

电脑仅一个C盘如何重装系统?超简单教程分享!

当我们的电脑仅配备一个C盘时&#xff0c;重装系统的过程可能会显得尤为棘手。因为一旦格式化硬盘&#xff0c;安装系统的分区也可能被一并清除&#xff0c;导致安装过程中断。这时候我们完全可以通过对电脑进行分区来解决这一问题。分区不仅能够帮助我们更好地管理硬盘空间&am…

提升网站速度与性能优化的有效策略与实践

内容概要 在数字化快速发展的今天&#xff0c;网站速度与性能优化显得尤为重要&#xff0c;它直接影响用户的浏览体验。用户在访问网站时&#xff0c;往往希望能够迅速获取信息&#xff0c;若加载时间过长&#xff0c;轻易可能导致他们转向其他更为流畅的网站。因此&#xff0…

流媒体协议.之(RTP,RTCP,RTSP,RTMP,HTTP)(二)

继续上篇介绍&#xff0c;本篇介绍一下封装RTP的数据格式&#xff0c;如何将摄像头采集的码流&#xff0c;音频的码流&#xff0c;封装到rtp里&#xff0c;传输。 有自己私有协议例子&#xff0c;有rtp协议&#xff0c;参考代码。注意不是rtsp协议。 一、私有协议 玩过tcp协议…

构建灵活、高效的HTTP/1.1应用:探索h11库

文章目录 构建灵活、高效的HTTP/1.1应用&#xff1a;探索h11库背景这个库是什么&#xff1f;如何安装这个库&#xff1f;库函数使用方法使用场景常见的Bug及解决方案总结 构建灵活、高效的HTTP/1.1应用&#xff1a;探索h11库 背景 在现代网络应用中&#xff0c;HTTP协议是基础…

利用游戏引擎的优势

大家好&#xff0c;我是小蜗牛。 在当今快速发展的游戏产业中&#xff0c;选择合适的游戏引擎对开发者来说至关重要。Cocos Creator作为一款功能强大且灵活的游戏引擎&#xff0c;为开发者提供了丰富的工具和资源&#xff0c;使他们能够高效地开发出优秀的游戏。本文将探讨如何…

仓颉编程语言官网正式上线 !首个公测版本开放下载 !

今年6月21日&#xff0c;华为开发者大会&#xff08;HDC&#xff09;正式公开介绍了华为自研的通用编程语言&#xff1a;仓颉编程语言&#xff0c;并发布了HarmonyOS NEXT仓颉语言开发者预览版&#xff0c;开发者可以使用仓颉开发鸿蒙原生应用。4个月以来&#xff0c;仓颉编程语…

PHP爬虫的奇幻之旅:如何用代码“偷窥”京东商品的SKU信息

开篇&#xff1a;代码界的007 想象一下&#xff0c;你是一名代码界的007&#xff0c;你的任务是潜入京东的数据库&#xff0c;获取商品的SKU信息。不过别担心&#xff0c;我们不是真的去偷数据&#xff0c;而是用PHP编写一个爬虫&#xff0c;合法地获取公开的API数据。这不仅是…

C++初阶(七)--类和对象(4)

目录 ​编辑 一、再谈构造函数 1.构造函数体赋值 2.初始化列表 二、类型转换 1.隐式类型转换 2.explicit关键字 3.类类型之间的对象隐式转换 三、static成员函数 1.概念 2.特性 3.面试题&#xff1a; 四、友元函数 1.基本介绍 2.回顾&#xff1a; 3.友元类&am…

【问题记录】当机器人存在多个串口需要绑定时udevadm的作用

一、正常绑定 输入sudo udevadm info -a /dev/ttyUSBx | grep KERNELS 命令 会出现KERNELS的编号&#xff0c;记录编号。 修改规则文件/etc/udev/rules.d/99-usb.rules 添加以下命令 KERNEL"ttyUSB*", KERNELS"2-1.2:1.0", MODE:"0666", GROU…

kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?

大家好&#xff0c;我是锋哥。今天分享关于【kafka 分布式&#xff08;不是单机&#xff09;的情况下&#xff0c;如何保证消息的顺序消费?】面试题&#xff1f;希望对大家有帮助&#xff1b; kafka 分布式&#xff08;不是单机&#xff09;的情况下&#xff0c;如何保证消息的…