Three js video with rounded corners

Hello.
Faced the task of making a video with rounded corners.
I tried to make 2 options.

Shape.
created a shape and added a video to it. But for some reason the video is not displayed as required. Apparently it is stretched.

https://jsfiddle.net/lighty1235/baeyv0km/8/

Clip.
created a plane and added a video to it.
But you also need to put a clipping (Shape) on this object.
No matter how I try to do it, it does not work.

https://jsfiddle.net/lighty1235/68cm7b2t/7/

1 Like

you could use css3d or html in general. with a video element. i had this usecase once: Mixing HTML and WebGL w/ occlusion - CodeSandbox not a video in this case but an interactive html view, and it has rounded corners with overflow: hidden, so that would work for sure. other than that, a clipping mask.

In the BeginnerExample of the Collection of examples from discourse.threejs.org I have a working video.
Different forms are possible.

<body>
 

<!-- // ======== to step 04 ======== - free video at Federico Maderno / Pixabay -->
<video id="video" loop crossOrigin="anonymous" playsinline style="display:none" >
<source src="[Robin - 21375.mp4](https://hofk.de/main/discourse.threejs/BeginnerExample/Robin%20-%2021375.mp4)" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>

</body>
// ... step 04:

...

// ----------------------------------------------------------------------------
			// https://threejs.org/docs/index.html#api/en/textures/VideoTexture  (see video tag in HTML body)
const videoTexture = new THREE.VideoTexture( video );
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
videoTexture.format = THREE.RGBFormat;
const videoGeometry = new THREE.CircleGeometry( 0.6, 72 ); 
const videoMaterial = new THREE.MeshBasicMaterial( { map: videoTexture , side: THREE.DoubleSide } );
const videoMesh = new THREE.Mesh( videoGeometry, videoMaterial );
videoMesh.scale.set( 1.5, 1, 0 );
videoMesh.rotation.y = -0.7; // radiant
videoMesh.position.set( 2.7, -0.3, -1.9 );
scene.add( videoMesh );						// note startVideo, stopVideo in function animate

BeginnerExample - Google Chrome 2021-07-31 19.48.4

this is the usual shape that a square that a circle is the same, the task is to make the desired shape using a vector.

I would code a rectangle with rounded corners as a self-defined geometry. Thereby you have to generate the uv-values as well.

that’s exactly what I did. But it doesn’t work as expected

new THREE.ShapeBufferGeometry( shape );
is not a geometry defined with attributes (position, uv).
I mean something like this, only much simpler
SphereWithoutTrigonometry

Dirty alternative :
Add normal rectangle plane matching video aspect
use same aspect html canvas to draw white color rounded rectangle
make a texture from the canvas and use it as opacity map on the rectangle plane

if we add a texture from the canvas, the shape of the rectangle itself does not change.

Yup that’s why its i said its an dirty alternative solution which gives the intended visual result .
Alpha test value can also help make the edges crisp.

if you want rounded geometry then try this

here a code block which will map the uv map to 0 to 1 range, use it on your shape geometry


var uvAttribute = geometry.attributes.uv;
		let min = Infinity, max = 0
		//find min max
		for (var i = 0; i < uvAttribute.count; i++) {
			let u = uvAttribute.getX(i);
			let v = uvAttribute.getY(i);
			min = Math.min(min, u, v)
			max = Math.max(max, u, v)
		}

		//map min map to 1 to 1 range
		for (var i = 0; i < uvAttribute.count; i++) {
			let u = uvAttribute.getX(i);
			let v = uvAttribute.getY(i);

			// do something with uv
			u = THREE.MathUtils.mapLinear(u, min, max, 0, 1)
			v = THREE.MathUtils.mapLinear(v, min, max, 0, 1)

			// write values back to attribute
			uvAttribute.setXY(i, u, v);

		}

your fiddle updated with this code https://jsfiddle.net/orion_prime/0v21ct8g/
make sure the shape aspect matches the video

1 Like

thanks it’s great!
I do not quite understand. Have we calculated the height and width of the shape here?

In the fiddle its set to 90 by 50 meters

let x = 1; let y = 1; let width = 90; let height = 50; let radius = 10;

the above width and height ratio needs to match the video aspect
and everything should look fine

Nce solution, I thought of a special geometry.

RoundedRectangle - Mozilla Firefox 2021-08-02 21.4

The uv’s still need to be edited - soon.

<!DOCTYPE html>
<!--https://discourse.threejs.org/t/three-js-video-with-rounded-corners/28543/10--> 
<head>
	<title> RoundedRectangle </title>
	<meta charset="utf-8" />
	<style>	
	body {  margin: 0; }
	</style>
</head>
<body>

</body>
 
 <script type="module">
 
// @author hofk
 
import * as THREE from "../jsm/three.module.130.js";
import { OrbitControls } from "../jsm/OrbitControls.130.js";

const scene = new THREE.Scene( );
const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.01, 10000 );
camera.position.set( 0, 6, 40 );
const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdedede, 1 );	
const container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );

let s = 12; // smoothness
const w = 16;
const h = 9;
const r = 2;

// helper const's
const wi = w / 2 - r;
const hi = h / 2 - r;
const w2 = w / 2;
const h2 = h / 2;
const ul = r / w;
const ur = ( w - r ) / w;
const vl = r / h;
const vh = ( h - r ) / h;

let positions = [

	-wi, -h2, 0,  wi, -h2, 0,  wi, h2, 0,
	-wi, -h2, 0,  wi,  h2, 0, -wi, h2, 0,	
	-w2, -hi, 0, -wi, -hi, 0, -wi, hi, 0,
	-w2, -hi, 0, -wi,  hi, 0, -w2, hi, 0,	
	 wi, -hi, 0,  w2, -hi, 0,  w2, hi, 0,
	 wi, -hi, 0,  w2,  hi, 0,  wi, hi, 0
	 
];
/*
let uvs = [
	
	ul,  0, ur,  0, ur,  1,
	ul,  0, ur,  1, ul,  1,
	 0, vl, ul, vl, ul, vh,
	 0, vl, ul, vh,  0, vh,
	ur, vl,  1, vl,  1, vh,
	ur, vl,  1, vh,	ur, vh 
	
];
*/
let phia = 0; 
let phib, xc, yc;

for ( let i = 0; i < s * 4; i ++ ) {
	
	xc = i < s || i >= 3 * s ? wi : - wi;
	yc = i < 2 * s ? hi : -hi;
	phib = Math.PI * 2 * ( i + 1 ) / ( 4 * s ); 
	positions.push( xc, yc, 0, xc + r * Math.cos( phia ), yc + r * Math.sin( phia ), 0,  xc + r * Math.cos( phib ), yc + r * Math.sin( phib ), 0 );
	phia = phib;
	
	// still without  uvs ... 
	
}

const material =  new THREE.MeshBasicMaterial( { color: 0xff0000 , side: THREE.DoubleSide, wireframe: true } );
const geometry = new THREE.BufferGeometry( );
geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), 3 ) );
//geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), 2 ) );
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
 
animate( );  

function animate( ) {
	
	requestAnimationFrame( animate );
	renderer.render( scene, camera );
		
} 
 
</script>

</html>
2 Likes

Soon is now.

The video on rounded rectangle.

RoundedRectangle Click to start video.

RoundedRectangleVideo - Mozilla Firefox 2021-08-03

4 Likes