深入分析TaskView源码之触摸相关

news2024/11/19 18:32:47

问题背景

hi,粉丝朋友们:
大家好!android 10以后TaskView作为替代ActivityView的容器,在课程的分屏pip自由窗口专题也进行了相关的详细介绍分析。
在这里插入图片描述
这里再补充一下相关的TaskView和桌面内嵌情况下的触摸分析

在这里插入图片描述

主要问题点:
1、明明TaskView属于CarLauncher的一个View,凭啥触摸自己的TaskView事件会让TaskView的Activity接收到
2、TaskView的Activity是怎么可以接收事件的呢?桌面怎么做到单独只排除TaskView其他地方都可以触摸呢?
哈哈,简单总结就是要搞清楚TaskView触摸响应原理。

问题分析切入点

一般说道触摸问题分析,一想到当然是窗口和input部分的dump信息分析
1、dumpsys activity containers

#1 DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]
        #2 Task=1000011 type=standard mode=multi-window override-mode=multi-window requested-bounds=[404,76][1408,696] bounds=[404,76][1408,696]
         #0 ActivityRecord{38f55a5 u10 com.android.car.mapsplaceholder/.MapsPlaceholderActivity t1000011} type=standard mode=multi-window override-mode=undefined requested-bounds=[0,0][0,0] bounds=[404,76][1408,696]
          #0 60a6fdf com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity type=standard mode=multi-window override-mode=undefined requested-bounds=[0,0][0,0] bounds=[404,76][1408,696]
        #1 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]
         #0 Task=1000006 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]
          #0 ActivityRecord{185661 u10 com.android.car.carlauncher/.CarLauncher t1000006} type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]
           #0 6845fdb com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]

明显看到地图Activity的Task,windowmode属于multi-window
#2 Task=1000011 type=standard mode=multi-window override-mode=multi-window requested-bounds=[404,76][1408,696] bounds=[404,76][1408,696]
在CarLauncher 的Task ,windowmode为fullscreen
#1 Task=1 type=home mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1408,792]

注意一下地图的Task的bounds区域[404,76][1408,696] ,而CarLauncher的区域属于全屏的 bounds=[0,0][1408,792]
这么一看确实桌面的显示bound是包含了地图的Bound

所以这里可以初步理解为:

TaskView的地图是可以独立接受触摸时间的,因为它本身是独立的bounds区域,触摸到了这个区域就行
但是因为和CarLauncher有重叠,那么CarLauncher对这个TaskView部分的区域触摸是怎么处理的,会接受这一部分的触摸事件吗?毕竟这区域又是CarLauncher的一个TaskView区域,地图Activity也只是TaskView显示的内容而已
哈哈,这里就需要使用我们dumpsys input来解密

adb shell dumpsys input:

Input Dispatcher State:
  DispatchEnabled: true
  DispatchFrozen: false
  InputFilterEnabled: false
  FocusedDisplayId: 0
  FocusedApplications:
    displayId=0, name='ActivityRecord{38f55a5 u10 com.android.car.mapsplaceholder/.MapsPlaceholderActivity t1000011}', dispatchingTimeout=5000ms
  FocusedWindows:
    displayId=0, name='60a6fdf com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity'
  FocusRequests:
    displayId=0, name='60a6fdf com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity' result='OK'
  Pointer Capture Requested: false
  Current Window with Pointer Capture: None
  TouchStates: <no displays touched>
  Display: 0
    logicalSize=1408x792
        transform (ROT_0) (IDENTITY)
    Windows:
      0: name='aa0d3fc BottomCarSystemBar', id=77, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH, alpha=1.00, frame=[0,696][1408,792], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,696][1408,792], ownerPid=1375, ownerUid=10150, dispatchingTimeout=5000ms, hasToken=0x7c04338b1ad0, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -0.0000
            0.0000  1.0000  -696.0000
            0.0000  0.0000  1.0000
      1: name='e8091e TopCarSystemBar', id=76, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH, alpha=1.00, frame=[0,0][1408,76], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1408,76], ownerPid=1375, ownerUid=10150, dispatchingTimeout=5000ms, hasToken=0x7c04338d6310, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      2: name='aff2cfa com.android.car.rotary', id=101, displayId=0, inputConfig=NOT_FOCUSABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH, alpha=1.00, frame=[1408,76][1408,76], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=1871, ownerUid=1010088, dispatchingTimeout=5000ms, hasToken=0x7c04338e0bd0, touchOcclusionMode=USE_OPACITY
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -1408.0000
            0.0000  1.0000  -76.0000
            0.0000  0.0000  1.0000
      3: name='2cdb9e1 ActivityRecordInputSink com.aospinsight.dummyaidlapp/.MainActivity', id=194, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14079,-7919][14080,7920], ownerPid=701, ownerUid=1000, dispatchingTimeout=0ms, hasToken=<null>, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      4: name='6845fdb com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher', id=205, displayId=0, inputConfig=TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1408,792], globalScale=1.000000, applicationInfo.name=ActivityRecord{185661 u10 com.android.car.carlauncher/.CarLauncher t1000006}, applicationInfo.token=0x7c04e3536310, touchableRegion=[0,0][1408,76]|[0,76][404,696]|[0,696][1408,792], ownerPid=1658, ownerUid=1010079, dispatchingTimeout=5000ms, hasToken=0x7c04338f3cd0, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (IDENTITY)
      5: name='60a6fdf com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity', id=223, displayId=0, inputConfig=0x0, alpha=1.00, frame=[404,76][1408,696], globalScale=1.000000, applicationInfo.name=ActivityRecord{38f55a5 u10 com.android.car.mapsplaceholder/.MapsPlaceholderActivity t1000011}, applicationInfo.token=0x7c04e355be70, touchableRegion=[404,76][1408,696], ownerPid=22792, ownerUid=1010122, dispatchingTimeout=5000ms, hasToken=0x7c0433933dd0, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -404.0000
            0.0000  1.0000  -76.0000
            0.0000  0.0000  1.0000
      6: name='a9ab86e ActivityRecordInputSink com.android.car.mapsplaceholder/.MapsPlaceholderActivity', id=221, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[404,76][404,76], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[404,76][1408,696], ownerPid=701, ownerUid=1000, dispatchingTimeout=0ms, hasToken=<null>, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -404.0000
            0.0000  1.0000  -76.0000
            0.0000  0.0000  1.0000
      7: name='c2d4eae ActivityRecordInputSink com.android.car.carlauncher/.CarLauncher', id=126, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14079,-7919][14080,7920], ownerPid=701, ownerUid=1000, dispatchingTimeout=0ms, hasToken=<null>, touchOcclusionMode=BLOCK_UNTRUSTED

这里我们只需要重点关注窗口4和窗口5:
–桌面Activity
4: name=‘6845fdb com.android.car.carlauncher/com.android.car.carlauncher.CarLauncher’, id=205, displayId=0, inputConfig=TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1408,792], globalScale=1.000000, applicationInfo.name=ActivityRecord{185661 u10 com.android.car.carlauncher/.CarLauncher t1000006}, applicationInfo.token=0x7c04e3536310, touchableRegion=[0,0][1408,76]|[0,76][404,696]|[0,696][1408,792], ownerPid=1658, ownerUid=1010079, dispatchingTimeout=5000ms, hasToken=0x7c04338f3cd0, touchOcclusionMode=BLOCK_UNTRUSTED
transform (ROT_0) (IDENTITY)
–地图Activity
5: name=‘60a6fdf com.android.car.mapsplaceholder/com.android.car.mapsplaceholder.MapsPlaceholderActivity’, id=223, displayId=0, inputConfig=0x0, alpha=1.00, frame=[404,76][1408,696], globalScale=1.000000, applicationInfo.name=ActivityRecord{38f55a5 u10 com.android.car.mapsplaceholder/.MapsPlaceholderActivity t1000011}, applicationInfo.token=0x7c04e355be70, touchableRegion=[404,76][1408,696], ownerPid=22792, ownerUid=1010122, dispatchingTimeout=5000ms, hasToken=0x7c0433933dd0, touchOcclusionMode=BLOCK_UNTRUSTED
transform (ROT_0) (TRANSLATE)
1.0000 0.0000 -404.0000
0.0000 1.0000 -76.0000
0.0000 0.0000 1.0000

明显发现触摸派发window层级方面还是以桌面为顶部window,地图为底下window,这样其实也可以理解,我们上面的说的情况一样,其实整个画面都是CarLauncher的,地图Activity也只是CarLauncher的一个View而已。所以当然把桌面作为顶部的派发事件window完全没有问题。
但是问题来了,桌面把fullscreen面积占了?那么怎么才可以轮到地图Activity

大家注意看看桌面的window的这个属性

