STM32硬件接口I2C应用(基于FT6336)

news2024/11/28 14:28:18

目录

概述

1 硬件介绍

1.1 ST7796-LCD

1.2 MCU IO与LCD PIN对应关系

1.3 MCU IO与Touch PIN对应关系

2 FT6336的寄存器

2.1 FT6336寄存器列表

2.2 寄存器功能介绍 

3 STM32Cube控制配置I2C

3.1  软硬件版本信息

3.2 I2C参数配置

3.3 使用STM32Cube产生工程

4 HAL库函数介绍

4.1 初始化函数

4.2 写数据函数

 4.3 读数据函数

5 FT6336驱动程序

5.1 读写寄存器接口

5.2 初始化函数

5.3 源代码

6 触摸屏功能实现

6.1 触摸屏应用程序

6.2 源代码

7 测试

7.1 代码实现

7.2 测试


概述

本文主要介绍FT6336触摸屏芯片的相关内容,主要包括其寄存器的信息,还介绍了LCD模组上使用的芯片的引脚定义,以及和STM32 IO的对应关系。重点介绍使用STM32硬件I2C接口驱动FT6336的实现方法。笔者使用基于STM32F407的板卡,使用STM32Cube创建工程,并完成整个项目的FT6336驱动程序和触摸功能程序,并验证其功能。

1 硬件介绍

1.1 ST7796-LCD

LCD的PIN引脚功能介绍

序号模块引脚引脚说明
1VCC屏电源正
2GND屏电源地
3LCD_CS液晶屏片选控制信号,低电平有效
4LCD_RST液晶屏复位控制信号,低电平复位
5LCD_RS液晶屏命令/数据选择控制信号

高电平:数据,低电平:命令

6SDI(MOSI)SPI总线写数据信号(SD卡和液晶屏共用)
7SCKSPI总线时钟信号(SD卡和液晶屏共用)
8LED液晶屏背光控制信号(如需要控制,请接引脚,如不需要控制,可以不接)
9SDO(MISO)SPI总线读数据信号(SD卡和液晶屏共用)
10CTP_SCL电容触摸屏IIC总线时钟信号(无触摸屏的模块不需连接)
11CTP_RST电容触摸屏复位控制信号,低电平复位(无触摸屏的模块不需连接)
12CTP_SDA电容触摸屏IIC总线数据信号(无触摸屏的模块不需连接)
13CTP_INT电容触摸屏IIC总线触摸中断信号,产生触摸时,输入低电平到主控(无触摸屏的模块不需连接)
14SD_CSSD卡片选控制信号,低电平有效(不使用SD卡功能,可不接)

实体LCD Port对应关系如下图所示

1.2 MCU IO与LCD PIN对应关系

STM32 PIN引脚LCD PIN引脚
PB5-MOSIMOSI
PB4-MISOMISO
PB3-SCKSCK
PB6CS
PB9RST
PB8RS

1.3 MCU IO与Touch PIN对应关系

STM32 PIN引脚touch PIN引脚
PH4I2C-SCK
PH5I2C-SDA
PH10INIT
PH9RST

2 FT6336的寄存器

2.1 FT6336寄存器列表

2.2 寄存器功能介绍 

1)设备模式配置

 2)姿势ID寄存器

 3)TD状态寄存器

4) Pn_XH寄存器

 5) Pn_XL寄存器

 6) Pn_YH寄存器

 7) Pn_YL寄存器

 8) Pn_WEIGHT寄存器 

  9) Pn_MISC寄存器 

3 STM32Cube控制配置I2C

3.1  软硬件版本信息

STM32CubeMX 版本: 6.11

HAL库版本: STM32Cube_FW_F4_V1.27.1

3.2 I2C参数配置

STM32F407 的标准I2C接口最大支持100K工作频率,笔者选择最大工作频100k,以配置I2C的参数。

I2C使用的GPIO接口如下:

使用MCU类型和HAL库的版本

