stereocubes(12*1) is getting rendered as black screen using threejs + webVr - javascript

I am trying to render 12x1 stereocube image strip using Three.js and want it to view in VR. But instead black screen is getting rendered every time without any error in console. basically I am extracting 12 images from the single stereocube image file using the function get TexturesFromAtlasFile , forming 2 meshes and passing to the scene. I am using a cube geometry. I am new to webVr and ThreeJs, please help. Code snippet used is given below:-
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.js"></script>
<script src="https://threejs.org/examples/js/controls/VRControls.js"></script>
<script src="https://threejs.org/examples/js/effects/VREffect.js"></script>
<script>
//Setup three.js WebGL renderer
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Append the canvas element created by the renderer to document body element.
document.body.appendChild(renderer.domElement);
// Create a three.js scene.
var scene = new THREE.Scene();
// Create a three.js camera.
var camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 1000);
//camera.layers.enable( 1 );
// Apply VR headset positional data to camera.
var controls = new THREE.VRControls(camera);
// Apply VR stereo rendering to renderer.
var effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);
//create a sphere - we'll use the inner surface to project our Mars image on to it
var geometry = new THREE.CubeGeometry(100, 100, 100);
var textures = this.getTexturesFromAtlasFile("img/san_miguel_vr_Samsung.png", 12);
var materialArray = [];
for (var i = 0; i < 6; i++) {
materialArray.push(new THREE.MeshBasicMaterial({
map: textures[i]
}));
}
// create the mesh based on geometry and material
//var mesh = new THREE.Mesh(geometry, materialArray);
var skybox = new THREE.Mesh(geometry, materialArray);
//skybox.layers.set( 1 );
scene.add(skybox);
var materialsR = [];
for (var i = 6; i < 12; i++) {
materialsR.push(new THREE.MeshBasicMaterial({
map: textures[i]
}));
}
var skyBoxR = new THREE.Mesh(geometry, materialsR);
//skyBoxR.layers.set( 2 );
scene.add(skyBoxR);
// Create a VR manager helper to enter and exit VR mode.
var manager = new WebVRManager(renderer, effect, {
hideButton: false
});
function animate(timestamp) {
// Update VR headset position and apply to camera.
controls.update();
// Render the scene through the manager.
manager.render(scene, camera, timestamp);
requestAnimationFrame(animate);
}
// Kick off animation loop
animate();
function getTexturesFromAtlasFile(atlasImgUrl, tilesNum) {
var textures = [];
for (var i = 0; i < tilesNum; i++) {
textures[i] = new THREE.Texture();
}
var imageObj = new Image();
imageObj.onload = function() {
var canvas, context;
var tileWidth = imageObj.height;
for (var i = 0; i < textures.length; i++) {
canvas = document.createElement('canvas');
context = canvas.getContext('2d');
canvas.height = tileWidth;
canvas.width = tileWidth;
context.drawImage(imageObj, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth);
textures[i].image = canvas
textures[i].needsUpdate = true;
}
};
imageObj.src = atlasImgUrl;
return textures;
}
</script>

Related

How does three.js render video according to spherical UV?

