A way to create a mask or clipping

Hello, i have an animation, a door that opens and the camera pass through, and goes to the next scene(room).I have also a plane that plays a video.The plane intesects the door, as you will see at the images.The problem is how i create a hole, in the door, so it passes thought and goes to the next room. O maybe a different way of organize the scene.

Picture one:


Picture Two (how the scene will be seen actually):


And here is my code:

<!DOCTYPE html>

	<meta charset=utf-8>
		body {
			margin: 0;

		canvas {
			width: 100%;
			height: 100%

	<script src="js/three.js"></script>

	<script src="js\OBJLoader.js"></script>
	<script src="js\JSONLoader.js"></script>
	<script src="js\MTLLoader.js"></script>
	<script src="js\ObjectLoader.js"></script>
	<script src="js\OrbitControls.js"></script>
	<script src="js\Box3.js"></script>
	<script src="js\BoxHelper.js"></script>
	<script src="js\CameraHelper.js"></script>

		var scene, camera, renderer, controls, cameraAnim, counter = 0,
			helperCamera, emptyCube,imageObject,planeHeightAtDistance,planeWidthAtDistance;

		var points = [];
		var CurveRes = 500;

		var clock = new THREE.Clock();
		var increment;

		var tangent = new THREE.Vector3();
		var axis = new THREE.Vector3();
		var up = new THREE.Vector3(0, 1, 0);

		var scrollCount = 1;

		var myObjs = {};

		function init() {

			scene = new THREE.Scene();

			camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
			camera.position.z = 8;
			camera.position.y = 1;

			cameraAnim = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
			helperCamera = new THREE.CameraHelper(cameraAnim);
			cameraAnim.position.z = 0;
			cameraAnim.position.y = 0;


			controls = new THREE.OrbitControls(camera);
			renderer = new THREE.WebGLRenderer();

			var video = document.createElement('video');
			var texture = new THREE.VideoTexture(video);
			texture.minFilter = THREE.LinearFilter;
			texture.magFilter = THREE.LinearFilter;
			texture.format = THREE.RGBFormat;
			texture.crossOrigin = 'anonymous';

			 imageObject = new THREE.Mesh(
				new THREE.PlaneGeometry(1, 1),
				new THREE.MeshBasicMaterial({
					map: texture
				}), );

			imageObject.position.y = 0
			imageObject.position.z = -1.5


			video.src = "./Assets/Test.mp4";

			var size = 10;
			var divisions = 10;
			var gridHelper = new THREE.GridHelper(size, divisions);

			var curve = new THREE.QuadraticBezierCurve3(
				new THREE.Vector3(0, 0, -10),
				new THREE.Vector3(0, 0, 5),
				new THREE.Vector3(0, 0, 5),
				new THREE.Vector3(0, 0, 10)

			points = curve.getPoints(CurveRes);
			var geometry = new THREE.Geometry().setFromPoints(points);
			var material = new THREE.LineBasicMaterial({
				color: 0xff0000
			var curveObject = new THREE.Line(geometry, material);
			for (i = 0; i < points.length; i++) {


			var material = new THREE.MeshBasicMaterial({
				color: 0x00ff00

			var ambientLight = new THREE.AmbientLight(0xcccccc, 0.8);
			ambientLight.position.y = -2;
			var pointLight = new THREE.PointLight(0xffffff, 1);
			pointLight.position.y = -2;

			var empty = new THREE.BoxGeometry(0.3, 0.3, 0.3);
			var materialEmpty = new THREE.MeshBasicMaterial({
				color: 0x00ff00
			emptyCube = new THREE.Mesh(empty, materialEmpty);


			function addObject(model, Matrix_x, Matrix_y, Matrix_z, pos_x, pos_y, pos_z) {
				var manager = new THREE.LoadingManager();

				manager.onStart = function() {

				manager.onLoad = function() {
					var box = new THREE.AxesHelper(5);
					myObjs[model].children[0].applyMatrix(new THREE.Matrix4().makeTranslation(Matrix_x, Matrix_y, Matrix_z));
					myObjs[model].position.set(pos_x, pos_y, pos_z);

				var mtlLoader = new THREE.MTLLoader(manager);
				var objLoader = new THREE.OBJLoader(manager);
				mtlLoader.load('Assets/' + model + '.mtl', function(materials) {
					objLoader.load('Assets/' + model + '.obj', function(object) {

						object.name = model;

						myObjs[model] = object;
						return object;


			addObject('window_R', -1, 0, 1.4, 1, 0, -1.4, 0);
			addObject('window_L', 1, 0, 1.4, -1, 0, -1.4);
			addObject('Fixed_window', 0, 0, 0, 0, 0, 0);


			camera.position.z = 10;

			renderer = new THREE.WebGLRenderer({
				antialias: true
			renderer.setSize(window.innerWidth, window.innerHeight);


			window.addEventListener('resize', onWindowResize, false);
			document.addEventListener('wheel', WheelControl, true);

		function moveCamera() {

			if (counter <= CurveRes) {

				for (i = 0; i < points.length; i++) {

					cameraAnim.position.copy(points[CurveRes - counter]);

				counter += 1;
			} else {
				counter = 0;


function videoResize(){
	var cameraZ = cameraAnim.position.z;
	var planeZ = imageObject.position.z;
	var distance = cameraZ - planeZ;
	var aspect = window.innerWidth / window.innerHeight;
	var vFov = camera.fov * Math.PI / 180;
	 planeHeightAtDistance = 2 * Math.tan(vFov / 2) * distance;
	 planeWidthAtDistance = planeHeightAtDistance * aspect;
	// console.log("planeWidthAtDistance: "+planeWidthAtDistance);
	// console.log("planeHeightAtDistance: "+planeHeightAtDistance);
	// console.log("planeZ: "+planeZ);
	// console.log("cameraZ: "+cameraZ);
	// console.log("aspect: "+aspect);
	console.log("distance: "+distance);
imageObject.scale.set( planeWidthAtDistance, planeHeightAtDistance, 1 );
	imageObject.scale.set( 0, 0, 1 )

		function windowOpen() {
			// maxRot_R=2
			// minRot_R=0
			// maxRot_L=-2
			// minRot_L=0

			var rotSpeed = 0.004;
			// console.log("Rotspeed" + rotSpeed);

			if (myObjs['window_R'] !== undefined) {
				if (myObjs['window_R'].rotation.y < 2) {
					myObjs['window_R'].rotation.y += rotSpeed;

				} else {
					myObjs['window_R'].rotation.y = 0
			if (myObjs['window_L'] !== undefined) {
				if (myObjs['window_R'].rotation.y < 2) {
					myObjs['window_L'].rotation.y -= rotSpeed;
				} else {
					myObjs['window_L'].rotation.y = 0

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			renderer.setSize(window.innerWidth, window.innerHeight);


		function WheelControl(e) {

			if (e.wheelDelta < 0 && scrollCount < 20) {
				scrollCount += 2;
			} else if (e.wheelDelta > 0 && scrollCount > -20) {
				scrollCount -= 2;

		function animate() {

			// cameraAnim.lookAt(emptyCube.position);


		function render() {

			renderer.render(scene, cameraAnim);




You can achieve this with a simple alpha map and the usage of Material.alphaTest.

Demo: https://jsfiddle.net/f2Lommf5/4703/

1 Like

I saw the fiddle and thanks for the answer, the planes texture is a video, so i have to use mov that supports alpha channel or dvx i think. The other problem is that the plane is bind with the fov of camera, the reason is to appear fullscreen and static as the camera moves, the plane gets smaller as the camera approaches.

The alpha map is an additional texture that can be combined with a video texture. Not sure about your camera stuff. I think you have to try if an alpha maps works in this use case…

In you fiddle tha alpha channel is in the texture.Can i create an other texture with a color as alpha and pass it to my video texture? The other way of doining it was to create a hole at the mesh and make it get large as the camera aproaches or if i can do it with texture tha could be perfect.

I’m not sure i understand you what you mean, sry. I was referring to this: Edit fiddle - JSFiddle - Code Playground

Ok thanks, i thought that the alpha channel was in the image that you passed as alpha mask. Is there any fuction that i can make the texture bigger or smaller?

You could scale the uv coordinates, but this will also affect the video texture. Another option is to modify the alpha map shader chunks and apply a custom scale value.

Ok i will check, is also possible to have two uv maps, one for each texture?

No, not for map and alphaMap. This is a current limitation of three.js.

Ok, you were very helpfull, i will try the alpha mask.

ok, i checked the alphamap, as i tested until now, it does not work.usually in a 3d program, if you have a uv on a plane and the texture image is bigger, it fills only the part that is covered from the uv.But i couldnt make it work.I found that you can create a second uv, with defining in the shader: attribute vec2 uv2 or create a buffer geometry.
Link here

Also this guy,transforms the alphap map, without accessing either the texture either the uvs
Link Here

The second set of uvs is intended for lightMap and aoMap. You can’t use them with alphaMap.

The animated alpha map is done via animating the value of Texture.offset. This is nothing else than a transformation of uv coordinates.

An alternate technique that I like to use to achieve a mask is to set a specific material on an object that will draw “nothing” on top of the other objects. It requires some specific settings on the renderer which might not fit your use case though.

Here is an example of it working:

The background of the canvas is set using CSS. The renderer has a fully transparent clear colour, and the material has ‘blending: 0’ in order to make it override the objects behind it.

It is similar with the solution i used, i used an object without casting shadows and receiving and is the same color with the background, it creates the mask effect.The problem are the objects behind the door, that they do not appear until, camera passes the door, also i cannot put anything else to background than a plain color.
Maybe i will create a fog or something else for the objects but i do not know for the background.
I would like to find a more legit solution, even if i had to mess with shaders.But i cannot find any solution that is easy to adapt.