Three.js机器人与星系动态场景(二):强化三维空间认识

在上篇博客中介绍了如何快速利用react搭建three.js平台,并实现3D模型的可视化。本文将在上一篇的基础上强化坐标系的概念。引入AxesHelper辅助工具及文本绘制工具,带你快速理解camer、坐标系、position、可视区域。

Three.js机器人与星系动态场景:实现3D渲染与交互式控制-CSDN博客

 AxesHelper辅助坐标系

three.js提供了 AxesHelper方法,在3D场景中建立一个,x、y、z两两垂直的坐标系。由于在网页中通常用z-index表示高度或者层级,在3D场景中z表示离屏幕的距离,z越大,物体离实现越近。所以在3D中的坐标系默认是y轴朝上。

辅助坐标系便于开发者或用户在视觉上识别和定位场景中的物体。坐标轴辅助器通常在开发阶段用于调试,但在最终的产品中也可以保留,以帮助用户理解3D空间

使用方法

  const axesHelper = new THREE.AxesHelper(150);
  scene.add(axesHelper);

AxesHelper是Three.js库中的一个类,用于创建一个可视化的坐标轴(X轴、Y轴和Z轴)。括号中的150是一个参数,表示坐标轴的长度为150个单位。 通过THREE的AxesHelper方法创建,并通过scene添加到场景中。

 通过这个方法可以看到在3D中生成了坐标轴辅助线。

three.js坐标轴颜色R绿GB分别对应坐标系的xyz

绘制文本并让文字始终朝向用户 

在旋转过程中坐标系可能会混乱,虽然你强迫自己记住xyz对应红绿蓝,但是用着用着就蒙了。可以借助文字辅助理解。然而在threeJS中文本也是当物体绘制出来。不是几行代码就能实现的。这里文字需要通过load进行加载,并且文字有自己的position,在循环动画时添加文本的lookAt为camera的position,让文本始终看着相机,即可实现文本朝向用户。

 创建文本

import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
//创建文本
function createText(content: string, font: any) {
  const textGeometry = new TextGeometry(content, {
    font: font,
    size: 1,
    height: 0.1,
    curveSegments: 1,
  });
  textGeometry.center();
  const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // front
  const mesh = new THREE.Mesh(textGeometry, textMaterial);
  return mesh;
}

 解析字体的json文件

  //坐标系添加文字
  const loader = new FontLoader();
  let meshX = new THREE.Mesh();
  let meshY = new THREE.Mesh();
  let meshZ = new THREE.Mesh();
  loader.load("fonts/optimer_regular.typeface.json", function (font) {
    meshX = createText("X", font);
    meshY = createText("Y", font);
    meshZ = createText("Z", font);
    meshX.position.x = 12;
    meshY.position.y = 12;
    meshZ.position.z = 12;
    scene.add(meshX);
    scene.add(meshY);
    scene.add(meshZ);
  });

 这个json后缀的文件是用来解析字体的,load的第一个参数是json的url。json数据从哪获取?

打卡node_modules或者你下的threejs源码,找到examples/fonts,将其复制到public文件夹。就可以引入了

 

 

在学习threeJS过程中,我也是不断参考example示例,找所需的资源 

 相机camera

camera相机

 相机在3D场景的作用可以想象成是你手中的一个真实的相机或者你的眼睛。在现实生活中,你站在某个地方,你的位置就是相机的位置。比如说,你站在一个公园的角落,从这个位置你可以看到公园里的不同景物。在Three.js中,camera代表了观察者(可以是你的眼睛或者一个虚拟的摄像头)在3D空间中的位置和视角。

 PerspectiveCamera 相机

three.js 里有几种不同的相机,在这里,我们使用的是 PerspectiveCamera(透视摄像机)这个相机类型最接近我们现实生活中观察世界的方式,因为它使用透视投影来渲染场景。透视投影的特点是近大远小,这使得远处的物体看起来比实际小,而近处的物体则显得更大。

关键参数

当你创建一个 PerspectiveCamera 时,通常需要设置以下几个参数:

  1. 视野(Field of View, FOV):这是相机视野的角度,通常以度数表示。较大的 FOV 会使场景看起来更宽广,而较小的 FOV 则会使场景看起来更狭窄。

  2. 长宽比(Aspect Ratio):这是相机视口的宽度与高度的比率。通常设置为渲染窗口的宽度除以高度。

  3. 近裁剪面(Near Clipping Plane):这是相机能够看到的最近的距离。任何比这个距离更近的物体都不会被渲染。

  4. 远裁剪面(Far Clipping Plane):这是相机能够看到的最远的距离。任何比这个距离更远的物体也不会被渲染。

   

