Getting a Black Screenshot with BabylonJS - babylonjs

I am having some trouble taking a screenshot. If you followed along with the tut, at: http://doc.babylonjs.com/tutorials/render_scene_on_a_png you see that they only provided one line which is BABYLON.Tools.CreateScreenshot(engine, camera, size);
With size and your camera being the variables that you can change. When I implemented this, I would get a black screenshot. I first thought that maybe the it was taking a screenshot before the page rendered so I added a simple loop to and added an alert box to wait until the scene loaded before the screenshot would execute. But for some reason I am still getting a black screenshot.
Thank you for your input :D
var canvas = document.querySelector("#renderCanvas");
var engine = new BABYLON.Engine(canvas, true);
//Needed for the CreateScene Function
var createScene = function () {
var scene = new BABYLON.Scene(engine);
// Setup camera
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 10, 0, BABYLON.Vector3.Zero(), scene);
camera.setPosition(new BABYLON.Vector3(-10, 10, 25));
camera.attachControl(canvas, true);
// Lights
var light0 = new BABYLON.PointLight("Omni0", new BABYLON.Vector3(0, 10, 5), scene);
var light1 = new BABYLON.PointLight("Omni1", new BABYLON.Vector3(0, -10, 5), scene);
var light2 = new BABYLON.PointLight("Omni2", new BABYLON.Vector3(10, 0, 5), scene);
var light3 = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3(1, -1, 2), scene);
var light4 = new BABYLON.SpotLight("Spot0", new BABYLON.Vector3(0, 5, -10), new BABYLON.Vector3(0, -1, 0), 0.8, 3, scene);
var light5 = new BABYLON.HemisphericLight("Hemi0", new BABYLON.Vector3(0, 1, 0), scene);
var material = new BABYLON.StandardMaterial("kosh", scene);
var sphere = BABYLON.Mesh.CreateSphere("Sphere", 16, 3, scene);
var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", 7.5, 3, 6, 6, 1, scene);
var box = BABYLON.Mesh.CreateBox("box", 6.0, scene);
// Creating light sphere
var lightSphere0 = BABYLON.Mesh.CreateSphere("Sphere0", 16, .5, scene);
var lightSphere1 = BABYLON.Mesh.CreateSphere("Sphere1", 16, 0.5, scene);
var lightSphere2 = BABYLON.Mesh.CreateSphere("Sphere2", 16, 0.5, scene);
//Shifting position up of Sphere
sphere.position.y = 5;
box.position.y = -2;
//generating shadows
var shadowGenerator = new BABYLON.ShadowGenerator(1024, light3);
shadowGenerator.getShadowMap().renderList.push(box);
shadowGenerator.getShadowMap().renderList.push(sphere);
shadowGenerator.getShadowMap().renderList.push(cylinder);
//Colors
lightSphere0.material = new BABYLON.StandardMaterial("red", scene);
lightSphere0.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
lightSphere0.material.specularColor = new BABYLON.Color3(0, 0, 0);
lightSphere0.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
lightSphere1.material = new BABYLON.StandardMaterial("green", scene);
lightSphere1.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
lightSphere1.material.specularColor = new BABYLON.Color3(0, 0, 0);
lightSphere1.material.emissiveColor = new BABYLON.Color3(0, 1, 0);
lightSphere2.material = new BABYLON.StandardMaterial("blue", scene);
lightSphere2.material.diffuseColor = new BABYLON.Color3(0, 0, 0);
lightSphere2.material.specularColor = new BABYLON.Color3(0, 0, 0);
lightSphere2.material.emissiveColor = new BABYLON.Color3(0, 0, 1);
// Sphere material
material.diffuseColor = new BABYLON.Color3(1, 1, 1);
sphere.material = material;
// Lights colors
light0.diffuse = new BABYLON.Color3(1, 0, 0);
light0.specular = new BABYLON.Color3(1, 0, 0);
light1.diffuse = new BABYLON.Color3(0, 1, 0);
light1.specular = new BABYLON.Color3(0, 1, 0);
light2.diffuse = new BABYLON.Color3(0, 0, 1);
light2.specular = new BABYLON.Color3(0, 0, 1);
light3.diffuse = new BABYLON.Color3(1, 1, 1);
light3.specular = new BABYLON.Color3(1, 1, 1);
light4.diffuse = new BABYLON.Color3(1, 0, 0);
light4.specular = new BABYLON.Color3(1, 1, 1);
light5.diffuse = new BABYLON.Color3(1, 1, 1);
light5.specular = new BABYLON.Color3(1, 1, 1);
light5.groundColor = new BABYLON.Color3(0, 0, 0);
//Adding the SkyBox
var skybox = BABYLON.Mesh.CreateBox("skyBox", 100.0, scene);
var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
skyboxMaterial.backFaceCulling = false;
skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("../textures/TropicalSunnyDay", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.disableLighting = true;
skybox.material = skyboxMaterial;
// Animations
var alpha = 0;
scene.beforeRender = function () {
light0.position = new BABYLON.Vector3(10 * Math.sin(alpha), 0, 10 * Math.cos(alpha));
light1.position = new BABYLON.Vector3(10 * Math.sin(alpha), 0, -10 * Math.cos(alpha));
light2.position = new BABYLON.Vector3(10 * Math.cos(alpha), 0, 10 * Math.sin(alpha));
lightSphere0.position = light0.position;
lightSphere1.position = light1.position;
lightSphere2.position = light2.position;
lightSphere0.position.y = 5;
lightSphere1.position.y = 5;
lightSphere2.position.y = 5;
alpha += 0.01;
};
//ground
var ground = BABYLON.Mesh.CreateGround("ground1", 100, 100, 2, scene);
ground.receiveShadows = true;
var materialGround = new BABYLON.StandardMaterial("grassTexture", scene);
materialGround.diffuseColor = new BABYLON.Color3(1,1,1);
materialGround.diffuseTexture = new
BABYLON.Texture("../textures/grass.png",scene);
ground.material = materialGround;
//wait loop for the screenshot
size = { width: 600, height: 400};
var i = 1;
function myLoop () {
setTimeout(function () {
alert('Taking Screenshot!');
//Creating png screenshot
BABYLON.Tools.CreateScreenshot(engine, camera, size);
i++;
if (i < 1) {
myLoop();
}
}, 2000)
}
myLoop();
//Returning the scene
return scene;
};
var scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
window.addEventListener("resize", function () {
engine.resize();
});

