Three.js 极简教程

简介

Three.JS 是什么

  • Three.JS是基于WebGL的Javascript开源框架,简言之,就是能够实现3D效果的JS库。

Three.JS 能做什么

  • 利用Three.JS可以制作出很多酷炫的3D动画,并且Three.js还可以通过鼠标、键盘、拖拽等事件形成交互,在页面上增加一些3D动画和3D交互可以产生更好的用户体验。通过Three.JS可以实现全景视图,这些全景视图应用在房产、家装行业能够带来更直观的视觉体验。在电商行业利用Three.JS可以实现产品的3D效果,这样用户就可以360度全方位地观察商品了,给用户带来更好的购物体验。另外,使用Three.JS还可以制作类似微信跳一跳那样的小游戏。随着技术的发展、基础网络的建设,web3D技术还能得到更广泛的应用。

WebGL

  • WebGL是一种Javascript的3D图形接口,把JavaScript和OpenGL ES 2.0(OpenGL for Embedded Systems)结合在一起。

OpenGL

  • OpenGL是开放式图形标准,跨编程语言、跨平台,Javascript、Java 、C、C++ 、 python 等都能支持OpenG ,OpenGL的Javascript实现就是WebGL,另外很多CAD制图软件都采用这种标准。OpenGL ES 2.0是OpenGL的子集,针对手机、游戏主机等嵌入式设备而设计。

Canvas

  • Canvas是HTML5的画布元素,在使用Canvas时,需要用到Canvas的上下文,可以用2D上下文绘制二维的图像,也可以使用3D上下文绘制三维的图像,其中3D上下文就是指WebGL。

基础知识

主要组件(现实世界的抽象3D模型)

  • 场景(scene)

    • 场景是一个容器,可以看做摄影的房间,在房间中可以布置背景、摆放拍摄的物品、添加灯光设备等。
  • 相机(camera)

    • 相机是用来拍摄的工具,通过控制相机的位置和方向可以获取不同角度的图像。

    • 常用相机

      • 透视相机

透视相机模拟的效果与人眼看到的景象最接近,在3D场景中也使用得最普遍,这种相机最大的特点就是近大远小,同样大小的物体离相机近的在画面上显得大,离相机远的物体在画面上显得小。
PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

fov — 摄像机视锥体垂直视野角度
aspect — 摄像机视锥体长宽比
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面

  • 正交相机
    使用正交相机时无论物体距离相机远或者近,在最终渲染的图片中物体的大小都保持不变。
    OrthographicCamera( left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number )

left — 摄像机视锥体左侧面
right — 摄像机视锥体右侧面
top — 摄像机视锥体上侧面
bottom — 摄像机视锥体下侧面
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面

  • 渲染器(renderer)

    • 渲染器利用场景和相机进行渲染,渲染过程好比摄影师拍摄图像,如果只渲染一次就是静态的图像,如果连续渲染就能得到动态的画面。在JS中可以使用requestAnimationFrame实现高效的连续渲染。

代码实例

  • 在Three.js中,要渲染物体到网页中,我们需要3个组建:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中去。
var scene = new THREE.Scene();  // 场景
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);// 透视相机
var renderer = new THREE.WebGLRenderer();   // 渲染器
renderer.setSize(window.innerWidth, window.innerHeight);    // 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度
document.body.appendChild(renderer.domElement);

进阶实战

组织网络协同图谱

源代码:

