3D模型顶点颜色转纹理【SIMPLYGON】

news2024/12/23 13:38:57

在这篇博客中,我们将了解如何将顶点颜色烘焙到纹理中。 其用例是某些照片扫描资产,其中颜色数据保存到顶点颜色中。 我们将了解如何使用 remesher 和聚合器管道来完成此操作。 我们还将介绍如何为顶点颜色材质创建着色网络以及如何从模型后处理中删除顶点颜色。

这个博客或多或少与我们的将纹理烘焙为顶点颜色博客相反,在那篇博客中我们采取了相反的方式; 纹理到顶点颜色。

此示例将使用 Blender 中的 Simplygon 集成,但相同的概念可以应用于 Simplygon API 的所有其他集成。

NSDT在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

1、需要解决的问题

我们要优化的资源是没有 UV 的照片扫描资源,其中颜色数据保存为顶点颜色。 我们想要的输出是一个模型,其中颜色数据保存在纹理中。 输入资源非常密集,因此我们希望使其更加轻量级。

2、使用remesh解决方案

由于我们的原始模型具有非常密集的几何形状,因此我们可能也希望减少其多边形数量。 我们的remesh管道非常适合这项任务。

2.1 Blender导出

第一步是从 Blender 导出到 Simplygon。 为此,我们将场景导出为 glTF,然后使用场景导入器将其导入 Simplygon。

def export_selection(sg, file_path):
    """Export the current selected objects into Simplygon."""
    bpy.ops.export_scene.gltf(filepath = file_path, use_selection=True)
    sceneImporter = sg.CreateSceneImporter()
    sceneImporter.SetImportFilePath(file_path)
    sceneImporter.Run()
    scene = sceneImporter.GetScene()
    return scene

2.2 设置顶点颜色着色网络

如果我们通过 UI 对资源执行颜色投射,我们将不会得到任何颜色输出。 原因是颜色存储在顶点颜色中而不是纹理中。 为了让颜色投射器理解我们想要使用顶点颜色作为输入,我们需要创建一个自定义着色网络。

首先,我们需要为基色添加材质通道。 在 Blender 中,这被称为 Basecolor。 然后我们可以创建一个顶点颜色节点并指定要使用的 VertexColorIndex。 在我们的例子中,我们只有一种顶点颜色,因此索引为 0。然后,我们将顶点颜色节点指定为材质颜色通道的着色网络。

def setup_vertex_color_material(sg, material, channel):
    """Set material to use vertex color as color."""

    material.AddMaterialChannel(channel)
    shading_node = sg.CreateShadingVertexColorNode()
    shading_node.SetVertexColorIndex(vertex_color_index)
    material.SetShadingNetwork(channel, shading_node)

一旦我们有了创建顶点颜色材质的函数,我们就可以迭代场景材质表中的每种材质,并将其设置为使用我们的自定义顶点颜色着色网络。

def setup_vertex_color_materials(sg, scene):
    """Set all materials in scene to vertex colored."""

    material_table = scene.GetMaterialTable()
    for i in range(0, material_table.GetMaterialsCount()):
        material = material_table.GetMaterial(i)
        setup_vertex_color_material(sg, material, color_channel)

2.3 创建remeshing管线

我们的remesh管道做了两件事; 创建一个水密的低多边形网格并将原始资源中的材料烘焙到其中。 这使得它非常适合我们的用例。 我们首先创建一个重新网格化管道,然后根据我们所需的模型输出质量设置 OnScreenSize。 值得一提的是,屏幕尺寸太大会导致缩放效果很差,在这种情况下,请查看我们的博客使用镶嵌属性加速重新网格化,了解如何加快速度。

映射图像负责将表面从原始模型转换为我们重新划分的模型。 我们需要创建一个来传输材质,因此需要将GenerateMappingImage 设置为True。 我们还可以使用TextureHeight和TextureWidth指定大小。

def create_pipline(sg): 
    """Create remesing pipeline and color caster."""
    pipeline = sg.CreateRemeshingPipeline()
    settings = pipeline.GetRemeshingSettings()

    settings.SetOnScreenSize(resolution)
    
    mapping_image_settings = pipeline.GetMappingImageSettings()
    material_output_settings = mapping_image_settings.GetOutputMaterialSettings(0)
    material_output_settings.SetTextureHeight(texture_size)
    material_output_settings.SetTextureWidth(texture_size)
    mapping_image_settings.SetGenerateMappingImage(True)
    mapping_image_settings.SetTexCoordName("MaterialLOD")

