Shader substitute for Fixed Function Pipeline

Discussions related to graphics (2D and 3D), animation and games programming
RichardRussell

Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

BB4W's and BBCSDL's 3D-rendering capabilities (encapsulated in the D3DLIB and ogllib/gleslib libraries respectively) make use of the so-called Fixed Function Pipeline, which does most of the work and is relatively easy to use. Although the FFP has long since been deprecated for 'serious' 3D work (such as modern video games), because it can't handle shadows, reflections and all that fancy stuff, it is fortunately still supported as a legacy functionality in both Direct3D and OpenGL (including OpenGLES 1.2).

But the in-browser edition of BBCSDL is not so lucky. The 3D rendering capabilities of browsers come from WebGL, which is compatible with OpenGLES 2.0 and doesn't support the Fixed Function Pipeline at all: everything has to be done using shaders! At first sight this suggests that BBC BASIC programs which generate 3D graphics (via the relevant library) won't run. But I don't give up that easily, and I have written an (admittedly quick and dirty) emulation of the basic FFP capabilities using shaders!

My code is encapsulated in the new webgllib.bbc library, which presents an identical interface to the older BB4W and BBCSDL libraries. It's very limited: it doesn't support lighting or materials - that would be much harder - just plain diffuse coloured surfaces and textures. But it works, and for those programs which don't use (or at least don't rely on) lighting it works surprisingly well. If you have a suitable desktop browser (Chrome, Edge, Firefox or Opera) you can try running Rubik.bbc, pyramid.bbc, world.bbc and soldiers.bbc (the last of these needs Firefox for the music to work properly).

As you can imagine writing shader code, even for this limited subset of 3D functionality, was not easy for somebody almost entirely unfamiliar with it. But it was made easier by being able to call upon BBC BASIC's matrix arithmetic capabilities to perform the calculations which convert world-space into screen-space. Here's a snippet of the code:

Code: Select all

      REM Projection matrix (perspective):
      fh=TAN(fv/2) * zn
      fw=fh * ar
      v(0,0) = zn/fw
      v(1,1) = zn/fh
      v(2,2) = -1
      v(3,2) = 2*zf*zn/(zn-zf)
      v(2,3) = -1

      REM Rotation matrix (camera roll):
      s = SIN(-cr) : c = COS(cr)
      w(0,0) = c
      w(1,0) = -s
      w(0,1) = s
      w(1,1) = c
      w(2,2) = 1
      w(3,3) = 1
      w() = w() . v()

      REM View matrix:
      f()=a() - e()
      f() /= MOD(f())
      s()=f(2),0,-f(0)
      s() /= MOD(s())
      u()=s(2)*f(1),s(0)*f(2)-s(2)*f(0),-s(0)*f(1)
      v()=s(0),u(0),-f(0),0,s(1),u(1),-f(1),0,s(2),u(2),-f(2),0,0,0,0,1
      v() = v() . w()

      REM Translation matrix:
      w() = 1,0,0,0,0,1,0,0,0,0,1,0,-e(0),-e(1),-e(2),1
      w() = w() . v()

      REM Object matrix:
      sy=SINp(I%)
      cy=COSp(I%)
      sp=SINt(I%)
      cp=COSt(I%)
      sr=SINr(I%)
      cr=COSr(I%)
      v() = cr*cy+sr*sp*sy,sr*cp,sr*sp*cy-cr*sy,0,\
      \     cr*sp*sy-sr*cy,cr*cp,sr*sy+cr*sp*cy,0,\
      \     cp*sy,-sp,cp*cy,0,x(I%),y(I%),z(I%),1

      v() = v() . w()
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

I hadn't realised that one advantage of doing lighting by shader programming (rather than using the Fixed Function Pipeline, when available) is that specular reflection calculations are done 'per pixel' rather than 'per vertex'. If you compare the video below with the teapot.bbc program supplied with BBC BASIC for Windows and BBC BASIC for SDL 2.0 you should be able to see how much better it is. You can run it yourself (Chrome, Edge, Firefox or Opera) here.