3.3 使用STM32Cube产生工程

 在配置完成项目后,点击GENERATE生成项目,打开项目后项目目录如下,和I2C相关的代码如下:

代码第40行:选择I2C2作为硬件接口

代码第41行:I2C通信速率为100K

代码第44行:定义地址位7bit

4 HAL库函数介绍

STM32 HAL库函数数量很多,本文仅介绍笔者使用的一些函数接口。其他函数在使用的时候在具体研究,而不许把每个函数搞清楚才去应用。

4.1 初始化函数

函数原型:

HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);

参数介绍

hi2c:  指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。

 一个使用案例: 如果已经初始化完成hi2c结构,初始化时,直接调用该结构体即可。

4.2 写数据函数

函数原型:

HAL_StatusTypeDef HAL_I2C_Mem_Write(   I2C_HandleTypeDef *hi2c, 
                                       uint16_t DevAddress, 
                                       uint16_t MemAddress, 
                                       uint16_t MemAddSize, 
                                       uint8_t *pData, 
                                       uint16_t Size, uint32_t Timeout)

参数介绍:

hi2c:  指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。

DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动

MemAddress:内存地址

MemAddSize:内存地址大小

pData:            写数据指针

Size:               写数据大小

Timeout:         写数据超时时间

 4.3 读数据函数

函数原型:

HAL_StatusTypeDef HAL_I2C_Mem_Read( I2C_HandleTypeDef *hi2c, 
                                    uint16_t DevAddress, 
                                    uint16_t MemAddress, 
                                    uint16_t MemAddSize, 
                                    uint8_t *pData, 
                                    uint16_t Size, 
                                    uint32_t Timeout)

参数介绍:

hi2c:  指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。

DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动

MemAddress:内存地址

MemAddSize:内存地址大小

pData:            读数据指针

Size:               读数据大小

Timeout:         读数据超时时间

5 FT6336驱动程序

5.1 读写寄存器接口

代码57行: 调用HAL库中的写数据函数,向FT6336寄存器写数据

代码69行:调用HAL库中的读数据函数,从FT6336寄存器读取数据

5.2 初始化函数

代码82行: 初始化Touch相关的IO

代码83行: RESET FT6336

代码85行:读取FT6336的ID参数

5.3 源代码

创建ft6336.c文件,编写如下代码:

/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name            : ft6336.c
* Description          : I2C drive based on STM32F4
* STM32 HAL library ver: STM32Cube_FW_F4_V1.27.1
* 
******************************************************************************
* @attention
*
* Copyright (c) 2024~2029 mingfei.tang
* All rights reserved.
*
*************************************************************************
*/
/* USER CODE END Header */
#include "ft6336.h"


static void touch_delay_us(uint32_t us)
{
    uint32_t i=0;
    
    while(us--){
        for(i=0;i<1000;i++);
    }
}

static void ft6336_TouchIO_Init( void )
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    RCC_TOUCH_CLK_ENABLE();
    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIO_PORT_TOUCH, FT_RST_PIN,GPIO_PIN_RESET);

    /*Configure GPIO pin : RST */
    GPIO_InitStruct.Pin = FT_RST_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIO_PORT_TOUCH, &GPIO_InitStruct);
}

static void  ft6336_rest( void )
{
    FT_RST_L;
    touch_delay_us( 10 );
    FT_RST_H;
    touch_delay_us( 50000 );
}

uint8_t ft6336_WeReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
    HAL_StatusTypeDef status;
    
    status = HAL_I2C_Mem_Write( &hi2c2, FT6336_ADDR, regAdd, 
                                I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
    if( status == HAL_OK)
        return FT6336_OK;
    else
        return FT6336_ERROR; 
}

uint8_t ft6336_RdReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
    HAL_StatusTypeDef status;
    
    status = HAL_I2C_Mem_Read( &hi2c2, FT6336_ADDR, regAdd, 
                               I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
    if( status == HAL_OK)
        return FT6336_OK;
    else
        return FT6336_ERROR; 
}