为了能够烘焙颜色,我们在remesh管道中添加了一个调色器。 当我们运行管道时它会自动被转换。 我们需要指定的是要烘焙的 MaterialChannel,这应该与我们的顶点颜色材质输出 - 基色相同。

    caster = sg.CreateColorCaster()
    caster_settings = caster.GetColorCasterSettings()
    caster_settings.SetMaterialChannel( color_channel )
    pipeline.AddMaterialCaster( caster, 0 )
    return pipeline

2.4 导入Blender

为了将结果返回到 Blender,我们将使用场景导出器将优化后的场景导出为 gltf 文件。 然后我们可以导入到 Blender 中。

def import_results(sg, scene, file_path):
    """Import the Simplygon scene into Blender."""
    scene_exporter = sg.CreateSceneExporter()
    scene_exporter.SetExportFilePath(file_path)
    scene_exporter.SetScene(scene)
    scene_exporter.Run()
    bpy.ops.import_scene.gltf(filepath=file_path)

2.5 整合在一起

一旦创建了所有辅助函数,我们就可以将它们放在一起。 首先,我们将从 Blender 中导出选定的网格,然后设置我们的自定义顶点颜色材质。 之后,我们创建一个remesh管道并运行它。 最后我们将结果导入到 Blender 中。

def process_selection(sg):
    """Process selected mesh in Blender"""

    # Export scene from Blender and import it 
    file_path = temp_path + file
    scene = export_selection(sg, file_path)
    
    # Setup vertex color shader
    setup_vertex_color_materials(sg, scene)

    # Process scene
    pipeline = create_pipline(sg)
    pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
    
    # Import result into Blender
    import_results(sg, scene, file_path)

2.6 remesh结果

最终结果是一个低多边形模型,其中顶点颜色被烘焙到纹理中。 非常适合用于运行时可视化。

资产三角形
原始资产673152
优化资产988

所有顶点颜色现在都被烘焙到纹理中:

进一步改善我们的结果的一件事是添加一个法线脚轮,它可以将任何微小的几何细节转移到法线贴图中。

3、聚合解决方案

如果我们想保持几何体完整但只是烘焙 UV 贴图,我们可以使用聚合管道而不是重新划分网格。 代码的许多部分是相同的,因此我们将只讨论新的部分。

3.1 删除顶点颜色

由于我们的颜色数据现在驻留在纹理中,我们可以从场景中删除顶点颜色字段。 为此,我们首先通过创建包含所有 SceneMesh 节点的选择集来查找场景中的所有网格。 之后我们一一迭代它们。

def remove_vertex_weights(sg, scene, vertex_color_index):
    """Remove all vertex colors of index from scene."""

    scene_meshes_selection_set_id = scene.SelectNodes("SceneMesh")
    scene_meshes_selection_set = scene.GetSelectionSetTable().GetSelectionSet(scene_meshes_selection_set_id)
    # Loop through all meshes in the scene
    for node_id in range(scene_meshes_selection_set.GetItemCount()):

将节点安全投射到 SceneMesh 后,我们可以从中获取几何数据。 在这里我们可以操纵它,在我们的例子中,我们将通过调用RemoveColors来删除顶点颜色字段。 在我们的 Blender 资源中,这是顶点颜色索引 0。

        scene_mesh = Simplygon.spSceneMesh.SafeCast(scene.GetNodeByGUID( scene_meshes_selection_set.GetItem(node_id)))
        # Get geometry for mesh
        geometry = scene_mesh.GetGeometry()
        if not geometry: 
            continue
        geometry.RemoveColors(vertex_color_index)

如果你的顶点颜色仅用于指导 Simplygon 使用顶点权重,则上述函数对于清理优化后的资源非常有用。 优化后可以调用该函数。

3.2 创建聚合管道