touchableRegion=[0,0][1408,76]|[0,76][404,696]|[0,696][1408,792],
是不是有个touchableRegion,对他就是真相,他负责了划定CarLauncher这个window可以响应的触摸区域,这里明显看出,这个区域划分了看了如下部分:

[0,76][404,696]| ----排除TaskView的的地图Activity区域

正常地图Activity的区域是[404,76][1408,696]从404开始到屏幕最右
[0,76][404,696]| 明显是只从0到404就截止了

这里就说明了CarLauncher虽然在顶部,但是他的touchRegion根本没有包含地图Activity的区域,所以派发事件时候根本不会抢地图Activity的,即地图区域的事件不会派发到桌面
总结:
问题关键找到了,就是靠touchRegion来让CarLauncher不接受地图Activity的Region

哪里设置的TouchRegion呢?

这里如果直接寻找比较麻烦可以用dumpsys window windows命令看看window是不是带了
在这里插入图片描述

下面就来分析这个桌面的TouchRegion是在哪里设置的呢?来看看对应dump代码
frameworks/base/services/core/java/com/android/server/wm/WindowState.java

 if (dumpAll) {
            pw.println(prefix + "mGivenContentInsets=" + mGivenContentInsets.toShortString(sTmpSB)
                    + " mGivenVisibleInsets=" + mGivenVisibleInsets.toShortString(sTmpSB));
            if (mTouchableInsets != 0 || mGivenInsetsPending) {
                pw.println(prefix + "mTouchableInsets=" + mTouchableInsets
                        + " mGivenInsetsPending=" + mGivenInsetsPending);
                Region region = new Region();
                getTouchableRegion(region);
                pw.println(prefix + "touchable region=" + region);
            }
            pw.println(prefix + "mFullConfiguration=" + getConfiguration());
            pw.println(prefix + "mLastReportedConfiguration=" + getLastReportedConfiguration());
        }
        //再来看看getTouchableRegion方法

  /** Get the touchable region in global coordinates. */
    void getTouchableRegion(Region outRegion) {
        final Rect frame = mWindowFrames.mFrame;
        switch (mTouchableInsets) {
            default:
            case TOUCHABLE_INSETS_FRAME:
                outRegion.set(frame);
                break;
            case TOUCHABLE_INSETS_CONTENT:
                applyInsets(outRegion, frame, mGivenContentInsets);
                break;
            case TOUCHABLE_INSETS_VISIBLE:
                applyInsets(outRegion, frame, mGivenVisibleInsets);
                break;
            case TOUCHABLE_INSETS_REGION: {//走的是这里
                outRegion.set(mGivenTouchableRegion);
                if (frame.left != 0 || frame.top != 0) {
                    outRegion.translate(frame.left, frame.top);
                }
                break;
            }
        }
        cropRegionToRootTaskBoundsIfNeeded(outRegion);
        subtractTouchExcludeRegionIfNeeded(outRegion);
    }

那么这里的mGivenTouchableRegion是哪里设置的呢?

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
            Rect visibleInsets, Region touchableRegion) {
        int uid = Binder.getCallingUid();
        int pid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                WindowState w = windowForClientLocked(session, client, false);
                if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w
                        + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets
                        + ", visibleInsets=" + w.mGivenVisibleInsets + " -> " + visibleInsets
                        + ", touchableRegion=" + w.mGivenTouchableRegion + " -> " + touchableRegion
                        + ", touchableInsets " + w.mTouchableInsets + " -> " + touchableInsets);
                if (w != null) {
                    w.mGivenInsetsPending = false;
                    w.mGivenContentInsets.set(contentInsets);
                    w.mGivenVisibleInsets.set(visibleInsets);
                    w.mGivenTouchableRegion.set(touchableRegion);//这里进行的设置
            
                    w.mTouchableInsets = touchableInsets;
                    if (w.mGlobalScale != 1) {
                        w.mGivenContentInsets.scale(w.mGlobalScale);
                        w.mGivenVisibleInsets.scale(w.mGlobalScale);
                        w.mGivenTouchableRegion.scale(w.mGlobalScale);
                    }
                    w.setDisplayLayoutNeeded();
                    w.updateSourceFrame(w.getFrame());
                    mWindowPlacerLocked.performSurfacePlacement();
                    w.getDisplayContent().getInputMonitor().updateInputWindowsLw(true);

                    // We need to report touchable region changes to accessibility.
                    if (mAccessibilityController.hasCallbacks()) {
                        mAccessibilityController.onSomeWindowResizedOrMovedWithCallingUid(
                                uid, w.getDisplayContent().getDisplayId());
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

那么接下来再看看谁进行的setInsetsWindow调用:
frameworks/base/services/core/java/com/android/server/wm/Session.java

  @Override
    public void setInsets(IWindow window, int touchableInsets,
            Rect contentInsets, Rect visibleInsets, Region touchableArea) {
        mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
                visibleInsets, touchableArea);
    }

那么是谁调用了setInsets呢?

frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java

    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
        // TODO(b/176854108): Consider to move the logic into gatherTransparentRegions since this
        //   is dependent on the order of listener.
        // If there are multiple TaskViews, we'll set the touchable area as the root-view, then
        // subtract each TaskView from it.
        if (inoutInfo.touchableRegion.isEmpty()) {
            inoutInfo.setTouchableInsets(
                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
            View root = getRootView();
            root.getLocationInWindow(mTmpLocation);
            mTmpRootRect.set(mTmpLocation[0], mTmpLocation[1], root.getWidth(), root.getHeight());
            inoutInfo.touchableRegion.set(mTmpRootRect);
        }
        getLocationInWindow(mTmpLocation);
        mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
                mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
        inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);

        if (mObscuredTouchRegion != null) {
            inoutInfo.touchableRegion.op(mObscuredTouchRegion, Region.Op.UNION);
        }
    }

