WebGL
Børre Stenseth
Basis > Torus >Torus i gull

En smultring i gull

Hva

Vi skal lage en gyllen smultring som roterer.

Vi bruker de samme geometriske betraktningene som i modulen Torus og overføring av punkter og indekser blir det samme.

Utfordringen her blir å sette og bruke materialer og lys.

Fragment shader

Fragment shaderen får satt materiale og lys i form av 10 uniform variable. Regnestykket med lysretninger og vinkler gjøres "for hånd". Denne jobben trenger vi ikke bekymre oss om når vi skriver "gammeldags" OpenGL. Målet er å få satte den predefinerte vektoren gl_FragColor.

#ifdef GL_ES
precision mediump float;
#endif
varying vec3 vTransformedNormal;
varying vec4 vPosition;
uniform vec3 uMaterialAmbientColor;
uniform vec3 uMaterialDiffuseColor;
uniform vec3 uMaterialSpecularColor;
uniform float uMaterialShininess;
uniform vec3 uMaterialEmissiveColor;
uniform bool uShowSpecularHighlights;
uniform vec3 uAmbientLightingColor;
uniform vec3 uPointLightingDiffuseColor;
uniform vec3 uPointLightingSpecularColor;
uniform vec3 uPointLightingLocation;
void main(void) {
    vec3 ambientLightWeighting = uAmbientLightingColor;
    vec3 lightDirection = normalize(uPointLightingLocation - vPosition.xyz);
    vec3 normal = normalize(vTransformedNormal);
    vec3 specularLightWeighting = vec3(0.0, 0.0, 0.0);
    if (uShowSpecularHighlights) {
        vec3 eyeDirection = normalize(-vPosition.xyz);
        vec3 reflectionDirection = reflect(-lightDirection, normal);
        float specularLightBrightness = 
            pow(max(dot(reflectionDirection, eyeDirection), 0.0), uMaterialShininess);
        specularLightWeighting = uPointLightingSpecularColor * specularLightBrightness;
    }
    float diffuseLightBrightness = max(dot(normal, lightDirection), 0.0);
    vec3 diffuseLightWeighting = uPointLightingDiffuseColor * diffuseLightBrightness;
    vec3 materialAmbientColor = uMaterialAmbientColor;
    vec3 materialDiffuseColor = uMaterialDiffuseColor;
    vec3 materialSpecularColor = uMaterialSpecularColor;
    vec3 materialEmissiveColor = uMaterialEmissiveColor;
    float alpha = 1.0;
    gl_FragColor = vec4(
        materialAmbientColor * ambientLightWeighting
        + materialDiffuseColor * diffuseLightWeighting
        + materialSpecularColor * specularLightWeighting
        + materialEmissiveColor,
        alpha
    );
}

Vertex shader

De tre variablene: uMVMatrix, uPMatrix og uNormalMatrix blir satt fra Javascriptkoden. aVertexPosition representerer det aktuelle punktet, slik det er ordnet i en buffer fra Javascriptet og aVertexNormal er normalen i punktet.

attribute vec3 aVertexNormal; // or in
attribute vec3 aVertexPosition;
uniform mat4 uNMatrix;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

varying vec3 vTransformedNormal;
varying vec4 vPosition;
void main(void) {
  vPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
  gl_Position = uPMatrix * vPosition;
  vTransformedNormal=(uNMatrix * vec4(aVertexNormal, 1.0)).xyz;        
}

Javascript

Javascriptet som handterer vår tegning er inkludert som egen fil. De viktigste delene av denne koden er kommentert funksjon for funksjon nedenfor. Hele fila ser slik ut:

_torusscript-mat.js

Det kan være lurt å kikke på OpenGL ES 2.0 Reference Pages [2] for å få en forklaring av de enkelte metodene.

De viktigste endringene fra den enkle torusen i modulen Torus er i rutinene initShaders() og drawScene()

I initShaders setter vi opp kontakt til de uniform variablene der vi skal plassere material- og lyssettinger.