由于我们希望保持网格完整,因此我们使用聚合管道来处理网格。 如上所述,我们需要创建一个映射图像,用于从顶点颜色传输到纹理。 将 TexCoordGeneratorType 设置为 ETexcoordGeneratorType_Parameterizer 后,我们使用 Simplygon 中的参数化器为我们的资源创建新的 UV 贴图。

def create_aggregaton_pipline(sg): 
    """Create aggregation pipeline with color material caster"""
    
    aggregation_pipeline = sg.CreateAggregationPipeline()
    aggregator_settings = aggregation_pipeline.GetAggregationSettings()
    mapping_image_settings = aggregation_pipeline.GetMappingImageSettings()
    mapping_image_settings.SetGenerateMappingImage(True)
    material_settings = mapping_image_settings.GetOutputMaterialSettings(0)
    material_settings.SetTextureWidth(texture_size)
    material_settings.SetTextureHeight(texture_size)
    
    mapping_image_settings.SetTexCoordGeneratorType( Simplygon.ETexcoordGeneratorType_Parameterizer )

然后,我们以与重新网格化管道完全相同的方式添加色彩投射器。

    caster = sg.CreateColorCaster()
    caster_settings = caster.GetColorCasterSettings()
    caster_settings.SetMaterialChannel( color_channel )
    aggregation_pipeline.AddMaterialCaster( caster, 0 )
    return aggregation_pipeline

3.3 整合在一起

与remesh解决方案的唯一区别是我们在运行管道后调用 remove_vertex_weights

def process_selection(sg):
    """Remove and bake decals on selected meshes."""

    # Export scene from Blender and import it 
    file_path = temp_path + file
    scene = export_selection(sg, file_path)
    
    # Setup vertex color shader
    setup_vertex_color_materials(sg, scene)

    # Aggregate optimized scene
    pipeline = create_aggregaton_pipline(sg)
    pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
    
    # Clean up vertex colors
    remove_vertex_weights(sg, scene, vertex_color_index)
    
    # Import result into Blender
    import_results(sg, scene, file_path)

3.4 聚合结果

运行聚合脚本后的结果是网格保持完整的模型。

我们已经从中删除了顶点颜色字段,并将颜色保存在纹理中,并使用新烘焙的 UV 贴图来访问它。 图像的黑色部分是非常密集的 UV 图。

其用例可能相当狭窄,但我们希望将其包括在内,因为它还介绍了如何从网格优化后删除顶点颜色,这是一个可能有用的代码片段。

4、完整的代码

remesh方案:

# Copyright (c) Microsoft Corporation. 
# Licensed under the MIT license. 

import os
import bpy
import gc

from simplygon10 import simplygon_loader
from simplygon10 import Simplygon

file = "scene.glb"
temp_path = "c:/tmp/"

# Change parameters for quality
texture_size = 4096
resolution = 300

# Blender specific settings
color_channel = "Basecolor"
vertex_color_index = 0

def export_selection(sg, file_path):
    """Export the current selected objects into Simplygon."""
    bpy.ops.export_scene.gltf(filepath = file_path, use_selection=True)
    sceneImporter = sg.CreateSceneImporter()
    sceneImporter.SetImportFilePath(file_path)
    sceneImporter.Run()
    scene = sceneImporter.GetScene()
    return scene


def import_results(sg, scene, file_path):
    """Import the Simplygon scene into Blender."""
    scene_exporter = sg.CreateSceneExporter()
    scene_exporter.SetExportFilePath(file_path)
    scene_exporter.SetScene(scene)
    scene_exporter.Run()
    bpy.ops.import_scene.gltf(filepath=file_path)
    

def create_pipline(sg): 
    """Create remesing pipeline and color caster."""
    pipeline = sg.CreateRemeshingPipeline()
    settings = pipeline.GetRemeshingSettings()

    settings.SetOnScreenSize(resolution)
    
    mapping_image_settings = pipeline.GetMappingImageSettings()
    material_output_settings = mapping_image_settings.GetOutputMaterialSettings(0)
    material_output_settings.SetTextureHeight(texture_size)
    material_output_settings.SetTextureWidth(texture_size)
    mapping_image_settings.SetGenerateMappingImage(True)
    mapping_image_settings.SetTexCoordName("MaterialLOD")
    
    caster = sg.CreateColorCaster()
    caster_settings = caster.GetColorCasterSettings()
    caster_settings.SetMaterialChannel( color_channel )
    pipeline.AddMaterialCaster( caster, 0 )
    return pipeline