<!DOCTYPE html>
<html>
<head><style>body {/* set margin to 0 and overflow to hidden, to go fullscreen */margin: 0;overflow: hidden;background-color: #000000;}</style><title>ANT</title><script src="/libs/three.js" type="text/javascript"></script><script src="/libs/stats.js" type="text/javascript"></script><script src="/libs/physi.js" type="text/javascript"></script><script src="/libs/dat.gui.js" type="text/javascript"></script><script src="/libs/chroma.js" type="text/javascript"></script><script src="/libs/perlin.js" type="text/javascript"></script><script type="text/javascript">'use strict';Physijs.scripts.worker = '/libs/physijs_worker.js';Physijs.scripts.ammo = '/libs/ammo.js';var scale = chroma.scale(['green', 'red']);var initScene, render, meshes = [], lines = [],renderer, scene, light, camera;initScene = function () {renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(window.innerWidth, window.innerHeight);renderer.setClearColor(new THREE.Color(0x000000));renderer.shadowMapEnabled = true;document.getElementById('viewport').appendChild(renderer.domElement);scene = new Physijs.Scene({reportSize: 20, fixedTimeStep: 1 / 60});scene.setGravity(new THREE.Vector3(0, 0, 0));camera = new THREE.PerspectiveCamera(35,window.innerWidth / window.innerHeight,1,1000);camera.position.set(105, 85, 85);camera.lookAt(new THREE.Vector3(0, 0, 0));scene.add(camera);// ambivar ambi = new THREE.AmbientLight(0x222222);scene.add(ambi);// Lightlight = new THREE.SpotLight(0xFFFFFF);light.position.set(40, 50, 100);light.castShadow = true;light.shadowMapDebug = true;light.shadowCameraNear = 10;light.shadowCameraFar = 200;light.intensity = 1.5;scene.add(light);var controls = new function () {this.addSphereMesh = function (radius, widthSegments, heightSegments) {var sphere = new Physijs.SphereMesh(// function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength )new THREE.SphereGeometry(radius, widthSegments, heightSegments),getMaterial());setPosAndShade(sphere);meshes.push(sphere);scene.add(sphere);};this.clearMeshes = function () {meshes.forEach(function (e) {scene.remove(e);});meshes = [];}};// add sphere nodesfor (let i = 0; i < 7; i++) {controls.addSphereMesh(3, 20, 20);}// link sphere nodesdrawLinks();addConstraints();requestAnimationFrame(render);scene.simulate();};function addConstraints() {for (let i = 0; i < meshes.length - 1; i++) {let node1 = meshes[i];let node2 = meshes[i + 1];// 铰链约束 HingeConstraintvar constraint = new Physijs.HingeConstraint(node1, node2, node2.position, new THREE.Vector3(0, 2, 0));scene.addConstraint(constraint);constraint.setLimits(-3.14, // minimum angle of motion, in radians, from the point object 1 starts (going back)3.14, // maximum angle of motion, in radians, from the point object 1 starts (going forward)0.1, // applied as a factor to constraint error, how big the kantelpunt is moved when a constraint is hit0.2 // controls bounce at limit (0.0 == no bounce));}}function drawLinks() {lines.forEach(function (e) {scene.remove(e);});lines = [];// 中心节点跟所有节点相连for (let i = 1; i < meshes.length; i++) {let node1 = meshes[0];let node2 = meshes[i];// add a line to link cube and sphere// 声明一个几何体geometryvar geometry = new THREE.Geometry();var material = new THREE.LineBasicMaterial({vertexColors: true});// 定义两种颜色,分别表示线条两个端点的颜色var color1 = new THREE.Color(0x444444), color2 = new THREE.Color(0x00FF00);// 线的材质可以由2点的颜色决定, 定义2个顶点的位置,并放到geometry中var p1 = new THREE.Vector3(node1.position.x, node1.position.y, node1.position.z);var p2 = new THREE.Vector3(node2.position.x, node2.position.y, node2.position.z);// 几何体里面有一个vertices变量,用来存放点。geometry.vertices.push(p1);geometry.vertices.push(p2);geometry.colors.push(color1, color2);// 定义线条,使用THREE.Line类var line = new THREE.Line(geometry, material, THREE.LineSegments);lines.push(line);// 将这条线加入到场景中scene.add(line);}// 首尾相连for (let i = 0; i < meshes.length - 1; i++) {let node1 = meshes[i];let node2 = meshes[i + 1];// add a line to link cube and sphere// 声明一个几何体geometryvar geometry = new THREE.Geometry();var material = new THREE.LineBasicMaterial({vertexColors: true});// 定义两种颜色,分别表示线条两个端点的颜色var color1 = new THREE.Color(0x444444), color2 = new THREE.Color(0x00FF00);// 线的材质可以由2点的颜色决定, 定义2个顶点的位置,并放到geometry中var p1 = new THREE.Vector3(node1.position.x, node1.position.y, node1.position.z);var p2 = new THREE.Vector3(node2.position.x, node2.position.y, node2.position.z);// 几何体里面有一个vertices变量,用来存放点。geometry.vertices.push(p1);geometry.vertices.push(p2);geometry.colors.push(color1, color2);// 定义线条,使用THREE.Line类var line = new THREE.Line(geometry, material, THREE.LineSegments);lines.push(line);// 将这条线加入到场景中scene.add(line);}}function setPosAndShade(obj) {let X = Math.random() * 20;let Y = 0;let Z = Math.random() * 20;obj.position.set(X, Y, Z);obj.rotation.set(Math.random() * 2 * Math.PI, Math.random() * 2 * Math.PI, Math.random() * 2 * Math.PI);obj.castShadow = true;}function getMaterial() {var material = Physijs.createMaterial(new THREE.MeshLambertMaterial({color: scale(Math.random()).hex(),// opacity: 0.8,// transparent: true}), 0.5, 0.7);return material;}render = function () {requestAnimationFrame(render);renderer.render(scene, camera);drawLinks();addConstraints();scene.simulate(undefined, 2);};window.onload = initScene;</script>
</head><body>
<div id="viewport"></div>
</body></html>

用Physijs在场景中添加物理效果

创建一个Physijs的Three.js场景非常简单,只要几个步骤即可。首先我们要包含正确的文件, 需要引入physi.js文件。实际模拟物理场景时非常耗费CPU的,如果我么能在render线程中做的话,场景的帧频会受到严重的影响。为了弥补这一点,Physijs选择在后台线程中执行计算。这里的后台是有Web workers(网页线程)规范定义的额,现在大多数浏览器都实现了该功能。

对Physijs来说也就意味着我们需要配置一个带有执行任务的JavaScipt文件,并告诉Physijs在哪里可以找到用来模拟场景的ammo.js文件。所以需要添加以下代码:

Physijs.scripts.worker = "../libs/physijs_worker.js";
Physijs.scripts.ammo = "../libs/ammo.js";

Physijs在Three.js的普通场景外又提供了一个包装器,所以我们代码可以想这样创建场景:

scene = new Physijs.Scene();
scene.setGravity(new THREE.Vector3(0, -50, 0));

在模拟物理效果之前,我们需要在场景中添加一些对象。为此,我们可以使用Three.js的普通方法来定义对象,但必须用一个特定的Physijs对象将这些对象包裹起来:

var stoneGeom = new THREE.BoxGeometry(0.6, 6, 2);var stone = new Physijs.BoxMesh(stoneGeom, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: scale(Math.random()).hex(),transparent: true,opacity: 0.8})));...scene.add(stone);

