three.js vr
Twitter是一个很棒的信息丰富的野兽。 我想将某些可视化功能,Three.js及其VR功能与Socket.IO和Node结合使用,以创建一个通过Twitter流生成的粒子的漂亮世界。
之前,我已经在SitePoint文章中讨论了开发虚拟现实Web体验的所有基础知识, 并使用Google Cardboard和Three.js将VR引入网络 ,因此,如果您不熟悉整个想法,请先读一遍,然后再回来。 本演示使用相同的基础。
我们将要构建的演示将观看Twitter直播流中的关键字。 当人们在观看小溪的同时发推文时,它会弹出一串闪亮的粒子,代表鸣叫持续了多长时间。 本演示尤其会寻找提及“ pizza”的信息。 你为什么问披萨? 我一直在寻找一个不常被称为“比伯”的术语,而比“棚车赛鬣狗”更频繁地被提及。 简而言之,最好的术语是相对频繁的术语,它们会在您观看时出现,但又不是那么频繁,以至于每秒出现数百个。 披萨是其中之一。
示范代码
如果您热衷于直接尝试代码,可以在GitHub上找到它。
想尝试一下吗? 我在这里托管了一个运行版本: VR Twitter World 。
我们的服务器代码
我们将从查看节点服务器代码开始。 它将显示我们的平面HTML,还可以用作Socket.IO服务器,该服务器将从Twitter提取数据流。
完整的服务器相对较短,看起来像这样:
var express = require('express'),
app = express(),
server = require('http').createServer(app),
port = process.env.PORT || 80,
io = require('socket.io')(server),
config = require('./config.json'),
Twitter = require('node-tweet-stream'),
t = new Twitter(config);
app.get('/', function(request, response) {
response.sendFile(__dirname + '/public/index.html');
});
app.get(/^(.+)$/, function(req, res) {
res.sendFile(__dirname + '/public/' + req.params[0]);
});
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
server.listen(port, function() {
console.log('Listening on ' + port);
});
t.track('pizza');
t.on('tweet', function(tweet){
console.log('Roger that. Tweets incoming!');
console.log(tweet);
io.emit('tweet', tweet);
});
t.on('error', function (err) {
console.log('Brace yourself! We are goin doooowwwwwwnnnnnnnn! ', err);
});
我们的第一行使用Node Express框架设置服务器。 这是一个非常简单的设置,它引入了我们所有的依赖关系,并准备了app变量供我们访问服务器功能。 port设置了我们希望服务器在哪个端口上运行( process.env.PORT是一个服务器变量,某些主机设置(如Heroku)将已定义)。
var express = require('express'),
app = express(),
server = require('http').createServer(app),
port = process.env.PORT || 80,
然后,我们设置io变量,同时启动Socket.IO服务器功能,并将其附加到上面设置的Express服务器上:
io = require('socket.io')(server),
设置Twitter访问
config变量是将应用程序的Twitter身份验证密钥和访问令牌保留在其自己的文件中的一种好方法。 为了实时查看Twitter流,我们将使用一个名为node-tweet-stream的npm模块,该模块提供了我们所需的所有功能。 我们将用于Twitter访问的对象和所有相关函数分配给t变量,并传入配置JSON以证明我们被允许访问它。
config = require('./config.json'),
Twitter = require('node-tweet-stream'),
t = new Twitter(config),
如果您没有用于访问Twitter API的任何Twitter键,请不要担心! 您只需要在Twitter上注册一个应用程序即可。 转到Twitter应用程序管理页面 ,使用您的Twitter凭据登录,然后单击“创建新应用程序” 。
拥有应用程序后,您可以通过单击将显示在应用程序管理页面上的“密钥和访问令牌”链接来获取密钥和访问令牌。 如果找不到,它将位于以下URL: https://apps.twitter.com/app/0000000/keys : 0000000用您的应用程序ID替换0000000 )。
然后,在与index.html相同级别的文件上创建一个名为config.json 。 在其中添加以下内容以及您自己的应用程序的值:
{
"consumer_key": "YOURKEY",
"consumer_secret": "YOURKEYSECRET",
"token": "YOURTOKEN",
"token_secret": "YOURTOKENSECRET"
}
其他服务器基础
在我们的index.js文件中,我们进一步设置了对服务器根目录的调用,以加载/public/index.html :
app.get('/', function(request, response) {
response.sendFile(__dirname + '/public/index.html');
});
我们还可以在服务器的public目录中提供其他任何静态文件:
app.get(/^(.+)$/, function(req, res) {
res.sendFile(__dirname + '/public/' + req.params[0]);
});
如果确实有错误,我们会在服务器的控制台中记录该错误并返回500错误:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
以下几行以上述所有设置启动我们的服务器。
server.listen(port, function() {
console.log('Listening on ' + port);
});
检索我们的实时Twitter流
最后,我们设置了特定于Twitter的服务器功能。 我们使用track()函数来指定我们要在不断扩展的Twitter内容流中跟踪哪个关键字。
t.track('pizza');
然后,我们设置一个回调函数以在node-tweet-stream模块发现带有该关键字的Tweet时运行。 如果看到一个,我们将其记录在服务器的控制台日志中(这是可选的,您可以根据需要将其删除),然后将该tweet作为Socket.IO事件发送给所有连接的客户端。
t.on('tweet', function(tweet){
console.log('Roger that. Tweets incoming!');
console.log(tweet);
io.emit('tweet', tweet);
});
<source type="image/webp"><source><img src="https://s2.51cto.com/images/blog/202406/27062917_667c963d1bcc469875.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=" alt="">
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。 原价$ 11.95 您的完全免费
免费获得这本书
如果我们的Twitter API出于任何原因出现错误,则会将其记录到服务器日志中:
t.on('error', function (err) {
console.log('Brace yourself! We are goin doooowwwwwwnnnnnnnn! ', err);
});
与所有Node应用程序一样,我们所有的服务器依赖性和详细信息都存储在package.json中。 如果您不熟悉Node.js,则可能需要仔细阅读所有内容: package.json 。
我们的前端代码
我们的前端代码以与使用Google Cardboard和Three.js将VR投放到网络中的文章相同的设置开始-我们通过立体效果显示的Three.js场景,使场景进入VR视图。 为了简短易懂,我将不介绍与该文章先前的演示相同的内容。 如果您不确定我在这里没有解释的任何内容,请查看该较早的文章以获取信息。
设置Socket.IO
与以前的基础相比,我们将添加的唯一新JS文件是Socket.IO JavaScript文件。 这是一个简单的班轮:
<script src="/socket.io/socket.io.js"></script>
为了从Socket.IO访问功能,我们所需要做的就是将功能分配给io变量,因为您会在index.html文件中看到更多信息:
socket = io(),
准备我们的塔
然后,我们为“塔”(基本上是代表一条推文的垂直粒子集)设置变量。 我们所有的塔都存储在名为tweetTowers的THREE.Object3D对象中。 这是一个容器对象,可让我们跟踪所有塔楼:
// Towers
tweetTowers = new THREE.Object3D(),
particleTexture和particleMaterial是我们的变量,它们代表粒子的外观:
particleTexture,
particleMaterial,
maxTowerCount是我们希望在场景中可见的最大塔数–如果将其设置得太高,我们最终将获得缓慢的体验。 我将其设置为6000,因为这将最大粒子设置为大约一百万。 我认为数量合理!
maxTowerCount = 6000,
range是我们希望放置这些塔的观众周围的面积有多大。 这些塔将放置在场景中的任意位置,因此这限制了它们的放置距离。 我发现与他们更贴近用户是一种更好的体验。 如果它们离用户较远,则看起来没有那么多(尽管有成千上万的粒子!)。 我将其设置为100:
range = 100;
我们的初始化功能
在我们的init()函数中没有太多新内容。 它主要按照上一篇文章中的说明设置我们的VR摄像机和控件。 新位在末尾。
我们将我们的particleTexture图像定义为一个名为particle-new.png的png,它在public文件夹中:
particleTexture = THREE.ImageUtils.loadTexture('textures/particle-new.png');
我们通过将tweetTowers容器添加到场景中来完成init()函数。 有了这个场景,我们就不必担心直接将任何塔添加到场景中,只需将它们直接添加到我们的tweetTowers对象中即可。
scene.add(tweetTowers);
对推文做出React
您会回想起,一旦我们的服务器发现使用关键字“ pizza”通过Twitter流式传输的推文,它就会发出一个名为“ tweet”的事件。 我们的客户端JavaScript现在将监视该事件并做出响应:
socket.on('tweet', function(tweet) {
// Our response
});
响应代码是对名为generateTower()的函数的调用,该函数将在我们的场景中添加一个表示该推文的塔。 我们为它传递四个值:
generateTower({
color: parseInt('0x'+ tweet.user.profile_background_color),
startingCoords: {
x: getRandomArbitrary(-1*range, range),
y: 0,
z: getRandomArbitrary(-1*range, range)
},
speed: 5,
size: (tweet.text.length / 140) * 100
});
- color是我们粒子的颜色。 我们传递用户个人资料背景的颜色。 这使我们可以显示不同的颜色来表示不同的饥饿用户在发送有关比萨的推文。
- startingCoords是放置塔的位置。 我们希望将它们放置在我们周围,因此我们将它们放置在x轴和z轴上方的范围变量之间(此范围应介于-100到100之间)。 如果我们将它们随机放置在y上,它们将从地面的不同高度开始,而不是像建筑物一样排列。 我们绝对不希望这样做,因此我们确保将它们都放置在0的ay位置getRandomArbitrary()是两个值之间的简单随机数生成器。
- speed定义了粒子最终放置的距离(或者,如果向上动画,则塔的上升速度)。
- size是我们的塔高多少个粒子。 假设Twitter的最大长度为140个字符,我们会将其平均化为一个百分比。
显示塔
我们的generateTower()函数本身首先定义了towerGeometry变量。 这是一个THREE.Geometry对象,它将包含塔中所有粒子的位置。 跟踪一个Geometry对象中的所有点可以帮助减少处理时间,因为Three.js只需要跟踪每个塔对象及其点,而不是跟踪一系列独立的粒子。 在代码的后面,我们将为THREE.PointCloud对象提供几何,该对象可以将这些点解释为粒子。
function generateTower(options) {
var towerGeometry = new THREE.Geometry();
// The rest of our code
}
然后,我们设置了一个名为particleMovementsJavaScript对象,该对象存储粒子在塔中开始和结束的位置,以及它们之间的距离(我们之前传入的值):
var particleMovements = {
start: 0,
end: options.size,
speed: options.speed
};
currentCoords变量跟踪塔中粒子的最后位置。 我们将其初始化为0,0,0 。 从前面的函数调用中解析了将要放置塔的startingCoords 。 如果函数调用中没有任何起始坐标,则将它们初始化为与currentCoords相同:
var currentCoords = {x: 0, y: 0, z: 0},
startingCoords = options.startingCoords ? options.startingCoords : currentCoords;
然后,我们遍历塔的大小以创建每个粒子。 我们将y的当前坐标设置为以我们的速度值乘以i来增加。 当我们向上移动时,我们的x和z值将保持在起点。
for (var i = 0; i With those co-ordinates defined for this particle, we attach that particle's position as a vertex in ourtowerGeometry object:
[code language="js"]
towerGeometry.vertices.push(new THREE.Vector3(currentCoords.x, currentCoords.y, currentCoords.z));
towerGeometry
这样可以确保正确设置粒子的位置。 接下来,我们定义该塔中的粒子在particleMaterial变量中的外观。 我们的粒子将放置在THREE.PointCloud对象中,因此要对其设置样式,我们将使用THREE.PointCloudMaterial材质:
particleMaterial = new THREE.PointCloudMaterial({
map: particleTexture,
color: options.color,
blending: THREE.AdditiveBlending,
transparent: true,
size: 4
});
- map定义了我们将用于粒子的图像,我们传入了之前定义的particleTexture纹理。
- color传递我们希望粒子为的颜色(Three.js中的默认值为0xffffff )。
- blending设置粒子如何融合到场景中。 THREE.AdditiveBlending将纹理的颜色添加到其后面的颜色。
- transparent确保融合可以发生,因为它需要一定程度的透明性才能起作用。
- size是我们粒子的大小。
最后,我们定义的变量中我国塔机的点云tower 。 我们传入包含希望每个粒子出现的点的几何图形,以及上面为每个粒子定义的材料。
var tower = new THREE.PointCloud(towerGeometry, particleMaterial);
我们将该塔添加到我们的tweetTowers集合对象中,然后检查场景中有多少塔。 如果塔的数量超过了允许的最大数量,我们将隐藏最旧的塔以减少设备的负载。 如果您有任何性能问题,减少maxTowerCount可能会更好maxTowerCount !
tweetTowers.add(tower);
if (tweetTowers.children.length > maxTowerCount) {
tweetTowers.children[tweetTowers.children.length - maxTowerCount].visible = false;
}
运行我们的代码
要在本地运行此演示,您需要安装Node并运行常规命令。 安装项目的所有依赖项:
npm install
然后运行它:
node index.js
为了在智能手机上进行测试,您要么需要确保智能手机位于同一本地网络上并找到计算机的IP地址,要么使用像ngrok这样的隧道服务(我在访问本地主机的文章中介绍了如何使用ngrok) 从任何地方 )。
您也可以在某个位置托管节点服务器。 我个人使用过Heroku ,但这完全是个人喜好。
一旦服务器启动并运行,请打开Chrome for Mobile并访问它! 戴上Google Cardboard或其他类似的耳机,如果您抬头看半分钟,应该会看到这样的体验:
结论
这应该使您对使用Node,Socket.IO和Three.js创建支持3D Web API的虚拟现实可视化有了一个很好的了解。 该演示本身可以进一步开发,添加更多的关键字,过滤器,使其在包含更多粒子的情况下运行起来更加流畅。 潜力巨大! 随意走到那里,尝试从此演示中做出自己的奇妙体验!
我在SitePoint上也有其他使用类似概念的演示,但是将它们带入了增强现实体验。 如果您有兴趣,可以使用JavaScript和Google Cardboard过滤现实,探索如何从智能手机中获取相机并为其添加滤镜,而使用Awe.js在浏览器中实现增强现实,可以一路探索并通过以下方式将元素添加到您的视野中Three.js和Awe.js的强大组合!
如果您确实面临将本文演示中的VR可视化放在一起(或将其与提到的AR示例中的元素组合在一起)的挑战,请在评论中留下
翻译自: https://www.sitepoint.com/visualizing-a-twitter-stream-in-vr-with-three-js-and-node/
three.js vr