The cool fellow (DeltaKosh) over at htmlgameDevs helped me out. He said that when you are creating an engine for a Screenshot or rendering a PNG file that you must define it this way:
engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
I also added a loop that waited a second until after the scene renders to take the screenshot
var scene = createScene();
var booleanR = false;
var size = 512;
engine.runRenderLoop(function () {
scene.render();
});
function myLoop () {
setTimeout(function () {
if(booleanR == false){
BABYLON.Tools.CreateScreenshot(engine, camera, size);
booleanR = true;
}
}, 1000)
}
This is the link from his response: http://www.html5gamedevs.com/topic/32765-getting-a-black-screenshot-with-babylonjs/?tab=comments#comment-187819

Related

Span selected Nodes after have declared the number of comumns and rows in javafx

I would like to know the way to span the next node in the second column after the node containing the label "Info" to the rest of the remaining columns and on 3 rows below.
Below is my present output with the associated code.
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 5 ;
final int numRows = 12 ;
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
Label nameLbl = new Label("Name");
Label nameFld = new Label();
Label infoLbl = new Label("Info : ");
Label infoFld = new Label();
infoFld.setStyle("-fx-background-color: lavender;-fx-font-size: 7pt;-fx-padding: 10 0 0 0;");
Button okBtn = new Button("OK");
Button cancelBtn = new Button("Cancel");
Label commentBar = new Label("Status: Ready");
commentBar.setStyle("-fx-background-color: lavender;-fx-font-size: 7pt;-fx-padding: 10 0 0 0;");
root.add(nameLbl, 0, 0, 1, 1);
root.add(nameFld, 1, 0, 1, 1);
root.add(infoLbl, 0, 1, 1, 1);
root.add(infoFld, 1, 1, 4, 4);
root.add(okBtn, 3, 9, 1, 1);
root.add(cancelBtn, 2, 9, 1, 1);
root.add(commentBar, 0, 11, GridPane.REMAINING, 1);
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want the label to span four rows, as well as four columns, set its column span as well as its row span to 4:
// root.add(infoFld, 1, 1, 4, 1);
root.add(infoFld, 1, 1, 4, 4);
By default a label will not grow beyond its preferred size (which in this case is zero, because it has no text). Allow it to grow indefinitely:
infoFld.setMaxWidth(Double.MAX_VALUE);
infoFld.setMaxHeight(Double.MAX_VALUE);