我们第一个Physijs场景中的各个部分都有了。剩下要做的就是告诉Physijs模拟物理效果,并更新场景中各对象的位置和角色。为此,我们可以调用创建的场景的simulate方法。修改基础render循环代码:

render = function(){requestAnimationFrame(render);renderer.render(scene, camera);render_stats.update();scene.simulate(undefined, 1);}

约束

Physijs提供了一些可以用来包装几何体的图形类。使用这些几何体唯一要做的就是讲THREE.Mesh的构造函数替换成这些网格对象的构造函数。下表是Physijs中所有网格对象的概览:

Physijs.PlaneMesh/这个网格可以用来创建一个厚度为0的平面。这样的平面也可以用BoxMesh对象包装一个高度很低的THREE.CubeGeometry来表示Physijs.BoxMesh/如果是类似方块的几何体,你可以使用这个网格。例如,它的属性跟THREE.CubeGeometry的属性很相配Physijs.SphereMesh/对于球形可以使用这个网格。它跟THREE.SphereGeometry的属性很相配Physijs.CylinderMesh/通过设置THREE.Cylinder的属性你可以创建出各种柱状图形。Physijs为各种柱性提供了不同网格。Physijs.CylinderMesh可以用于一般的、上下一致的圆柱形Physijs.ConeMesh/如果顶部的半径为0,底部的半径值大于0,那么你可以用THREE.Cylinder创建一个圆锥体。如果你想在这样一个对象上应用物理效果,那么可以使用的、最相匹配的网格类就是ConeMeshPhysijs.CapsuleMesh(胶囊网格)/跟THREE.Cylinder属性很相似,但其底部和底部是圆的Physijs.ConvexMesh(凸包网格)/Physijs.ConvexMesh是一种比较粗略的图形,可用于多数复杂退行。它可以创建一个模拟复杂图形的凸包Physijs.ConcaveMesh/ConvexMesh是一个比较粗略的图形,而ConcaveMesh则可以对负责图形进行比较细致的表现。需要注意的是使用ConcaveMesh对效率的影响比较大Physijs.HeightfieldMesh(高度场网格)/这是一种非常特别的网格。通过该网格你可以从一个THREE.PlaneGeometry对象创建出一个高度场。