然后在调用对于的setInsets
在 performTraversals() 中进行相关的调用操作
frameworks/base/core/java/android/view/ViewRootImpl.java
在这里插入图片描述

setInsets
在这里插入图片描述

更多framework干货课程如下(需要的可以私聊马哥 获取优惠 +V :androidframework007):
在这里插入图片描述

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

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

相关文章

Power Apps-灵活高度库和普通库的区别

点击插入&#xff0c;可以选择布局中的灵活高度库或其他库 两种库同样把item大小设置得比组件排列起来的小 实现效果&#xff1a; 根据实践发现&#xff0c;如果item中组件排列大小超出item本身大小&#xff0c;灵活高度的库会按照组件排列大小自适应高度&#xff0c;其他库则严…

SVN 修改版本库地址url路径

一、win11用户 1. win11系统右链菜单比较优秀&#xff0c;如果菜单中选择“TortoiseSVN”找不到“重新定位”&#xff0c;如下图所示&#xff0c;则需要添加右键菜单&#xff1a; 2.添加右键菜单&#xff1a;选择“TortoiseSVN”&#xff0c;点击设置&#xff0c;如下图所示&a…

qt和window抓包程序

1.思路 使用原始套接字&#xff0c;将网卡设置为混杂模式&#xff0c;监听该网卡的数据。 2. 了解协议封包和协议层 下图是tcp封包详细过程 数据包传输情况 在TCP/IP协议栈中的每一层为了能够正确解析出上层的数据包&#xff0c;从而使用一些“协议类型”来标记&#xff0c;详…

redis的高可用

redis-cli -h 192.168.233.10 -p 6379 redis的数据类型的增删改查 redis的高可用在集群当中有一个非常重要的指标&#xff0c;提供正常服务的时间的百分比(365天) 99.9% redis的高可用含义更加广泛&#xff0c;正常服务是指标之一&#xff0c;数据容量的扩展&#xff0c;数据…

利用Python进行中文分词——实现中文文本处理的基础工具

中文是一种复杂的语言&#xff0c;其词语之间没有明显的分隔符号&#xff0c;这给中文文本处理带来了一定的挑战。为了更好地处理中文文本数据&#xff0c;Python提供了许多优秀的中文分词工具和库。中文分词是将连续的中文文本切分成独立词语的过程&#xff0c;是中文文本处理…

Kubernetes Gateway API 攻略:解锁集群流量服务新维度!

Kubernetes Gateway API 刚刚 GA&#xff0c;旨在改进将集群服务暴露给外部的过程。这其中包括一套更标准、更强大的 API资源&#xff0c;用于管理已暴露的服务。在这篇文章中&#xff0c;我将介绍 Gateway API 资源&#xff0c;并以 Istio 为例来展示这些资源是如何关联的。通…

抖店与维格表的对接只需轻松几步