想象一下你正在用眼睛看世界。PerspectiveCamera 就像你的眼睛,它有一个视野范围(FOV),决定了你能看到多宽或多窄的场景。长宽比(Aspect Ratio)决定了你看到的画面是宽屏还是窄屏。近裁剪面和远裁剪面则决定了你能看到的最近和最远的物体。 

 在three.js中通常通过下面的方式创建透视相机,通常设置宽高比就用视口可视区域的宽高比。

  // 创建一个Three.js相机,包括透视投影、宽高比、近裁剪面和远裁剪面
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

 position位置

position就是在3D场景中的物体的坐标信息,在Three.js中,设置camera.position就是确定你的“观察点”在哪里

 可以对具有postion属性的物体通过set方法设置x,y,z坐标信息

  camera.position.set(15, 12, 8);

 也可以对Three.js的Object3D对象通过position.x和position.y单独设置坐标轴的值

lookAt方法

lookAt方法就像是你在决定你的相机或者你的眼睛要聚焦在哪个点上。当你调整相机对准某个特定对象时,你实际上是在使用lookAt方法。在现实生活中,即使你站在一个固定的位置,你的头可以转向不同的方向,去看向不同的物体。

 lookAt看向的是3D空间中的具体点,相机的位置和lookAt看向的点覆盖的区域就是网页渲染初始时的视野

举例:继续上面的操场例子,即使你站在同一个角落,你可以选择看向操场的中心点,也可以看向操场上的某个运动员或者某个特定的物体。当你看向某个点时,你的注意力就集中在了那个方向上,就像是在Three.js中调用lookAt方法,让相机镜头指向那个点。

在本文中相机的位置position和lookAt坐标系

  camera.position.set(15, 12, 8);
  camera.lookAt(0, 0, 0);

可以看到,你的眼睛是能够看到x、y、z三个坐标的正向,并且视线正对坐标原点。也就是第一个机器人。 

  robot2.position.x = 6;
  robot2.position.z = 6;

camera位置和lookAt对可视物体的影响 

1.物体放在camera后面

 示例的第一个机器人位于坐标原点,第二个机器人x轴和z轴分别偏移了6个单位。因为camera的位置是x轴偏移15,y轴偏移12,因此能够看到两个机器人。如果我将第二个机器人的x和y都大于camera呢?比如如下的设置

  robot2.position.x = 20;
  robot2.position.z = 20;

 可以看到默认页面加载是看不到第二个机器人的。但是相机位置和看向点不变,我们旋转3D坐标系,可以看到第二个机器人。说明此时机器人“站在了你的后面”,因为你没看向它,但它存在吗?当然存在。

 2.切换camera的lookAt

机器人2的位置信息 

  robot2.position.x = 20;
  robot2.position.z = 20;

切换相机的视角使其看到机器人2

camera.position.set(15, 12, 8);
camera.lookAt(20, 0, 20);

 可以看到页面初始时只能看到机器人2,坐标原点在后面,所以看不到原点上的机器人。但是旋转坐标系能够看到。

 OrbitControls旋转坐标系

前面提了很多,旋转坐标系。默认坐标系是不能旋转的,在空间中位置信息确认了就是相对静止的。那我们怎么可以拖动屏幕实现立体观察的效果呢?

在 Three.js 中,如果你希望通过拖动屏幕来旋转场景中的坐标轴,通常需要使用一些交互控制器,例如 OrbitControlsOrbitControls 是一个控制器,它允许用户通过拖动、滚动和按键来控制相机的位置和方向。

 使用OrbitControls

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

可以通过给controls对象添加一个事件监听,当orbitControls改变了,调用renderer重新渲染scene和camera

// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
    renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件

但在我们的代码中并没有显示的调用change的监听,而是在设置循环动画的时候通过renderer.render方法重新渲染每一帧 

  const update = () => {
    requestAnimationFrame(update);
    camera.lookAt(20, 0, 20);
    robot.rotation.y -= 0.005; //机器人旋转
    robot2.rotation.y -= 0.005;
    // 粒子旋转
    starts.rotation.y -= 0.001;
    starts.rotation.z += 0.001;
    starts.rotation.x += 0.001;
    renderer.render(scene, camera);
  };
  update(); //自动更新

