I have problem masking image in cocos2d-js. Using this code i have successfully masked image and added this to Scene but after switching back to previous scene where i have written this code in previous scene, error comes.
// Create a mask
var maskSprite = new cc.Sprite(spriteFrameCache.getSpriteFrame("mask.png"));
// maskSprite.setBlendFunc(cc.ONE, cc.ZERO);
maskSprite.setPosition(maskSprite.width / 2, maskSprite.height / 2);
var puzzleImage = new cc.Sprite(spriteFrameCache.getSpriteFrame("puzzle.png"));
puzzleImage.setBlendFunc(cc.DST_ALPHA, cc.ONE_MINUS_DST_ALPHA);
puzzleImage.setPosition(maskSprite.width / 2, maskSprite.height / 2);
var cs = maskSprite.getBoundingBox();
var rendererTexture = new cc.RenderTexture(cs.width, cs.height);
rendererTexture.beginWithClear(0, 0, 0, 0);
// rendererTexture.begin();
maskSprite.visit();
puzzleImage.visit();
rendererTexture.end();
var rtSprite = new cc.Sprite();
rtSprite.initWithTexture(rendererTexture.getSprite().getTexture());
rtSprite.getTexture().setAntiAliasTexParameters();
rtSprite.flippedY = true;
rtSprite.setPosition(500,450);
this.addChild( rtSprite,20);
I am getting correct result once i added this in scene but switching scene back and forth its creating bug.
Something Like - RendererWebGL.js:314 Uncaught TypeError: Cannot read property 'indexOf' of undefined
To reproduce this problem add this code to your main scene.
Now change your scene to any other scene and again come back to previous scene.
Please help me...
Related
I'm trying to get the basic ThreeJS Water2 example setup that you can find here: https://threejs.org/examples/?q=water#webgl_water
Source code here: https://github.com/mrdoob/three.js/blob/master/examples/webgl_water.html
The process seems so straightforward it hurts that it's not working: Supply the geometry of a plane to the constructor, supply parameters, and then add that object to the scene. You can see an example of this on line 86 of the examples' source above.
Here's my attempt at doing it inside an Aframe component:
init() {
let mesh;
let waterObj;
this.el.object3D.traverse(obj => {
if (obj.type == "Mesh") {
mesh = obj;
}
});
waterObj = new Water(mesh, {
scale: 4,
flowDirection: new THREE.Vector2(1, 1),
textureWidth: 1024,
textureHeight: 1024
});
this.el.object3D.attach(waterObj);
}
});
but it doesn't seem to work. If I use object3D.attach() it produces an error that says sphere is undefined (no idea what "sphere," is), and if I use object3D = waterObj then the color of the plane slightly changes, but nothing else.
Does anyone have experience with getting this setup?
It should be working as long as you provide the geometry in the constructor, not the mesh:
waterObj = new Water(mesh.geometry, {
scale: 4,
flowDirection: new THREE.Vector2(1, 1),
textureWidth: 1024,
textureHeight: 1024
});
Also keep in mind that attach won't apply the parent transform to the waterObj, so the plane might appear at (0,0,0).
Other than that - it should be working - check out
this a-frame + THREE.Water example
I'm creating an ExtrudeGeometry of a hexagon shape and trying to set a different material for the front side and back side, as it is stated in this thread.
let shape = new THREE.Shape();
/*...*/
let geometry = new THREE.ExtrudeGeometry(shape, {
steps: 2,
amount: 0.05,
bevelEnabled: false,
material: 0, //frontMaterial = green
extrudeMaterial: 1 //sideMaterial = gray
});
//Searching for the back side and setting the marialIndex accordingly
for (let face of geometry.faces) {
if (face.normal.z == 1) {
face.materialIndex = 2; //backMaterial = red
}
}
let mesh = new THREE.Mesh(geometry, new THREE.MultiMaterial([frontMaterial, sideMaterial, backMaterial]));
The problem now is, that this method (iterating over the faces and looking for those with normal.z == 1) does not work correctly with a extrudeGeometry.amount = 0.05. A value of 0.1 works fine.
See this jsfiddle
Is there another method for setting a different material for front and back side or am I doing it just wrong?
Thanks for your help!
The problem is due to rounding. Do this, instead
if ( face.normal.z < - 0.99999 ) { // instead of == - 1
face.materialIndex = 2;
}
Also, the back face normal is in theory (0, 0, - 1 ).
updated fiddle: https://jsfiddle.net/xhbu2e01/3/
three.js r.84
All I want to do is load an OBJ file and translate its coordinates to the world origins (0,0,0) so that orbit controls work perfectly (no Pivot points please).
I'd like to load random OBJ objects with different geometries/center points and have them translated automatically to the scene origin. In other words, a 'hard coded' translate solution for a specific model won't work
This has got to be one of the most common scenarios for Three JS (basic 3d object viewer), so I'm surprised I can't find a definitive solution on SO.
Unfortunately there are a lot of older answers with deprecated functions, so I would really appreciate a new answer even if there are similar solutions out there.
Things I've tried
the code below fits the object nicely to the camera, but doesn't solve the translation/orbiting problem.
// fit camera to object
var bBox = new THREE.Box3().setFromObject(scene);
var height = bBox.size().y;
var dist = height / (2 * Math.tan(camera.fov * Math.PI / 360));
var pos = scene.position;
// fudge factor so the object doesn't take up the whole view
camera.position.set(pos.x, pos.y, dist * 0.5);
camera.lookAt(pos);
Apparently the geometry.center() is good for translating an object's coordinates back to the origin, but the THREE.GeometryUtils.center has been replaced by geometry.center() and I keep getting errors when trying to use it.
when loading OBJs, geometry has now been replaced by bufferGeometry. I can't seem to cast the buffergeometry into geometry in order to use the center() function. do I have to place this in the object traverse > child loop like so? this seems unnecessarily complicated.
geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
My code is just a very simple OBJLoader.
var objLoader = new THREE.OBJLoader();
objLoader.setPath('assets/');
objLoader.load('BasketballNet_Skull.obj', function (object) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
scene.add(object);
});
(BTW first real question on SO so forgive any formatting / noob issues)
Why not object.geometry.center()?
var objLoader = new THREE.OBJLoader();
objLoader.setPath('assets/');
objLoader.load('BasketballNet_Skull.obj', function (object) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
child.geometry.center();
}
} );
scene.add(object);
OK figured this out, using some very useful functions from Meshviewer Master, an older Three JS object viewer.
https://github.com/ideesculture/meshviewer
All credit to Gautier Michelin for this code
https://github.com/gautiermichelin
After loading the OBJ, you need to do 3 things:
1. Create a Bounding Box based on the OBJ
boundingbox = new THREE.BoundingBoxHelper(object, 0xff0000);
boundingbox.update();
sceneRadiusForCamera = Math.max(
boundingbox.box.max.y - boundingbox.box.min.y,
boundingbox.box.max.z - boundingbox.box.min.z,
boundingbox.box.max.x - boundingbox.box.min.x
)/2 * (1 + Math.sqrt(5)) ; // golden number to beautify display
2. Setup the Camera based on this bounding box / scene radius
function showFront() {
if (objectCopy !== undefined) objectCopy.rotation.z = 0;
controls.reset();
camera.position.z = 0;
camera.position.y = 0;
camera.position.x = sceneRadiusForCamera;
camera.lookAt(scene.position);
}
(the mesh viewer code also contains functions for viewing left, top, etc)
3. Reposition the OBJ to the scene origin
Like any centering exercise, the position is then the width and height divided by 2
function resetObjectPosition(){
boundingbox.update();
size.x = boundingbox.box.max.x - boundingbox.box.min.x;
size.y = boundingbox.box.max.y - boundingbox.box.min.y;
size.z = boundingbox.box.max.z - boundingbox.box.min.z;
// Repositioning object
objectCopy.position.x = -boundingbox.box.min.x - size.x/2;
objectCopy.position.y = -boundingbox.box.min.y - size.y/2;
objectCopy.position.z = -boundingbox.box.min.z - size.z/2;
boundingbox.update();
if (objectCopy !== undefined) objectCopy.rotation.z = 0;
}
From my understanding of your question, you want the objects that are added to the scene in the origin of the camera view. I believe the common way of achieving an object viewer solution is adding camera controls to your camera in the scene mostly THREE.OrbitControls and specifying the target for the camera as the object that you want to focus on. This makes the object focused to be in the center and the camera rotation and movement will be based on that object.
The problem:
In the awesome Three.js, I can't figure out how to convert an EllipseCurve into a path that I can extrude along.
In the example below, if I uncomment the LineCurve3, my square extrudes along it nicely. If I run it as the EllipseCurve, there are no errors but nothing shows on screen. I have tried zooming the camera right out to make sure it's not off the screen for any reason.
I know the EllipseCurve is being generated correctly as I can write it out with a line material (not shown in the code below).
The code
var radius = 1100;
var degreesStart = 75;
var degreesEnd = 30;
var radiansStart = (degreesStart * Math.PI) / 180;
var radiansEnd = ((degreesEnd) * Math.PI) / 180;
// this won't seem to work as an extrude path, but doesn't give any errors
var path = new THREE.EllipseCurve(0, 0, radius, radius, radiansStart, radiansEnd, true);
// this works fine as an extrude path
//var path = new THREE.LineCurve3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(1000, 1000, 0));
var extrusionSettings = { steps: 100, bevelEnabled: false, extrudePath: path };
// draw a square to extrude along the path
var sectionSize = [];
sectionSize.push(new THREE.Vector2(0, 0));
sectionSize.push(new THREE.Vector2(1000, 0));
sectionSize.push(new THREE.Vector2(1000, 1000));
sectionSize.push(new THREE.Vector2(0, 1000));
var sectionShape = new THREE.Shape(sectionSize);
var componentGeometry = new THREE.ExtrudeGeometry(sectionShape, extrusionSettings);
var component = new THREE.Mesh(componentGeometry, material);
group.add(component);
What I have tried:
My attempts to make it work have all tried to extract the points from the curve into a path to use in the extrusion. The closest I felt I got was
var ellipsePath = new THREE.CurvePath(path.getSpacedPoints(20));
// where 'path' is my EllipseCurve in the code above
// (and then changed the extrusion settings to use 'ellipsePath ' instead).
This gave the error "Cannot read property 'distanceTo' of null".
I can't seem to get my head around how the EllipseCurve relates to points that relate to a path.
Can anyone point me in the right direction please, or have code where you've come across the same problem? Many thanks.
I ran into the same problem. After experimenting with EllipseCurve and CurvePath, I concluded that these two are building 2D paths which lead to problems inside ExtrudeGeometry. Examining the source of three.js and the example extrusion based on a 3D spline, I built my own Curve and defined a 3D .getPoint function. This solved the problem and rendered a perfect extrusion. Replace the "var path" line of your code with the following:
var path = new THREE.Curve();
path.getPoint = function (t) {
// trace the arc as t ranges from 0 to 1
var segment = (radiansStart - radiansEnd) * t;
return new THREE.Vector3(radius * Math.cos(segment), radius * Math.sin(segment), 0);
};
Inspired by #james-dunn’s solution, I implemented a Path3D class that’s the same as a regular THREE.Path except that getPoint() returns a Vector3 with z = 0:
class Path3D extends THREE.Path {
constructor(pts) {
super(pts);
}
getPoint(t) {
const pt2d = super.getPoint(t);
const pt3d = new THREE.Vector3(pt2d.x, pt2d.y, 0);
return pt3d;
}
}
Given the lens flares example: http://threejs.org/examples/#webgl_lensflares,
Why am I not able to post process this scene correctly? The blocks will all show up correctly but the light sources and the lens flares are gone and I get a bunch of warnings in the console stating: copyTexImage2D: framebuffer is incompatible format. I have all the same code except for the following snippets added to the init() and render() loop:
// init()
//
// Post Processing (
//
var rtParameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat,
stencilBuffer: true
};
// Vignette scene.
var shaderVignette = THREE.VignetteShader;
var effectVignette = new THREE.ShaderPass(shaderVignette);
effectVignette.uniforms[ "offset" ].value = 0.95;
effectVignette.uniforms[ "darkness" ].value = 1.6;
// What are these??
var clearMask = new THREE.ClearMaskPass();
var renderMask = new THREE.MaskPass(scene, camera);
effectVignette.renderToScreen = true;
// Render entire scene as a texture.
var renderModel = new THREE.RenderPass(scene, camera);
// renderModel.clear = false;
// Notice: Takes *entire* canvas.
composerScene = new THREE.EffectComposer(renderer,
new THREE.WebGLRenderTarget(width, height, rtParameters));
composerScene.addPass(renderModel);
composerScene.addPass(clearMask);
// Not sure what this does... renderTarget2 is the buffer we read from...
renderScene = new THREE.TexturePass(composerScene.renderTarget2);
// Add first composer -- don't add any passes except for renderScene.
composer1 = new THREE.EffectComposer(renderer,
new THREE.WebGLRenderTarget(width / 2, height, rtParameters));
composer1.addPass(renderScene);
composer1.addPass(effectVignette);
// Add second composer -- do image processing passes here.
composer2 = new THREE.EffectComposer(renderer,
new THREE.WebGLRenderTarget(width / 2, height, rtParameters));
composer2.addPass(renderScene);
composer2.addPass(effectVignette);
renderScene.uniforms[ "tDiffuse" ].value = composerScene.renderTarget2;
Then within in my render loop, I have the following:
//render()
// Set view port to entire region
renderer.setViewport(0, 0, width, height);
renderer.clear();
composerScene.render(delta);
// Render original scene.
renderer.setViewport(0, 0, width / 2, height);
composer1.render(delta);
// Render modified scene.
renderer.setViewport(width / 2, 0, width / 2, height);
composer2.render(delta);
Found the problem. It was in this line:
// Notice: Takes *entire* canvas.
composerScene = new THREE.EffectComposer(renderer,
new THREE.WebGLRenderTarget(width, height, rtParameters));
Since I have dividing the scene into two different sections, width should be width/2. So the corrected code is:
// Notice: Takes only the size of the image we want to render.
composerScene = new THREE.EffectComposer(renderer,
new THREE.WebGLRenderTarget(width/2, height, rtParameters));
Please note: This had nothing to do with lens flares. The issue was much more fundamental. Sorry about that!!