使用约束限制对象移动: 我们已经了解到各种图形如何对重力、摩擦和弹性做出反应。并影响碰撞。Physijs还提供了一些高级对象,让i可以限制对象的移动。在Physijs里,这些对象呗称作约束。下表是Physijs中可用约束概览:

PointConstraint/通过这个约束,你可以将一个对象与另一个对象之间的位置固定下来。例如一个对象动了,另一个对象也会随着移动,它们之间的距离和方向保持不变HingeConstraint/通过活页约束,你可以限制一个对象只能像活页一样移动,例如门SliderConstraint/将对象的移动限制在一个轴上。例如移门ConeTwistConstraint/通过这个约束,你可以用一个对象限制另一个对象的旋转和移动。这个约束的功能类似于一个球削式关节。例如,胳膊在肩关节中的活动DOFConstraint/通过自由度约束,你可以限制对象在任意轴上的活动,你可以设置对象活动的额最小、最大角度。这是最灵活的约束方式
点对点
var constraint = new Physijs.PointConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ) // point in the scene to apply the constraint
);
scene.addConstraint( constraint );
铰链约束
var constraint = new Physijs.HingeConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraintnew THREE.Vector3( 1, 0, 0 ) // Axis along which the hinge lies - in this case it is the X axis
);
scene.addConstraint( constraint );
constraint.setLimits(low, // minimum angle of motion, in radianshigh, // maximum angle of motion, in radiansbias_factor, // applied as a factor to constraint errorrelaxation_factor, // controls bounce at limit (0.0 == no bounce)
);
constraint.enableAngularMotor( target_velocity, acceration_force );
constraint.disableMotor();
滑块约束
var constraint = new Physijs.SliderConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraintnew THREE.Vector3( 1, 0, 0 ) // Axis along which the hinge lies - in this case it is the X axis
);
scene.addConstraint( constraint );
constraint.setLimits(linear_lower, // lower limit of linear movement, expressed in world unitslinear_upper, // upper limit of linear movement, expressed in world unitsangular_lower, // lower limit of angular movement, expressed in radiansangular_upper // upper limit of angular movement, expressed in radians
);
constraint.setRestitution(linear, // amount of restitution when reaching the linear limitsangular // amount of restitution when reaching the angular limits
);
constraint.enableLinearMotor( target_velocity, acceration_force );
constraint.disableLinearMotor();
constraint.enableAngularMotor( target_velocity, acceration_force );
constraint.disableAngularMotor();
锥形约束
var constraint = new Physijs.ConeTwistConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // Second object to be constrainednew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraint
);
scene.addConstraint( constraint );
constraint.setLimit( x, y, z ); // rotational limit, in radians, for each axis
constraint.setMotorMaxImpulse( max_impulse ); // float value of the maximum impulse the motor can apply toward its target
constraint.setMotorTarget( target ); // target is the desired rotation for the constraint and can be expressed by a THREE.Vector3, THREE.Matrix4, or THREE.Quaternion
constraint.enableMotor();
constraint.disableMotor();
自由度约束
var constraint = new Physijs.DOFConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraint
);
scene.addConstraint( constraint );
constraint.setLinearLowerLimit( new THREE.Vector3( -10, -5, 0 ) ); // sets the lower end of the linear movement along the x, y, and z axes.
constraint.setLinearUpperLimit( new THREE.Vector3( 10, 5, 0 ) ); // sets the upper end of the linear movement along the x, y, and z axes.
constraint.setAngularLowerLimit( new THREE.Vector3( 0, -Math.PI, 0 ) ); // sets the lower end of the angular movement, in radians, along the x, y, and z axes.
constraint.setAngularUpperLimit( new THREE.Vector3( 0, Math.PI, 0 ) ); // sets the upper end of the angular movement, in radians, along the x, y, and z axes.
constraint.configureAngularMotor(which, // which angular motor to configure - 0,1,2 match x,y,zlow_limit, // lower limit of the motorhigh_limit, // upper limit of the motorvelocity, // target velocitymax_force // maximum force the motor can apply
);
constraint.enableAngularMotor( which ); // which angular motor to configure - 0,1,2 match x,y,z
constraint.disableAngularMotor( which ); // which angular motor to configure - 0,1,2 match x,y,z

冻结一个对象