虽然在 update 函数中没有显式调用 controls.update(),但是 OrbitControls 在内部已经通过事件监听器在每次交互时更新了相机的位置和方向。当你移动鼠标或触摸屏幕时,这些交互事件会被监听器捕获,OrbitControls 会相应地调整相机,然后 renderer.render(scene, camera) 会使用新的相机状态来渲染场景。

简而言之,OrbitControls 的设计允许它不需要显式的 change 事件监听就能工作。它会在用户交互时自动更新相机,然后在你的渲染函数中,通过 renderer.render(scene, camera) 来反映这些更新。

如果你的场景中确实需要响应用户交互以外的事件来触发渲染,或者你想要在特定条件下禁用某些控制行为,那么监听 change 事件会很有用。但在大多数情况下,对于基本的交互控制,OrbitControls 已经提供了所需的功能。

OrbitControls本质 

OrbitControls本质上就是改变相机的参数,比如相机的位置属性,改变相机位置也可以改变相机拍照场景中模型的角度,实现模型的360度旋转预览效果  

 完整版代码

import { useEffect, useRef } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
//机器人脑袋
function createHead() {
  //SphereGeometry创建球形几何体
  const head = new THREE.SphereGeometry(4, 32, 16, 0, Math.PI * 2, 0, Math.PI * 0.5);
  const headMaterial = new THREE.MeshStandardMaterial({
    color: 0x43b988,
    roughness: 0.5,
    metalness: 1.0,
  });
  const headMesh = new THREE.Mesh(head, headMaterial);
  return headMesh;
}
//触角
function generateHorn(y: number, z: number, angle: number) {
  //触角 CapsuleGeometry 创建胶囊形状的几何体。胶囊形状可以看作是一个圆柱体两端加上半球体
  const line = new THREE.CapsuleGeometry(0.1, 2);
  const lineMaterial = new THREE.MeshStandardMaterial({
    color: 0x43b988,
    roughness: 0.5,
    metalness: 1.0,
  });
  const lineMesh = new THREE.Mesh(line, lineMaterial);
  lineMesh.position.y = y;
  lineMesh.position.z = z;
  lineMesh.rotation.x = angle;
  return lineMesh;
}
//机器人眼睛
function generateEye(x: number, y: number, z: number) {
  //SphereGeometry创建球形几何体
  const eye = new THREE.SphereGeometry(0.5, 32, 16, 0, Math.PI * 2, 0, Math.PI * 2);
  const eyeMaterial = new THREE.MeshStandardMaterial({
    color: 0x212121,
    roughness: 0.5,
    metalness: 1.0,
  });
  const eyeMesh = new THREE.Mesh(eye, eyeMaterial);
  eyeMesh.position.x = x;
  eyeMesh.position.y = y;
  eyeMesh.position.z = z;
  return eyeMesh;
}
//机器人身体
function generateBody() {
  //CylinderGeometry第一个参数是上部分圆的半径,第二个参数是下部分圆的半径,第三个参数是高度,材质使用的跟腿一样
  const body = new THREE.CylinderGeometry(4, 4, 6);
  const bodyMaterial = new THREE.MeshStandardMaterial({
    color: 0x43b988,
    roughness: 0.5,
    metalness: 1.0,
  });
  const bodyMesh = new THREE.Mesh(body, bodyMaterial);
  return bodyMesh;
}
//胳膊、腿
function generateLegs(y: number, z: number) {
  const leg1 = new THREE.CapsuleGeometry(1, 4);
  const legMaterial1 = new THREE.MeshStandardMaterial({
    color: 0x43b988,
    roughness: 0.5,
    metalness: 1.0,
  });
  const leg1Mesh = new THREE.Mesh(leg1, legMaterial1);
  leg1Mesh.position.y = y;
  leg1Mesh.position.z = z;
  return leg1Mesh;
}
//创建机器人
function generateRobot() {
  // 创建一个Three.js对象,用于存放机器人
  const robot = new THREE.Object3D();
  const headMesh = createHead();
  headMesh.position.y = 6.5;
  robot.add(headMesh);
  //眼睛
  const leftEye = generateEye(3, 8, -2);
  const rightEye = generateEye(3, 8, 2);
  robot.add(leftEye);
  robot.add(rightEye);
  const leftHorn = generateHorn(11, -1, (-Math.PI * 30) / 180);
  const rightHorn = generateHorn(11, 1, (Math.PI * 30) / 180);
  robot.add(leftHorn);
  robot.add(rightHorn);
  const body = generateBody();
  body.position.y = 4;
  robot.add(body);

  // 生成机器人左腿
  robot.add(generateLegs(0, -2));
  // 生成机器人右腿
  robot.add(generateLegs(0, 2));
  //胳膊
  robot.add(generateLegs(3, 5));

  robot.add(generateLegs(3, -5));
  //物体缩放
  robot.scale.x = 0.3;
  robot.scale.y = 0.3;
  robot.scale.z = 0.3;
  return robot;
}
//创建粒子星星
function generateStarts(num: number) {
  //制作粒子特效
  const starts = new THREE.Object3D();
  const obj = new THREE.SphereGeometry(0.2, 3, 3);
  const material = new THREE.MeshStandardMaterial({
    color: 0x43b988,
    roughness: 0.5,
    metalness: 5,
  });
  const mesh = new THREE.Mesh(obj, material);
  for (let i = 0; i < num; i++) {
    const target = new THREE.Mesh();
    target.copy(mesh);
    target.position.x = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));
    target.position.y = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));
    target.position.z = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));
    starts.add(target);
  }
  return starts;
}
//创建文本
function createText(content: string, font: any) {
  const textGeometry = new TextGeometry(content, {
    font: font,
    size: 1,
    height: 0.1,
    curveSegments: 1,
  });
  textGeometry.center();
  const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // front
  const mesh = new THREE.Mesh(textGeometry, textMaterial);
  return mesh;
}
/**
 * 创建一个Three.js场景,包括相机和渲染器
 */
