ThreeJS-3D教学十四:ShaderMaterial(length、fract、step)

news2024/12/22 23:25:58

在这里插入图片描述
length() 内置函数可以获取向量的长度,
这里用 vUv 计算每个像素离原点(0.0, 0.0)位置的距离 dist,将其设置到颜色上,
会得到圆心在左下角的1/4渐变圆形效果,左上角(0.0, 1.0)和右下角(1.0, 0.0)离原点距离都是1,
对应颜色正好是白色,当dist>1后,颜色仍为白色。

颜色突变 GLSL函数 step 、fract
除了渐变,我们可以结合 GLSL 的内置函数做出颜色突变的效果,借助 step(edge, x) 函数,其会返回0.0或1.0数值,如果 x<edge 返回0.0,如果 x>edge 返回1.0。
step(0.5, vUv.x) 通过 vUv.x 和 0.5(vUv中心点 0.5 0.5) 比较,小于0.5的返回0.0,大于0.5的返回1.0,并将该 color 变成转换成 vec3() 格式,于是就是黑白突变的格式。
float color = step(0.5, vUv.x);
gl_FragColor = vec4(vec3(color), 1.0);

fract() 函数取小数使得数值在 0.0-1.0 里循环重复,
比如1.1、2.1取小数后都变回0.1,再将该数值转换成 vec3 再设置到颜色上,
就会产生重复的黑白渐变效果。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    body {
      width: 100%;
      height: 100%;
    }

    * {
      margin: 0;
      padding: 0;
    }

    .label {
      font-size: 20px;
      color: #fff;
      font-weight: 700;
    }
  </style>
</head>

<body>
<div id="container"></div>
<script type="importmap">
  {
    "imports": {
      "three": "../three-155/build/three.module.js",
      "three/addons/": "../three-155/examples/jsm/"
    }
  }
</script>
<script type="module">
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GPUStatsPanel } from 'three/addons/utils/GPUStatsPanel.js';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
let stats, labelRenderer, gpuPanel, shaderMaterial, boxShaderMaterial;
let camera, scene, renderer, mesh, target, controls, shaderMaterialSphere;
const group = new THREE.Group();
let time = 0;
let time1 = 0;
init();
initHelp();
initLight();
axesHelperWord();
animate();

const box = boxModel();
box.position.set(0, 120, 0);
scene.add(box);

let fragmentShader11 = [
  "varying vec2 vUv;",
  "uniform float uTime;",
  "void main(){",
  " gl_FragColor = vec4(vUv, 1.0, 1.0);",
  "}"
].join('\n');
const sphere11 = sphereModel1(fragmentShader11);
sphere11.position.set(250, 120, -250);
scene.add(sphere11);

let fragmentShader12 = [
  "varying vec2 vUv;",
  "uniform float uTime;",
  "void main(){",
  " float color = step(0.5, vUv.y);",
  " gl_FragColor = vec4(vec3(color), 1.0);",
  "}"
].join('\n');
const sphere12 = sphereModel1(fragmentShader12);
sphere12.position.set(250, 120, -100);
scene.add(sphere12);

let fragmentShader13 = [
  "varying vec2 vUv;",
  "uniform float uTime;",
  "void main(){",
  " float color = step(uTime, fract(vUv.y * 5.0));",
  " gl_FragColor = vec4(vec3(color), 1.0);",
  "}"
].join('\n');
const sphere13 = sphereModel1(fragmentShader13);
sphere13.position.set(250, 120, 50);
scene.add(sphere13);