https://www.youtube.com/watch?v=baQmpyW8huw
Ric
Posts: 208
Joined: Tue 17 Apr 2018, 21:03

Re: Shader substitute for Fixed Function Pipeline

Post by Ric »

I would be very interested in the code for the shader/s. Are you now using a vertex and pixel shader?
Regards Ric
Kind Regards Ric.

6502 back in the day, BB4W 2017 onwards, BBCSDL from 2023
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

Ric wrote: Sat 10 Oct 2020, 14:36 I would be very interested in the code for the shader/s.
The shader code for the existing 2D examples (fluid.bbc, mandel.bbc, seascape.bbc and slitscan.bbc) can of course be found in the programs themselves; they are supplied with all editions of BBC BASIC for SDL 2.0. The shader code used to allow the 3D examples to be run in a browser (Rubik.bbc, bbcowl.bbc, lighting.bbc, pyramid.bbc, spotlight.bbc and world.bbc) can be found in the webgllib.bbc library which comes with the in-browser (Emscripten / WebAssembly) edition.
Are you now using a vertex and pixel shader?
All the 2D and 3D shader examples use both vertex and fragment (pixel) shaders. In every case the vertex shader is relatively trivial, but obviously the fragment shader varies greatly in complexity depending, for example, on whether the lighting model is enabled or not. I'm pleased to have been able to write the fragment shader which emulates the Fixed Function Pipeline, including lighting, substantially from scratch (having done no shader programming prior to a week ago). :)
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

An even more dramatic demonstration of the difference between 3D rendering using the Fixed Function Pipeline and shaders is the spotlight.bbc example program. On the left is what you currently get running it in BBC BASIC for Windows or BBC BASIC for SDL 2.0, on the right is the result using the new webgllib library.

In the former case the boundary of the lit region is determined by the vertices of the underlying 3D model, whereas in the latter it's calculated to pixel accuracy. Again you can run this yourself if you have a suitable browser (desktop Chrome, Edge, Firefox or Opera). Click on the lights to cycle between spotlight, directional and point-source types.

spotlight_small.png
You do not have the required permissions to view the files attached to this post.
Ric
Posts: 208
Joined: Tue 17 Apr 2018, 21:03

Re: Shader substitute for Fixed Function Pipeline

Post by Ric »

Thanks, I'll have a look
Kind Regards Ric.

6502 back in the day, BB4W 2017 onwards, BBCSDL from 2023
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

This is quite interesting. BBCSDL running two copies of bbcowl.bbc, the only difference being that one is using ogllib.bbc (51% CPU, 3.4% GPU) and the other webgllib (31% CPU, 8.9% GPU). This is exactly what one might expect: CPU load reduced because of the use of retained mode (less work in transferring client-side buffers etc.) and GPU load increased (per-pixel rather than per-vertex lighting computations).

glcpu.png
You do not have the required permissions to view the files attached to this post.
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

I have added the following programs to the in-browser (Emscripten / Web Assembly) edition of BBCSDL. If you are using a suitable browser you can just click on the links to run them. They work better in Firefox, in the others (Chrome, Edge, Opera) you are likely to experience 'choppy' sound:
Sorry, I have had to disable the 'Easter Egg' in skaters.bbc, it relies on a feature of the Fixed Function Pipeline that I have not emulated in webgllib!
RichardRussell

Re: Shader substitute for Fixed Function Pipeline

Post by RichardRussell »

I've now added the 'missing' music program: carolmedley.bbc. This required more work because it relied on a feature not supported in WebGL (glAlphaFunc) and indeed the workaround is not perfect: you may notice a few graphical glitches that were not present in the original. But it's not too bad and I will be updating the version in the other editions in due course for consistency.

As with all the music programs accompanied by animated 3D graphics, it works better in Firefox than the other browsers. Firefox seems to make the audio callback from a worker thread, so it is not dependent on the frame rate in the way the others are.