I have a dash streaming video. According to its title, it is a 3*3. Now I can splice the complete video through the THREE,
// 3*3 PlaneGeometry
var geometry = new THREE.PlaneGeometry(400, 200, 3, 3);
const video1 = document.getElementById("videos1");
...................
...................
const texture1 = new THREE.VideoTexture(video3);
texture1.maxFilter = THREE.NearestFilter;
texture1.minFilter = THREE.NearestFilter;
...................
...................
var geometryfaces = geometry.faces;
for (let i = 0; i < geometryfaces.length; i++) {
const faces = geometryfaces[i];
materials[i] = new THREE.MeshBasicMaterial({
map: textures[i],
});
}
var uv = [
new THREE.Vector2(0, 0),
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 1),
new THREE.Vector2(1, 0),
];
// Set the texture coordinates
for (var m = 0; m < geometryfaces.length; m += 2) {
geometry.faces[m].materialIndex = faceId;
console.log(geometry.faces);
geometry.faces[m + 1].materialIndex = faceId;
geometry.faceVertexUvs[0][m] = [uv[2], uv[3], uv[1]];
geometry.faceVertexUvs[0][m + 1] = [uv[3], uv[0], uv[1]];
faceId++;
}
var bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);
var material = new THREE.MeshFaceMaterial(materials);
var mesh = new THREE.Mesh(bufferGeometry, material); //网格模型对象Mesh
This way I can get a full flat video, but this video is panoramic and I need to render it on the ball, and I don't know much about the UV of the ball。
I need help. Thank you
picture:enter image description here
picture2:enter image description here
Three.js SphereGeometry automatically creates the UV mapping for you. Since the image you're using is equirectangular, you can just map the image onto the inside of the sphere for the effect you want:
var camera, scene, renderer, vp, sphere;
vp = new THREE.Vector2(window.innerWidth, window.innerHeight);
// Init WebGL stuff
function init() {
// WebGL Renderer
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(vp.x, vp.y);
renderer.domElement.classList.add("canvasWebGL");
// append to DOM
document.body.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xe1e1e1);
// camera
camera = new THREE.PerspectiveCamera(55, vp.x / vp.y, 0.05, 100);
// Sphere radius is large enough to surround the camera
let sphereGeom = new THREE.SphereGeometry( 20, 128, 128 );
// Just use your equirect image as the texture
// And render the INSIDE of the sphere, not the outside
const tex = new THREE.TextureLoader().load("https://i.imgur.com/1VECsLy.jpg");
let sphereMat = new THREE.MeshBasicMaterial({
map: tex,
side: THREE.BackSide
});
sphere = new THREE.Mesh(sphereGeom, sphereMat);
scene.add(sphere);
}
function animate(s) {
sphere.rotation.set(
Math.cos(s / 3000), s / 3000, 0
);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
animate(0);
<script src="https://cdn.jsdelivr.net/npm/three#0.123/build/three.js"></script>
Read more about sphere geometry here: https://threejs.org/docs/?q=material#api/en/geometries/SphereGeometry

Change color of an svg dynamically and apply as texture in three.js

i´m trying to create a configurator with three.js but im at the point that i need to change the color of the product dinamycally, i though that i can use an svg as texture, change the fill property of the svg and update the texture easily, but im not having good results
at the moment what i have is
-A 3D model with an svg applied as texture with a TextureLoader, but the svg is placed in a external file ("images/texture.svg")(also three.js is reducing the size of the texture, but i think its a mapping problem)
-The svg is separated in layers, so i can manually change the color and apply it
But im trying to make it dynamic, you choose a color and it automatically updates the svg applied as texture
Any ideas?
Thanks!
I forked someone else's fiddle to show the solution. I added a click function which modifies the SVG and redraws the material on the model.
See http://jsfiddle.net/L4pepnj7/
Click anywhere on the example to change the color of the circle in the SVG.
The operation which converts the SVG to an encodedURI is to intensive to have in a constant loop, but you can put the color change in a click event while the renderer is doing it's own thing. I added a function called "clickBody" to the existing fiddle which changes the color of one of the SVG elements.
var mesh;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, 500 / 400, 0.1, 1000);
camera.position.z = 10;
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(500, 400);
document.body.appendChild(renderer.domElement);
var svg = document.getElementById("svgContainer").querySelector("svg");
var svgData = (new XMLSerializer()).serializeToString(svg);
var canvas = document.createElement("canvas");
var svgSize = svg.getBoundingClientRect();
canvas.width = svgSize.width;
canvas.height = svgSize.height;
var ctx = canvas.getContext("2d");
var img = document.createElement("img");
var material;
img.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))));
img.onload = function() {
ctx.drawImage(img, 0, 0);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
material = new THREE.MeshBasicMaterial({
map: texture
});
material.map.minFilter = THREE.LinearFilter;
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
};
var colors = ["red", "orange", "yellow", "green", "blue"];
var c = 0;
function clickBody() {
document.getElementById("test").setAttribute("fill", colors[c]);
var svgData = (new XMLSerializer()).serializeToString(svg);
img.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))));
img.onload = function() {
ctx.drawImage(img, 0, 0);
var texture = new THREE.Texture(canvas);
material.map = texture;
material.map.needsUpdate = true;
renderer.render(scene, camera);
}
c = c + 1;
if (c == colors.length) {
c = 0;
}
}
document.body.addEventListener("click", clickBody)
var render = function() {
requestAnimationFrame(render);
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();

Three.js render not showing a simple cube when I want to show simple mesh

I want to show a simple plane and a simple cube but the plane hides the cube, the cube is located between the camera and the plane, but the plane "hides" the cube.
This is my scene without plane:
and here it is with the plane added:
I am pretty sure they are in a location where the cube should to be showed.
Here is my code:
var scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(45,Window.innerWidth,window.innerHeight,0.1,1000),
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
var axes = new THREE.AxisHelper(20);
scene.add(axes);
var cubeGeometry = new THREE.CubeGeometry(4,4,4);
var cubeMaterial = new THREE.MeshBasicMaterial({color:0x777777});
var cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
//cube.castShadow = true;
cube.position.x = 0;
cube.position.y = 10;
cube.position.z = 5;
scene.add(cube);
var planeGeometry = new THREE.PlaneGeometry(60,20);
var planeMaterial = new THREE.MeshBasicMaterial({color: 0x55cc88});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
plane.rotation.x = -0.5*Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
//scene.add(plane);
//plane.receiveShadow = true;
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40,60,-10);
scene.add(spotLight);
//renderer.setClearColor(0xEEEEEE,1);
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.render(scene,camera);
$("#WebGl-salida").append(renderer.domElement);
Pay attention to names of objects and order and correctness of parameters in methods:
camera = new THREE.PerspectiveCamera(45,Window.innerWidth,window.innerHeight,0.1,1000)
should be like:
camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
jsfiddle example
Many thanks! Both for the answer and for the suggestion to edit the question to make it more understandable (my English has to improve) Now it is working perfectly.