function sphereModel1(fragmentShader) {
  let vertexShader = [
    "varying vec2 vUv;",
    "void main(){",
    "	gl_Position	= projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    " vUv = uv;",
    "}"
  ].join('\n');

  /**
   * 颜色渐变
   * 就是照理 position 是每个顶点的坐标,uv 是每个顶点的纹理坐标
   * shader 里的代码是对每个顶点或片元单独执行的,这里的 vUv 就只是每个片元其各自的数值
   * (每个片元甚至连周围片元的数值是多少都不知道),
   * 比如左下角 vUv 为 (0.0, 0.0) 所以对应的 vUv.x=vUv.y=0.0,颜色为 vec4(0.0, 0.0, 0.0, 1.0)
   * 即黑色,同理把左上角 (0.0, 1.0)、右下角 (1.0, 0.0)、右上角 (1.0, 1.0)、最中间 (0.5, 0.5)
   * 等每个位置的数值分别带入上面的代码,就能得到上图的效果。
   */

  // gl_FragColor.a = 0.9;
  // gl_FragColor.rgb = vec3(1, 1, 1)

  // 如果用 vUv 里的 x 或 y 分量分别设置到 rgba 颜色里的 red 通道并赋值给
  // gl_FragColor,会有左右或者上下的黑色到红色的渐变效果。
  // gl_FragColor = vec4(vUv.x, 0.0, 0.0, 1.0);
  // gl_FragColor = vec4(vUv.y, 0.0, 0.0, 1.0);
  // gl_FragColor = vec4(vec3(vUv.x), 1.0);
  // gl_FragColor = vec4(vec3(vUv.y), 1.0);

  // 如果将 vUv 设置到 red 和 green 通道、blue 通道设为0.0,
  // 就是这个非常常见的 uv 青色红色颜色效果,如果大家用过其他一些3D软件,应该对这个图并不陌生。
  // gl_FragColor = vec4(vUv, 0.0, 1.0);

  /**
    * 颜色突变 GLSL函数 step 、fract
      除了渐变,我们可以结合 GLSL 的内置函数做出颜色突变的效果,借助 step(edge, x) 函数,
      其会返回0.0或1.0数值,如果 x<edge 返回0.0,如果 x>edge 返回1.0。step(0.5, vUv.x)
      通过 vUv.x 和 0.5(vUv中心点 0.5 0.5) 比较,小于0.5的返回0.0,大于0.5的返回1.0,并将该 color 变成转换成 vec3() 格式,
      于是就是黑白突变的格式。
      float color = step(0.5, vUv.x);
      gl_FragColor = vec4(vec3(color), 1.0);
    */

  /**
   * fract() 函数取小数使得数值在 0.0-1.0 里循环重复,
   * 比如1.1、2.1取小数后都变回0.1,再将该数值转换成 vec3 再设置到颜色上,
   * 就会产生重复的黑白渐变效果。
   */
  

  const planeGeo = new THREE.SphereGeometry(45, 30, 30);
  shaderMaterialSphere = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: {
      uTime: { value: 0.5 },
    },
    transparent: false,
    depthWrite: true
  });
  return new THREE.Mesh(planeGeo, shaderMaterialSphere);
}

function boxModel() {
  let vertexShader = [
    "varying vec2 vUv;",
    "void main(){",
    "	gl_Position	= projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    " vUv = uv;",
    "}"
  ].join('\n');


  // 当我们有了每个 uv 离中心的距离后,可以对它运用翻倍再取小数的操作进行重复,
  // 这样就能做出由里向外一圈圈黑白交错的径向条纹效果。

  // 有个小细节需要注意,上面我们翻了5倍,但看效果里一黑一白为1组,其实只有3组多点,
  // 究其原因是 length(vUv - vec2(0.5)) 一开始的范围并不是0到1,最大值是四个角离中心的距离,
  // 也就是 (1.0, 1.0) 离 (0.5, 0.5) 的距离,
  // 即 √2/2=0.707,因而我们可以先对其除以 0.707 再去翻倍取小数进行重复,
  // 这样就能如愿想有几组就几组、想重复几次就重复几次。

  // 然后将 uTime 加到变换到0-1范围后的数值上,使得径向条纹动起来
  // 反向运动可以减去 uTime,运动速率可以通过 uTime 的倍数来控制。

let fragmentShader = `
  varying vec2 vUv;
  uniform float uTime;
  void main() {
    // 先居中,再绘制圆形
    float dist = fract((length(vUv - vec2(0.5)) / 0.707 - uTime * 0.5) * 5.0);
    float radius = 0.5;
    vec3 color = vec3(step(radius, dist));
    gl_FragColor = vec4(color, 1.0);
  }
`;
  const planeGeo = new THREE.BoxGeometry(70, 70, 70);
  boxShaderMaterial = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: {
      uTime: { value: 0 },
    },
    transparent: false,
    depthWrite: true
  });
  return new THREE.Mesh(planeGeo, boxShaderMaterial);
}

