GithubHelp home page GithubHelp logo

ogl's Introduction

OGL

OGL

version license size

Minimal WebGL library.


See the Examples!

OGL is a small, effective WebGL library aimed at developers who like minimal layers of abstraction, and are interested in creating their own shaders.

Written in es6 modules with zero dependencies, the API shares many similarities with ThreeJS, however it is tightly coupled with WebGL and comes with much fewer features.

In its design, the library does the minimum abstraction necessary, so devs should still feel comfortable using it in conjunction with native WebGL commands.

Keeping the level of abstraction low helps to make the library easier to understand, extend, and also makes it more practical as a WebGL learning resource.

Install

Download

or

npm i ogl

or

yarn add ogl

Examples

Show me what you got! - Explore a comprehensive list of examples, with comments in the source code.

Inspired by the effectiveness of ThreeJS' examples, they will hopefully serve as reference for how to use the library, and to achieve a wide range of techniques.

Weight

Even though the source is modular, as a guide, below are the complete component download sizes.

Component Size (minzipped)
Core 8kb
Math 6kb
Extras 15kb
Total 29kb

With tree-shaking applied in a build step, one can expect the final size to be much lighter than the values above.

Usage

If installed amongst your project files, importing can be done from one single entry point.

import { ... } from './path/to/src/index.js';

Else if using a bundler or import maps with node modules, then import directly from the installed node module.

import { ... } from 'ogl';

By default, the ES source modules are loaded (src/index.js).

As another alternative, you could load from a CDN, using either the jsdelivr, unpkg or skypack services.

import { ... } from 'https://cdn.jsdelivr.net/npm/ogl';
import { ... } from 'https://unpkg.com/ogl';
import { ... } from 'https://cdn.skypack.dev/ogl';

If you take this route, I would highly recommend defining a specific version (append @x.x.x) to avoid code breaking, rather than fetching the latest version, as per the above links.

As a basic API example, below renders a spinning white cube.

import { Renderer, Camera, Transform, Box, Program, Mesh } from 'ogl';

{
    const renderer = new Renderer();
    const gl = renderer.gl;
    document.body.appendChild(gl.canvas);

    const camera = new Camera(gl);
    camera.position.z = 5;

    function resize() {
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.perspective({
            aspect: gl.canvas.width / gl.canvas.height,
        });
    }
    window.addEventListener('resize', resize, false);
    resize();

    const scene = new Transform();

    const geometry = new Box(gl);

    const program = new Program(gl, {
        vertex: /* glsl */ `
            attribute vec3 position;

            uniform mat4 modelViewMatrix;
            uniform mat4 projectionMatrix;

            void main() {
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `,
        fragment: /* glsl */ `
            void main() {
                gl_FragColor = vec4(1.0);
            }
        `,
    });

    const mesh = new Mesh(gl, { geometry, program });
    mesh.setParent(scene);

    requestAnimationFrame(update);
    function update(t) {
        requestAnimationFrame(update);

        mesh.rotation.y -= 0.04;
        mesh.rotation.x += 0.03;

        renderer.render({ scene, camera });
    }
}

Here you can play with the above template live in a codesandbox https://codesandbox.io/s/ogl-5i69p

For a simpler use, such as a full-screen shader, more of the core can be omitted as a scene graph (Transform) and projection matrices (Camera) are not necessary. We'll also show how to easily create custom geometry.

import { Renderer, Geometry, Program, Mesh } from 'ogl';

{
    const renderer = new Renderer({
        width: window.innerWidth,
        height: window.innerHeight,
    });
    const gl = renderer.gl;
    document.body.appendChild(gl.canvas);

    // Triangle that covers viewport, with UVs that still span 0 > 1 across viewport
    const geometry = new Geometry(gl, {
        position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
        uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
    });
    // Alternatively, you could use the Triangle class.

    const program = new Program(gl, {
        vertex: /* glsl */ `
            attribute vec2 uv;
            attribute vec2 position;

            varying vec2 vUv;

            void main() {
                vUv = uv;
                gl_Position = vec4(position, 0, 1);
            }
        `,
        fragment: /* glsl */ `
            precision highp float;

            uniform float uTime;

            varying vec2 vUv;

            void main() {
                gl_FragColor.rgb = vec3(0.8, 0.7, 1.0) + 0.3 * cos(vUv.xyx + uTime);
                gl_FragColor.a = 1.0;
            }
        `,
        uniforms: {
            uTime: { value: 0 },
        },
    });

    const mesh = new Mesh(gl, { geometry, program });

    requestAnimationFrame(update);
    function update(t) {
        requestAnimationFrame(update);

        program.uniforms.uTime.value = t * 0.001;

        // Don't need a camera if camera uniforms aren't required
        renderer.render({ scene: mesh });
    }
}

