Simple curved plane

Hi.

Discovering threejs since one month with an Oculus. Wow. WOW. Seem’s i found a really great toy for the rest of my addict dev life.

I already made some basic stuff successfully. I’m learning three, i dev vanillia js since a long time. I found a lot of answers in discourse, google, doc …

I’m using the dev branch of threejs (because i’d like to understand how gui.dat in vr mode is working without a raytracer :slight_smile: )

My question is :

how to draw a simple plane (or rectangle) curved, like a curved screen ? (the texture may be a canvas or a video or a webcam stream)

I found some code playing with vertices, but probably because of the three version i’m using,
planegeometry don’t provide vertices array attributes. I didn’t test with previous version. The texture part with video is ok, just wondering how can i curve this plane like a curved TV

Thank you !

https://threejs.org/examples/webgl_materials_video_webcam.html

I’m trying to curve the rectangles

Just use SphereGeometry, and play with the phiLength, thetaStart, and thetaLength parameters to get the curved sphere segment that you desire.

curved

https://threejs.org/docs/#api/en/geometries/SphereGeometry

2 Likes

Thank you @marguizzo

After playing with your suggestion, I’m definitively looking for another way, i.e planebuffergeometry with modified vertices or something like that.

@eviltik
Hi!
To bend/distort a plane is not that hard, having desired radius and limiting angles. :slight_smile:
What have you tried?

@prisoner849 thank you.

Got it

const geometry = new THREE.PlaneGeometry(16/10, 9/10, 16, 16);
const positions = geometry.attributes.position;

const axis = new THREE.Vector3(0, 1, 0);
const axisPosition = new THREE.Vector3(-2, 0, 2);
const vTemp = new THREE.Vector3(0, 0, 0);
let lengthOfArc;
let angleOfArc;

for (let i = 0; i < positions.count; i++){
	vTemp.fromBufferAttribute(positions, i);
	lengthOfArc = (vTemp.x - axisPosition.x);
  	angleOfArc = (lengthOfArc / axisPosition.z);
  	vTemp.setX(0).setZ(-axisPosition.z).applyAxisAngle(axis, -angleOfArc).add(axisPosition);
  	positions.setXYZ(i, vTemp.x, vTemp.y, vTemp.z);
}

It give the result i want. Need to fix initial position/rotation.

But lookat camera position give a bad result :frowning:

Any chance to provide an editable live code example, that demonstrates the issue? jsfiddle, codepen etc.

Hi @prisoner849

While i was preparing a minimal code for you, i’ve found the solution.

Here is the result:
https://threejs.innovastorm.com/curved-rectangle/

Source

Next step i’m working on: make a generic function planeCurve(plane, z)

I tried to make one :slight_smile:
Code:

function planeCurve(g, z){
	
  let p = g.parameters;
  let hw = p.width * 0.5;
  
  let a = new THREE.Vector2(-hw, 0);
  let b = new THREE.Vector2(0, z);
  let c = new THREE.Vector2(hw, 0);
  
  let ab = new THREE.Vector2().subVectors(a, b);
  let bc = new THREE.Vector2().subVectors(b, c);
  let ac = new THREE.Vector2().subVectors(a, c);
  
  let r = (ab.length() * bc.length() * ac.length()) / (2 * Math.abs(ab.cross(ac)));
  
  let center = new THREE.Vector2(0, z - r);
  let baseV = new THREE.Vector2().subVectors(a, center);
  let baseAngle = baseV.angle() - (Math.PI * 0.5);
  let arc = baseAngle * 2;
  
  let uv = g.attributes.uv;
  let pos = g.attributes.position;
  let mainV = new THREE.Vector2();
  for (let i = 0; i < uv.count; i++){
  	let uvRatio = 1 - uv.getX(i);
    let y = pos.getY(i);
    mainV.copy(c).rotateAround(center, (arc * uvRatio));
    pos.setXYZ(i, mainV.x, y, -mainV.y);
  }
  
  pos.needsUpdate = true;
  
}

Example: Edit fiddle - JSFiddle - Code Playground
Picture:

2 Likes

lol ! excellent !

I took your code and i’ve put a link on this page. Very interesting for learning purpose, thank you !

So. My next step is to project multiple curved rectangles aligned horizontaly but following a cylinder geometry, with 8 rectangles max per horizontal, 4 horizontal max, 32 participants max. Starting point here (sphere geometry, for learning) : Planes on Sphere

What’s your goal? Any explanatory picture?

No serious goal, pure experiences. Investigating/learning three, xr, oculus. The possibilities make me crazy. Challenging myself (math …)

Currently it’s seem’s that i’m about to code something like 3D UI, video conf room. Then, transform it into sandbox to play with immersive mode and keyboard/mouse behavior. No man’s sky demystification using threejs, sound nice !