/**
 * 通过 length() 内置函数可以获取向量的长度,
 * 这里用 vUv 计算每个像素离原点(0.0, 0.0)位置的距离 dist,将其设置到颜色上,
 * 会得到圆心在左下角的1/4渐变圆形效果,左上角(0.0, 1.0)和右下角(1.0, 0.0)离原点距离都是1,
 * 对应颜色正好是白色,当dist>1后,颜色仍为白色。
 */
let fragmentShader1 = `
varying vec2 vUv;
uniform float uTime;
void main() {
  float dist = length(vUv);
  vec3 color = vec3(dist);
  gl_FragColor = vec4(color, 1.0);
}
`;
const sphere1 = sphereModel(fragmentShader1);
sphere1.position.set(-250, 120, -250);
scene.add(sphere1);

// 绘制渐变圆形
let fragmentShader2 = `
varying vec2 vUv;
uniform float uTime;
void main() {
  float dist = length(vUv);
  vec3 color = vec3(step(0.5, dist));
  gl_FragColor = vec4(color, 1.0);  // 1.0 是透明度
}
`;
const sphere2 = sphereModel(fragmentShader2);
sphere2.position.set(-250, 120, -100);
scene.add(sphere2);

let fragmentShader3 = `
varying vec2 vUv;
uniform float uTime;
void main() {
  // float dist = length(vUv - vec2(0.5));
  float dist = distance(vUv, vec2(0.5));
  float radius = 0.5; // 0.25
  vec3 color = vec3(step(radius, dist));
  gl_FragColor = vec4(color, 1.0);
}
`;
const sphere3 = sphereModel(fragmentShader3);
sphere3.position.set(-250, 120, 50);
scene.add(sphere3);

let fragmentShader4 = `
varying vec2 vUv;
uniform float uTime;
void main() {
  // 先重复 uv,再居中,再绘制圆形
  float dist = length(fract(vUv * 5.0) - vec2(0.5));
  float radius = 0.5; // 0.25
  vec3 color = vec3(step(radius, dist));
  gl_FragColor = vec4(color, 1.0);
}
`;
const sphere4 = sphereModel(fragmentShader4);
sphere4.position.set(-250, 120, 200);
scene.add(sphere4);

let fragmentShader5 = `
varying vec2 vUv;
uniform float uTime;
void main() {
  // 先居中,再绘制圆形
  float dist = length(fract(vUv * 5.0) - vec2(0.5));
  // float dist = distance(vUv, vec2(0.5));
  float radius = 0.5 * (sin(uTime + vUv.x) * 0.5 + 0.5); // 0.25
  vec3 color = vec3(step(radius, dist));
  gl_FragColor = vec4(color, 1.0);
}
`;
const sphere5 = sphereModel(fragmentShader5);
sphere5.position.set(-250, 120, 350);
scene.add(sphere5);

function sphereModel(fragmentShader) {
  let vertexShader = [
    "varying vec2 vUv;",
    "void main(){",
    "	gl_Position	= projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    " vUv = uv;",
    "}"
  ].join('\n');

  /**
   // 绘制渐变圆形
    float dist = length(vUv);
    vec3 color = vec3(dist);
    gl_FragColor = vec4(color, 1.0);

    // 绘制圆形
    float dist = length(vUv);
    vec3 color = vec3(step(0.5, dist));
    gl_FragColor = vec4(color, 1.0);

    // 先居中,再绘制圆形
    float dist = length(vUv - vec2(0.5));
    // float dist = distance(vUv, vec2(0.5));
    float radius = 0.5; // 0.25
    vec3 color = vec3(step(radius, dist));
    gl_FragColor = vec4(color, 1.0);

    // 先重复 uv,再居中,再绘制圆形
    float dist = length(fract(vUv * 5.0) - vec2(0.5));

    但此时每个圆圈都是通过 sin(uTime) 控制动画,半径变化同步进行,很统一也很单调,
    这里可以通过 sin(uTime + vUv.x) 将不同水平值作为偏差值加进去,
    于是会有水平波浪起伏的效果

    如果再把 vUv.y 也一起加上,变化效果更有趣丰富。
    float radius = 0.5 * (sin(uTime + vUv.x + vUv.y) * 0.5 + 0.5);
    */
  const planeGeo = new THREE.BoxGeometry(70, 70, 70);
  shaderMaterial = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: {
      uTime: { value: 0 },
    },
    transparent: false,
    depthWrite: true
  });
  return new THREE.Mesh(planeGeo, shaderMaterial);
}