def setup_vertex_color_materials(sg, scene):
    """Set all materials in scene to vertex colored."""

    material_table = scene.GetMaterialTable()
    for i in range(0, material_table.GetMaterialsCount()):
        material = material_table.GetMaterial(i)
        setup_vertex_color_material(sg, material, color_channel)
            

def setup_vertex_color_material(sg, material, channel):
    """Set material to use vertex color as color."""

    material.AddMaterialChannel(channel)
    shading_node = sg.CreateShadingVertexColorNode()
    shading_node.SetVertexColorIndex(vertex_color_index)
    material.SetShadingNetwork(channel, shading_node)

def process_selection(sg):
    """Process selected mesh in Blender"""

    # Export scene from Blender and import it 
    file_path = temp_path + file
    scene = export_selection(sg, file_path)
    
    # Setup vertex color shader
    setup_vertex_color_materials(sg, scene)

    # Process scene
    pipeline = create_pipline(sg)
    pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
    
    # Import result into Blender
    import_results(sg, scene, file_path)


def main():
    sg = simplygon_loader.init_simplygon()

    process_selection(sg)
    sg = None
    gc.collect()


if __name__== "__main__":
    main()

聚合方案:

# Copyright (c) Microsoft Corporation. 
# Licensed under the MIT license. 

import os
import bpy
import gc

from simplygon10 import simplygon_loader
from simplygon10 import Simplygon

file = "scene.glb"
temp_path = "c:/tmp/"


# Change parameters for quality
texture_size = 4096


# Blender specific settings
color_channel = "Basecolor"
vertex_color_index = 0


def export_selection(sg, file_path):
    """Export the current selected objects into Simplygon."""
    bpy.ops.export_scene.gltf(filepath = file_path, use_selection=True)
    sceneImporter = sg.CreateSceneImporter()
    sceneImporter.SetImportFilePath(file_path)
    sceneImporter.Run()
    scene = sceneImporter.GetScene()
    return scene


def import_results(sg, scene, file_path):
    """Import the Simplygon scene into Blender."""
    scene_exporter = sg.CreateSceneExporter()
    scene_exporter.SetExportFilePath(file_path)
    scene_exporter.SetScene(scene)
    scene_exporter.Run()
    bpy.ops.import_scene.gltf(filepath=file_path)
    

def create_aggregaton_pipline(sg): 
    """Create aggregation pipeline with color material caster"""
    
    aggregation_pipeline = sg.CreateAggregationPipeline()
    aggregator_settings = aggregation_pipeline.GetAggregationSettings()
    mapping_image_settings = aggregation_pipeline.GetMappingImageSettings()
    mapping_image_settings.SetGenerateMappingImage(True)
    material_settings = mapping_image_settings.GetOutputMaterialSettings(0)
    material_settings.SetTextureWidth(texture_size)
    material_settings.SetTextureHeight(texture_size)
    
    mapping_image_settings.SetTexCoordGeneratorType( Simplygon.ETexcoordGeneratorType_Parameterizer )
    
    caster = sg.CreateColorCaster()
    caster_settings = caster.GetColorCasterSettings()
    caster_settings.SetMaterialChannel( color_channel )
    aggregation_pipeline.AddMaterialCaster( caster, 0 )
    return aggregation_pipeline


def setup_vertex_color_materials(sg, scene):
    """Set all materials in scene to vertex colored."""

    material_table = scene.GetMaterialTable()
    for i in range(0, material_table.GetMaterialsCount()):
        material = material_table.GetMaterial(i)
        setup_vertex_color_material(sg, material, color_channel)
            
def setup_vertex_color_material(sg, material, channel):
    """Set material to use vertex color as color."""

    material.AddMaterialChannel(channel)
    shading_node = sg.CreateShadingVertexColorNode()
    shading_node.SetVertexColorIndex(vertex_color_index)
    material.SetShadingNetwork(channel, shading_node)

