Navigation überspringen

Harald Markus Wirth


Seiteninhalt:

07 Video

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
// VERTEX SHADER
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
attribute vec4 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;

uniform mat4 uNormalMatrix;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

varying highp vec2 vTextureCoord;
varying highp vec3 vLighting;

void main () {
	gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
	vTextureCoord = aTextureCoord;

	highp vec3 ambient_light = vec3( 0.3, 0.3, 0.3 );
	highp vec3 directional_light_color = vec3( 1, 1, 1 );
	highp vec3 directional_vector = normalize( vec3( 0.85, 0.8, 0.75 ) );

	highp vec4 transformed_normal = uNormalMatrix * vec4( aVertexNormal, 1.0 );

	highp float directional = max( dot( transformed_normal.xyz, directional_vector ), 0.0 );
	vLighting = ambient_light + (directional_light_color * directional);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
// FRAGMENT SHADER
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
varying highp vec2 vTextureCoord;
varying highp vec3 vLighting;

uniform sampler2D uSampler;

void main () {
	highp vec4 texel_color = texture2D( uSampler, vTextureCoord );
	gl_FragColor = vec4( texel_color.rgb * vLighting, texel_color.a );
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
// WebGL TUTORIAL CODE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/

"use strict";

const DtoR = Math.PI / 180; // Convert degrees to radians
var frame_count = 0; // Count each drawn frame for calculating frames per second


/**
* init_shader_program()
* Compile and link the shader program
*/
function init_shader_program (gl_context, vertex_shader_source, fragment_shader_source) {
const gl = gl_context;

function load_shader (gl, type, source) {
const shader = gl.createShader( type );
gl.shaderSource( shader, source );
gl.compileShader( shader );
if (! gl.getShaderParameter( shader, gl.COMPILE_STATUS )) {
const compile_result = gl.getShaderInfoLog( shader )
gl.deleteShader( shader );
throw new Error( "Error while compiling shader program: " + compile_result );
}
return shader;

} // load_shader

const vertex_shader = load_shader( gl, gl.VERTEX_SHADER, vertex_shader_source );
const fragment_shader = load_shader( gl, gl.FRAGMENT_SHADER, fragment_shader_source );

const shader_program = gl.createProgram();
gl.attachShader( shader_program, vertex_shader );
gl.attachShader( shader_program, fragment_shader );

gl.linkProgram( shader_program );
if (! gl.getProgramParameter( shader_program, gl.LINK_STATUS )) {
const link_result = gl.getProgramInfoLog( shader_program );
throw new Error( "Error while linking shader program: " + link_result );
}

return shader_program;

} // init_shader_program


/**
* setup_video()
*/
function setup_video (url, callback_update) {

const video = document.createElement( 'video' );

var playing = false;
var time_update = false;

video.autoplay = true;
video.muted = true;
video.loop = true;

// When the video has arrived, call the update function
function check_ready () {
if (playing && time_update) {
callback_update();
}

} // check_ready


// Waiting for these 2 events ensures
// there is data in the video

video.addEventListener( 'playing', ()=>{
playing = true;
check_ready();
}, true );

video.addEventListener('timeupdate', ()=>{
time_update = true;
check_ready();
}, true );

// Trigger download
video.src = url;
video.play();

return video;

} // setup_video


/**
* init_texture()
*/
function init_texture (gl_context) {
const gl = gl_context;

const texture = gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, texture );

// Because video has to be download over the internet they might take a moment until it's ready so put a single
// pixel in the texture so we can use it immediately
const level = 0;
const internal_format = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const src_format = gl.RGBA;
const src_type = gl.UNSIGNED_BYTE;

const pixel = new Uint8Array( [0, 0, 255, 255] ); // Opaque blue

gl.texImage2D(
gl.TEXTURE_2D,
level,
internal_format,
width,
height,
border,
src_format,
src_type,
pixel,
);

// Turn off mips and set wrapping to clamp to edge so it will work regardless of the dimensions of the video
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );

return texture;

} // init_texture