function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 10, 2000);
  camera.position.set(0, 500, 500);
  camera.up.set(0, 1, 0);
  camera.lookAt(0, 0, 0);

  scene = new THREE.Scene();

  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize(window.innerWidth, window.innerHeight);
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = '0px';
  labelRenderer.domElement.style.pointerEvents = 'none';
  document.getElementById('container').appendChild(labelRenderer.domElement);

  window.addEventListener('resize', onWindowResize);

  controls = new OrbitControls(camera, renderer.domElement);
  controls.minDistance = 10;
  controls.maxDistance = 1000;
  // 设置为true可启用阻尼(惯性),可用于为控件提供重量感。默认值为false。
  // 请注意,如果启用了此选项,则必须在动画循环中调用.update()。
  controls.enableDamping = false;
  controls.screenSpacePanning = false; // 定义平移时如何平移相机的位置 控制不上下移动

  stats = new Stats();
  document.body.appendChild(stats.dom);

  gpuPanel = new GPUStatsPanel(renderer.getContext());
  stats.addPanel(gpuPanel);
  stats.showPanel(0);

  scene.add(group);
}

function initLight() {
  const light = new THREE.DirectionalLight(new THREE.Color('rgb(253,253,253)'));
  light.position.set(100, 100, -10);
  light.intensity = 3; // 光线强度
  light.castShadow = true; // 是否有阴影
  light.shadow.mapSize.width = 2048; // 阴影像素
  light.shadow.mapSize.height = 2048;
  // 阴影范围
  const d = 80;
  light.shadow.camera.left = -d;
  light.shadow.camera.right = d;
  light.shadow.camera.top = d;
  light.shadow.camera.bottom = -d;
  light.shadow.bias = -0.0005; // 解决条纹阴影的出现
  // 最大可视距和最小可视距
  light.shadow.camera.near = 0.01;
  light.shadow.camera.far = 2000;
  const AmbientLight = new THREE.AmbientLight(new THREE.Color('rgb(255,255,255)'));
  scene.add(light);
  scene.add(AmbientLight);
}

function initHelp() {
  const size = 1000;
  const divisions = 20;
  const gridHelper = new THREE.GridHelper(size, divisions);
  scene.add(gridHelper);

  // The X axis is red. The Y axis is green. The Z axis is blue.
  const axesHelper = new THREE.AxesHelper(500);
  scene.add(axesHelper);
}

function axesHelperWord() {
  let xP = addWord('X轴');
  let yP = addWord('Y轴');
  let zP = addWord('Z轴');
  xP.position.set(400, 0, 0);
  yP.position.set(0, 400, 0);
  zP.position.set(0, 0, 400);
}

function addWord(word) {
  let name = `<span>${word}</span>`;
  let moonDiv = document.createElement('div');
  moonDiv.className = 'label';
  // moonDiv.textContent = 'Moon';
  // moonDiv.style.marginTop = '-1em';
  moonDiv.innerHTML = name;
  const label = new CSS2DObject(moonDiv);
  group.add(label);
  return label;
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  time += 0.05;
  if (shaderMaterial) {
    shaderMaterial.uniforms.uTime.value = time;
  }
  time1 += 0.01;
  if (boxShaderMaterial) {
    boxShaderMaterial.uniforms.uTime.value = time1;
  }
  if (shaderMaterialSphere) {
    shaderMaterialSphere.uniforms.uTime.value += 0.005;
    if (shaderMaterialSphere.uniforms.uTime.value >= 0.9) {
      shaderMaterialSphere.uniforms.uTime.value = -0.1;
    }
  }
  requestAnimationFrame(animate);
  stats.update();
  controls.update();
  labelRenderer.render(scene, camera);
  renderer.render(scene, camera);
}
</script>
</body>

