天天看点

Vue实现图形化积木式编程(一)前言最终实现效果本文实现效果技术选型完整代码代码分解后续计划开源项目GitHub链接资源下载链接你的点赞是我继续编写的动力

Babylon.js基础场景搭建

  • 前言
  • 最终实现效果
  • 本文实现效果
  • 技术选型
    • 1.前端
    • 2.后端
  • 完整代码
  • 代码分解
    • 0.npm安装相关依赖
    • 1.引入模块
    • 2.场景初始化
    • 3.ArcRotateCamera 相机初始化
    • 4.灯光初始化
    • 5.地面初始化
      • 5-1. 绿地
      • 5-2.网格地面
    • 6.正方体物体初始化
    • 7.天空盒初始化
  • 后续计划
    • Babylon.js
    • Blockly
  • 开源项目GitHub链接
  • 资源下载链接
  • 你的点赞是我继续编写的动力

前言

前段时间想要做一个web端的图形化积木式编程(类似少儿编程)的案例,网上冲浪了一圈又一圈,终于技术选型好,然后代码一顿敲,终于出来了一个雏形。

TIPS:该案例设计主要参考iRobot Coding,只用做学习用途,侵删。

https://code.irobot.com/#/

最终实现效果

Vue实现图形化积木式编程(一)前言最终实现效果本文实现效果技术选型完整代码代码分解后续计划开源项目GitHub链接资源下载链接你的点赞是我继续编写的动力

本文实现效果

  • 可移动相机视角查看3d模型
    Vue实现图形化积木式编程(一)前言最终实现效果本文实现效果技术选型完整代码代码分解后续计划开源项目GitHub链接资源下载链接你的点赞是我继续编写的动力

技术选型

1.前端

  • vuetify - 基于vue的界面框架
  • babylon.js - 3d图形引擎
  • ammo.js - 物理引擎库
  • blockly - 模块化编程工具

2.后端

  • ThinkJS - 基于Node.js的后端框架

完整代码

  • 一个完整的vue文件
<template>
  <div style="height: 100%;width: 100%;">
    <div>
      <canvas id="renderCanvas"></canvas>
    </div>
  </div>
</template>

<script>
import * as BABYLON from 'babylonjs';
import * as BABYLON_MATERAIAL from "babylonjs-materials"

function loadScene() {
  //获取到renderCanvas这个元素
  var canvas = document.getElementById("renderCanvas");
  //初始化引擎
  var engine = new BABYLON.Engine(canvas, true);
  //初始化场景
  var scene = new BABYLON.Scene(engine);
  //注册一个渲染循环来重复渲染场景
  engine.runRenderLoop(function () {
    scene.render();
  });
  //浏览器窗口变化时监听
  window.addEventListener("resize", function () {
    engine.resize();
  });

  //相机初始化
  var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 5, new BABYLON.Vector3(0, 0, 10), scene);
  camera.setPosition(new BABYLON.Vector3(20, 200, 400));
  //相机角度限制
  camera.upperBetaLimit = 1.5;//最大z轴旋转角度差不多45度俯瞰
  camera.lowerRadiusLimit = 50;//最小缩小比例
  camera.upperRadiusLimit = 1500;//最大放大比例
  //变焦速度
  camera.wheelPrecision = 1; //电脑滚轮速度 越小灵敏度越高
  camera.pinchPrecision = 20; //手机放大缩小速度 越小灵敏度越高
  scene.activeCamera.panningSensibility = 100;//右键平移灵敏度
  // 将相机和画布关联
  camera.attachControl(canvas, true);

  //灯光初始化
  var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 10, 0), scene);
  //设置高光颜色
  light.specular = new BABYLON.Color3(0, 0, 0);
  //设置灯光强度
  light.intensity = 1

  // 绿地初始化
  var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
  materialPlane.diffuseColor = new BABYLON.Color3(152 / 255.0, 209 / 255.0, 115 / 255.0)
  materialPlane.backFaceCulling = false;
  materialPlane.freeze()
  var plane = BABYLON.MeshBuilder.CreateDisc("ground", {radius: 3000}, scene);
  plane.rotation.x = Math.PI / 2;
  plane.material = materialPlane;
  plane.position.y = -0.1;
  plane.freezeWorldMatrix()

  //网格地板初始化
  const groundSide = 144;
  var ground = BABYLON.Mesh.CreateGround("ground", groundSide, groundSide, 1, scene, true);
  var groundMaterial = new BABYLON_MATERAIAL.GridMaterial("grid", scene);
  groundMaterial.mainColor = BABYLON.Color3.White();//底板颜色
  groundMaterial.alpha = 1;//透明度
  const gridLineGray = 0.95;
  groundMaterial.lineColor = new BABYLON.Color3(gridLineGray, gridLineGray, gridLineGray);
  groundMaterial.backFaceCulling = true; // 可看到背面
  //大网格间距
  groundMaterial.majorUnitFrequency = 16;
  //小网格间距
  groundMaterial.minorUnitVisibility = 0;
  const gridOffset = 8; // 网格偏移量
  groundMaterial.gridOffset = new BABYLON.Vector3(gridOffset, 0, gridOffset);
  groundMaterial.freeze(); // 冻结材质,优化渲染速度
  ground.material = groundMaterial
  ground.freezeWorldMatrix()

  //正方形物体初始化
  var blueBox = BABYLON.Mesh.CreateBox("blue", 10, scene);
  var blueMat = new BABYLON.StandardMaterial("ground", scene);
  blueMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
  blueMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
  blueMat.emissiveColor = BABYLON.Color3.Blue();
  // blueMat.wireframe = true;//网格状
  blueBox.material = blueMat;
  //起始位置坐标
  blueBox.position.x = 0;
  blueBox.position.y = 5;
  blueBox.position.z = 0;

  //天空盒初始化
  var skyMaterial = new BABYLON_MATERAIAL.SkyMaterial("skyMaterial", scene);
  skyMaterial.inclination = 0
  skyMaterial.backFaceCulling = false;
  var skybox = BABYLON.Mesh.CreateBox("skyBox", 5000.0, scene);
  skybox.material = skyMaterial;
}


