Looking for a WebGL example

SchnauzerDad
Posts: 8
Joined: Fri Jun 17, 2016 6:27 am

Looking for a WebGL example

Postby SchnauzerDad » Mon Dec 26, 2016 5:19 am

I have been banging my head trying to do a minimal WebGL example in CSHTML5.

Does anyone happen to have just a minimal example (spinning cube with mouse-hit type of thing) that they could post before I go mad?

If so I would truly appreciate it.

Thanks

RKM

JS-Support @Userware
Site Admin
Posts: 1142
Joined: Tue Apr 08, 2014 3:42 pm

Re: Looking for a WebGL example

Postby JS-Support @Userware » Mon Dec 26, 2016 6:44 am

Hi,

We are going to make an example as soon as the feature to import TypeScript Definition files is finished, in a few weeks. You will be able to interact with WebGL in a strongly-typed manner, with intellisense and more. Stay tuned on the Pre-Releases section and the Extensions section of the forums.

Regards,
JS-Support

SchnauzerDad
Posts: 8
Joined: Fri Jun 17, 2016 6:27 am

Re: Looking for a WebGL example

Postby SchnauzerDad » Mon Dec 26, 2016 10:27 am

That is great! I can't wait to see it

JS-Support @Userware
Site Admin
Posts: 1142
Joined: Tue Apr 08, 2014 3:42 pm

Re: Looking for a WebGL example

Postby JS-Support @Userware » Mon Jan 02, 2017 10:34 am

Hi!

We are working on adding TypeScript Definitions support in order to be able to call WebGL from C# in a strongly-typed manner.

In the meantime, please find attached a very cool WebGL example by learningwebgl.com ported to CSHTML5.

It was ported to CSHTML5 using the "HtmlPresenter" control and the "Interop.ExecuteJavaScript" method (documentation).

The demo shows an animation where the camera zooms into the Mandelbrot fractal set using a WebGL fragment shader (tested on desktop browsers Chrome and Firefox).

For those who would like to see the source code without downloading the project, here it is:

MAINPAGE.XAML:

Code: Select all

<Page
    x:Class="Cshtml5WebGLSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <Border x:Name="LayoutRoot" Background="#FFCCCCFF">
        </Border>
    </ScrollViewer>
</Page>


MAINPAGE.XAML.CS:

Code: Select all