</html>

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

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

相关文章

雷池WAF+Modsecurity安装防护及系统加固

君衍. 一、雷池WAF1、什么是雷池2、什么是WAF3、雷池的功能4、WAF部署架构5、整体检测流程 二、雷池WAF环境依赖1、查看本地CPU架构2、Docker安装2.1 卸载旧版本2.2 安装yum-utils工具包2.3 设置镜像仓库2.4 安装docker2.5 启动docker并查看版本 3、Docker Compose安装3.1 卸载…

flex布局中子元素内容超出时,子元素本身出现滚动条实现方法

flex布局中子元素宽度平均分配&#xff0c;并且当子元素内容超出时&#xff0c;子元素本身出现滚动条实现方法&#xff1a; 将父元素设置为display: flex&#xff0c;以启用Flexbox布局。将每个子元素的flex属性设置为1&#xff0c;以使其宽度平均分配。设置子元素的overflow属…

《Linux开发笔记》C语言编译过程

C语言编译过程 编译过程主要分为四步&#xff1a;预处理、编译、汇编、链接 预处理&#xff1a;主要用于查找头文件、展开宏 编译&#xff1a;把.i文件编译成.s文件 汇编&#xff1a;把.s文件汇编为.o文件 链接&#xff1a;把多个.o文件链接成一个app 以上四个步骤主要由3个命…

MySQL常用操作命令大全

文章目录 一、连接与断开数据库1.1 连接数据库1.2 选择数据库1.3 断开数据库 二、数据库操作2.1 创建数据库2.2 查看数据库列表2.3 删除数据库 三、表操作3.1 创建表3.2 查看表结构3.3 修改表结构3.3.1 添加列3.3.2 删除列3.3.3 修改列数据类型 3.4 删除表 四、数据操作4.1 插入…

一文讲懂npm link

前言 在本地开发npm模块的时候&#xff0c;我们可以使用npm link命令&#xff0c;将npm 模块链接到对应的运行项目中去&#xff0c;方便地对模块进行调试和测试 用法 包链接是一个两步过程&#xff1a; 1.为依赖项创建全局软链npm link。一个符号链接&#xff0c;简称软链&a…

DataWhale-吃瓜教程学习笔记 (六)

学习视频**&#xff1a;第4章-决策树_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第五章 5.1&#xff1b;5.2&#xff1b;5.3 文章目录 MP 神经元- 感知机模型 &#xff08;分类模型&#xff09;-- 损失函数定义--- 感知机学习算法 - 随机梯度下降法 - 神经网络需要解决的问…

electron教程(一)创建项目

一、方式① 根据官网描述将electron/electron-quick-start项目克隆下来并启动 electron/electron-quick-start地址&#xff1a; GitHub - electron/electron-quick-start: Clone to try a simple Electron app git clone https://github.com/electron/electron-quick-start…

HBM是什么?因AI而崛起,它有哪些优势?

南韩存储大厂SK海力士宣布&#xff0c;将与台积电公司密切合作&#xff0c;联手生产下一代HBM——即预计在2026年投产的第六代HBM产品HBM4&#xff0c;双方并于近期签署合作备忘录&#xff08;MOU&#xff09;。 SK海力士以往的HBM产品&#xff0c;包括HBM3E&#xff08;第五代…

感动的短视频:成都柏煜文化传媒有限公司

感动的短视频&#xff1a;瞬间触动心灵的温暖力量 在这个快节奏、高压力的时代&#xff0c;我们常常在忙碌与喧嚣中穿梭&#xff0c;心灵深处那份最纯粹的感动似乎变得愈发珍贵而难得。然而&#xff0c;就在这样一个数字化盛行的今天&#xff0c;短视频以其独特的魅力&#xf…

LLM学习记录

概述 语言模型的发展 语言模型经历过四个阶段的发展&#xff0c;依次从统计语言模型到神经网络语言模型&#xff08;NLM&#xff09;&#xff0c;到出现以 BERT 和 Transformer 架构为代表的预训练语言模型&#xff08;PLM&#xff09;&#xff0c;最终到大型语言模型阶段&am…