export default {
  name: "test",
  data() {
    return {
    }
  },
  mounted() {
    //加载场景
    loadScene()
  },
}
</script>

<style scoped>
#renderCanvas {
  width: 680px;
  height: 680px;
  touch-action: none;
  z-index: 10000;
  border-radius: 10px;
}
</style>
           

代码分解

0.npm安装相关依赖

npm install babylonjs babylonjs-gui babylonjs-loaders babylonjs-materials --save
           
  • 安装的模块在package.json中生成
"dependencies": {
 {
    "babylonjs": "^4.2.0",//babylon核心库
    "babylonjs-gui": "^4.2.0",//UI界面库(按钮等)
    "babylonjs-loaders": "^4.2.0",//开机加载库(修改启动动画的)
    "babylonjs-materials": "^4.2.0"//材质库,有些材质像是SkyMaterial,babylonjs库的默认材质中是没有这个对象的
}
           

1.引入模块

import * as BABYLON from 'babylonjs';
import * as BABYLON_MATERAIAL from "babylonjs-materials"
           

2.场景初始化

  • template中
<div>
     <canvas id="renderCanvas"></canvas>
</div>
           
  • css中
#renderCanvas {
  width: 680px;
  height: 680px;
  touch-action: none;
  z-index: 10000;
  border-radius: 10px;
}
           
  • js中
//获取到renderCanvas这个元素
var canvas = document.getElementById("renderCanvas");
//初始化引擎
var engine = new BABYLON.Engine(canvas, true);
//初始化场景
var scene = new BABYLON.Scene(engine);
//注册一个渲染循环来重复渲染场景
engine.runRenderLoop(function () {
  scene.render();
});
//浏览器窗口变化时监听
window.addEventListener("resize", function () {
  engine.resize();
});
           

3.ArcRotateCamera 相机初始化

var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 5, new BABYLON.Vector3(0,0,10), scene);
camera.setPosition(new BABYLON.Vector3(20, 200, 400));
//相机角度限制
 camera.upperBetaLimit = 1.5;//最大z轴旋转角度差不多45度俯瞰
camera.lowerRadiusLimit = 50;//最小缩小比例
camera.upperRadiusLimit = 1500;//最大放大比例
//变焦速度
camera.wheelPrecision = 1; //电脑滚轮速度 越小灵敏度越高
camera.pinchPrecision = 20; //手机放大缩小速度 越小灵敏度越高
scene.activeCamera.panningSensibility = 100;//右键平移灵敏度
// 将相机和画布关联
camera.attachControl(canvas, true);
           