Hey,
I’m using your planed curve code and it works pretty well! I have problems understanding the math though, would you be able to summarize what each section of the code does?
I did some research and found out the following (added comments to the sections):

function planeCurve(planeGeometry ,z){
    let p = planeGeometry.parameters;
    let hw = p.width * 0.5;
  
    //Here three points are defined, the left edge, right edge and the z bend in y direction.
    //These three points touch the circle with radius r at its border.
    let a = new THREE.Vector2(-hw,0); 
    let b = new THREE.Vector2(0,z);
    let c = new THREE.Vector2(hw,0);
  
    let ab = new THREE.Vector2().subVectors(a,b);
    let bc = new THREE.Vector2().subVectors(b,c);
    let ac = new THREE.Vector2().subVectors(a,c);
  
    //formula for finding a circle which contains all points on its edge.
    let r = (ab.length() * bc.length() * ac.length()) / (2 * Math.abs(ab.cross(ac)));

    //Calculation of the center of the circle. The center of the circle has to be at z - r, because r is the radius of the circle and b is positioned on the edge of the circle with (0,z)
    let center = new THREE.Vector2(0, z - r);
    //Generates a vector from the central point to the point to the left bottom.
    let baseV = new THREE.Vector2().subVectors(a, center);
    //And this is where i fail to get your code... Why these calculations?
    let baseAngle = baseV.angle() - (Math.PI * 0.5);
    let arc = baseAngle * 2;
  
    let uv = planeGeometry.attributes.uv;
    let pos = planeGeometry.attributes.position;
    let mainV = new THREE.Vector2();
    for(let i = 0; i < uv.count; i++){
      //Why the 1 - uv.getX(i)? I don't understand it.
      let uvRatio = 1 - uv.getX(i);
      let y = pos.getY(i);
      mainV.copy(c).rotateAround(center, (arc * uvRatio));
      pos.setXYZ(i, mainV.x, y, -mainV.y);
    }
  
    pos.needsUpdate = true;

    return planeGeometry;
  }

I created a geogebra link for this to represent it more visually for me: Calculator Suite - GeoGebra
But i don’t understand what the calculations or the angle in general do? The angle alpha is equivalent to your baseV in the code, whereas your angle beta is equivalent to arc. Would be glad for any explanations regarding this!

Hi @prisoner849, can I ask how can I implemented this in R3F ? I check it other way but I couldn’t apply it. I was imaging it was the same as in R3F.

I image it something like this but I couldn’t imagine it if it was to pass in the planeGeometry, and also I wanna use other random images like a scenery image in the map is that also possible?

here is the code.

const PlaneGeometryImage = () => {

    const plane = useMemo(() => {
        function planeCurve(
            g: { parameters: any; attributes: { uv: any; position: any; }; }, 
            z: number
        ){
        
            let p = g.parameters;
            let hw = p.width * 0.5;
            
            let a = new THREE.Vector2(-hw, 0);
            let b = new THREE.Vector2(0, z);
            let c = new THREE.Vector2(hw, 0);
            
            let ab = new THREE.Vector2().subVectors(a, b);
            let bc = new THREE.Vector2().subVectors(b, c);
            let ac = new THREE.Vector2().subVectors(a, c);
            
            let r = (ab.length() * bc.length() * ac.length()) / (2 * Math.abs(ab.cross(ac)));
            
            let center = new THREE.Vector2(0, z - r);
            let baseV = new THREE.Vector2().subVectors(a, center);
            let baseAngle = baseV.angle() - (Math.PI * 0.5);
            let arc = baseAngle * 2;
            
            let uv = g.attributes.uv;
            let pos = g.attributes.position;
            let mainV = new THREE.Vector2();
            for (let i = 0; i < uv.count; i++){
                let uvRatio = 1 - uv.getX(i);
                let y = pos.getY(i);
                mainV.copy(c).rotateAround(center, (arc * uvRatio));
                pos.setXYZ(i, mainV.x, y, -mainV.y);
            }
            
            pos.needsUpdate = true;
        }

        return planeCurve
    },[])

    return (<>
        <mesh>
            <planeGeometry 
                // how I will pass it here? 
                // and If it I will pass it here can how I add the 
                // image on it? 
            ></planeGeometry>
            <meshBasicMaterial  
                wireframe={true}
            />
        </mesh>
    </>)
}

I share with you a directly related r3f thread with detailed codesandbox examples: Discord

among CurvedPlane (forked) + video + independent curvature - CodeSandbox

1 Like

Hello! May I ask what the final effect is

Thanks for the post - very helpful. I also wanted a convex version and found that adding a negative z did not seem to do it with the @prisoner849 version. So what I did was added a few changes:

// at the top in the function
const negative = z<0;
z = Math.abs(z);

// down below in the function
pos.setXYZ(i, mainV.x, y, negative?mainV.y:-mainV.y);