通过数环通&#xff0c;您可以使用不到几分钟的时间即可实现抖店与维格表的对接与集成&#xff0c;从而高效实现工作流程自动化&#xff0c;降本增效&#xff01; 1.产品介绍 维格表是一种数据协作工具&#xff0c;具有多维度表格、实时在线编辑、数据可视化等特点。它可以帮助…

数字化转型与企业创新—基于中国上市公司年报的经验证据(2007-2022年)

参照潘红波&#xff08;2022&#xff09;的做法&#xff0c;对来自中南大学学报《数字化转型与企业创新—基于中国上市公司年报的经验证据》一文中的基准回归部分进行复刻。文章实证检验数字化转型对企业创新的影响。用年报词频衡量 一、数据介绍 数据名称&#xff1a;数字化转…

el-date-picker ie模式下 初始化未赋值;未清空

el-date-picker ie模式下 初始化未赋值;未清空 给 dete-picker 加key属性 eg:

二蛋赠书九期:《机器学习图解》

前言 大家好&#xff01;我是二蛋&#xff0c;一个热爱技术、乐于分享的工程师。在过去的几年里&#xff0c;我一直通过各种渠道与大家分享技术知识和经验。我深知&#xff0c;每一位技术人员都对自己的技能提升和职业发展有着热切的期待。因此&#xff0c;我非常感激大家一直…

V8引擎隐藏类(VIP课程)

上一章我们讲了V8如何存储的对象&#xff0c;其中提到了隐藏类&#xff0c;这一章我们来看看隐藏类到底做了什么。 为什么要讲V8&#xff1f;&#xff1f;&#xff1f;&#xff1f; 隐藏类是V8引擎在运行时自动生成和管理的数据结构&#xff0c;用于跟踪对象的属性和方法 隐藏…

【C++心愿便利店】No.14---C++之探索list底层原理

文章目录 前言一、list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list operations1.2.7 list的迭代器失效 二、list的模拟实现2.1 定义一个结构体实现list的…

北斗成为全球民航通用卫星导航系统

北斗成为全球民航通用卫星导航系统 日前&#xff0c;包含北斗卫星导航系统&#xff08;以下简称“北斗系统”&#xff09;标准和建议措施的《国际民用航空公约》附件10最新修订版正式生效。这标志着北斗系统正式加入国际民航组织&#xff08;ICAO&#xff09;标准&#xff0c;成…

NLP:使用 SciKit Learn 的文本矢量化方法

一、说明 本文是使用所有 SciKit Learns 预处理方法生成文本数字表示的深入解释和教程。对于以下每个矢量化器&#xff0c;将给出一个简短的定义和实际示例&#xff1a;one-hot、count、dict、TfIdf 和哈希矢量化器。 SciKit Learn 是一个用于机器学习项目的广泛库&#xff0c;…

轻量封装WebGPU渲染系统示例<36>- 广告板(Billboard)(WGSL源码)

原理不再赘述&#xff0c;请见wgsl shader实现。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/BillboardEntityTest.ts 当前示例运行效果: WGSL顶点shader: group(0) binding(0) var<uniform> objMat :…

腾讯云CVM标准型S5性能如何?CPU采用什么型号?

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CVM 2核2G S5活动优惠价格280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月&#xff0c;CPU内存配置还可以选择4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾…

维基百科文章爬虫和聚类【二】:KMeans

维基百科是丰富的信息和知识来源。它可以方便地构建为带有类别和其他文章链接的文章&#xff0c;还形成了相关文档的网络。我的 NLP 项目下载、处理和应用维基百科文章上的机器学习算法。 一、说明 在我的上一篇文章中&#xff0c;展示了该项目的轮廓&#xff0c;并奠定了其基础…

【JavaEE】Spring核心与设计思想(控制反转式程序演示、IoC、DI)

一、什么是Spring&#xff1f; 通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃⽽庞⼤的社区&#xff0c;这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景&#xff0c;它可以让 …

【机器学习】对比学习(contrastive learning)

对比学习是一种机器学习技术&#xff0c;算法学习区分相似和不相似的数据点。对比学习的目标是学习数据的表示&#xff0c;以捕捉不同数据点之间的基本结构和关系。 在对比学习中&#xff0c;算法被训练最大化相似数据点之间的相似度&#xff0c;并最小化不相似数据点之间的相似…

基于springboot实现大学生就业服务平台系统项目【项目源码】

基于springboot实现大学生就业服务平台系统演示 Java技术 Java是由SUN公司推出&#xff0c;该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称&#xff0c;也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著…