Structure

In an attempt to keep things light and modular, the library is split up into three components: Math, Core, and Extras.

The Math component is an extension of gl-matrix, providing instancable classes that extend Array for each of the module types. 8kb when gzipped, it has no dependencies and can be used separately.

The Core is made up of the following:

  • Geometry.js
  • Program.js
  • Renderer.js
  • Camera.js
  • Transform.js
  • Mesh.js
  • Texture.js
  • RenderTarget.js

Any additional layers of abstraction will be included as Extras, and not part of the core as to reduce bloat. These provide a wide breadth of functionality, ranging from simple to advanced.

Unlicense

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to https://unlicense.org

ogl's People

Contributors

akira-cn avatar andersonleite avatar ayamflow avatar codehz avatar codyjasonbennett avatar dekdevy avatar exponenta avatar farazzshaikh avatar gordonnl avatar jeremboo avatar jniac avatar joonas-yoon avatar lissandre avatar matiasngf avatar michaeldll avatar nam-hai avatar nikrowell avatar nshen avatar pschroen avatar pvdosev avatar rax7 avatar shampliu avatar terkelg avatar timvanscherpenzeel avatar valentinwalter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ogl's Issues

Example for mouse unprotect

Hi,
wanted to have understanding on unproject in camera, comment says it converts 2d point to 3d, but I tried to convert mouseX and mouseY to 3d space, but result is not correct, using it wrong ?

 // Unproject 2D point to 3D coordinate
    unproject(v) {
        v.applyMatrix4(tempMat4.inverse(this.projectionMatrix));
        v.applyMatrix4(this.worldMatrix);
        return this;
    }

my aim is to move stick mesh to mouse cords
thank you

Add VR support - exposing x and y for setViewport

Hi,
in order to render in specific viewport position x,y position needs to be exposed from ogl api, right now it have default 0,0.

This feature is necessary for VR rendering as each eye needs specific position

Canvas blur issue

Using this demo https://oframe.github.io/ogl/examples/?src=mouse-flowmap.html I have created a new example but I face some issues on the frontend.

The front end of the demo shows blurs SVG image in the canvas.

Javascript Code:

import {Geometry} from '../src/core/Geometry.js';
import {Program} from '../src/core/Program.js';
import {Renderer} from '../src/core/Renderer.js';
import {Camera} from '../src/core/Camera.js';
import {Transform} from '../src/core/Transform.js';
import {Mesh} from '../src/core/Mesh.js';
import {Texture} from '../src/core/Texture.js';
import {RenderTarget} from '../src/core/RenderTarget.js';
import {Vec2} from '../src/math/Vec2.js';
import {Vec4} from '../src/math/Vec4.js';
import {Flowmap} from '../src/extras/Flowmap.js';
import {Triangle} from '../src/extras/Triangle.js';


    
    const vertex = /* glsl */ `
        attribute vec2 uv;
        attribute vec2 position;

        varying vec2 vUv;

        void main() {
            vUv = uv;
            gl_Position = vec4(position, 0, 1);
        }
    `;

    const fragment = /* glsl */ `
        precision highp float;
                precision highp int;
                uniform sampler2D tWater;
                uniform sampler2D tFlow;
                uniform float uTime;
                varying vec2 vUv;
                uniform vec4 res;

        void main() {

                        // R and G values are velocity in the x and y direction
                        // B value is the velocity length
                        vec3 flow = texture2D(tFlow, vUv).rgb;
          vec2 uv = .5 * gl_FragCoord.xy / res.xy ;

          vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);
          myUV -= flow.xy * (0.15 * 0.5);
          vec3 tex = texture2D(tWater, myUV).rgb;

          gl_FragColor.rgb = vec3(tex.r, tex.g, tex.b);
          gl_FragColor.a = tex.r;
                }
    `;

    {
        const renderer = new Renderer({dpr: 2});
        const gl = renderer.gl;
        document.body.appendChild(gl.canvas);

        // Variable inputs to control flowmap
        let aspect = 1;
        const mouse = new Vec2(-1);
        const velocity = new Vec2();

        function resize() {
            renderer.setSize(window.innerWidth, window.innerHeight);
            aspect = window.innerWidth / window.innerHeight;
        }
        window.addEventListener('resize', resize, false);
        resize();

        const flowmap = new Flowmap(gl);

        // Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
        const geometry = new Triangle(gl);

        const texture = new Texture(gl, {wrapS: gl.REPEAT, wrapT: gl.REPEAT});

        const img = new Image();
        img.onload = () => texture.image = img;
        img.src = 'assets/Alienation-o.svg';

        const program = new Program(gl, {
            vertex,
            fragment,
            uniforms: {
                uTime: {value: 0},
                tWater: {value: texture},
                res: {
                    value: new Vec4(window.innerWidth, window.innerHeight, 1,1)
                  },
                // Note that the uniform is applied without using an object and value property
                // This is because the class alternates this texture between two render targets
                // and updates the value property after each render.
                tFlow: flowmap.uniform,
            }
        });

        const mesh = new Mesh(gl, {geometry, program});

        // Create handlers to get mouse position and velocity
        const isTouchCapable = 'ontouchstart' in window;
        if (isTouchCapable) {
            window.addEventListener('touchstart', updateMouse, false);
            window.addEventListener('touchmove', updateMouse, false);
        } else {
            window.addEventListener('mousemove', updateMouse, false);
        }

        let lastTime;
        const lastMouse = new Vec2();
        function updateMouse(e) {
            if (e.changedTouches && e.changedTouches.length) {
                e.x = e.changedTouches[0].pageX;
                e.y = e.changedTouches[0].pageY;
            }
            if (e.x === undefined) {
                e.x = e.pageX;
                e.y = e.pageY;
            }

            // Get mouse value in 0 to 1 range, with y flipped
            mouse.set(
                e.x / gl.renderer.width,
                1.0 - e.y / gl.renderer.height
            );

            // Calculate velocity
            if (!lastTime) {
                
                // First frame
                lastTime = performance.now();
                lastMouse.set(e.x, e.y);
            }
            
            const deltaX = e.x - lastMouse.x;
            const deltaY = e.y - lastMouse.y;
            
            lastMouse.set(e.x, e.y);
            
            let time = performance.now();
            
            // Avoid dividing by 0
            let delta = Math.max(14, time - lastTime);
            lastTime = time;

            velocity.x = deltaX / delta;
            velocity.y = deltaY / delta;

            // Flag update to prevent hanging velocity values when not moving
            velocity.needsUpdate = true;
        }

        requestAnimationFrame(update);
        function update(t) {
            requestAnimationFrame(update);

            // Reset velocity when mouse not moving
            if (!velocity.needsUpdate) {
                mouse.set(-1);
                velocity.set(0);
            }
            velocity.needsUpdate = false;

            // Update flowmap inputs
            flowmap.aspect = aspect;
            flowmap.mouse.copy(mouse);

            // Ease velocity input, slower when fading out
            flowmap.velocity.lerp(velocity, velocity.len ? 0.5 : 0.1);

            flowmap.update();

            program.uniforms.uTime.value = t * 0.001;

            renderer.render({scene: mesh});
        }
    }

Check the attached screenshot for more information.

Mouse Flowmap

undefined skeleton /w GLTF loader

Heya!

So I exported a skinned mesh from blender and noticed that my skeleton is undefined, resulting in an error that says it can't find the skeletons world matrix. Tested the rig in THREE's web editor and it appears to be working. Is there any settings that should be considered when exporting skinned meshes for use with OGL?

Screenshot (70)_LI

edit

Attaching a screen of my blender setup with my rigged mesh. If requested, I can send the blender project.

Screenshot (71)

gl.readPixels

Hi Nathan,

Sorry to bother you,

I want to get the results of my WebGL canvas to feed into some sound processing I am doing on the side, so I need to read the "imageData" buffer that WebGL produces.

The internet tells me the best way to do that is to use the function WebGLRenderingContext.readPixels()

Right after my renderer.render({scene, camera}); call, I try to execute this code:

            const width = gl.canvas.width;
            const height = gl.canvas.height;
            const pixelDataLength = width * height * 4;
            let pixelData = new Uint8Array(pixelDataLength);
            gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
            console.log(pixelData);

This is returning an array where only the A channel is always 255, the rest are all 0.

At the suggestion of several StackOverflow answers, adding preserveDrawingBuffer: true to the renderer attributes, yields nothing different. However, if I set alpha to true in the renderer, it will now return an array of all zeros.

Wonder what it could be?

Here is a working simplified version: https://codepen.io/arifd/pen/xxGOxaq

group of objects

Hi,
I discovered OGL recently. I like it a lot and I use it for my 3D experiments in that project :
https://github.com/gregja/oglXperiments

Maybe it exists yet in OGL, but I didn't find it in the examples : is it possible to create groups of objects ?