function Robot() {
  // 创建一个div容器,用于存放渲染的Three.js场景
  const containerRef = useRef<HTMLDivElement>(null);
  const scene = new THREE.Scene();
  // 创建一个Three.js相机,包括透视投影、宽高比、近裁剪面和远裁剪面
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.set(15, 12, 8);
  camera.lookAt(0, 0, 0);
  // 创建一个Three.js渲染器,包括抗锯齿
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);

  //添加坐标系
  const axisHelper = new THREE.AxesHelper(150);
  scene.add(axisHelper);
  //坐标系添加文字
  const loader = new FontLoader();
  let meshX = new THREE.Mesh();
  let meshY = new THREE.Mesh();
  let meshZ = new THREE.Mesh();
  loader.load("fonts/optimer_regular.typeface.json", function (font) {
    meshX = createText("X", font);
    meshY = createText("Y", font);
    meshZ = createText("Z", font);
    meshX.position.x = 12;
    meshY.position.y = 12;
    meshZ.position.z = 12;
    scene.add(meshX);
    scene.add(meshY);
    scene.add(meshZ);
  });

  const robot = generateRobot();
  const robot2 = generateRobot();
  robot2.position.x = 6;
  robot2.position.z = 6;
  // 将机器人身体添加到场景中
  scene.add(robot);
  scene.add(robot2);
  // 创建一个Three.js方向光,包括颜色、强度
  const straightLight = new THREE.DirectionalLight(0xffffff, 5);
  // 设置方向光的位置
  straightLight.position.set(20, 20, 20);
  // 将方向光添加到场景中
  scene.add(straightLight);

  const starts = generateStarts(200);
  scene.add(starts);

  //轨道控制器
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.update();

  const animate = () => {
    requestAnimationFrame(animate);
    robot.rotation.y -= 0.005; //机器人旋转
    robot2.rotation.y -= 0.005;
    // 粒子旋转
    starts.rotation.y -= 0.001;
    starts.rotation.z += 0.001;
    starts.rotation.x += 0.001;
    //
    meshX.lookAt(camera.position);
    meshY.lookAt(camera.position);
    meshZ.lookAt(camera.position);
    renderer.render(scene, camera);
  };
  animate(); //添加动画

  // 监听组件挂载和卸载
  useEffect(() => {
    // 如果div存在,将渲染器dom元素添加到div中
    if (containerRef.current) {
      containerRef.current.appendChild(renderer.domElement);
      // 渲染场景
      renderer.render(scene, camera);
    }
  }, [containerRef]);

  // 返回div容器,用于存放渲染的Three.js场景
  return <div ref={containerRef} style={{ width: "100vw", height: "100vh" }}></div>;
}