Center mesh at world origin in Babylon.js

I have a set of 3D face scan obj files I need to display, and I am looking to center each mesh in the world origin.
I have an example below with one of the actual meshes, but if you look, I just tweaked some numbers and rotated it to look right:
mesh.position.x = .1;
mesh.position.y = .46;
mesh.position.z = 0;
mesh.setPivotPoint(mesh.getBoundingInfo().boundingBox.center);
mesh.rotate(BABYLON.Axis.Y, -(Math.PI / 2), BABYLON.Space.WORLD);
mesh.rotate(BABYLON.Axis.X, -(Math.PI / 2), BABYLON.Space.WORLD);
I enabled the bounding box and that is correct.
How can I render each one centered on the origin without magic numbers?
Thanks!
var canvas = document.getElementById("renderCanvas"); // Get the canvas element
var engine = new BABYLON.Engine(canvas, true);
var createScene = function () {
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3.FromInts(1, 1, 1);
//Adding a light
var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(20, 20, 100), scene);
//Adding an Arc Rotate Camera
// var camera = new BABYLON.ArcRotateCamera("Camera", 3, 0, .7, BABYLON.Vector3.Zero(), scene);
var camera = new BABYLON.ArcRotateCamera("Camera", -(Math.PI/2), Math.PI/2, .5, BABYLON.Vector3.Zero(), scene);
// camera.panningAxis = new BABYLON.Vector3(0, 1, 0);
camera.attachControl(canvas, false);
BABYLON.SceneLoader.ImportMesh("" , "https://dl.dropboxusercontent.com/s/n4gwsdn9en6pi86/", "test_ms_simple.obj", scene, function (newMeshes) {
camera.target = BABYLON.Vector3.Zero();
// var mesh = newMeshes[0].getChildMeshes()[0];
var mesh = newMeshes[0];
mesh.showBoundingBox = true;
mesh.position.x = .1;
mesh.position.y = .46;
mesh.position.z = 0;
mesh.setPivotPoint(mesh.getBoundingInfo().boundingBox.center);
mesh.rotate(BABYLON.Axis.Y, -(Math.PI / 2), BABYLON.Space.WORLD);
mesh.rotate(BABYLON.Axis.X, -(Math.PI / 2), BABYLON.Space.WORLD);
camera.minZ = 0;
camera.wheelPrecision = 500;
});
// Move the light with the camera
scene.registerBeforeRender(function () {
light.position = camera.position;
});
// showAxis(10);
return scene;
}
var scene = createScene(); //Call the createScene function
// Register a render loop to repeatedly render the scene
engine.runRenderLoop(function () {
scene.render();
});
// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
engine.resize();
});
function showAxis(size) {
var makeTextPlane = function(text, color, size) {
var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", 50, scene, true);
dynamicTexture.hasAlpha = true;
dynamicTexture.drawText(text, 5, 40, "bold 36px Arial", color , "transparent", true);
var plane = BABYLON.Mesh.CreatePlane("TextPlane", size, scene, true);
plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", scene);
plane.material.backFaceCulling = false;
plane.material.specularColor = new BABYLON.Color3(0, 0, 0);
plane.material.diffuseTexture = dynamicTexture;
return plane;
};
var axisX = BABYLON.Mesh.CreateLines("axisX", [
BABYLON.Vector3.Zero(), new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, 0.05 * size, 0),
new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, -0.05 * size, 0)
], scene);
axisX.color = new BABYLON.Color3(1, 0, 0);
var xChar = makeTextPlane("X", "red", size / 10);
xChar.position = new BABYLON.Vector3(0.9 * size, -0.05 * size, 0);
var axisY = BABYLON.Mesh.CreateLines("axisY", [
BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3( -0.05 * size, size * 0.95, 0),
new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3( 0.05 * size, size * 0.95, 0)
], scene);
axisY.color = new BABYLON.Color3(0, 1, 0);
var yChar = makeTextPlane("Y", "green", size / 10);
yChar.position = new BABYLON.Vector3(0, 0.9 * size, -0.05 * size);
var axisZ = BABYLON.Mesh.CreateLines("axisZ", [
BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3( 0 , -0.05 * size, size * 0.95),
new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3( 0, 0.05 * size, size * 0.95)
], scene);
axisZ.color = new BABYLON.Color3(0, 0, 1);
var zChar = makeTextPlane("Z", "blue", size / 10);
zChar.position = new BABYLON.Vector3(0, 0.05 * size, 0.9 * size);
};
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.min.js"></script>
<canvas id="renderCanvas" width=350 height=350>

