写一个Orillusion编辑器(伪)

界面效果

在这里插入图片描述

思路

  1. bootstrap控制界面效果
  2. jquery动态修改界面内容
  3. [Add]增加一个box
  4. [Play]导出play.html,打开play.html就可以看到程序运行效果

编辑器代码

<!DOCTYPE html>
<html>
<!-- TODO
1. 序列化数据,保存工程
2. 反序列化数据,打开工程 -->

<head>
	<meta charset="utf-8">
	<title>编辑器</title>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
	<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
	<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
	<style>
		body {
      
      
			margin: 0;
			width: 100%;
			height: 100%;
		}

		#project {
      
      
			position: absolute;
			z-index: 100;
		}

		#propertyList {
      
      
			position: absolute;
			z-index: 100;
			left: 80%;
			right: 0px;
			top: 25%;
		}

		#canvas {
      
      
			position: absolute;
			top: 0px;
			left: 0px;
			width: 100%;
			height: 100%;
			z-index: 0;
			background: transparent;
			touch-action: none;
			object-fit: cover;
		}
	</style>
</head>

<body οnresize="resize_canvas()">
	<div class="panel panel-default" id="project">
		<button type="button" class="btn btn-default" onclick="addBox()">Add</button>
		<button type="button" class="btn btn-default" onclick="startSimulate()">Play</button>
		<br />
		project
		<div class="panel-body">
			<ul class="list-group" id="projectUl">
			</ul>
		</div>
	</div>


	<div class="panel panel-default" id="propertyList">
		property
		<div class="panel-body" id="propertyListBody">
		</div>
	</div>

	<canvas id="canvas"></canvas>

	<!-- 可以定义ES模块的名称和对应地址 -->
	<script type="importmap">
	{
      
      
	  "imports": {
      
      
		"@orillusion/core": "https://unpkg.com/@orillusion/core/dist/orillusion.es.js",
		"@orillusion/stats": "https://unpkg.com/@orillusion/stats/dist/stats.es.js",
		"dat.gui": "https://npm.elemecdn.com/[email protected]/build/dat.gui.module.js"
	  }
	}
	</script>
	<!-- 可以使用自定义名称引入 -->
	<script type="module">

		import {
      
       Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'
		import {
      
       Stats } from '@orillusion/stats'
		import * as dat from 'dat.gui'

		window.startGame = startGame
		window.continueGame = continueGame
		window.endGame = endGame
		window.showMenu = showMenu
		window.hideMenu = hideMenu
		window.resize_canvas = resize_canvas
		window.initGame = initGame

		window.selectItem = selectItem
		window.startSimulate = startSimulate
		window.serializeGame = serializeGame
		window.saveFile = saveFile
		window.scene2Json = scene2Json

		window.addBox = addBox
		window.addCamera = addCamera
		window.addLight = addLight

		let gameState = 'none'
		let GUIHelp
		let gItemes = new Array()
		let scene3D
		let gCurrentItemIndex = -1
		let gItemsSize = 0
		let dataMap = []

		function startGame() {
      
      
			console.log("StartGame")
			if (gameState == 'pause') {
      
      
				continueGame()
				return
			}

			hideMenu()
			gameState = 'start'
			initGame()
		}

		function continueGame() {
      
      
			console.log("ContinueGame")
			hideMenu()
			if (gameState == 'none') {
      
      
				startGame()
			}
		}

		function endGame() {
      
      
			console.log("EndGame")
			// gameState = 'none'
		}

		function showMenu() {
      
      
			console.log("showMenu")
			// let canvas = document.getElementById('canvas')
			// canvas.setAttribute('style', 'display:none');

			if (gameState == 'start') {
      
      
				gameState = 'pause'
				Engine3D.pause()
			}

		}

		function hideMenu() {
      
      
			console.log("hideMenu")

			let canvas = document.getElementById('canvas')

			if (gameState == 'pause') {
      
      
				gameState = 'start'
				Engine3D.resume()
			}
		}

		function resize_canvas() {
      
      
			canvas = document.getElementById("canvas");
			if (canvas.width < window.innerWidth) {
      
      
				canvas.width = window.innerWidth;
			}

			if (canvas.height < window.innerHeight) {
      
      
				canvas.height = window.innerHeight;
			}
		}

		async function initGame() {
      
      

			// initializa engine
			await Engine3D.init({
      
      
				canvasConfig: {
      
       canvas }
			})
			// create new scene as root node
			scene3D = new Scene3D()
			// add an Atmospheric sky enviroment			
			addSky()
			// create camera
			let camera = addCamera()
			// create light
			addLight()
			// create new object

			// create a view with target scene and camera
			let view = new View3D()
			view.scene = scene3D
			view.camera = camera
			// start render
			Engine3D.startRenderView(view)

			const GUIHelp = new dat.GUI()
			GUIHelp.addFolder('Setting')

			GUIHelp.add({
      
       menu: () => showMenu() }, 'menu')
		}

		function addSky() {
      
      
			let sky = scene3D.addComponent(AtmosphericComponent)
			sky.sunY = 0.6
			scene3D.name = 'scene3D'

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "scene3D" + "</button> </li>")

			gItemes.push({
      
      
				"obj": scene3D,
				"type": 'scene3D',
				"scriptContent": "",
				"scriptClassName": "",
			})
			return sky
		}

		function addBox() {
      
      
			gCurrentItemIndex = gItemes.length
			let name = 'box-' + gCurrentItemIndex

			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + name + "</button> </li>")

			const obj = new Object3D()
			obj.name = name
			// add MeshRenderer
			let mr = obj.addComponent(MeshRenderer)
			// set geometry
			mr.geometry = new BoxGeometry(5, 5, 5)
			// set material
			mr.material = new LitMaterial()
			// add object
			scene3D.addChild(obj)

			gItemes.push({
      
      
				"obj": obj,
				"type": 'box',
				"scriptContent": "",
				"scriptClassName": "",
			})
		}

		function addCamera() {
      
      
			let cameraObj = new Object3D()
			cameraObj.name = "camera"
			let camera = cameraObj.addComponent(Camera3D)
			// adjust camera view
			camera.perspective(60, Engine3D.aspect, 1, 5000.0)
			// set camera controller
			let controller = cameraObj.addComponent(HoverCameraController)
			controller.setCamera(0, 0, 15)
			// add camera node
			scene3D.addChild(cameraObj)

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "camera" + "</button> </li>")

			gItemes.push({
      
      
				"obj": cameraObj,
				"type": 'camera',
				"scriptContent": "",
				"scriptClassName": "",
			})

			return camera
		}

		function addLight() {
      
      
			let light = new Object3D()
			light.name = "light"
			// add direct light component
			let component = light.addComponent(DirectLight)
			// adjust lighting
			light.rotationX = 45
			light.rotationY = 30
			component.intensity = 1
			// add light object
			scene3D.addChild(light)

			gCurrentItemIndex = gItemes.length
			$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "light" + "</button> </li>")

			gItemes.push({
      
      
				"obj": light,
				"type": 'light',
				"scriptContent": "",
				"scriptClassName": "",
			})
			return light
		}

		function selectItem(index) {
      
      
			console.log("selectItemIndex: " + index)
			gCurrentItemIndex = index
			showItemProrperty(gItemes[index])
		}

		function showItemProrperty(item) {
      
      
			let name = item['obj'].name
			console.log("showItemProrperty: " + item)
			$("#propertyListBody").empty()

			// let obj = scene3D.getObjectByName(name)
			let obj = item['obj']
			if (!obj) {
      
      
				console.warn("scene3D not find: " + name)
				return
			}
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">name</span><input type=\"text\" id=\"objName\" value=" + obj.name + "></input></div><br/>")

			let trans = obj.transform
			$("#propertyListBody").append("<p>transform</p>")
			$("#propertyListBody").append("<p>position</p>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">x</span><input type=\"text\" id=\"transX\" value=" + trans.x + "></input></div>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">y</span><input type=\"text\" id=\"transY\" value=" + trans.y + "></input></div>")
			$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">z</span><input type=\"text\" id=\"transZ\" value=" + trans.z + "></input></div>")

			$("#transX").change(function () {
      
       obj.x = $("#transX").val() })
			$("#transY").change(function () {
      
       obj.y = $("#transY").val() })
			$("#transZ").change(function () {
      
       obj.z = $("#transZ").val() })

			$("#propertyListBody").append("<p>script</p>")
			$("#propertyListBody").append("<textarea class=\"form-control\" rows=\"6\" id=\"textareaScript\">" + item.scriptContent + "</textarea>")
			// console.log("----------" + item.scriptContent + "-" + item.scriptClassName)
			$("#textareaScript").change(function () {
      
      
				let str = $("#textareaScript").val()

				let className = str.split(/\s* extends/)[0].replace('class', '')
				console.log("className = " + className + ";gCurrentItemIndex=" + gCurrentItemIndex + ";str=" + str)

				if (gCurrentItemIndex > -1) {
      
      
					gItemes[gCurrentItemIndex].scriptContent = str
					gItemes[gCurrentItemIndex].scriptClassName = className.trim()
				}
			})


		}

		function startSimulate() {
      
      
			serializeGame()
		}

		function serializeGame() {
      
      
			saveFile('play.html')
		}

		async function getFile() {
      
      
			// Open file picker and destructure the result the first handle
			const [fileHandle] = await window.showOpenFilePicker();
			const file = await fileHandle.getFile();
			return file;
		}

		async function saveFile(path) {
      
      
			// create a new handle
			const newHandle = await window.showSaveFilePicker();

			// create a FileSystemWritableFileStream to write to
			const writableStream = await newHandle.createWritable();
			
			dataMap = []
			let data = scene2Json()
			console.log("scene2Json=" + data)

			// write our file
			await writableStream.write("<!DOCTYPE html>");
			await writableStream.write("<html>");
			await writableStream.write("<head>\n");
			await writableStream.write("<meta charset=\"utf-8\">\n");
			await writableStream.write("<title>Play</title>\n");

			await writableStream.write("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
			await writableStream.write("<link rel=\"stylesheet\" href=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css\">\n");
			await writableStream.write("<script src=\"https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js\"><\/script>\n");
			await writableStream.write("<script src=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"><\/script>\n");
			await writableStream.write("<style>body {margin: 0;width: 100%;height: 100%;}\n");
			await writableStream.write("#canvas {position: absolute;top: 0px;left: 0px;width: 100%;height: 100%;z-index: 0;background: transparent;touch-action: none;object-fit: cover;}\n");
			await writableStream.write("</style>\n");
			await writableStream.write("</head>\n");
			await writableStream.write("<body οnresize=\"resize_canvas()\">\n");
			await writableStream.write("<canvas id=\"canvas\"></canvas>\n");
			await writableStream.write("<script type=\"importmap\">{\n");
			await writableStream.write(" \"imports\": {\n");
			await writableStream.write("\"@orillusion/core\": \"https://unpkg.com/@orillusion/core/dist/orillusion.es.js\",\n");
			await writableStream.write("\"@orillusion/stats\": \"https://unpkg.com/@orillusion/stats/dist/stats.es.js\",\n");
			await writableStream.write("\"dat.gui\": \"https://npm.elemecdn.com/[email protected]/build/dat.gui.module.js\"}}\n");
			await writableStream.write("<\/script>\n");
			await writableStream.write("<script type=\"module\">\n");
			await writableStream.write("import { Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'\n");
			await writableStream.write("import { Stats } from '@orillusion/stats'\n");
			await writableStream.write("import * as dat from 'dat.gui'\n");
			await writableStream.write("import * as localSprite from './localScript.mjs'\n");

			//script generate
			for(var s = 0; s < dataMap.length; s++){
      
      
				let strScript = dataMap[s].scriptContent
				if(strScript == "") continue;

				// console.log(s + ": " + strScript)
				await writableStream.write(strScript);
				await writableStream.write("\n");
			}
			

			//main generate
			await writableStream.write("async function initGame() {\n");
			await writableStream.write("await Engine3D.init({ canvasConfig: { canvas } })\n");
			await writableStream.write("let scene3D = new Scene3D()\n");
			await writableStream.write("let view = new View3D()\n");
			await writableStream.write("view.scene = scene3D\n");
			await writableStream.write("localSprite.testlocalScript()\n");

			await writableStream.write("localSprite.loadObj(scene3D, view, " + data + ")\n");
			
			for(var s = 0; s < dataMap.length; s++){
      
      		
				if(dataMap[s].scriptClassName != ""){
      
      					
					await writableStream.write("{ let obj = scene3D.getObjectByName(\"" + dataMap[s].name + "\"); ");
					await writableStream.write("obj.addComponent(" + dataMap[s].scriptClassName + ") }\n");
				}
			}

			await writableStream.write("Engine3D.startRenderView(view) }\n");
			await writableStream.write("initGame()\n");

			await writableStream.write("<\/script>\n");
			await writableStream.write("</body>\n");
			await writableStream.write("</html>");
			// close the file and write the contents to disk.
			await writableStream.close();
		}

		function scene2Json() {
      
      
			for (var i = 0; i < gItemes.length; i++) {
      
      
				let item = gItemes[i]
				console.log(item.obj.name)

				let mapobj = {
      
      
					name: item.obj.name,
					type: item.type,
					scriptContent: item.scriptContent,
					scriptClassName: item.scriptClassName,
					x: item.obj.x,
					y: item.obj.y,
					z: item.obj.z,
					scaleX: item.obj.scaleX,
					scaleY: item.obj.scaleY,
					scaleZ: item.obj.scaleZ,
					rotationX: item.obj.rotationX,
					rotationY: item.obj.rotationY,
					rotationZ: item.obj.rotationZ,
				}

				let mr = item.obj.getComponent(MeshRenderer)
				if (mr) {
      
      
					mapobj.MeshRenderer = {
      
      }
					let geometry = mr.geometry
					if (geometry) {
      
      
						mapobj.MeshRenderer.geometry = {
      
      }
						if (geometry.constructor === BoxGeometry) {
      
      
							console.log("===========BoxGeometry======================")
							mapobj.MeshRenderer.geometry.type = 'BoxGeometry'
							mapobj.MeshRenderer.geometry.width = geometry.width
							mapobj.MeshRenderer.geometry.height = geometry.height
							mapobj.MeshRenderer.geometry.depth = geometry.depth
						}
					}

				}

				dataMap.push(mapobj)
			}
			return JSON.stringify(dataMap)
		}

		startGame()

	</script>
</body>

</html>

play.html是编辑器自动生成的不用修改

localScript.mjs是方便play.html动态创建加载Object3D

/**
 * localScript
 * @version 0.1.0
 * @author CC
 * @license MIT
 */

// export const name = 'localScript';

export function testlocalScript() {
    
    
    console.log("testlocalScript~~~~~~~~~~~~~")
}

import {
    
     Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from "https://unpkg.com/@orillusion/core/dist/orillusion.es.js"
//Scene3D View3D
export function loadObj(scene3D, view, content) {
    
    
    console.log("loadObj~~~~~~~~~~~~~" + content)

    // let data = JSON.parse(content)
    for (var i = 0; i < content.length; i++) {
    
    
        let item = content[i]
        console.log("loadObj~~~~~~~~~~~~~" + i + item)

        if (item.type == "scene3D") {
    
    
            addSky(item, scene3D)
        }
        else if (item.type == "light") {
    
    
            addLight(item, scene3D)
        }
        else if (item.type == "camera") {
    
    
            let camera = addCamera(item, scene3D)
            view.camera = camera
        }
        else if (item.type == "box") {
    
    
            addBox(item, scene3D)
        }
    }
}


function addBox(item, scene3D) {
    
    
    const obj = new Object3D()
    obj.name = item.name
    // add MeshRenderer
    let mr = obj.addComponent(MeshRenderer)
    if (item.MeshRenderer) {
    
    
        if (item.MeshRenderer.geometry) {
    
    
            // set geometry
            mr.geometry = new BoxGeometry(item.MeshRenderer.geometry.width, 
                item.MeshRenderer.geometry.height, 
                item.MeshRenderer.geometry.depth)
        }
    }

    // set material
    mr.material = new LitMaterial()
    setObjInfo(item, obj)
    // add object
    scene3D.addChild(obj)
}

function addCamera(item, scene3D) {
    
    
    let cameraObj = new Object3D()
    cameraObj.name = item.name
    let camera = cameraObj.addComponent(Camera3D)
    // adjust camera view
    camera.perspective(60, Engine3D.aspect, 1, 5000.0)
    // set camera controller
    let controller = cameraObj.addComponent(HoverCameraController)
    controller.setCamera(0, 0, 15)
    // add camera node
    scene3D.addChild(cameraObj)

    return camera
}

function addLight(item, scene3D) {
    
    
    let light = new Object3D()
    light.name = item.name
    // add direct light component
    let component = light.addComponent(DirectLight)
    // adjust lighting
    light.rotationX = 45
    light.rotationY = 30
    component.intensity = 1
    // add light object
    scene3D.addChild(light)

    return light
}

function addSky(item, scene3D) {
    
    
    let sky = scene3D.addComponent(AtmosphericComponent)
    sky.sunY = 0.6
    return sky
}

function setObjInfo(item, obj){
    
    
    obj.x = item.x
    obj.y = item.y
    obj.z = item.z
    obj.rotationX = item.rotationX
    obj.rotationY = item.rotationY
    obj.rotationZ = item.rotationZ
}

物体的脚本也会动态写入play.html,所以支持物体脚本行为

play效果

请添加图片描述

猜你喜欢

转载自blog.csdn.net/chen_227/article/details/131127718