int ft6336_Init( void )
{
    uint8_t id;
   
    ft6336_TouchIO_Init();
    ft6336_rest();
    // read chip id 
    ft6336_RdReg(FT_ID_G_FOCALTECH_ID,&id, 1);
    if(id != PANNEL_ID)
    {
        return FT_FALSE;
    }
    return FT_TRUE;
}



/* End of this file */

 创建ft6336.h文件,编写如下代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : ft6336.h
  * Description        : I2C drive based on STM32F4
  * 
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024~2029 mingfei.tang
  * All rights reserved.
  *
  *************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FT6336_H
#define __FT6336_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "stdio.h"
#include "main.h"


#define RCC_TOUCH_CLK_ENABLE()       __HAL_RCC_GPIOH_CLK_ENABLE()

#define GPIO_PORT_TOUCH              GPIOH

#define FT_RST_PIN                   GPIO_PIN_9      //FT6636复位引脚
#define FT_INT_PIN                   GPIO_PIN_10     //FT6636中断引脚

#define FT_RST_L                     HAL_GPIO_WritePin(GPIO_PORT_TOUCH, FT_RST_PIN, GPIO_PIN_RESET)
#define FT_RST_H                     HAL_GPIO_WritePin(GPIO_PORT_TOUCH, FT_RST_PIN, GPIO_PIN_SET)



#define FT6336_OK                 1
#define FT6336_ERROR              0

#define FT_TRUE                   1
#define FT_FALSE                  0

#define FT6336_ADDR              0X71

//FT5426 部分寄存器定义 
#define FT_DEVIDE_MODE           0x00         //FT6336模式控制寄存器
#define FT_REG_NUM_FINGER        0x02         //触摸状态寄存器

#define FT_TP1_REG               0X03         //第一个触摸点数据地址
#define FT_TP2_REG               0X09         //第二个触摸点数据地址

#define FT_ID_G_CIPHER_MID       0x9F         //芯片代号(中字节) 默认值0x26
#define FT_ID_G_CIPHER_LOW       0xA0         //芯片代号(低字节) 0x01: Ft6336G  0x02: Ft6336U 
#define FT_ID_G_LIB_VERSION      0xA1         //版本
#define FT_ID_G_CIPHER_HIGH      0xA3         //芯片代号(高字节) 默认0x64 
#define FT_ID_G_MODE             0xA4         //FT6636中断模式控制寄存器
#define FT_ID_G_FOCALTECH_ID     0xA8         //VENDOR ID 默认值为0x11
#define FT_ID_G_THGROUP          0x80         //触摸有效值设置寄存器
#define FT_ID_G_PERIODACTIVE     0x88         //激活状态周期设置寄存器


// MATCH VALUE LIST 
#define PANNEL_ID                0x11


int ft6336_Init( void );
uint8_t ft6336_RdReg( uint16_t regAdd, uint8_t *pData, uint16_t Size );
uint8_t ft6336_WeReg( uint16_t regAdd, uint8_t *pData, uint16_t Size );

#ifdef __cplusplus
}
#endif

#endif /*__FT6336_H */

6 触摸屏功能实现

6.1 触摸屏应用程序

代码第45行:读取当前触摸点的个数

代码第59行:读取触摸点的值

6.2 源代码

 创建usr_touch.c文件,编写如下代码:

/**
  ******************************************************************************
  *                              (c) Copyright 2024, tangmingfei2013@126.com
  *                                      All Rights Reserved
  * @file    usr_touch.c
  * @author  mingfei tang
  * @version V1.0.0
  * @date    2018/03/25
  * @description:
    This source code and any compilation or derivative thereof is the proprietary
    information of mingfei.tang and is confidential in nature.
    Under no circumstances is this software to be combined with any
    Open Source Software in any way or placed under an Open Source License
    of any type without the express written permission of mingfei.tang
  ******************************************************************************
**/
/* Includes ------------------------------------------------------------------*/
#include "usr_touch.h"
#include "lcd_drv.h"