The group would be a virtual artefact, not a visible object, but the children of the group would inherit of parameters of the group, like position, scale and rotation. It would be helpful to create joints with specific rotation, applied to the children of the joint. I have an example with this sketch (inspired of an old processing sketch), where I would like to hide the cubes I used to attach the wings to the book :
http://ledefrichoir.com/labo/oglXperiments/ogl_flying_book.html

Thank's a lot for your attention,
Best regards

Video texture support

Hi,
trying to Redner video as texture and found out that its not possible to update texture right now as there are check if image is same it ignores update.

Cached textures bound to gl context that are invalid for different scenes

I've hit against an edge case where I am loading different scenes into my app, which sometimes use the same textures.
When loading the second scene it will pull the texture object from the cache but this is invalid as it was created for the gl context of the first scene.

As far as I can tell the gl context doesn't have a unique identifier that could be included in the cacheID

Ideally in my case I would use a TextureLoader.clearCache() method to manually reset the cache before loading a new scene to my app.
Happy to create a PR for it.

Color Object

Looking around your source and saw a TODO for color. I wrote this recently, thought it might give you something to work from if you want to support various formats from RGB and RGBA. Its crazy simple.

https://gist.github.com/sketchpunk/d710cd486cf9f9c6f9c8f212e38296b1

EDIT:

I took your color object and rewrote it for funs. I saved it to the same gist but as another file called color_webgl. I included the short hand form #fff since you where doing that. I also changed it to a Float32Array but you can always change it back to a regular array.

All the new forms you can use.
console.log( new Color() ); // Test Blank
console.log( new Color( 0xff00ff ) ); // Test Number form
console.log( new Color( 100, "200", 300 ) ); // Test RGB, String and Overflow
console.log( new Color( "#f50" ) ); // Test Short Hand Hex
console.log( new Color( "#ff00ff" ) ); // Test Hex
console.log( new Color( "red" ) ); // Test Color Names
console.log( new Color( "w00t" ) ); // Test Unknown Color name

jsdoc

Why ogl does not has JSDoc for type checking and intelisense?

I can do it, because i use TS and currently OGL unusable for me.

Transparency failed when enable depth test on polylines.

The transparent options take no effect sometimes when I use polyline.

import {Renderer, Camera, Transform, Program, Mesh, Plane, Polyline, Orbit, Vec3, Color} from '../src/index.mjs';

const vertex = /* glsl */ `
  precision highp float;
  precision highp int;

  attribute vec3 position;
  attribute vec3 normal;

  uniform mat3 normalMatrix;
  uniform mat4 modelViewMatrix;
  uniform mat4 projectionMatrix;

  void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;

const fragment = /* glsl */ `
  precision highp float;
  precision highp int;

  uniform vec3 uColor;

  void main() {
      gl_FragColor.rgb = uColor;
      gl_FragColor.a = 0.2;
  }
`;


  const polylineVertex = /* glsl */ `
    precision highp float;
    attribute vec3 position;
    attribute vec3 next;
    attribute vec3 prev;
    attribute vec2 uv;
    attribute float side;
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    uniform vec2 uResolution;
    uniform float uDPR;
    uniform float uThickness;
    uniform float uMiter;
    varying vec2 vUv;
    vec4 getPosition() {
        mat4 mvp = projectionMatrix * modelViewMatrix;
        vec4 current = mvp * vec4(position, 1);
        vec4 nextPos = mvp * vec4(next, 1);
        vec4 prevPos = mvp * vec4(prev, 1);
        vec2 aspect = vec2(uResolution.x / uResolution.y, 1);    
        vec2 currentScreen = current.xy / current.w * aspect;
        vec2 nextScreen = nextPos.xy / nextPos.w * aspect;
        vec2 prevScreen = prevPos.xy / prevPos.w * aspect;
    
        vec2 dir1 = normalize(currentScreen - prevScreen);
        vec2 dir2 = normalize(nextScreen - currentScreen);
        vec2 dir = normalize(dir1 + dir2);
    
        vec2 normal = vec2(-dir.y, dir.x);
        normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter);
        normal /= aspect;
        float pixelWidthRatio = 1.0 / (uResolution.y / uDPR);
        float pixelWidth = current.w * pixelWidthRatio;
        normal *= pixelWidth * uThickness;
        current.xy -= normal * side;

        return current;
    }
    void main() {
        vUv = uv;
        gl_Position = getPosition();
    }