可以使用两种方法来使对象冻结或不可移动。

  1. 如果对象始终是静态的,例如地面,则可以0使用第三个参数创建网格时将其设置为质量:new Physijs.BoxMesh( geometry, material, 0)。任何具有质量的对象0将永远是静态的。
  2. 用于对象在某些时候是静态的,并且在其他方​​面是动态的。
    The second method can be used for objects when they will be static at some times and dynamic at others, like in the jenga example. If you call object.setAngularFactor
    and object.setLinearFactor
    with a THREE.Vector3( 0, 0, 0 )
    then no energy will be applied to the object. You can use object.setAngularVelocity
    and object.setLinearVelocity
    in the same way to clear any velocities the object may already have. At a later point you can reset the object's linear and angular factors to ( 1, 1, 1 )
    , again as it's done in the jenga example.

材质Materials

在THREE材质基础上增加了摩擦度和恢复度

var friction = 0.8; // 摩擦度
var restitution = 0.3; // 恢复度
var material = Physijs.createMaterial(new THREE.MeshBasicMaterial({ color: 0x888888 }),friction,restitution
);
var mesh = new Physijs.BoxMesh(new THREE.CubeGeometry( 5, 5, 5 ),material
);

暂停/恢复模拟

var render = function() {if (!isPaused) {scene.simulate();}renderer.render();
};
var unpauseSimulation = function() {isPaused = false;scene.onSimulationResume();
};

恢复模拟需要调用场景的onSimulationResume方法.

场景配置

var scene = new Physijs.Scene({ reportsize: 50, fixedTimeStep: 1 / 60 });
  1. fixedTimeStep default=1/60 此数字确定模拟步骤的模拟时间。数字越小,模拟越准确
  2. broadphase 指定将使用哪个宽带,选择是dynamic和sweepprune。
  3. reportsize default 50 作为优化,包含对象位置的世界报告基于此数字预先初始化。最好将其设置为您的场景将具有的对象数量。
  4. setGravity方法 default ( 0, -10, 0 ) 设定重力的数量和方向
  5. setFixedTimeStep 在构造函数中default 1 / 60 重置fixedTimeStep给定的值

更新对象的位置和旋转

有一个方面,无法与three.js进行无缝集成:更改对象的位置和/或旋转。如果这样做,您必须将该对象__dirtyPosition或__dirtyRotation标志设置为true,否则将从模拟中的最后一个已知值覆盖。

var mesh = new Physijs.BoxMesh( geometry, material );
scene.add( mesh );var render = function() {// Change the object's positionmesh.position.set( 0, 0, 0 );mesh.__dirtyPosition = true;// Change the object's rotationmesh.rotation.set(0, 90, 180);mesh.__dirtyRotation = true;// You may also want to cancel the object's velocitymesh.setLinearVelocity(new THREE.Vector3(0, 0, 0));mesh.setAngularVelocity(new THREE.Vector3(0, 0, 0));scene.simulate();renderer.render();
};

参考资料:

https://github.com/mrdoob/three.js
https://threejs.org/
https://github.com/chandlerprall/Physijs
http://www.hewebgl.com/article/articledir/1
https://github.com/to-be-architect/learning-threejs
https://threejs.org/examples/#webgl_postprocessing_nodes_pass
https://www.zhihu.com/topic/20024068/hot
https://www.cnblogs.com/w-wanglei/p/6790942.html


Kotlin 开发者社区

国内第一Kotlin 开发者社区公众号,主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。

越是喧嚣的世界,越需要宁静的思考。