// 导出Robot组件
export default Robot;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

红酒的秘密花园:探索葡萄的种植艺术

在远离城市喧嚣的某个角落&#xff0c;隐藏着一座神秘的红酒秘密花园。这里&#xff0c;葡萄藤缠绵交织&#xff0c;绿叶间闪烁着晶莹的露珠&#xff0c;仿佛在诉说着关于红酒与葡萄种植艺术的古老传说。今天&#xff0c;就让我们一起走进这片神秘的花园&#xff0c;探寻葡萄种…

Mysql查询IFNULL和想象的不一样

select sum(ifnull(a,0)) aaa,ifnull(sum(a),0) bbb from (select g.goodsid a from goods g where g.goodsid 601 ) tmp #注意 goodsid 601 的不存在 ​​​ 返回的结果和想象中不同&#xff0c;解释如下 在您SQL查询中&#xff0c;创建了一个子查询&#xff08;别名为tmp&a…

FEBLESS SAP软件对芯片设计企业的重要性

在集成电路(IC)设计行业&#xff0c;无晶圆厂模式(Fabless)企业专注于芯片的设计和销售&#xff0c;而将制造和封装测试外包给专业的代工厂和封测厂。Fabless模式下&#xff0c;企业面临着复杂的供应链管理和项目协同挑战&#xff0c;而SAP软件作为一款成熟的企业资源规划(ERP)…

iiiiiiiiiiiiiiiiiiiiiiiiiio_contexttttttttttttttttttttttttt

https://www.cnblogs.com/bwbfight/p/17594353.html 谈一谈linux下线程池 - 白伟碧一些小心得 - 博客园 (cnblogs.com) 谈一谈linux下线程池 - 白伟碧一些小心得 - 博客园 (cnblogs.com) https://www.cnblogs.com/bwbfight/p/10901574.html 前面的设计&#xff0c;我们对asio…

Kafka集群安装部署

简介 Kafka是一款分布式的、去中心化的、高吞吐低延迟、订阅模式的消息队列系统。 同RabbitMQ一样&#xff0c;Kafka也是消息队列。不过RabbitMQ多用于后端系统&#xff0c;因其更加专注于消息的延迟和容错。 Kafka多用于大数据体系&#xff0c;因其更加专注于数据的吞吐能力…

AI网络爬虫006:从当当网批量获取图书信息

文章目录 一、目标二、输入内容三、输出内容一、目标 用户输入一个图书名称,然后程序自动从当当网批量获取图书信息 查看相关元素在源代码中的位置: 二、输入内容 第一步:在deepseek中输入提示词: 你是一个Python爬虫专家,一步步的思考,完成以下网页爬取的Python脚本任…

WEB攻防-XSS跨站反射型存储型DOM型标签闭合输入输出JS代码解析

文章目录 XSS跨站-输入输出-原理&分类&闭合XSS跨站-分类测试-反射&存储&DOM反射型XSS存储型XSSDOM-base型XSS XSS跨站-输入输出-原理&分类&闭合 漏洞原理&#xff1a;接受输入数据&#xff0c;输出显示数据后解析执行 基础类型&#xff1a;反射(非持续…

ffmpeg下载/配置环境/测试

一、下载 1、访问FFmpeg官方网站下载页面&#xff1a;FFmpeg Download Page&#xff1b; 2、选择适合Windows的版本&#xff08;将鼠标移动到windows端&#xff09;。通常&#xff0c;你会找到“Windows builds from gyan.dev”或者“BtbN GitHub Releases”等选项&#xff0…

Java的异常处理体系

目录 异常处理1、Java的异常类层次结构2、try-catch-finally 使用注意事项3、在Web应用中如何实现全局异常处理机制 异常处理 1、Java的异常类层次结构 其中Error表示程序运行错误 常见的错误类型有&#xff1a; OutOfMemoryError (内存溢出错误) StackOverFlowError (栈内存溢…

ctfshow-web入门-命令执行(web118详解)Linux 内置变量与Bash切片