I just know how to use for to draw the tree, but now I want to use recursion to draw the tree

I just know how to use for to draw a tree (the tree data is the picture one, the result is picture two), but now I want to use recursion to draw the tree.
Please tell me how change writing style from for to recursive
first input point
//input point
const line_point =[0, 0, 0,
2, 151, 2,
2, 151, 2,
-62, 283, 63,
2, 151, 2,
62, 297, -58,
-62, 283, 63,
-104, 334, 74,
-62, 283, 63,
-58, 338, 45,
62, 297, -58,
67, 403, -55,
62, 297, -58,
105, 365, -86];
take out star point and end point
const star_line_x= new Array();
const star_line_y= new Array();
const star_line_z= new Array();
const end_line_x= new Array();
const end_line_y= new Array();
const end_line_z= new Array();
for (var q=0; q < line_point.length; q+=6){
star_line_x.push(line_point[q]);
}
for (var r=1; r < line_point.length; r+=6){
star_line_y.push(line_point[r]);
}
for (var s=2; s < line_point.length; s+=6){
star_line_z.push(line_point[s]);
}
for (var t=3; t < line_point.length; t+=6){
end_line_x.push(line_point[t]);
}
for (var u=4; u < line_point.length; u+=6){
end_line_y.push(line_point[u]);
}
for (var v=5; v < line_point.length; v+=6){
end_line_z.push(line_point[v]);
}
var cylinder_star_point = new Array();
var cylinder_end_point = new Array();
//star_point end_point
for (var w=0; w < line_point.length/6; w++){
var star_point = new THREE.Vector3 (star_line_x[w],star_line_y[w],star_line_z[w]);
var end_point = new THREE.Vector3 (end_line_x[w],end_line_y[w],end_line_z[w]);
cylinder_star_point.push( star_point);
cylinder_end_point.push( end_point);
}
calculation cylinder high
//calculation cylinder high
var line_len = new Array();
for (var dd=0; dd < line_point.length/6; dd++){
var len_x = Math.pow(end_line_x[dd]-star_line_x[dd],2);
var len_y = Math.pow(end_line_y[dd]-star_line_y[dd],2);
var len_z = Math.pow(end_line_z[dd]-star_line_z[dd],2);
var len_direction = Math.sqrt(len_x+len_y+len_z);
line_len.push(len_direction);//Cylinder high
}
calculation center point
//center_point
const cylinder_center_point= new Array();
for (var bb=0; bb< cylinder_end_point.length; bb++){
var star_set_point = cylinder_star_point[bb];
var end_set_point = cylinder_end_point[bb];
var center_point = end_set_point.clone().add(star_set_point).divideScalar(2);
cylinder_center_point.push(center_point);
}
calculation cylinder direction vector
//cylinder direction
const cylinder_direction= new Array();
for (var cc=0; cc < cylinder_end_point.length; cc++){
var star_direction = cylinder_star_point[cc];
var end_direction = cylinder_end_point[cc];
var center_direction = end_direction.clone().sub(star_direction);
cylinder_direction.push(center_direction);
}
draw cylinder
for (var dd=0; dd <cylinder_direction.length;dd++){
var material = new THREE.MeshPhongMaterial({color:'#ff0000'});
let upVector = new THREE.Vector3(0, 1, 0);
var geometry = new THREE.CylinderGeometry(5, 5, line_len[dd], 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, line_len[dd]/2, 0);
var group = new THREE.Group();
group.position.set(star_line_x[dd],star_line_y[dd],star_line_z[dd]);
group.add(mesh);
let targetVector =cylinder_direction[dd];
let quaternion = new THREE.Quaternion().setFromUnitVectors(upVector, targetVector.normalize());
group.setRotationFromQuaternion(quaternion)
scene.add(group)
}
picture two: use for to draw the tree
For a tree the simplest method is to start with just a tree depth and assume 2 children. The function makes one branch and if depth > 0 then it recursively calls itself to make 2 more branches.
const numBranches = 2;
const spread = 1.5;
const branchShrinkFactor = 0.8;
const branchSpreadFactor = 0.8;
function addBranch(parent, depth, offset, angle, branchLength, spread) {
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderBufferGeometry(5, 5, branchLength, 20, 1, false);
geometry.translate(0, branchLength / 2, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = offset;
mesh.rotation.z = angle;
parent.add(mesh);
if (depth > 1) {
for (let i = 0; i < numBranches; ++i) {
const a = i / (numBranches - 1) - 0.5;
addBranch(mesh, depth - 1, branchLength, a * spread, branchLength * branchShrinkFactor, spread * branchSpreadFactor)
}
}
}
addBranch(scene, 5, 0, 0, 100, 1.5);
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 150, 300);
const scene = new THREE.Scene();
scene.background = new THREE.Color('lightskyblue');
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const numBranches = 2;
const spread = 1.5;
const branchShrinkFactor = 0.8;
const branchSpreadFactor = 0.8;
function addBranch(parent, depth, offset, angle, branchLength, spread) {
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderBufferGeometry(5, 5, branchLength, 20, 1, false);
geometry.translate(0, branchLength / 2, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = offset;
mesh.rotation.z = angle;
parent.add(mesh);
if (depth > 1) {
for (let i = 0; i < numBranches; ++i) {
const a = i / (numBranches - 1) - 0.5;
addBranch(mesh, depth - 1, branchLength, a * spread, branchLength * branchShrinkFactor, spread * branchSpreadFactor)
}
}
}
addBranch(scene, 5, 0, 0, 100, 1.5);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
// requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
If you want specific data for each branch then you need to pass that in. For example
const tree = [
{ length: 100, angle: 0, branches: 2 }, // root
{ length: 40, angle: -1, branches: 3 }, // first branch
{ length: 50, angle: 0.8, branches: 0 }, // 1st child branch
{ length: 40, angle: 0.3, branches: 0 }, // 2nd child branch
{ length: 30, angle: -0.3, branches: 0 }, // 3rd child branch
{ length: 50, angle: 0.8, branches: 2 }, // second branch
{ length: 50, angle: 0.5, branches: 0 }, // 1st child branch
{ length: 40, angle: -0.6, branches: 2 }, // 2nd child branch
{ length: 40, angle: -0.3, branches: 0 }, // 1st grandchild branch
{ length: 95, angle: 0.3, branches: 0 }, // 2st grandchild branch
];
and then walk the tree description, if a branches for a particular branch is > 0 then it recursively calls itself to add those branches. Each branches consumes a row in the array of branches so we pass back ndx so we can tell how many rows were consumed.
function addBranch(parent, offset, tree, ndx = 0) {
const {length, angle, branches} = tree[ndx];
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = offset;
mesh.rotation.z = angle;
parent.add(mesh);
for (let i = 0; i < branches; ++i) {
ndx = addBranch(mesh, length, tree, ++ndx);
}
return ndx;
}
addBranch(scene, 0, tree);
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 150, 300);
const scene = new THREE.Scene();
scene.background = new THREE.Color('lightskyblue');
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const tree = [
{ length: 100, angle: 0, branches: 2 }, // root
{ length: 40, angle: -1, branches: 3 }, // first branch
{ length: 50, angle: 0.8, branches: 0 }, // 1st child branch
{ length: 40, angle: 0.3, branches: 0 }, // 2nd child branch
{ length: 30, angle: -0.3, branches: 0 }, // 3rd child branch
{ length: 50, angle: 0.8, branches: 2 }, // second branch
{ length: 50, angle: 0.5, branches: 0 }, // 1st child branch
{ length: 40, angle: -0.6, branches: 2 }, // 2nd child branch
{ length: 40, angle: -0.3, branches: 0 }, // 1st grandchild branch
{ length: 95, angle: 0.3, branches: 0 }, // 2st grandchild branch
];
function addBranch(parent, offset, tree, ndx = 0) {
const {length, angle, branches} = tree[ndx];
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = offset;
mesh.rotation.z = angle;
parent.add(mesh);
for (let i = 0; i < branches; ++i) {
ndx = addBranch(mesh, length, tree, ++ndx);
}
return ndx;
}
addBranch(scene, 0, tree);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
// requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
It's not clear to me what your input data is. Your tree has a depth of 3 and 2 branches per level so this data would work
const endPoints = [
[ 0, 0, 0], // A
[ 2, 151, 2], // B
[ -62, 283, 63], // C
[-104, 334, 74], // E
[ -58, 338, 45], // F
[ 62, 296, -58], // D
[ 67, 403, -55], // G
[ 105, 365, -86], // H
];
using this code
// assumes there are 2 branches per
function addBranch(parent, depth, offset, tree, parentNdx = 0, childNdx = 1) {
const start = tree[parentNdx];
const end = tree[childNdx];
const length = start.distanceTo(end);
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
geometry.rotateX(Math.PI / 2);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z = offset;
parent.add(mesh);
mesh.lookAt(end);
let ndx = childNdx + 1;
if (depth > 1) {
const numBranches = 2;
for (let i = 0; i < numBranches; ++i) {
ndx = addBranch(mesh, depth - 1, length, tree, childNdx, ndx);
}
}
return ndx;
}
addBranch(scene, 3, 0, tree);
I pointed the cylinders in the positive Z direction which means I can use lookAt to point the cylinder from its start to its end point.
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(250, 170, 250);
camera.lookAt(0, 170, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('lightskyblue');
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const tree = [
[ 0, 0, 0], // A
[ 2, 151, 2], // B
[ -62, 283, 63], // C
[-104, 334, 74], // E
[ -58, 338, 45], // F
[ 62, 296, -58], // D
[ 67, 403, -55], // G
[ 105, 365, -86], // H
].map(v => new THREE.Vector3().fromArray(v));
// assumes there are 2 branches per
function addBranch(parent, depth, offset, tree, parentNdx = 0, childNdx = 1) {
const start = tree[parentNdx];
const end = tree[childNdx];
const length = start.distanceTo(end);
const material = new THREE.MeshPhongMaterial({color:'#ff0000'});
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
geometry.rotateX(Math.PI / 2);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z = offset;
parent.add(mesh);
mesh.lookAt(end);
let ndx = childNdx + 1;
if (depth > 1) {
const numBranches = 2;
for (let i = 0; i < numBranches; ++i) {
ndx = addBranch(mesh, depth - 1, length, tree, childNdx, ndx);
}
}
return ndx;
}
addBranch(scene, 3, 0, tree);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
// requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>
note: this only one of infinite ways to create the tree recursively. Rather than an array in depth first order you could also create a tree structure to pass into the algorithm
const E = {
pos: [-104, 334, 74],
};
const F = {
pos: [ -58, 338, 45],
};
const C = {
pos: [ -62, 283, 63],
children: [E, F],
};
const G = {
pos: [ 67, 403, -55],
};
const H = {
pos: [ 105, 365, -86],
};
const D = {
pos: [ 62, 296, -58],
children: [G, H],
};
const B = {
pos: [ 2, 151, 2],
children: [C, D],
};
const A = {
pos: [0, 0, 0],
children: [B],
};
function addBranch(parent, branch, offset = 0) {
const {pos, children} = branch;
const start = new THREE.Vector3().fromArray(pos);
for (const child of children) {
const end = new THREE.Vector3().fromArray(child.pos);
const length = start.distanceTo(end);
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
geometry.rotateX(Math.PI / 2);
const material = new THREE.MeshPhongMaterial({color: 'red'});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z = offset;
parent.add(mesh);
mesh.lookAt(end);
if (child.children) {
addBranch(mesh, child, length);
}
}
}
addBranch(scene, A);
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = 2; // the canvas default
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(250, 170, 250);
camera.lookAt(0, 170, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color('lightskyblue');
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const E = {
pos: [-104, 334, 74],
};
const F = {
pos: [ -58, 338, 45],
};
const C = {
pos: [ -62, 283, 63],
children: [E, F],
};
const G = {
pos: [ 67, 403, -55],
};
const H = {
pos: [ 105, 365, -86],
};
const D = {
pos: [ 62, 296, -58],
children: [G, H],
};
const B = {
pos: [ 2, 151, 2],
children: [C, D],
};
const A = {
pos: [0, 0, 0],
children: [B],
};
function addBranch(parent, branch, offset = 0) {
const {pos, children} = branch;
const start = new THREE.Vector3().fromArray(pos);
for (const child of children) {
const end = new THREE.Vector3().fromArray(child.pos);
const length = start.distanceTo(end);
const geometry = new THREE.CylinderGeometry(5, 5, length, 20, 1, false);
geometry.translate(0, length / 2, 0);
geometry.rotateX(Math.PI / 2);
const material = new THREE.MeshPhongMaterial({color: 'red'});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.z = offset;
parent.add(mesh);
mesh.lookAt(end);
if (child.children) {
addBranch(mesh, child, length);
}
}
}
addBranch(scene, A);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
// requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>

Xamarin.Forms: Putting A Label Inside A BarChart Layout

I am using oxyplot to plot a bar chart. I wish to add an extra label in the chart. I've tried to use Textannotation but it's not showing on the chart. What is the mistake I'm making to cause the text not to appear, is it the DataPoint? Please help.
plotModel = new PlotModel
{
Title = "Daily",
LegendPlacement = LegendPlacement.Outside,
LegendPosition = LegendPosition.BottomCenter,
LegendOrientation = LegendOrientation.Horizontal,
LegendBorderThickness = 0
};
TextAnnotation txtlabel = new TextAnnotation();
txtlabel.Text = "Test";
txtlabel.TextColor = OxyColors.Red;
txtlabel.Stroke = OxyColors.Red;
txtlabel.StrokeThickness = 5;
txtlabel.FontSize = 36;
txtlabel.TextPosition = new DataPoint(21, 3.5);
plotModel.Annotations.Add(txtlabel);
string sPrevType = "";
string sCurrentType = "";
DateTime dtdate;
var sr = new ColumnSeries();
var col = new ColumnItem();
int iCount = 0;
List<decimal> lstI = new List<decimal>();
List<decimal> lstD = new List<decimal>();
List<decimal> lstS = new List<decimal>();
foreach (var itm in _dateodr)
{
dtdate = itm.date;
sCurrentType = itm.Type;
lstI.Add(itm.I_Unit);
lstD.Add(itm.D_Unit);
lstS.Add(itm.S_Unit);
if (sCurrentType != sPrevType && sPrevType != "")
{
sr = new ColumnSeries();
sr.Title = sPrevType;
sr.LabelPlacement = LabelPlacement.Outside;
sr.StrokeColor = OxyColors.Black;
sr.StrokeThickness = 1;
//sr.LabelFormatString = "{0:#,##0.00}";
plotModel.Series.Add(sr);
}
sPrevType = sCurrentType;
iCount += 1;
}
if (iCount == _dateodr.Count)
{
sr = new ColumnSeries();
sr.Title = sPrevType;
sr.LabelPlacement = LabelPlacement.Outside;
sr.StrokeColor = OxyColors.Black;
sr.StrokeThickness = 1;
//sr.LabelFormatString = "{0:#,##0.00}";
sr.FontSize = 10;
plotModel.Series.Add(sr);
}
for (int i = 0; i < iCount; i++)
{
ColumnSeries ssr = (ColumnSeries)plotModel.Series[i];
var colIm = new ColumnItem();
colIitm.Value = double.Parse(lstI[i].ToString()) / 1000;
ssr.Items.Add(colIitm);
var colDOitm = new ColumnItem();
colDitm.Value = double.Parse(lstD[i].ToString()) / 1000;
ssr.Items.Add(colDitm);
var colSitm = new ColumnItem();
colSitm.Value = double.Parse(lstS[i].ToString()) / 1000;
ssr.Items.Add(colSitm);
}
categoryaxis.Labels.Add("I");
categoryaxis.Labels.Add("Dr");
categoryaxis.Labels.Add("Sr");
switch (sUnitType)
{
case "2":
valueAxis = new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0, Title = "m", Angle = 90, FontWeight = FontWeights.Bold, FontSize = 15 };
break;
case "qy":
valueAxis = new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0, Title = "Qy", Angle = 90, FontWeight = FontWeights.Bold, FontSize = 15 };
break;
case "Am":
valueAxis = new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0, Title = "Am", Angle = 90, FontWeight = FontWeights.Bold, FontSize = 15 };
break;
}
plotModel.Axes.Add(categoryaxis);
plotModel.Axes.Add(valueAxis);
}
PlotView plot = new PlotView
{
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.Fill,
BackgroundColor = Color.White,
Model = plotModel
};
Content = plot;