extern _lcd_dev lcddev;
const uint16_t touch_press_reg[2]={FT_TP1_REG,FT_TP2_REG};
static int touch_isOK;

void usr_touchInit( void )
{
   touch_isOK = ft6336_Init();
}

uint8_t usr_ScanTouchProcess( stru_pos *pPos)
{
    uint8_t buf[4];
    uint8_t i = 0;
    uint8_t set = FT_FALSE;;
    uint8_t pointNub = 0;
    static uint8_t cnt = 0;
    
    if( touch_isOK == FT_FALSE )
        return set;
    
    cnt++;
    if((cnt%10)==0 || cnt<10)
    {
        // read number of touch points 
        ft6336_RdReg(FT_REG_NUM_FINGER,&pointNub,1);
         
        pointNub= pointNub&0x0f;
        if( pointNub && (pointNub < 3) )
        {
            cnt=0;
            // read the point value 
            pPos->status_bit.tpDown = 1;
            pPos->status_bit.tpPress = 1;
            pPos->status_bit.ptNum = pointNub;
            
            for( i=0; i < CTP_MAX_TOUCH; i++)
            {

                ft6336_RdReg( touch_press_reg[i], buf, 4 );
                if( pPos->status_bit.ptNum )
                {
                    switch(lcddev.dir)
                    {
                        case 0:
                            pPos->xpox[i]=((uint16_t)(buf[0]&0X0F)<<8)+buf[1];
                            pPos->ypox[i]=((uint16_t)(buf[2]&0X0F)<<8)+buf[3];
                            break;
                        case 1:
                            pPos->ypox[i]=lcddev.height-(((uint16_t)(buf[0]&0X0F)<<8)+buf[1]);
                            pPos->xpox[i]=((uint16_t)(buf[2]&0X0F)<<8)+buf[3];
                            break;
                        case 2:
                            pPos->xpox[i]=lcddev.width-(((uint16_t)(buf[0]&0X0F)<<8)+buf[1]);
                            pPos->ypox[i]=lcddev.height-(((uint16_t)(buf[2]&0X0F)<<8)+buf[3]);
                            break;
                        case 3:
                            pPos->ypox[i] = ((uint16_t)(buf[0]&0X0F)<<8)+buf[1];
                            pPos->xpox[i] = lcddev.width-(((uint16_t)(buf[2]&0X0F)<<8)+buf[3]);
                            break;
                    } 
                    printf("x[%d]:%d,y[%d]:%d\r\n",i,pPos->xpox[i],i,pPos->ypox[i]);
                }
            } 
            
            set = FT_TRUE;
            if( pPos->xpox[0]==0 && pPos->ypox[0]==0)
            {
                pPos->status = 0;
            }
        }
    }
    
    if( pPos->status_bit.ptNum == 0)
    { 
        if( pPos->status_bit.tpDown )
        {   
            pPos->status_bit.tpDown = 0;
        }
        else
        { 
            pPos->xpox[0] = 0xffff;
            pPos->ypox[0] = 0xffff;
            pPos->status = 0;
        }
    }
    
    if( cnt>240 )
       cnt=10;
    
    return set;
}


/* End of this file */ 

 创建usr_touch.h文件,编写如下代码:

#ifndef __USR_TOUCH_H
#define __USR_TOUCH_H

#include <stdlib.h>
#include <stdio.h>
#include "main.h"
#include "ft6336.h"

#define CTP_MAX_TOUCH               2

typedef struct
{
   uint8_t ptNum                    : 4;
   uint8_t tpDown                   : 1;
   uint8_t tpPress                  : 1;
   uint8_t res                      : 2;
} Status_bit;

typedef struct
{
    uint16_t xpox[CTP_MAX_TOUCH];
    uint16_t ypox[CTP_MAX_TOUCH];
    union
    {
        uint8_t status;
        Status_bit status_bit;
    };
}stru_pos;

void usr_touchInit( void );
uint8_t usr_ScanTouchProcess( stru_pos *pPos);


#endif  /*  __USR_TOUCH_H */

7 测试

7.1 代码实现