输入数字和小写字母&#xff0c;回显 evil input 查看源码&#xff0c;发现这里会将提交的参数 code 传给 system 函数 使用 burpsuite 抓包进行单个字符的模糊测试 fuzz&#xff1a; 发现过滤掉了数字和小写字母以及一些符号&#xff0c;下面框起来的部分是可用的 结合题目提…

vue2使用use注册自定义指令实现输入控制与快捷复制

使用场景 在一些form表单填写内容的时候&#xff0c;要限制输入的内容必须是数值、浮点型&#xff0c;本来el-input-number就可以实现&#xff0c;但是它本身带那个数值控制操作&#xff0c;等一系列感觉不舒服的地方。如果只是使用el-input该多好&#xff0c;只要监听一下输入…

爬虫笔记20——票星球抢票脚本的实现

以下内容仅供交流学习使用&#xff01;&#xff01;&#xff01; 思路分析 前面的爬虫笔记一步一步走过来我们的技术水平也有了较大的提升了&#xff0c;现在我们来进行一下票星球抢票实战项目&#xff0c;实现票星球的自动抢票。 我们打开票星球的移动端页面&#xff0c;分…

身份证OCR识别的深度解读

引言 随着信息技术的飞速发展&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术在各个领域得到了广泛应用。身份证OCR识别&#xff0c;作为OCR技术的一个重要分支&#xff0c;以其高效、准确的特点&#xff0c;在身份验证、信息录入等方面发挥着重要作用。本文将深入解…

【Linux】Linux用户,用户组,其他人

1.文件拥有者 初次接触Linux的朋友大概会觉得很怪异&#xff0c;怎么“Linux有这么多用户&#xff0c;还分什么用户组&#xff0c;有什用呢&#xff1f;”&#xff0c;这个“用户与用户组”的功能可是相当健全而且好用的一个安全防护措施。 怎么说呢&#xff1f;由于Linux是个…

Chapter10 高级纹理——Shader入门精要学习笔记

Chapter10 高级纹理 一、立方体纹理1.基本概念①组成②采样 2.天空盒子 Sky Box3.环境映射三种方法①特殊布局的纹理创建②手动创建Cubemap——老方法③脚本生成 4.反射5.折射6.菲涅尔反射 二、渲染1.镜子效果2.玻璃效果3.渲染纹理 vs GrabPass 三、程序纹理1.简单程序纹理2.Un…

使用 bend-ingest-kafka 将数据流实时导入到 Databend

作者&#xff1a;韩山杰 Databend Cloud 研发工程师 https://github.com/hantmac Databend是一个开源、高性能、低成本易于扩展的新一代云数据仓库。bend-ingest-kafka 是一个专为 Databend 设计的实时数据导入工具&#xff0c;它允许用户从 Apache Kafka 直接将数据流导入到 D…

MacOS下更新curl

苹果自带的curl不支持Https,我们可以通过curl -V看到如下结果 curl 7.72.0 (x86_64-apple-darwin18.6.0) libcurl/7.72.0 zlib/1.2.12 libidn2/2.3.7 librtmp/2.3 Release-Date: 2020-08-19 Protocols: dict file ftp gopher http imap ldap ldaps pop3 rtmp rtsp smtp telne…

LabVIEW汽车ECU测试系统

开发了一个基于LabVIEW开发的汽车发动机控制单元&#xff08;ECU&#xff09;测试系统。该系统使用了NI的硬件和LabVIEW软件&#xff0c;能够自动执行ECU的功能测试和性能测试&#xff0c;确保其在不同工作条件下的可靠性和功能性。通过自动化测试系统&#xff0c;大大提高了测…

基于xilinx FPGA的GTX/GTH/GTY位置信息查看方式(如X0Y0在bank几)

目录 1 概述2 参考文档3 查看方式4查询总结&#xff1a; 1 概述 本文用于介绍如何查看xilinx fpga GTX得位置信息&#xff08;如X0Y0在哪个BANK/Quad&#xff09;。 2 参考文档 《ug476_7Series_Transceivers》 《pg156-ultrascale-pcie-gen3-en-us-4.4》 3 查看方式 通过…

linux——IPC 进程间通信

IPC 进程间通信 interprocess communicate IPC&#xff08;Inter-Process Communication&#xff09;&#xff0c;即进程间通信&#xff0c;其产生的原因主要可以归纳为以下几点&#xff1a; 进程空间的独立性 资源隔离&#xff1a;在现代操作系统中&#xff0c;每个进程都…