How to add additionalIcons to the tile in a Band

I am developing Microsoft Band2 Apps, I want to add Additional icons to my app tile in a band, like setting tile in Band2. I followed the below code to add Additional icons to the tile
Guid pageguid = Guid.NewGuid();
var panel = new ScrollFlowPanel
{
Rect = new PageRect(0, 0, 260, 128),
};
panel.Elements.Add(new FlowPanel
{
Rect = new PageRect(0, 0, 32, 32),
HorizontalAlignment = Microsoft.Band.Tiles.Pages.HorizontalAlignment.Center,
});
panel.Elements.Add(new Icon
{
HorizontalAlignment = Microsoft.Band.Tiles.Pages.HorizontalAlignment.Center,
Rect= new PageRect(0, 0, 32, 32),
ColorSource= ElementColorSource.BandHighlight,
});
var layout = new PageLayout(panel);
BandTile tile = new BandTile(tileGuid)
{
Name = "EmergencyHelp ",
TileIcon = await LoadIcon("ms-appx:///Assets/User that is member of security group.png"),
SmallIcon = await LoadIcon("ms-appx:///Assets/User that is member of security groupSmall.png"),
};
int firstIconIndex = tile.AdditionalIcons.Count + 2; // First 2 are used by the Tile itself
tile.AdditionalIcons.Add(await LoadIconMethod(AdjustUriMethod("ms-appx:///Assets/User that is member of security groupSmall.png")));
pageLayoutData.ById<IconData>(3).IconIndex = (ushort)(firstIconIndex + 0);
tile.PageLayouts.Add(layout);
if (tile.TileId != null)
{
await client.TileManager.RemoveTileAsync(tile.TileId);
}
await client.TileManager.AddTileAsync(tile);
await client.TileManager.SetPagesAsync(
tileGuid,
new PageData(pageguid, 0, new TextButtonData(1, "Emergency")));
I am getting the exception as shown in below figure,

Resources