i want to load a .obj file and change its texture/material at run-time by button click using three.js

each time i wants to load load my model and change its texture the model not loading, and there is nothing in the screen. i am a noob in three.js/webgl languages and javascript. please help me to proceed with right information.
here is the following code.
https://drive.google.com/open?id=0BxJJ7XpRqKz4S3JONlAwSHJxdFk this link provides the assets im using in this projects.
// once everything is loaded, we run our Three.js stuff.
function init() {
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;
// position and point the camera to the center of the scene
camera.position.x = 100;
camera.position.y = 40;
camera.position.z = 50;
camera.lookAt(scene.position);
scene.add(camera);
// add spotlight for the shadows
var spotLight = new THREE.DirectionalLight(0xfa93e5);
spotLight.position.set(30, 40, 50);
spotLight.intensity = 0.5;
scene.add(spotLight);
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
// call the render function
var step = 0;
// setup the control gui
var controls = new function () {
// we need the first child, since it's a multimaterial
};
var gui = new dat.GUI();
//model
var loader = new THREE.OBJLoader();
loader.load( 'sofa 1.obj', function (object) );
var sofa = new THREE.Mesh(object,fabric_1);
var texture = new THREE.ImageUtils.loadTexture("defaultMat_Base_Color(1).png");
var texture2 = new THREE.ImageUtils.loadTexture("defaultMat_Base_Color_1.png");
var material = THREE.ImageUtils.loadTexture("defaultMat_Normal_DirectX bump.png");
var material1 = THREE.ImageUtils.loadTexture("sofa new final4 high-AO_u0_v0.png");
var material2 = THREE.ImageUtils.loadTexture("lambert2SG_Roughness specular.png");
var fabric_1 = new THREE.MeshPhongMaterial(
{ fabric_1.map = texture;
fabric_1.normalMap = material;
fabric_1.aoMap = material1;
fabric_1.specularMap = material2; });
var fabric_2 = new THREE.MeshPhongMaterial(
{ fabric_2.map = texture_2;
fabric_2.normalMap = material;
fabric_2.aoMap = material1;
fabric_2.specularMap = material2;
});
scene.add(sofa),
function setfabric_1 () {
sofa.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = fabric_1;
}
sofa.geometry.uvsNeedUpdate = true;
sofa.needsupdate = true;
});
}
function setfabric_2 () {
sofa.traverse(function(child){
if(child instanceof THREE.Mesh){
child.material = fabric_2;
}
sofa.geometry.uvsNeedUpdate = true;
sofa.needsupdate = true;
});
}
render();
function render() {
stats.update();
if (mesh) {
mesh.rotation.y += 0.006;
;
}
// render using requestAnimationFrame
requestAnimationFrame(render);
webGLRenderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init;
Use uniforms to link local variables to the shader, make sure you preload the textures first though. threejs.org/uniforms. Better yet use
"uTexArray" : { type: "tv", value: [ new THREE.Texture(), new THREE.Texture() ] } // texture array (regular)
enter link description here

Three JS, WebGl, display sprite on top of panorama

I'm building a simple panorama webapp, where a user will be able to turn in circles and click on sprites in the loaded panorama. I have this working in CSS3D using three.js, now I need to get it to work in WebGL. I've loaded the panorama, and a sprite must be getting added to the scene since there are no errors, but I can't see the sprite.
How do I make it visible?
Here's the relevant code (omitting all the standard event functions and the rendering loop):
function init() {
var container, mesh;
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
camera.target = new THREE.Vector3(0, 0, 0);
scene = new THREE.Scene();
var sides = [
{
url: '/assets/posx.jpg'
},
{
url: '/assets/negx.jpg'
},
{
url: '/assets/posy.jpg'
},
{
url: '/assets/negy.jpg'
},
{
url: '/assets/posz.jpg'
},
{
url: '/assets/negz.jpg'
}
];
var k = 8
for (var i = 0; i < sides.length; i++) {
var side = sides[ i ];
var geometry = new THREE.SphereGeometry(5, k, k);
k += 8;
geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
var material = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture(side.url)
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
var map = THREE.ImageUtils.loadTexture("/assets/soap.png");
material = new THREE.SpriteMaterial({ map: map, color: 0xffffff, fog: false });
var sprite = new THREE.Sprite(material);
sprite.position.x = 128;
sprite.position.y = 128;
sprite.position.z = 128;
scene.add(sprite);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mousewheel', onDocumentMouseWheel, false);
document.addEventListener('touchstart', onDocumentTouchStart, false);
document.addEventListener('touchmove', onDocumentTouchMove, false);
window.addEventListener('resize', onWindowResize, false);
}
Any help appreciated!
If I'm not mistaken your sphere has a radius of 5 while your sprite is positioned way beyond the sphere at 128,128,128. You need to either increase your sphere radius or reduce your sprite position to something that lies within the radius.
var geometry = new THREE.SphereGeometry(256, k, k);

Categories