function initShaders() {
  var fragmentShader = getShader(gl, "shader-fs");
  var vertexShader = getShader(gl, "shader-vs");
  
  // Create the shader program  
  shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);
  
  // ok? 
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert("Unable to initialize the shader program.");
  }
  
  gl.useProgram(shaderProgram);
  
  // connect shader attribute to buffers.
  // attributes, understood as attributes to verteces 
  vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
  gl.enableVertexAttribArray(vertexPositionAttribute);
  vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
  gl.enableVertexAttribArray(vertexNormalAttribute);
  
  // mark light and material
    shaderProgram.materialAmbientColorUniform = 
        gl.getUniformLocation(shaderProgram, "uMaterialAmbientColor");
    shaderProgram.materialDiffuseColorUniform = 
        gl.getUniformLocation(shaderProgram, "uMaterialDiffuseColor");
    shaderProgram.materialSpecularColorUniform = 
        gl.getUniformLocation(shaderProgram, "uMaterialSpecularColor");
    shaderProgram.materialShininessUniform = 
        gl.getUniformLocation(shaderProgram, "uMaterialShininess");
    shaderProgram.materialEmissiveColorUniform = 
        gl.getUniformLocation(shaderProgram, "uMaterialEmissiveColor");
    shaderProgram.showSpecularHighlightsUniform = 
        gl.getUniformLocation(shaderProgram, "uShowSpecularHighlights");
    shaderProgram.ambientLightingColorUniform = 
        gl.getUniformLocation(shaderProgram, "uAmbientLightingColor");
    shaderProgram.pointLightingLocationUniform = 
        gl.getUniformLocation(shaderProgram, "uPointLightingLocation");
    shaderProgram.pointLightingSpecularColorUniform = 
        gl.getUniformLocation(shaderProgram, "uPointLightingSpecularColor");
    shaderProgram.pointLightingDiffuseColorUniform = 
        gl.getUniformLocation(shaderProgram, "uPointLightingDiffuseColor");
}

I drawScene overfører vi material- og lyssettinger til shaderen.

function drawScene() {
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);  
  perspectiveMatrix = makePerspective(45, viewAspect, 0.1, 100.0);
    
  loadIdentity();
  
  // Move the drawing a bit from default eye-pos
  mvTranslate([-0.0, 0.0, -16.0]);
  
  // Save the current matrix, then rotate before we draw. 
  mvPushMatrix();
  mvRotate(torusRotation, [1, 0, 1]);
   
  // Draw the torus by binding the array buffer to the torus's vertices
  // array, setting attributes, and pushing it to GL. 
  gl.bindBuffer(gl.ARRAY_BUFFER, torusVerticesBuffer);
  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
   
  // Set the normal attribute for the vertices. 
  gl.bindBuffer(gl.ARRAY_BUFFER, torusVerticesNormalBuffer);
  gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
  
  // tell the shader about transformation status
  setMatrixUniforms();
  // setup materials and light
    // material: gold
    gl.uniform3f(shaderProgram.materialAmbientColorUniform, 0.24725, 0.1995, 0.0745);
    gl.uniform3f(shaderProgram.materialDiffuseColorUniform, 0.7516, 0.6065, 0.2265);
    gl.uniform3f(shaderProgram.materialSpecularColorUniform, 0.62828, 0.55580, 0.36606);
    gl.uniform1f(shaderProgram.materialShininessUniform, 51.2);
    gl.uniform3f(shaderProgram.materialEmissiveColorUniform, 0.0, 0.0, 0.0);
    gl.uniform3f(shaderProgram.pointLightingLocationUniform, 10.0, 10.0, 5.0);
    
    gl.uniform3f(shaderProgram.ambientLightingColorUniform, 1.0, 1.0, 1.0);
    gl.uniform3f(shaderProgram.pointLightingDiffuseColorUniform, 1.0, 1.0, 1.0);
    gl.uniform3f(shaderProgram.pointLightingSpecularColorUniform, 1.0, 1.0, 1.0);
    gl.uniform1i(shaderProgram.showSpecularHighlightsUniform, true);  
 
  // Draw the torus.
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, torusVerticesIndexBuffer); 
  gl.drawElements(gl.TRIANGLE_STRIP, (N+1)*(n+1)*2, gl.UNSIGNED_SHORT, 0);
 
  // Restore the original matrix  
  mvPopMatrix();
  
  // Update the rotation for the next draw, if it's time to do so.
  var currentTime = (new Date).getTime();
  if (lastTorusUpdateTime) {
    var delta = currentTime - lastTorusUpdateTime;    
    torusRotation += (30 * delta) / 1000.0;
  }  
  lastTorusUpdateTime = currentTime;
}

Dette er resultatet lagt i en iframe:

Du kan også inspisere resultatet og kildekoden på en enklere side:
index-mat.html https://borres.hiof.no/wep/webgl/basis/torusgull/index-mat.html

Referanser
  1. Sylvester sylvester.jcoglan.com/ 14-05-2011
  1. OpenGL ES Software Development Kit Khronos Group www.khronos.org/opengles/sdk/docs/man/ 14-05-2011
Basis > Torus >Torus i gull