def remove_vertex_weights(sg, scene, vertex_color_index):
    """Remove all vertex colors of index from scene."""

    scene_meshes_selection_set_id = scene.SelectNodes("SceneMesh")
    scene_meshes_selection_set = scene.GetSelectionSetTable().GetSelectionSet(scene_meshes_selection_set_id)
    # Loop through all meshes in the scene
    for node_id in range(scene_meshes_selection_set.GetItemCount()):
        scene_mesh = Simplygon.spSceneMesh.SafeCast(scene.GetNodeByGUID( scene_meshes_selection_set.GetItem(node_id)))
        # Get geometry for mesh
        geometry = scene_mesh.GetGeometry()
        if not geometry: 
            continue
        geometry.RemoveColors(vertex_color_index)
    

def process_selection(sg):
    """Remove and bake decals on selected meshes."""

    # Export scene from Blender and import it 
    file_path = temp_path + file
    scene = export_selection(sg, file_path)
    
    # Setup vertex color shader
    setup_vertex_color_materials(sg, scene)

    # Aggregate optimized scene
    pipeline = create_aggregaton_pipline(sg)
    pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
    
    # Clean up vertex colors
    remove_vertex_weights(sg, scene, vertex_color_index)
    
    # Import result into Blender
    import_results(sg, scene, file_path)


def main():
    sg = simplygon_loader.init_simplygon()

    process_selection(sg)
    sg = None
    gc.collect()


if __name__== "__main__":
    main()

原文链接:顶点颜色转纹理 - BimAnt

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

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

相关文章

leetcode每日一题34

89.格雷编码 观察一下n不同时的格雷编码有什么特点 n1 [0,1] n2 [0,1,3,2] n3 [0,1,3,2,6,7,5,4] …… 可以看到nk时,编码数量是nk-1的数量的一倍 同时nk编码的前半部分和nk-1一模一样 nk编码的最后一位是2k-1 后半部分的编码是其对应的前半部分的对称的位置的数字…

Matlab论文插图绘制模板第128期—函数三维折线图(fplot3)

在之前的文章中,分享了Matlab函数折线图的绘制模板: 进一步,再来分享一下函数三维折线图。 先来看一下成品效果: 特别提示:本期内容『数据代码』已上传资源群中,加群的朋友请自行下载。有需要的朋友可以关…

【后端】数据字典自动生成枚举

前言 随着我老板给我灌溉的思想,逐渐开始利用代码来完成一些重复性且没有创造性的工作(我变懒啦),当我发现数据字典可以生成枚举从而大大减少开发时间的时候,我意识到事情的重要性。 数据字典 我一开始在网上找各种代码生成器的框架,然后突然意识到,这个不就是简单的…

C语言键盘输入字符串小写转大写输出及scanf的小问题解决

1.博主在学习C语言时,也没太关注C语言的一些细节问题,导致后面有人问问题的时候一时没回答出来,也就是所谓的基础不牢地动山摇,比如这一次有同学问的scanf键盘输入的小问题,折腾了一阵子还是想出来问题所在。 2.废话不…

Docker:深入解析Nexus技术构建可靠的软件仓库管理系统

1、简述 在现代软件开发中,有效的软件仓库管理是确保项目成功的关键一环。Nexus Repository Manager作为一种流行的仓库管理系统,为开发人员提供了强大的工具,用于存储、检索和管理软件构建。本文将深入解析Nexus技术,探讨其关键…

瑞数五代ast反混淆笔记二

第一部分 瑞数五代ast反混淆笔记一 第二部分 瑞数五代ast反混淆笔记二 文章目录 前言一、分析思路二、轨迹合并思路三、避免重复调用一个轨迹四、自己调用自己所在的函数五、语句中包含if的处理六、语句中包含try的处理七、节点中包含影响自身值的操作总结 前言 当if转为switc…

机器视觉 AI 数据集制作

工业中,机器视觉物体分拣时,需要制作,数据集,那么,一般情况下,可以选择几个物体的几张图片,或者视频,将待识别的物体的掩模扣取出来,随机的贴在 传送带背景中&#xff0c…

多线程04 死锁,线程可见性