第一后裔怎么绑定NEXON账号 NEXON账号绑定Steam第一后裔教程

刚上线就特别好评的多人刷榜刚上线就特别好评的多人刷宝射击爽游《第一后裔》免费上线了&#xff0c;快和小伙伴们一起来闯荡这个神秘的世界吧&#xff0c;整体还是mmo的玩法&#xff0c;开放世界任意探索&#xff0c;全新虚幻五引擎带来的不俗的画面表现&#xff0c;在游戏中扮…

Sharding-JDBC分库分表的基本使用

前言 传统的小型应用通常一个项目一个数据库&#xff0c;单表的数据量在百万以内&#xff0c;对于数据库的操作不会成为系统性能的瓶颈。但是对于互联网应用&#xff0c;单表的数据量动辄上千万、上亿&#xff0c;此时通过数据库优化、索引优化等手段&#xff0c;对数据库操作…

昇思25天学习打卡营第04天 | 数据集 Dataset

昇思25天学习打卡营第04天 | 数据集 Dataset 文章目录 昇思25天学习打卡营第04天 | 数据集 Dataset数据集加载数据集迭代数据集的变换shufflemapbatch 自定义数据集可随机访问数据集对象可迭代数据集生成器 总结打卡 数据集Dataset对原始数据进行封装、变换&#xff0c;为神经网…

OpenSSH漏洞扫描(CVE-2024-6387、CVE-2006-5051、CVE-2008-4109)

目录 POC&#xff1a;ssh_poc.py 使用方法 github CVE-2024-6387 漏洞信息 补丁 POC&#xff1a;ssh_poc.py import sys import socket import argparse import threading import queue import os from datetime import datetime from urllib.parse import urlparse from…

全年免费!环信发布出海创新版,助力泛娱乐创业者扬帆起航

目前&#xff0c;以陌生人社交、直播、语聊、电商等热门场景为代表的社交泛娱乐出海正发展得如火如荼&#xff0c;成为企业新的增长曲线。但随着出海企业增多&#xff0c;海外市场争夺、资源竞争与技术博弈也愈加激烈。 为了让更多创业者与创新者获得支持&#xff0c;快速高效…

宠物博主亲测养宠好物安利,口碑好的狗毛空气净化器推荐

作为一名6年资深铲屎官&#xff0c;一到春季换季就开始各种疯狂打喷嚏、全身过敏红肿&#xff0c;这是因为宠物在换季的时候就疯狂掉毛&#xff0c;家里就想下雪一样&#xff0c;空气中都是宠物浮毛。而宠物毛上附带的细菌会跟随浮毛被人吸入人体&#xff0c;从而产生打喷嚏、过…

VBA字典与数组第十六讲:行、列数不相同的数组间运算规律

《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;字典是VBA的精华&#xff0c;我要求学员必学。7.1.3.9教程和手册掌握后&#xff0c;可以解决大多数工作中遇到的实际问题。…

云服务器中的地域和可用区是什么意思?

一、地域介绍 1、概念 地域&#xff08;Region&#xff09;&#xff1a;从地理位置和网络时延维度划分&#xff0c;同一个地域内共享弹性计算、块存储、对象存储、VPC网络、弹性公网IP、镜像等公共服务。不同地域之间完全隔离&#xff0c;保证不同地域间最大程度的稳定性和容…

0628_ARM4

练习&#xff1a; stm32流水灯 .text .global _start _start: 使能GPIOE外设时钟 0X50000A28 RCC_MP_AHB4ENSETR[4]->1 LDR R0,0x50000a28 指定操作的内存地址 LDR R1,[R0] 将R0对应的地址空间中的值读取出来 ORR R1,R1,#(0x3<<4) 将第4,5位设置为1 STR…

ForkJoinPool与ThreadPoolExecutor

ThreadPoolExecutor不多介绍&#xff0c;重点介绍ForkJoinPool&#xff0c;以及二者的区别 ForkJoinPool ForkJoinPool 是 Java 7 引入的一种用于并行计算的框架&#xff0c;特别适合处理递归任务。它是 java.util.concurrent 包的一部分&#xff0c;基于工作窃取算法&#x…