using CSHTML5;
using CSHTML5.Native.Html.Controls;
using System.Windows;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Cshtml5WebGLSample
{
    public partial class MainPage : Page
    {
        //------------------------------------------------------
        // CSHTML5 WebGL sample - Zooming into the Mandelbrot set in a WebGL fragment shader!
        // Credits: http://learningwebgl.com/blog/?p=205
        // Original source code: https://github.com/gpjt/webgl-lessons/blob/master/example01/index.html
        // The main changes that were done to adapt the code are:
        // - Explicitely declared all the variables because CSHTML5 runs JavaScript in "strict mode" (see the lines that have the comment "//strictmode").
        // - Made the functions globally accessible by adding them to the "window" object.
        // - Loaded the shaders from string instead of loading them from <script> tags (just changed the "getShader" method).
        //------------------------------------------------------

        public MainPage()
        {
            this.InitializeComponent();

            //---------------------------------------------------------------------
            // Load the HTML code of the demo by using an "HtmlPresenter" control:
            // This section was copy/pasted from the <body> tag of the original example.
            //---------------------------------------------------------------------
            var htmlPresenter = new HtmlPresenter();
            LayoutRoot.Child = htmlPresenter;
            htmlPresenter.Html = @"
  <canvas id=""example01-canvas"" style=""border: none;"" width=""425"" height=""330""></canvas>

  <h2>Inputs</h2>
  <form name=""inputs"">
  <p>
  Zoom target: <br />
  X <input type=""text"" id=""zoomCenterXInput"" value=""0.28693186889504513"" />
  Y <input type=""text"" id=""zoomCenterYInput"" value=""0.014286693904085048"" />

  <p>
  <input type=""button"" value=""Reset Zoom"" onClick=""resetZoom()"" />
  </form>

  <h2>Current state (read-only)</h2>
  <form name=""outputs"">
  <p>
  Current center: <br />
  X <input type=""text"" id=""centerOffsetXOutput"" /> Y <input type=""text"" id=""centerOffsetYOutput"" />

  <p>
  Zoom: <input type=""text"" id=""zoomOutput"" />
  </form>

  <br/>
  <a href=""http://learningwebgl.com/blog/?p=205"">&lt;&lt; Back to the blog</a><br />
";

            this.Loaded += MainPage_Loaded;
        }

        //-----------------------
        // Declare the shaders.
        // This section was copy/pasted from the first two <script> tags of the original example.
        //-----------------------
        const string ShaderFragment = @"
  precision mediump float;
  varying vec2 vPosition;
  void main(void) {
    float cx = vPosition.x;
    float cy = vPosition.y;
    float hue;
    float saturation;
    float value;
    float hueRound;
    int hueIndex;
    float f;
    float p;
    float q;
    float t;
    float x = 0.0;
    float y = 0.0;
    float tempX = 0.0;
    int i = 0;
    int runaway = 0;
    for (int i=0; i < 100; i++) {
      tempX = x * x - y * y + float(cx);
      y = 2.0 * x * y + float(cy);
      x = tempX;
      if (runaway == 0 && x * x + y * y > 100.0) {
        runaway = i;
      }
    }
    if (runaway != 0) {
      hue = float(runaway) / 200.0;
      saturation = 0.6;
      value = 1.0;
      hueRound = hue * 6.0;
      hueIndex = int(mod(float(int(hueRound)), 6.0));
      f = fract(hueRound);
      p = value * (1.0 - saturation);
      q = value * (1.0 - f * saturation);
      t = value * (1.0 - (1.0 - f) * saturation);
      if (hueIndex == 0)
        gl_FragColor = vec4(value, t, p, 1.0);
      else if (hueIndex == 1)
        gl_FragColor = vec4(q, value, p, 1.0);
      else if (hueIndex == 2)
        gl_FragColor = vec4(p, value, t, 1.0);
      else if (hueIndex == 3)
        gl_FragColor = vec4(p, q, value, 1.0);
      else if (hueIndex == 4)
        gl_FragColor = vec4(t, p, value, 1.0);
      else if (hueIndex == 5)
        gl_FragColor = vec4(value, p, q, 1.0);
    } else {
      gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
    }
  }
";

        const string ShaderVertex = @"
  attribute vec2 aVertexPosition;
  attribute vec2 aPlotPosition;
  varying vec2 vPosition;
  void main(void) {
    gl_Position = vec4(aVertexPosition, 1.0, 1.0);
    vPosition = aPlotPosition;
  }
";

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            if (Interop.IsRunningInTheSimulator)
            {
                MessageBox.Show("WebGL is currently not supported in the Simulator. Please launch the application in the browser to test it.");
            }
            else
            {
                //-----------------------
                // Load the main script (this was orignally done in the last <script> tag, in the original example):
                //-----------------------
                RunWebGLInitialisationScript();

                //-----------------------
                // Start the animation (this was originally done in the "onload" event of the html Body, in the original example):
                //-----------------------
                Interop.ExecuteJavaScript("webGLStart()");
            }
        }

        void RunWebGLInitialisationScript()
        {
            //-----------------------
            // This section was copy/pasted from the last <script> tag of the original example.
            // Some changes were made to the code: read the comments at the beginning of this class for more information.
            // Please note that the two shaders are passed as $0 and $1 parameters to the "ExecuteJavaScript" method.
            // More info about the "ExecuteJavaScript" method can be found at: http://cshtml5.com/links/how-to-call-javascript.aspx]Interop.ExecuteJavaScript
            //-----------------------
            Interop.ExecuteJavaScript(@"
var gl;
window.initGL = function(canvas) {
    try {
      gl = canvas.getContext(""webgl"");
      gl.viewportWidth = canvas.width;
            gl.viewportHeight = canvas.height;
        } catch(e) {
    }
    if (!gl) {
      alert(""Could not initialise WebGL, it is probably not supported on this browser."");
    }
}
window.getShader = function(gl, id)
{
    var str;
    var shader;
    if (id == ""shader-fs"")
    {
        str = $0;
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    }
    else if (id == ""shader-vs"")
    {
        str = $1;
        shader = gl.createShader(gl.VERTEX_SHADER);
    }
    else
    {
        alert(""invalid shader id: "" + id);
        return null;
    }
    gl.shaderSource(shader, str);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
    {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }
    return shader;
}
var shaderProgram;
var aPlotPosition; //strictmode
var aVertexPosition;
window.initShaders = function()
{
    var fragmentShader = getShader(gl, ""shader-fs"");
    var vertexShader = getShader(gl, ""shader-vs"");
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
    {
        alert(""Could not initialise shaders"");
    }
    gl.useProgram(shaderProgram);
    aVertexPosition = gl.getAttribLocation(shaderProgram, ""aVertexPosition"");
    gl.enableVertexAttribArray(aVertexPosition);
    aPlotPosition = gl.getAttribLocation(shaderProgram, ""aPlotPosition"");
    gl.enableVertexAttribArray(aPlotPosition);
}
var centerOffsetX = 0;
var centerOffsetY = 0;
var zoom;
var zoomCenterX;
var zoomCenterY;
var vertexPositionBuffer;
var corners; //strictmode
var x; //strictmode
var y; //strictmode
window.initBuffers = function()
{
    vertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
    var vertices = [
         1.0, 1.0,
        -1.0, 1.0,
         1.0, -1.0,
        -1.0, -1.0,
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    vertexPositionBuffer.itemSize = 2;
    vertexPositionBuffer.numItems = 4;
}
var baseCorners = [

    [0.7, 1.2],

    [-2.2, 1.2],

    [0.7, -1.2],

    [-2.2, -1.2],
  ];
window.drawScene = function()
{
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
    gl.vertexAttribPointer(aVertexPosition, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
    var plotPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, plotPositionBuffer);
    var cornerIx;
    corners = [];
    for (cornerIx in baseCorners)
    {
        x = baseCorners[cornerIx][0];
        y = baseCorners[cornerIx][1];
        corners.push(x / zoom + centerOffsetX);
        corners.push(y / zoom + centerOffsetY);
    }
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(corners), gl.STATIC_DRAW);
    gl.vertexAttribPointer(aPlotPosition, 2, gl.FLOAT, false, 0, 0);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    gl.deleteBuffer(plotPositionBuffer)
    zoom *= 1.02;
    document.getElementById(""zoomOutput"").value = zoom;
    if (centerOffsetX != zoomCenterX)
    {
        centerOffsetX += (zoomCenterX - centerOffsetX) / 20;
    }
    document.getElementById(""centerOffsetXOutput"").value = centerOffsetX;
    if (centerOffsetY != zoomCenterY)
    {
        centerOffsetY += (zoomCenterY - centerOffsetY) / 20;
    }
    document.getElementById(""centerOffsetYOutput"").value = centerOffsetY;
}
window.resetZoom = function() {
    zoom = 1.0;
    zoomCenterX = parseFloat(document.getElementById(""zoomCenterXInput"").value);
    zoomCenterY = parseFloat(document.getElementById(""zoomCenterYInput"").value);
}
window.webGLStart = function()
{
    resetZoom();
    var canvas = document.getElementById(""example01-canvas"");
    initGL(canvas);
    initShaders()
    initBuffers();
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    setInterval(drawScene, 15);
}
webGLStart();
",
    ShaderFragment,
    ShaderVertex);
        }
    }
}