代码110行: 初初始化touch接口

代码117行: monitor触摸点

7.2 测试

编译代码下载到板卡中

点击屏幕,运行触摸点信息如下:

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

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

相关文章

深入了解RTMP推流技术:视频汇聚EasyCVR低延迟与高稳定性分析

RTMP&#xff08;Real Time Messaging Protocol&#xff09;视频推流技术&#xff0c;作为音视频传输领域的关键技术之一&#xff0c;已经在直播、视频会议、在线教育等多个场景中得到了广泛应用。RTMP以其独特的优势&#xff0c;为实时音视频传输提供了高效、稳定的解决方案。…

前端路线指导(4):前端春招秋招经验分享

春招/秋招经验分享(前端) 哈喽大家好&#xff0c;我是小粉&#xff0c;双一流本科&#xff0c;自学前端一年&#xff0c;收获腾讯&#xff0c;字节等多家大厂offer&#xff0c;一半以上ssp~ 今天给大家分享一下我的春招&#xff08;暑期实习&#xff09;、秋招经历&#xff0c;…

咖啡事故,上海Manner咖啡店,1天两起店员和顾客发生冲突

上海咖啡店Manner&#xff0c;一天的时间竟然发生两起店员和员工发生肢体冲突&#xff1a; 事情详情&#xff1a; Manner威海路716店事件: 店员泼顾客咖啡粉&#xff0c;随后被辞退品牌方回应媒体&#xff0c;表示将严肃处理Manner梅花路门店事件:顾客因等待时间长抱怨&…

Docker部署MySQL8.3.0(保姆级图文教程)

系列文章目录 Docker部署Nginx1.21.5&#xff08;保姆级图文教程&#xff09; Docker部署MySQL8.3.0&#xff08;保姆级图文教程&#xff09; 文章目录 一、环境二、拉取镜像2.1 查找 Docker Hub 上的 MySQL 镜像2.2 拉取MySQL镜像2.3 查看MySQL镜像 三、在宿主机创建目录3.1 创…

查看LabVIEW及各个模块和驱动的版本号

要方便地查看当前计算机上安装的LabVIEW版本以及各个模块和驱动的版本号&#xff0c;可以使用以下几种方法&#xff1a; 1. 使用NI MAX (Measurement & Automation Explorer) NI MAX 是一个强大的工具&#xff0c;可以帮助你管理National Instruments硬件、软件和驱动程序…

5G/4G/北斗遥测终端机全国各省水利平台无缝对接

物联网技术的广泛应用正在深刻影响水利行业&#xff0c;计讯物联致力于推动水利技术的持续革新和服务的持续升级&#xff0c;依托国家级专业水利资质认证&#xff0c;在多个大型水利项目中展现的项目管理专长&#xff0c;为水利项目建设提供了高效的解决方案&#xff0c;持续推…

通用大模型的低代码平台——3分钟内快速搭建一个邮件提醒工具

文章目录 ⭐前言⭐node-koa开发一个发送邮件的api⭐百度智能云控制面板&#x1f496; 发送邮件的组件配置&#x1f496; 配置应用发布 ⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;通用大模型的低代码平台——3分钟内快速搭建一个智能股票分析邮件提醒工具。…

OpenCV Mat实现图像四则运算及常用四则运算的API函数

装载有图像数据的OpenCV Mat对象&#xff0c;可以说是一个图像矩阵&#xff0c;可以进行加、减、乘、除运算。特别是加运算特别有用。 一 与常数的四则运算 与常数的加运算 示例&#xff1a; #include <iostream> #include <opencv2/opencv.hpp>using namespace …

Google Adsense----Wordpress插入谷歌广告

1.搭建个人博客,绑定谷歌search consol,注册adsense 详细可以参考这个视频b站视频 2.将个人博客网站关联到Adsense 在adsense里新加网站,输入你的博客网址,双击网站 将这段代码复制到header.php的里面 在wordpress仪表盘的外观-主题文件编辑器,找到header.php将代码复制,…

