Change canvas rendering dynamically

Hello everybody !
I’m currently coding a small app which allows to create 2D shapes and display then in 3D.
The html code creates 1 button for 2D rendering and another one for 3D rendering.
In the p5.js file, I create a canvas in P2D mode at the beginning : the user can create 2D shapes.
When the user wants to display in 3D what he has created in 2D, he has to click on the 3D button.
I’d like to change the rendering mode of the canvas to WEBGL in order to display the created shapes in 3D.
In fact, I’d like to be able to switch from 2D to 3D and 3D to 2D changing dynamically the rendering mode.
I tried in many ways but it failed.
Someone can help me ?
Thanks in advance.

Hello!

What have you tried, and how is it failing? Can you show us an example?

Maybe it’s easier, or at least less work, to stick with the WebGL renderer? You could just change the camera perspective on button click.

1 Like

Hello Swen !
I’ve got two button in the html page : @D and 3D button.
In fact, on 3D button click, I remove the canvas (.remove()) and create another one with WEBGL rendering.
On 2D button click, I remove the canvas and create another one with P2D rendering.

When I go back to 2D, I’ve got a lot of error concerning WEBGL !
Example of error : WEBGL: you must load and set a font before drawing text. See loadFont and textFont for more details.
It’s an error that I should not have in P2D rendering mode. It’s linked to WEBGL rendering mode…

If you want a piece of code, I can extract it from my app…

Thanks .

1 Like

Find below an example…

In the file Index.html :

<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script language="javascript" type="text/javascript" src="libraries/p5.min.js"></script>
  <script language="javascript" type="text/javascript" src="test3d.js"></script>
  <style> body { padding: 0; margin: 0; } </style>
</head>

<body>
<div style="border: solid 1px rgb(0, 0, 0); padding:2px;">
  <button type="button" onclick="genHexagones2D();">2D</button>&nbsp&nbsp&nbsp
  <button type="button" onclick="genHexagones3D();">3D</button>&nbsp&nbsp&nbsp
</div>
<p id="mainCanvas"></p>
</body>
</html>

In the file test3d.js :

var pts = [];
var epHex = 40;
var angle = 10;
var renderMode = "2D";
const widthScreen=1000;
const heightScreen=600;
var cnv2D;
var cnv3D;

function setup() {
 pts[0] = createVector(388,249.96,0);
 pts[1] = createVector(368,215.32,0);
 pts[2] = createVector(328,215.32,0);
 pts[3] = createVector(308,249.96,0);
 pts[4] = createVector(328,284.60,0);
 pts[5] = createVector(368,284.60,0);
 genHexagones2D();
}

function genHexagones2D() {
 renderMode = "2D";
 if (cnv3D != undefined) {cnv3D.remove();}
 cnv2D = createCanvas(widthScreen, heightScreen, P2D);
 cnv2D.parent('mainCanvas');
 angleMode(DEGREES);
}

function genHexagones3D() {
 renderMode = "3D";
 cnv2D.remove();
 cnv3D = createCanvas(widthScreen, heightScreen, WEBGL);
 cnv3D.parent('mainCanvas');
 angleMode(RADIANS);
}

function draw() {
 background(220);

 if (renderMode == "3D") {
   translate(-width/2, -height/2);
   camera(-300,500,600,  400,0,300,  0,0,1) ;
   
   rotateX(radians(angle));
   rotateY(radians(angle*0.3));
   rotateZ(radians(angle*1.2));
 }
 
 // Top face
 fill(255);
 noStroke();
 beginShape();
 for (let i=0; i<6; i++) {
   vertex(pts[i].x, pts[i].y, pts[i].z);
 }
 endShape(CLOSE);
 
 if (renderMode == "3D") {
   // Back face
   fill(200);
   noStroke();
   beginShape();
   for (let i=0; i<6; i++) {
     vertex(pts[i].x, pts[i].y, pts[i].z+ epHex);
   }
   endShape(CLOSE);
   
   // Side face
   stroke(200);
   strokeWeight(2);
   for (let i=0; i<6; i++) {
     let j;
     if (i==5) {j=0;} else {j=i+1;}
     beginShape();
     line(pts[i].x, pts[i].y, pts[i].z,pts[j].x, pts[j].y, pts[j].z);
     line(pts[j].x, pts[j].y, pts[j].z,pts[j].x, pts[j].y, pts[j].z+ epHex);
     line(pts[j].x, pts[j].y, pts[j].z+epHex,pts[i].x, pts[i].y, pts[i].z+epHex);
     line(pts[i].x, pts[i].y, pts[i].z+epHex,pts[i].x, pts[i].y, pts[i].z);
     endShape(CLOSE);
   
     angle-=0.5;
   } 
 }
 if (renderMode == "2D") {
   // Display a grid
   for (let j=0; j<widthScreen; j+=50){
     textSize(10);stroke(255,0,0);strokeWeight(1);text(j,j, 10);
     for (let t=0; t<heightScreen; t+=50) {        
       if (j == 0) {textSize(10);stroke(0,0,255);strokeWeight(1);text(t,0, t);}
       stroke(20); strokeWeight(1); point(j,t);
     }
   }
   
 }
}

Switch 2D to 3D, then 3D to 2D, you will see errors concerning WEBGL (F12 to see errors)…

1 Like

Yeah, as I wrote before, you’re setting yourself up for a lot of trouble. Take it from the official documentation:

This method should be called only once at the start of setup. Calling createCanvas more than once in a sketch will result in very unpredictable behavior.

I would go with changing the camera perspective. If you don’t like that approach, maybe instance mode could be the solution to your problem? With instance mode, you can have multiple sketches on one webpage, each with is own canvas. You can stack two canvasses on top of each other and control which one is showing with the buttons.

1 Like

Ok I understand…
I will try the two approches…
Many thanks for your answer ! I appreciate.
Patrick.

1 Like

Keep me posted, I would love to see how it turns out. :slight_smile: Good luck!