`;

const polylineFragment = /* glsl */ `
    precision highp float;
    uniform vec3 uColor;
    
    varying vec2 vUv;
    void main() {
        gl_FragColor.rgb = uColor;
        gl_FragColor.a = 0.2;
    }
`;

const renderer = new Renderer({dpr: 2, alpha: true, premultipliedAlpha: true});
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
// gl.clearColor(1, 1, 1, 1);

const camera = new Camera(gl, {fov: 35});
camera.position.set(0, 0, 5);

// Create controls and pass parameters
const controls = new Orbit(camera, {
    target: new Vec3(0, 0, 0),
});

function resize() {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.perspective({aspect: gl.canvas.width / gl.canvas.height});
}
window.addEventListener('resize', resize, false);
resize();

const scene = new Transform();

const geometry = new Plane(gl);

const program = new Program(gl, {
    transparent: true,
    vertex,
    fragment,
    uniforms: {
      uColor: {value: new Color('#f00')},
    },
    // Don't cull faces so that plane is double sided - default is gl.BACK
    cullFace: null,
});

const p1 = new Mesh(gl, {geometry, program});
p1.setParent(scene);
p1.position.z = 0.1;

const polyline = new Polyline(gl, {
  // points: [
  //   new Vec3(0, 0.5, -0.1),
  //   new Vec3(0, -1.0, -0.1),
  // ],
  points: [
    new Vec3(0, 0.5, 0.5),
    new Vec3(0, -1.0, 0.5),
  ],
  uniforms: {
    uColor: {value: new Color('#00f')},
    uThickness: {value: 12},
  }
});


// polyline.program.transparent = true;
// polyline.mesh.setParent(scene);
const polylineProgram = new Program(gl, {
  // depthTest: false,
  transparent: true,
  vertex: polylineVertex,
  fragment: polylineFragment,
  uniforms: {
    uResolution: {value: polyline.program.uniforms.uResolution.value},
    uDPR: {value: polyline.program.uniforms.uDPR.value},
    uMiter: {value: polyline.program.uniforms.uMiter.value},
    uColor: {value: new Color('#00f')},
    uThickness: {value: 12},
  }
});

const mesh = new Mesh(gl, {geometry: polyline.mesh.geometry, program: polylineProgram});
mesh.setParent(scene);

requestAnimationFrame(update);
function update() {
    requestAnimationFrame(update);
    controls.update();
    renderer.render({scene, camera});
}

The output graph seems no transparency.

But if I change p1.position.z = 0.1; to p1.position.z = -0.1; or any negative value๏ผŒthe transparency will take effect again.

p1.position.z = -0.1

Any chance to get IE11 support back ?

Hi,
didn't found better place so will ask it here :)

Right now ogl code don't work on IE11 as some code can not be launched there, I think extend Array was one of it.

Is there plan to get back IE11 or it will be left out ?

Thank you

Consolidate options for geometry primitives?

More of an idea than an issue, and obviously an API breaking change, but would it make sense to consolidate the constructor args for primitives (Sphere, Cube, Plane) into a single options object to allow an optional third attributes object to be passed to the parent Geometry class?

Looks like you can achieve the same result by calling addAttribute on an instance, but this at least makes the api more concise and consistent. Thoughts?

const plane = new Plane(gl, {width: 5}, {
  color: {
    size: 3,
    data: new Float32Array(...)
  },
});

Set custom frame buffer before render

Hi,
I need to pass custom frame buffer for rendering, so tried to use bindFramebuffer on renderer, but this dont work as on each render bindFramebuffer is called without any params so it sets it to null,

what would be the best way to expose such functionality ?

difficulties to use OGL and Oimo together

Hi,
I need some help.
I would like to know if anyone has used OGL and Oimo.js together ?
Because I'm trying to implement, on OGL, a simplified version of this example :

http://lo-th.github.io/Oimo.js/examples/test_basic.html

The original example is written with Three.js. My intermediate version for OGL is visible here :

http://ledefrichoir.com/labo/oglXperiments/sources/ogl_oimo_basic.html

On my version, you will see the cubes cross the gray support instead of bouncing on it. I suppose I need to adjust the coordinates system to Oimo.js, but my different tests failed.

If someone has a trick to offer me, he will receive my eternal gratitude :).
Thank's

STATIC_DRAW

this.gl.bufferData(attr.target, attr.data, this.gl.STATIC_DRAW);

This line makes the assumption that the buffer is altered rarely. In my application, when I change a buffer often, this will break after a few frames. Setting it to DYNAMIC_DRAW fixes the issue.

The error that is thrown:
GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 3
Since changing the usage type fixes the issue for me, I am assuming that the reason lies therein. However, I am not 100% sure that this is the actual problem, so I cant speak with full certainty on this. It might after all be some other obscure bug.

Transparent textures?

Thanks for a great little framework.

I'm having problems getting transparent textures to work. I have tried these:

transparent: true on program
premultiplyAlpha: true on texture
premultipliedAlpha: true on the renderer.

Also tried these in the shader:

gl_FragColor = vec4(color.rgb * color.a, color.a);

And:

if (color.a < .5) {
  discard;
}

But can't seem to get it to work. Any tip?

bug on Transform

Hello,
I come back with my "flying box" (previously "flying book") because I met a bug with the Transform class.
I followed the proposition of @akira-cn to replace "new Box" by "new Transform", but the script crashes with this message :
TypeError: node.geometry.attributes is undefined (in Camera.js)

Maybe I made something wrong.
You can see the bug in live mode by using the option "jointDefault" with the value "Not visible" on this page :
http://ledefrichoir.com/labo/oglXperiments/ogl_flying_box.html
Thank's for you help.
Best regards
Greg

How to pass array of structs to glsl ?

Hi,
saw in code that there is case for passing array of structs to shader,
but could not find any example how to define such uniforms.

Missing something or its not documented yet ? :)

[Question] Run shadertoy shaders with ogl

Hi there
I am quite new to webgl so please apologize for any stupid question I might ask...

I am currently trying to run a shader from Shadertoy (https://www.shadertoy.com/view/4sdXDl) with ogl.
I thought I would just have to use the vertexShader and the fragmentShader, which are defined there and pass them with some uniforms into a new Program.

This is what I tried, but I would get this error

TypeError: this.uniformLocations is undefined

And following the stack trace I end up here:

this.uniformLocations.set(uniform, gl.getUniformLocation(this.program, uniform.name));

I first thought it was because I was not passing in every uniform, but even with defining all of them:

    // just taking random values ๐Ÿคทโ€โ™‚๏ธ
    const uniforms = {
      iGlobalTime: { value: 1.0 },
      iChannelTime: { value: 1.0 },
      iMouse: { value: new Vec4(1, 1, 1, 1)},
      iDate: { value: new Vec4(1, 1, 1, 1)},
      iSampleRate: { value: 1.0 },
      iChannelResolution: new Vec3(100, 100, 0),
      iFrame: { value: 1 },
      iTimeDelta: { value: 1.0 },
      iFrameRate: { value: 1.0 }
    }

I know the examples are nicely structured, but in comparison to an oldschool documentation I don't really know where to start looking.
Maybe you could point me into the right direction?
Huge thanks in advance. Cheers

Ah, and of course: my current standing:
https://github.com/Jones-S/sound-machine/blob/16e655534972127cb879bbddcc6d7498065e3e72/src/components/PulsingSphere/PulsingSphere.svelte

--- Edit:
And some of the code I got from this post:
https://stackoverflow.com/a/36994606/1121268
Where somebody wanted to run a shaderToy Shader in three js. That's where I copied the fragmentShader definition...

Safari Flowmap performance issue

It seems that on the latest version of Safari OSX the flowmap example which can be found here causes the overall machine performance to degrade to almost an unusable state, obviously a frame rate issue.

Is this a known issue with Safari?

glTF integration?

Hello, is anyone working on this? Or can point me to something I can use that works well with ogl? (great library btw! I stopped writing my own because yours is so well written!)

I have found this: https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/README.md

And this video at first glance, seems to go through the concepts pretty well: https://www.youtube.com/watch?v=cWo-sghCp8Y

I found this: https://github.com/wnayes/glTF-js-utils, but honestly, not really sure what it's trying to do, Okay it's for exporting glTF

This may really speed up the process: https://www.patreon.com/posts/28395927

Raycast & Orthographic Camera

Hi Gordon,

First, i do really love your framework. Readable, straight to the point. For learning GL it's perfect!

Not really an issue, but a request.
I like to use orthographic camera. But then raycasting is not working anymore.
Since your code is very clear, i managed to get it work with two modifications :

First, Raycast.js, where origin and direction must be set in an other way:

    castMouse(camera, mouse = [0, 0]) {
        if (camera.type === 'orthographic') {
            // Set origin
            // Since camera is orthographic, origin is not the camera position
            const {left, right, bottom, top} = camera;
            const x = left + (right - left) * (mouse[0] * .5 + .5);
            const y = bottom + (top - bottom) * (mouse[1] * .5 + .5);
            this.origin.set(x, y, 0);
            this.origin.applyMatrix4(camera.worldMatrix);

            // Set direction
            // https://community.khronos.org/t/get-direction-from-transformation-matrix-or-quat/65502/2
            this.direction.x = -camera.worldMatrix[8];
            this.direction.y = -camera.worldMatrix[9];
            this.direction.z = -camera.worldMatrix[10];
        } else {
            // Set origin
            camera.worldMatrix.getTranslation(this.origin);

            // Set direction
            this.direction.set(mouse[0], mouse[1], 0.5);
            camera.unproject(this.direction);
            this.direction.sub(this.origin).normalize();
        }
    }

Then, since i'm trying to get back {left, right, bottom, top} values from camera, we need to store it right? so in Camera.js:

    orthographic({
        near = this.near,
        far = this.far,
        left = -1,
        right = 1,
        bottom = -1,
        top = 1,
    } = {}) {
+       Object.assign(this, {left, right, bottom, top});
        this.projectionMatrix.fromOrthogonal({left, right, bottom, top, near, far});
        this.type = 'orthographic';
        return this;
    }

Would you me to make a PR ?

Also, since you've been writing helper function as Mat4Func/getTranslation I was wondering if it would be relevant to have some:

  • Mat4Func/getUp(out, mat)
  • Mat4Func/getDown(out, mat)
  • Mat4Func/getLeft(out, mat)
  • Mat4Func/getRight(out, mat)
  • Mat4Func/getBack(out, mat)
  • Mat4Func/getFront(out, mat)

As an example Unity is providing such values (ex forward) from the Transform class. Maybe ThreeJS too.

This will allow to write the Raycast.castMouse method in a clearer way :

if (camera.type === 'orthographic') {
    // Set origin
    ...

    // Set direction
    camera.worldMatrix.getFront(this.direction);
}

What do you think about it ?

Question on Orbit wheel event

Hi Nathan,

Love the library and working with it! I have a question about the Orbit controls.
I was wondering why is the wheel event directly connected to the window instead of the element provided in the function call when creating an orbit?
Orbit.js line 313 & 322

In the current implementation it triggers scrolling everywhere in the window even though the canvas might not be the full browser window size. In a local branch I changed it to attach the event listener the same element as the other events and it seems to work as I expected, where it only zooms when scrolling on the canvas and not on the other elements on the page.

Error when updating vec3 uniforms

Hello!

I'm getting the following error when trying to update a vec3 uniform:

setValue.set is not a function

I tried both those solutions to update the uniform's value and they both yield that same error

// First try, won't work
this.program.uniforms.uColor1.value = ogl.Color.hexToRGB(hex);

// Second try, won't work either
const color = ogl.Color.hexToRGB(hex);
this.program.uniforms.uColor1.value[0] = color[0];
this.program.uniforms.uColor1.value[1] = color[1];
this.program.uniforms.uColor1.value[2] = color[2];

This error is happening at this particular line: https://github.com/oframe/ogl/blob/master/src/core/Program.js#L224

Updating float type uniforms does not yield any error.

Is this a bug or I am missing something an this isn't the right way to update vec3 type uniforms?

Thanks!

TypeScript support

I'm submitting a ...

  • feature request

What is the current behavior?

ogl does not have TypeScript support.

What is the expected behavior?

I would love to see this project support TypeScript, either through source or a library definition file. TS support is very important for me (and I suspect a lot of other users) as it gives you so many guarantees and improved developer experience that plain JS cannot.

What is the motivation / use case for changing the behavior?

Without TS support, I'd either have to maintain my own library definition file, or allow imports from ogl to be automatically cast to any. Both of these solutions increase the surface area for potential bugs in my codebase.

TypeScript has risen in popularity over the last few years and, in my experience, is very commonly used to build web apps of medium->large complexity. Other popular WebGL libraries (like three and babylon.js) have support for TypeScript, and I think it would be a great addition to this library, too!

Other information

@endel addresses this PR in #23

this.projectionMatrix.fromPerspective is not a function

Hi Nathan,

I wanted to try the module on a site with browserify. I'm seeing some errors that don't show up on your demos. It seems that projectionMatrix from the Camera component is just an array instead of being a Mat4.

Screen Shot 2019-09-05 at 3 19 45 PM

Do you have any ideas why it wouldn't work on a build file? Also, I had to download the repository and load it in a folder of my site instead of node_modules.

On your demos, you import the files with relative paths:

import {Renderer, Camera, Transform, Program, Mesh} from './Core.js';
import {Box} from './Extras.js';

Could I do this using npm instead? Something like this...

import { Renderer, Camera, Transform, Program, Mesh, Box } from 'ogl';

Thank you, it's amazing work!

Struct array uniforms not setting value correctly

Hi @gordonnl - I noticed noticed uniforms using a struct array weren't setting the value correctly. I attempted to fix this in a pull request, but realized there were flaws in my implementation. Adding this as an issue for the sake of tracking. Thanks for your work this great framework!

precision highp float;
const int NUM_LIGHTS = 3;

struct Light {
  vec2 position;
  vec3 color;
};

uniform Light lights[NUM_LIGHTS];

void main() {
  vec3 color = vec3(0);
  for(int i = 0; i < NUM_LIGHTS; i++) {
    Light light = lights[i];
    // lighting stuff here
  }
  gl_FragColor = vec4(color, 1.0);
}

In Program.use()

// for struct arrays, get uniform value by key
// so 'lights[0].position' uses uniforms.lights[0].position
// Need a more bulletproof way to check for array uniforms?
// Is there a use case for supporting nested arrays?
const index = Number(/[\[](\d+)[\]]+/.exec(activeUniform.name)[1]);
const key = activeUniform.name.split('.').pop();
setUniform(this.gl, activeUniform.type, location, uniform.value[index][key]);

Triangle Raycasting

Hi Nathan,
Here is a draft: examples/raycasting-triangles.html

Please do not look at the code inside the html page, i've tried different options, copied & pasted some of your example, without cleaning anything... ok.

Here are the line that compute the triangle raycast. Not so much. I wrote it my style (no semicolon, leading blank line, no inline-if) because it's a draft, if there's a PR i will rewrite it in ogl actual style.

It's not exactly the same code than three.js which i do not really understand in the details, but we are trying to solve the same equation.

The one i use is O + k * D = A + ku * U + kv * V

image

For better performances, i prefer to dereference all the component (x, y, z) from the vector, and write directly dot and cross product rather than calling function (since calculations are not as dense as in the case of matrices). Generally speaking i do not think that seeking optimization in javascript is a primary goal, but here, since meshes can have thousands of triangles, i prefer to be careful.

If the code for raycast triangle seems ok, i still have bug with non-indexed geometry (sometimes hover produce flickering, triangles are not drawn under the mouse):
examples/raycasting-triangles.html?fox=true.

I do not have time yet to understand why. A first bug came from null triangle than can be provided in models, so i wrote a check first. For non-indexed geometries, every 3 vertices from the position attributes represent a triangle right?

Also, raycast may have some option (backface culling, distance max), actually i only return the closest triangles, but it may be useful to have all the triangles (in case of non-convex geometries). And also actually the test is made mesh by mesh, but may be done from any node (eg: scene) by walking through every child.

At last, is there actually a way to display debug lines / dot / vectors?
It could be useful to display pivot from any Transform, normal from raycast etc. What could be the best option to achieve that do you think?

Many questions. Not sure the current issue is really concerned. Should we move the discussion elsewhere?

Originally posted by @jniac in #38 (comment)

Geometry bugged when index buffer too large

When you create any geometry which makes use of index buffers and the resulting gl.drawElements call you will get skewed geometry rendering if the index buffer is referencing anything outside of the gl.UNSIGNED_SHORT range.

To reproduce this, create any geometry with a large vertice count.
This works:
const planeGeometry = new Plane(gl,1,1,200)
This is where it breaks:
const planeGeometry = new Plane(gl,1,1,256)

I assume this has to do with older WebGL limitations and is fixable, for reference:
https://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/

Vec2's cross product function not work

Two vec2's cross product will return a vec3

export function cross(out, a, b) {
    var z = a[0] * b[1] - a[1] * b[0];
    out[0] = out[1] = 0;
    out[2] = z;
    return out;
};

But cross function transfer a vec2 value now

cross(va, vb) {
    Vec2Func.cross(this, va, vb);//this => Vec2
    return this;
}

use OpenJSCad with OGL

Hi @gordonnl ,
I hope everyhing is OK for you (reference to coronavirus).
This is not an issue, just an information.
I made some experiments to use OpenJSCad (for modelization) with OGL (for rendering).
You can test it with that 2 options :

It's not perfect, because some shapes with extrusions are badly rendered, for the moment.
To improve the rendering on extrusions, I suppose I should take example on that ThreeJS wrapper :
https://joostn.github.io/OpenJsCad/src/threecsg.js
... but I'm not a specialist of WebGL (and of ThreeJS), so, probably it will take a long time :(

Take care,
Greg

PS : all source code of my experiments is here https://github.com/gregja/oglXperiments

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.