有玩家在2011年的MacBook上成功运行了Windows XP 还安装了触摸屏

我们已经在许多不同的设备上看到过 Windows XP 正在运行。这个古老的操作系统于 2001 年正式推出&#xff0c;现在已经老到其最后一次软件更新是在近十年前。一位好奇的玩家试图在 2011 年的触摸屏 MacBook 上为 Windows XP 打造了一个新家&#xff0c;复古技术探索者 Michael …

vmware虚拟机安装ubuntu20.04

1.下载Ubuntu 20.04的ISO镜像 Index of /ubuntu-releases/ 2.安装VMware 3.创建新的虚拟机&#xff1a;打开VMware&#xff0c;选择“创建新的虚拟机”或通过文件菜单新建虚拟机。 4.选择典型&#xff0c;然点点击下一步&#xff1a; 5.选择稍后安装操作系统&#xff1a; 6.…

LLC开关电源开发:第四节,LLC软件设计报告

LLC源代码链接 数控全桥LLC开发板软件设计报告  1. LLC硬件及软件框架2. LLC软件设计2.1 工程文件说明2.2 LLC中断设计2.2.1 20us中断2.2.2 5ms中断 2.3 LLC状态机设计2.3.1 初始化状态2.3.2 空闲状态2.3.3 软启动状态2.3.4 正常运行状态2.3.5 故障状态 2.4 环路设计2.4.1 环路…

1095 解码PAT准考证(测试点3)

solution 测试点3超时&#xff1a;命令为3时&#xff0c;用unordered_map而非map&#xff0c;否则会超时 #include<iostream> #include<string> #include<algorithm> #include<unordered_map> using namespace std; const int maxn 1e4 10; struct…

实战|YOLOv10 自定义目标检测

引言 YOLOv10[1] 概述和使用自定义数据训练模型 概述 由清华大学的研究团队基于 Ultralytics Python 包研发的 YOLOv10&#xff0c;通过优化模型结构并去除非极大值抑制&#xff08;NMS&#xff09;环节&#xff0c;提出了一种创新的实时目标检测技术。这些改进不仅实现了行业领…

Appium + Python App自动化第一个脚本

今天跟大家讲解一个Appium和Python App自动化的脚本。 【1】打开你的夜神模拟器&#xff08;或者连接你的手机&#xff09; 【2】打开桌面的Appium 【3】下载你要测的App的apk文件&#xff0c;放到桌面 【4】拖动你的apk安装包到夜神模拟器里&#xff0c;然后模拟器会提示你…

pyinstaller, cx_Freeze打包 pyqt 桌面应用-实操

1 pyinstaller 打包成 exe 参考这个连接&#xff0c; 写的比较全面&#xff1a; https://blog.csdn.net/qq_48979387/article/details/132359366 唯一发现一个错误是增加资源文件时候的分隔符(-add-data SOURCE:DEST)&#xff0c; 按照自己环境的实际的情况来&#xff1a; $…

CS162 Operating System-lecture2

A tread is suspended or no longer executing when its state’s not loaded in registers the point states is pointed at some other thread .so the thread that’s suspended is actually siting in memory and not yet executing or not executing at all with some thi…

探索Linux的奇妙世界:第二关---Linux的基本指令1

1. xshell与服务器的连接 想必大家在看过上一期视频时已经搭建好了Linux的环境了并且已经下好了终端---xshell了吧?让我来带大家看一看下好了是什么样子的: 第一次登陆会让你连接你的服务器,就是我们买的云服务器,买完之后需要把公网地址ip复制过来进行链接,需要用户名和密码连…

Node.js 渲染三维模型并导出为图片

Node.js 渲染三维模型并导出为图片 1. 前言 本文将介绍如何在 Node.js 中使用 Three.js 进行 3D 模型渲染。通过结合 gl 和 canvas 这两个主要依赖库&#xff0c;我们能够在服务器端实现高效的 3D 渲染。这个方法解决了在服务器端生成和处理 3D 图形的需求&#xff0c;使得可…