/**
* update_video_texture()
*/
function update_video_texture (gl_context, texture, video) {
const gl = gl_context;

const level = 0;
const internal_format = gl.RGBA;
const src_format = gl.RGBA;
const src_type = gl.UNSIGNED_BYTE;

gl.bindTexture(
gl.TEXTURE_2D,
texture,
);
gl.texImage2D(
gl.TEXTURE_2D,
level,
internal_format,
src_format,
src_type,
video, // Instead of using an image, we pass the video element
// WebGL knows, how to pull the current frame out
);

} // update_video_texture


/**
* init_buffers()
* Make our data accessible to the GPU
*/
function init_buffers (gl) {
const positions = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,

// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,

// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,

// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,

// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,

// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
];


const vertex_normals = [
// Front
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,

// Back
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,

// Top
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,

// Bottom
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,

// Right
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,

// Left
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];


// This array defines each face as two triangles, using the indices into the vertex array to specify each
// triangle's position
const indices = [
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // back
8, 9, 10, 8, 10, 11, // top
12, 13, 14, 12, 14, 15, // bottom
16, 17, 18, 16, 18, 19, // right
20, 21, 22, 20, 22, 23, // left
];


const texture_coordinates = [
// Front
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Back
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Top
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Bottom
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Right
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Left
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
];


// Create and select texture coordinates buffer and send data to WebGL
const texture_coord_buffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, texture_coord_buffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( texture_coordinates ), gl.STATIC_DRAW );

// Create and select normals buffer and send data to WebGL
const normal_buffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, normal_buffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertex_normals ), gl.STATIC_DRAW );

// Create and select position buffer and send data to WebGL
const position_buffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, position_buffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( positions ), gl.STATIC_DRAW );

// Create and select index buffer and send data to WebGL
const index_buffer = gl.createBuffer();
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, index_buffer );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW );

return {
position : position_buffer,
normal : normal_buffer,
textureCoord : texture_coord_buffer,
indices : index_buffer,
}

} // init_buffers