【企业数字化转型】数据可视化技术:Three.js 用Physijs在场景中添加物理效果相关推荐

  1. three.js后期处理-使用UnrealBloomPass通道在场景中添加泛光效果,三维物体表面发光效果(vue中使用three.js85)

    使用UnrealBloomPass通道在场景中添加泛光效果 1.demo效果 2. 重要知识点 2.1 回顾要点 2.2 UnrealBloomPass通道介绍 3. 实现要点 3.1 相关文件引入 ...

  2. 麦肯锡:企业数字化转型不要被技术“绑架”

    来源:澳财网 随着技术带动流程的改善和数字化时代的带来,平台经济日益兴起,视频租赁.电影.实体零售.广告和媒体.数据存储.出租车行业.餐馆和外卖.酒店和其他行业开始出现颠覆.在这个过程中,想客户之所想 ...

  3. 企业数字化转型:聊聊数据思维!

     关注ITValue,看企业级最新鲜.最价值报道! 作者丨石秀峰 笔者在<深入聊一聊企业数字化转型这个事儿>一文中给出了数字化转型的定义,即:通过应用数字化技术来重塑企业的信息化环境和业务 ...

  4. 企业数字化转型本质上是“人”的转型和“组织”的转型

    2021年是机遇与挑战并存的一年.这场数字化变革摆在所有人面前,每个企业都必须重视起来,也不得不重视起了,因为数字化已经成为企业的起跑线了. 说起数字化,很多企业都认为是技术问题,认为企业数字化转型就 ...

  5. 后疫情时代下,企业数字化转型之路如何走?

    如今,推进数字化转型正成为多数中国企业的核心战略,据国际数据公司IDC与浪潮联合发布的<2019年数据及存储发展研究报告>显示,2019年中国数字化转型IT支出首次超过非数字化转型IT支出 ...

  6. 以视频直播为牵引 企业数字化转型的又一次“大迁徙”

    关注我们牛年牛气冲天 坐地铁时刷刷短视频,购物时逛逛直播平台,我们在生活中已经习以为常.那么,视频.直播这些新的工具和方式,在企业数字化转型的过程中又会催生出哪些新的应用场景和商业模式呢? 01 企业 ...

  7. 企业数字化转型到底该怎么做?

    企业数字化转型涉及实施技术和利用数字工具来增强业务流程.改善客户体验和推动创新.主要包括: 愿景和战略:首先明确定义数字化转型目标.确定数字技术可以对企业的业务产生最重大影响的领域,例如运营效率.客户 ...

  8. 新融合,新跳板:智能云网如何让企业数字化转型,起步即领先?

    数字化转型,正在从企业的可选项变成必选项.随之而来,企业也更需要掌握数字化进程中的契机.节点和全新机遇. 根据清华大学全球产业研究院发布的<中国企业数字化转型研究报告>,2020年企业数字 ...

  9. 【金猿产品展】元年云——成长型企业数字化转型的领航者

    元年云产品 本项目由元年云投递并参与"数据猿年度金猿策划活动--2021大数据产业创新服务产品榜单及奖项"评选. 数据智能产业创新服务媒体 --聚焦数智 · 改变商业 元年云产品秉 ...

最新文章

  1. 二叉树代码 java面试题_《剑指offer》面试题39 二叉树的深度(java)
  2. JavaScript数组方法大全(推荐)
  3. wxWidgets:wxTreeCtrl类用法
  4. SQLServer数据库获取重复记录中日期最新的记录
  5. client copy sap论坛上看到的
  6. 个性化推荐从入门到精通(附推荐产品经理修炼秘籍)
  7. C++字符串格式化 sprintf详解
  8. jetty源码阅读总结1
  9. Hibernate注解与JPA
  10. 2021学习 - OEM,ODM,OBM,JDM和白牌化
  11. instagram动态网页图片内容爬取(一)
  12. 25岁社招进阿里,从电商到有赞新零售,他仅1年就打开了马云一直想做的新领域!...
  13. 【Unity3D-Mirror多人坦克大战】子弹及其开火位置的生成、子弹开火逻辑(四)
  14. 第六章、Tiny4412 U-BOOT移植六 Nand Flash源码分析
  15. 62_LP-3DCNN: Unveiling Local Phase in 3D Convolutional Neural Networks 2019 论文笔记
  16. windows 7 下让 Delphi 2010 开发的程序具备UAC管理员权限
  17. 国科大学习资料--最优化计算方法(王晓)--第六次作业答案
  18. 中国象棋对弈系统java的程序包谁有?
  19. c++语言小游戏源码,跪求小游戏c++代码
  20. 碳中和背景下我国空调系统发展趋势2022(李先庭)

热门文章

  1. 用java如何进行图片去白色_java如何对图片去除图片的白色的背景
  2. DBC2000DB Commander 2000 PRO 升级记录
  3. android适配各种机型及其分辨率
  4. ROS开发实践(十)——ROS多机通讯及网络配置讲解
  5. 运行tomcat时,解析 HTTP 请求 header 错误 Note: further occurrences of HTTP 在方法名称中发现无效的字符串, HTTP 方法名必须是有效的符号
  6. idea Message: 前言中不允许有内容【解决】
  7. 苹果手机透明桌面_原来苹果手机辨别真假很简单!查看桌面1个图标,就能轻松分辨...
  8. Linux 运维知识梳理(5)Nginx 详解
  9. 基于Photoshop的logo样机使用
  10. Python(一)- 安装与升级!