前言 前面我们讲到了简单的线程安全问题以及简单的解决策略 其根本原因是cpu底层对线程的抢占式调度策略,随机调度 其他还有一些场景的问题如下 1.多个线程同时修改一个变量问题 2.执行的操作指令本身不是原子的 比如自增操作就分为三步,加载,自增,保存 3.内存可见性问题 4.指令…

【vue】浏览器安装vue插件不生效

上一篇:浏览器安装vue插件 https://blog.csdn.net/m0_67930426/article/details/134598104 目录 问题情景 解决办法 问题情景 输入框无内容 解决办法 添加 Vue.config.devtools true; 并且控制台不显示的vue又出现

13.端点、簇、属性

源码地址:13.端点、簇、属性 端点(endPoint) 一个端点就是一个应用 一个字节编号,数据收和发送的基本单元,在模块通信的时候,发送模块必须指定收发双方模块的网络地址和端点。端点要使用必须要和模块里的…

「Linux」git的安装与使用

💻文章目录 📄前言安装git的使用配置git初始化 git 仓库提交文件推送到远端使用HTPPS方式:SSH方式 📓总结 📄前言 git是一款多平台的版本管理器,用于对代码进行版本控制,如果你还不知如何安装gi…

Git指定分支或文件回退到指定版本

文章目录 一、分支回滚1.1、使用 git reset 命令1.2、使用 git revert 命令1.3、使用 git checkout 命令 二、文件回滚2.1、回滚未提交文件2.2、回滚已提交文件2.2.1、首先查看文件的历史版本2.2.2、找到你想要还原的版本2.2.3、将文件还原到你想要还原的版本2.2.4、提交代码 三…

【数据结构初阶(5)】链式队列的基本操作实现

文章目录 队列的定义初始化队列队尾入队列队头出队列取队头元素取队尾元素获取队列有效元素个数判断队空销毁队列 因为队列比较简单,关于队列的概念就不过多赘述了,本文只讲链队的基本操作实现 队列的定义 定义队列结点结构 链队中的每个结点都应该包…

RK3568平台开发系列讲解(Linux系统篇)pinctrl api介绍及实验

🚀返回专栏总目录 文章目录 一、pinctrl函数介绍二、设备树案例三、驱动案例 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍pinctrl api及其使用案例 。 一、pinctrl函数介绍 ①获取设备对应的 pinctrl…

在Matlab里安装gurobipy怎么安装教程

在Matlab 里安装gurobipy 先在CMD里激活, 然后添加系统环境变量 GRB_LICENSE_FILEC:\gurobi10.2\gurobi.lic 然后输入 addpath(D:\gurobi1003\win64\matlab) addpath(C:\gurobi1003\win64\matlab) addpath(C:\gurobi1002\win64\matlab) C:\gurobi1003\win64\m…

多功能智慧路灯系统整体解决方案介绍

在不改变现有城市景观的前提下,利用现有路灯改造,或新建多功能叁仟智慧路灯的方法,可实现城市无线网络、视频监控、物联传感网络、新能源充电系统、网格信息化管理的全覆盖,有效解决信息化设备选址难、取电难等问题。在目前无线通…

可以免费使用的Axure在线版来了

Axure作为一种功能强大的原型设计工具,一直受到设计师的青睐。然而,其高昂的价格可能成为一个门槛,限制了一些设计师的选择。但不用担心,现在有一个免费的Axure在线工具即时设计,功能更完整,更划算&#xf…

智能优化算法应用:基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于飞蛾扑火算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.飞蛾扑火算法4.实验参数设定5.算法结果6.参考…

小程序如何进行版本回退

当商家决定回退小程序版本时,可能是因为新版本出现了一些问题或者不符合预期,需要恢复到之前的稳定版本。下面具体介绍怎么回退小程序的版本。 在小程序管理员后台->版本设置处,点击版本回退。确认后,小程序会回退到上一次的版…

基于springboot-“有光”摄影分享网站系统(2023年☆全网唯一)【附源码|数据库|表结构|万字文档(LW)|技术文档|说明文档】

主要功能 前台登录: 注册用户:用户账号、密码、姓名、手机号、身份证号、性别、邮箱 用户: ①首页、公告资讯展示、图片素材展示、活动展示、视频素材展示、查看更多 ②论坛、发布帖子、活动、活动标题、活动类型、公告资讯、公告标题、公告…