/**
* draw_scene()
*/
function draw_scene (gl_context, program_info, buffers, texture, rotation) {
const gl = gl_context;

// Fill canvas with grayish blue
gl.clearColor( 0.1, 0.3, 0.5, 1.0 );
gl.clearDepth( 1.0 );
gl.enable ( gl.DEPTH_TEST );
gl.depthFunc ( gl.LEQUAL );

gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

const field_of_view = 45 * DtoR;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const z_near = 0.1;
const z_far = 100.0;


// Set up camera
const projection_matrix = mat4.create();
mat4.perspective(
projection_matrix,
field_of_view,
aspect,
z_near,
z_far,
);


// Set up world coordinate transformation ("move the camera")
const model_view_matrix = mat4.create();
mat4.translate(
model_view_matrix,
model_view_matrix,
[-0.0, 0.0, -6.0],
);
mat4.rotate(
model_view_matrix,
model_view_matrix,
rotation,
[0, 0, 1],
);
mat4.rotate(
model_view_matrix,
model_view_matrix,
rotation * 0.7,
[0, 1, 0],
);


// Set up nomral matrix
const normal_matrix = mat4.create();
mat4.invert( normal_matrix, model_view_matrix );
mat4.transpose( normal_matrix, normal_matrix );


// Tell WebGL how to pull out the positions from the position buffer into the vertexPosition attribute
{
const num_components = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;

gl.bindBuffer( gl.ARRAY_BUFFER, buffers.position );
gl.vertexAttribPointer(
program_info.attribLocations.vertexPosition,
num_components,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(
program_info.attribLocations.vertexPosition
);
}


// Tell WebGL how to pull out the normals from the normal buffer into the vertextNormal attribute
{
const num_components = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;

gl.bindBuffer( gl.ARRAY_BUFFER, buffers.normal );
gl.vertexAttribPointer(
program_info.attribLocations.vertexNormal,
num_components,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray( program_info.attribLocations.vertexNormal );
}


// Tell WebGL how to pull out the texture coordinates from the buffer into the textureCoord attribute
{
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;

gl.bindBuffer( gl.ARRAY_BUFFER, buffers.textureCoord );
gl.vertexAttribPointer(
program_info.attribLocations.textureCoord,
numComponents,
type,
normalize,
stride,
offset
);
gl.enableVertexAttribArray( program_info.attribLocations.textureCoord );
}


// Tell WebGL which indices to use for indexing the vertices
{
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffers.indices );
}


// Upload the shader program to the GPU
gl.useProgram( program_info.program );


// Upload matrices
gl.uniformMatrix4fv(
program_info.uniformLocations.projectionMatrix,
false,
projection_matrix,
);
gl.uniformMatrix4fv(
program_info.uniformLocations.modelViewMatrix,
false,
model_view_matrix,
);
gl.uniformMatrix4fv(
program_info.uniformLocations.normalMatrix,
false,
normal_matrix,
);


// Specify the texture to map onto the faces

// Tell WebGL we want to affect texture unit 0
gl.activeTexture( gl.TEXTURE0 );

// Bind the texture to texture unit 0
gl.bindTexture( gl.TEXTURE_2D, texture );

// Tell the shader we bound the texture to texture unit 0
gl.uniform1i( program_info.uniformLocations.uSampler, 0 );

// Trigger rendering
{
const vertex_count = 36;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
gl.drawElements( gl.TRIANGLES, vertex_count, type, offset );
}

++frame_count;

} // draw_scene


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/
// PROGRAM ENTRY POINT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////119:/

/**
* body.onload()
*/
window.addEventListener( "load", ()=>{

function computed_style( element ) {
return element.currentStyle || window.getComputedStyle( element );

} // computedStyle

// Get size of the <canvas> element
const canvas = document.querySelector( ".viewport" );
const style = computed_style( canvas );
const new_width = parseInt( style.width ); // We could use different dimensions, if so desired
const new_height = parseInt( style.height );

// Initialize the <canvas> element
// Set size of the DOM element (how large the canvas appears on the page) and its drawing surface
canvas.setAttribute( "width", canvas.width = new_width ); // Setting both sizes in one go
canvas.setAttribute( "height", canvas.height = new_height );

// Attempt to retreive the WebGL context
const gl = canvas.getContext( "webgl" );
if (! gl) throw new Error( "Unable to initialize WebGL." );

// Fill the canvas with a dark red. If this color appears on the page, something went wrong
gl.clearColor( 0.5, 0.0, 0.0, 1.0 );
gl.clear( gl.COLOR_BUFFER_BIT );

// Load shader sources
const vertex_shader_source = document.querySelector( "#vertex_shader" ).innerText;
const fragment_shader_source = document.querySelector( "#fragment_shader" ).innerText;

// Compile shaders
const shader_program = init_shader_program( gl, vertex_shader_source, fragment_shader_source );

// Store all info
const program_info = {
program: shader_program,
attribLocations: {
vertexPosition : gl.getAttribLocation( shader_program, "aVertexPosition" ),
vertexNormal : gl.getAttribLocation( shader_program, "aVertexNormal" ),
textureCoord : gl.getAttribLocation( shader_program, "aTextureCoord" ),
},
uniformLocations: {
projectionMatrix : gl.getUniformLocation( shader_program, "uProjectionMatrix" ),
modelViewMatrix : gl.getUniformLocation( shader_program, "uModelViewMatrix" ),
normalMatrix : gl.getUniformLocation( shader_program, "uNormalMatrix" ),
uSampler : gl.getUniformLocation( shader_program, 'uSampler' ),
},
};

// Set up memory
const buffers = init_buffers( gl );

// Prepare texture
const texture = init_texture( gl );

// Load video
const video = setup_video( 'babelfisch.webm', ()=>{
update_video_texture( gl, texture, video );
});

// Animate
let then = 0;
let rotation = 0.0;

function render (now) {
now *= 0.001; // Convert to seconds
const delta_t = now - then;
then = now;
rotation += delta_t;

draw_scene( gl, program_info, buffers, texture, rotation );
requestAnimationFrame( render );
} // render

requestAnimationFrame( render ); // Start render loop

// Display frames per second
setInterval( ()=>{
document.title = "F/s: " + frame_count;
frame_count = 0;
}, 1000 );
});

https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL



Content Management:

μCMS α1.6