4.灯光初始化

//设置半球光
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 10, 0), scene);
//设置高光颜色
light.specular = new BABYLON.Color3(0, 0, 0);
//设置灯光强度
light.intensity = 1
           

5.地面初始化

5-1. 绿地

// 添加地面
var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
materialPlane.diffuseColor = new BABYLON.Color3(152 / 255.0, 209 / 255.0, 115 / 255.0)
materialPlane.backFaceCulling = false;//Allways show the front and the back of an element
materialPlane.freeze()
var plane = BABYLON.MeshBuilder.CreateDisc("ground", {radius: 6000}, scene);
plane.rotation.x = Math.PI / 2;
plane.material = materialPlane;
plane.position.y = -0.01;
plane.freezeWorldMatrix()
           

5-2.网格地面

//地板
  const groundSide = 144;
  var ground = BABYLON.Mesh.CreateGround("ground", groundSide, groundSide, 1, scene, true);
  var groundMaterial = new BABYLON_MATERAIAL.GridMaterial("grid", scene);
  groundMaterial.freeze(); // Optimization.
  groundMaterial.mainColor = BABYLON.Color3.White();//底板颜色
  groundMaterial.alpha = 1;//透明度
  const gridLineGray = 0.95;
  groundMaterial.lineColor = new BABYLON.Color3(gridLineGray, gridLineGray, gridLineGray);
  groundMaterial.backFaceCulling = true; // Change this if the back of the pad needs to be visible.
  //大网格间距
  groundMaterial.majorUnitFrequency = 16;
  //小网格间距
  groundMaterial.minorUnitVisibility = 0;
  const gridOffset = 0; // This makes the grid cells to be aligned with the pad's borders.
  groundMaterial.gridOffset = new BABYLON.Vector3(gridOffset, 0, gridOffset);
  ground.material = groundMaterial
  ground.freezeWorldMatrix()
           
  • TIPS:很多同学会发现,将两个平面叠加时,移动相机视角,会出现虫影现象
Vue实现图形化积木式编程(一)前言最终实现效果本文实现效果技术选型完整代码代码分解后续计划开源项目GitHub链接资源下载链接你的点赞是我继续编写的动力
  • 优化方案
//1、冻结材质和模型
//绿地
//设置为静态网格,freezeWorldMatrix之后,改变postion、rotation是无效的
plane.freezeWorldMatrix()
//将材质冻结
plane.material.freeze()
//网格
ground.freezeWorldMatrix()
ground.material.freeze()
//2、增大两个物体的y轴间距
plane.position.y = -0.1
           

6.正方体物体初始化

//添加物体
var blueBox = BABYLON.Mesh.CreateBox("blue", 10, scene);
var blueMat = new BABYLON.StandardMaterial("ground", scene);
blueMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
blueMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
blueMat.emissiveColor = BABYLON.Color3.Blue();
// blueMat.wireframe = true;//网格状
blueBox.material = blueMat;
//起始位置坐标
blueBox.position.x = 0;
blueBox.position.y = 5;
blueBox.position.z = 0;
           

7.天空盒初始化

//天空盒初始化
var skyMaterial = new BABYLON_MATERAIAL.SkyMaterial("skyMaterial", scene);
skyMaterial.inclination = 0
skyMaterial.backFaceCulling = false;
var skybox = BABYLON.Mesh.CreateBox("skyBox", 5000.0, scene);
skybox.material = skyMaterial;
           

后续计划

Babylon.js

  • 加载网络模型
  • 点击移动物体
  • 自定义启动界面
  • 初始化摄像机动画
  • 物体重力效果
  • babylonjs-gui 按钮实现
  • babylonjs+ammojs 碰撞体实现
  • 将3d界面放入可拖动窗口中

Blockly

  • 入门使用blockly
  • 自定义block块
  • blockly第三方组件使用
  • 接入js-interpreter,步骤运行block块
  • …(想到啥写啥)

开源项目GitHub链接

https://github.com/Wenbile/Child-Programming-Web

资源下载链接

  • Vue前端源码
  • ThinkJS后端源码

你的点赞是我继续编写的动力

继续阅读