Regards,
JS-Support
Attachments
Cshtml5WebGLSample.zip
(12.67 KiB) Downloaded 422 times

rkmore
Posts: 55
Joined: Mon Dec 07, 2015 1:53 pm

Re: Looking for a WebGL example

Postby rkmore » Wed Jan 04, 2017 5:47 am

Trying it now...

Thanks for the support

RKM

JS-Support @Userware
Site Admin
Posts: 1142
Joined: Tue Apr 08, 2014 3:42 pm

Re: Looking for a WebGL example

Postby JS-Support @Userware » Mon Jan 09, 2017 8:18 am

rkmore wrote:Trying it now...


Did the demo work for you?

We are preparing a strongly-typed C#-based version of the same demo.

Thanks.
Regards,
JS-Support

rkmore
Posts: 55
Joined: Mon Dec 07, 2015 1:53 pm

Re: Looking for a WebGL example

Postby rkmore » Fri Jan 13, 2017 8:31 am

Yes, thank you. I look forward to the strongly typed demo and hope that it illustrates some more user interaction.

Might I suggest that a 2D Mandelbrot set might not be the best demo. Something like a 3D cube that allows the user to rotate the object and also does hit testing would be very useful.

Thank you.


Return to “General Discussion and Other”

Who is online

Users browsing this forum: No registered users and 30 guests

 

 

cron