0 Favourites

Drawing content from another canvas onto c2canvas

  • I'm trying to make a plugin to use three.js for 3D rendering with construct 2.

    Right now i have everything working so that i can render onto a separate canvas element on the page, and copy that content onto a texture construct can use.

    Because the way construct draws is pretty undocumented and i'm new to javascript i'm having difficulty understanding how i can efficiently pass the texture from the other canvas onto the "c2canvas" without significant slowdown.

    right now i'm using:

    this.webGL_texture = this.runtime.glwrap.loadTexture(MYCANVAS, true, this.runtime.linearSampling, this.texture_pixelformat); etc.

    and rendering webGL_texture using glw.quad(). All this stuff is currently working as intended but it's very slow to copy a screen sized image into memory every frame, and it's not a usable solution.

    The problem im having is that i don't know a more efficient way to do this. Using three.js i'm able to render to a texture as well, but the method of doing this produces an object defined by three.js that contains the texture which is also pretty undocumented, and i have no clue how to get this texture to a form construct can use.

    some information on how construct 2 handles webGL textures so i can interface the two systems might prove insightful, or perhaps a better way to transfer the contents of the other canvas to a texture for construct to render.

    Would i be better off just laying my three.js canvas below the c2canvas, and save the overhead of passing anything? Maybe i'm doing things right but something is going wrong somewhere? i've been looking at R0J0hound 's paster to see how he grabbed the content of sprites but it seems hes just calling their draw function.

    I'd be grateful for any insight as im just scratching my head with this right now.

  • I did about the same thing in my canvas plugin to get a webgl texture and had the same effect of being slow.

    If you look in the text object it uses a function from Glwrap that just copies the pixels from a canvas to a webgl texture instead of loading a new texture each time. I haven't used it yet but it should be a bit faster especially since it should give less for the gc to collect.

    That sounds interesting that three.js can render directly to a texture. As far as I'm aware c2 uses just a standard webgl texture handle. I'll try to investigate furthur when I get to my PC.

  • Nice! Looking forward to when you have it working!

  • 'loadTexture' is the wrong function to use! It will allocate a whole new texture every call which will kill performance and leak memory.

    Call glw.createEmptyTexture(w, h, linearsampling) to create an empty texture, and update its contents with glw.videoToTexture(canvas, texture). Despite the name it can also copy a canvas to a texture. This may still be a bottleneck; on some system's WebGL implementations it could do a slow CPU-readback-and-upload, but efficient implementations should be able to do a GPU copy. If it turns out it's still slow, consider just having a separate canvas underlay as you already considered.

    In canvas2d mode you should just be able to drawImage() the canvas directly.

  • ah thanks for all the help, that looks like exactly what I've been looking for, ill try it later!

    I'd also like to know if maybe i can directly pass a webgl texture handle somehow like r0j0 mentioned, because im sure three.js is using the same webGL calls for textures at some level. I'd be able to circumvent rendering it to a separate canvas completely if this were the case at least in webGL mode.

    EDIT:

    I tried using videototexture, seems to be working very well in chrome (slow in ie11 but what can you do). There might be a minor issue with the function as its copying the texture upside down(?). i just had to draw my quad inverted but seems like this is a bug.

  • QuaziGNRLnose

    Ok, I found where the webgl texture handle is in the __webglTexture attribute of WebGLRenderTarget.

    var rendertexture = new THREE.WebGLRenderTarget(100,100 );
    //texture to use with setTexture()
    rendertexture.__webglTexture[/code:2w4vnv08]
    
    The problem that I've found after that is the texture still won't work since by default textures aren't shared between different contexts.  But there is a way to share it:
    [url]http://www.khronos.org/webgl/wiki/SharedResouces[/url]
    
    From that page I found this tidbit of code that shows what needs to be done to share textures:
    [code:2w4vnv08]var gl1 = someCanvas.getContext('webgl');
    var sg1 = someCanvas.getExtension("WEBGL_shared_resources");
    var gl2 = someOtherCanvas.getContext('webgl', {
        shareGroup: gl1.shareGroup
    });
    var sg2 = someOtherCanvas.getExtension("WEBGL_shared_resources");
    var tex = gl1.createTexture();
    sg1.releaseSharedResource(tex);
    sg2.acquireSharedResource(tex, gl.READ_ONLY, function() {
       gl2.bindTexture(gl.TEXTURE_2D, tex);
    });[/code:2w4vnv08]
    
    I'm still working out the details for getting it working but a few points I have so far.
    1. The first context doesn't need to be created, we can get it from this.runtime.gl.
    2. For the second context it seems we have to create the canvas and context for WebGLRenderer first and then pass them as parameters like this: [code:2w4vnv08]var renderer = new WebGLRenderer({"canvas":mycanvas, "context":mycontext});[/code:2w4vnv08] The context creation can likely be copied basically from what threejs already does plus the shareGroup stuff.
    3. The bindtexture() function should be replaceable by the set Texture() function.
    
    I hope to have it more ironed out later.
    
    Edit:
    Well it seems that resource sharing isn't implemented as of yet...
    
    Edit2:
    After further testing the idea won't work.  I also tried making threejs use the same canvas and context as c2 but it's giving errors, probably due to conflicts in gl states from the two.  So Ashley's solution is probably the best you can get at the moment.
  • Yeah, I doubt you could get it to render directly to the same canvas, both C2 and Three.js will be constantly clobbering the WebGL state that each tries to set.

  • alright so for now ill use videototexture, and provide an option to just place the three.js canvas below the c2canvas since this is fastest if you have no reason to pass the texture to construct, and just want construct to render 2D stuff for a ui etc. Thanks for all the help guys!

  • I tried writing a set of plugins for three.js a year ago, but it became rapidely cumbersome.

    I tried two designs:

    1. everything in one plugin. But you have to handle references to every objects by tagging them... it was a pain. Also the ACE started to get very long

    2. one plugin per three.js type of object. So I had a renderer plugin, a camera plugin, geometry plugin, material plugin, light plugin, etc etc etc..

    In both case I wasn't really satisfied. But it worked:

    https://dl.dropboxusercontent.com/u/23551572/C2-Games/3DMaze/index.html made with the first design

    https://dl.dropboxusercontent.com/u/23551572/C2-Games/3DTest/index.html made with the second.

  • I'm leaning towards doing something similar to what you were doing with your first design.

  • Construct 3

    Buy Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Buy Now Construct 3 users don't see these ads
  • quazi - are you sure that's the better way? The second seems more in line with how C2 works. How does picking work if everything is in the same plugin? How could I do something like:

    If 3denemyobject variable 'mode' = "patrolling"

    If distance(3denemyobject.x, 3denemyobject.y, 3dplayerobject.x, 3dplayerobject.y) < 1000

    • set 3denemyobject.mode to "chasing"

    If 3denemyobject variable 'mode' = "chasing"

    • move 3denemyobject 50*dt pixels at angle: angle(3denemyobject.x, 3denemyobject.y, 3dplayerobject.x, 3dplayerobject.y)
  • It's more in line with how C2 works which makes it intrinsically not inline with how three.js works. It would introduce significant overhead to do it with objects outside of the plugin i'd think

  • Ergh, that's frustrating. Depending, though, I think it still might be worth it. C2's event system adds overhead to normal JavaScript as well, but it's still fast enough in most cases (on desktop especially). It might be too confusing for many users to have to adapt to whatever system three.js uses, but then again, I don't know how it works, so I guess it's hard for me to make an informed comment on the matter. I'm just concerned because I've tried normal programming before and it made no sense to me at all.

  • i plan to just have most of the functions/methods you would use with three.js implemented as actions, and some way of looping through all the three.js objects/materials, to select them/modify/create/destroy them. It's all just brainstorming right now cause to be honest i'm not entirely certain of what to do yet.

  • Are you going to load models, rigging's, bones, or scenes?

    Or is this Thumb Warz Two: Enter the Digits?

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)