HetaJs

Fragment Shader Scroll

Your browser does not support the HTML5 canvas element.
- http://en.wikipedia.org/wiki/Mandelbrot_set
- disable cache 설정해야됨 플래그먼트 쉐이더는 캐쉬를 사용하기 때문.


Vertax Shader

precision mediump float;

attribute vec2 vPos;

void main()
{
	gl_Position = vec4(vPos, 0.0, 1.0);	
}

Fragment Shader

precision mediump float;

uniform vec2 viewportDimensions;
uniform float minI;
uniform float maxI;
uniform float minR;
uniform float maxR;

void main(){
	//[0,1080] -> [-2.0, 2.0] (1): Multiply by (2.0 - -2.0) / (1080 - 0)	//높이
	//[0,4.0] -> [-2.0, 2.0] (2): 
	//[-2.0, 2.0]
	//그릴 위치
	vec2 c = vec2(
		gl_FragCoord.x * (maxR -minR) / viewportDimensions.x + minR,
		gl_FragCoord.y * ( maxI - minI) / viewportDimensions.y + minI
	);

	//Mandelbrot formula!
	vec2 z = c;
	float iterations = 0.0;
	float maxIterations = 2000.0;
	const int imaxIterations = 2000;				//이거 넘으면 동작 없음.
	
	for(int i = 0; i < imaxIterations; i++){
		float t = 2.0 * z.x * z.y + c.y;
		z.x = z.x* z.x - z.y *z.y + c.x;
		z.y = t;

		if(z.x*z.x +z.y*z.y > 4.0){
			break;
		}

		iterations += 1.0;

	}

	if(iterations < maxIterations){
		discard;	//실행안함.
	}else{
		gl_FragColor = vec4(0.0,0.0, 1.0, 1.0);
	}

}

Script

var gl;
var program;
var canvas;
function WebGLRenderApp(modelObj,imgSource) {
	
	AddEvent(window, 'resize',  OnResizeWindow);
	AddEvent(window, 'wheel',  OnZoom);
	AddEvent(window, 'mousemove',  onMouseMove);
	
	
	
	canvas = document.getElementById("canvas-element-id");
	gl = canvas.getContext('webgl');
	
	if(!gl){
		console.log("WebGL not supported falling back on experimental-webgl");
		gl = canvas.getContext('experimental-webgl');
	}
	if(!gl){
		alert("Your browser does not support WebGL");
	}
	
	
	
// 	gl.enable(gl.DEPTH_TEST);
// 	gl.enable(gl.CULL_FACE);
// 	gl.frontFace(gl.CCW);
// 	gl.cullFace(gl.BACK);
	
	
	var fragmentShader          = getShader(gl, "shader-fs");
    var vertexShader            = getShader(gl, "shader-vs");
    
    //program
    program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
		console.log('There was a problem with the PROGRAM :\n\n'+ gl.getProgramInfoLog(program));
		gl.deleteProgram(program);
    }
    gl.validateProgram(program);
    if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
   	 console.error('Error validating program!', gl.getProgramInfoLog(program));
    }
    gl.useProgram(program);
	
	//========================= uniform
	var uniforms = {
		viewportDimensions:gl.getUniformLocation(program,'viewportDimensions'),
		minI:gl.getUniformLocation(program,'minI'),
		maxI:gl.getUniformLocation(program,'maxI'),
		minR:gl.getUniformLocation(program,'minR'),
		maxR:gl.getUniformLocation(program,'maxR')
	}
	//setCPU-side variables for all of our shader variables
	var vpDimensions = [canvas.width, canvas.height];
	var minI = -2.0;
	var maxI = 2.0;
	var minR = -2.0;
	var maxR = 2.0;

	//create buffer
	var vertexBuffer = gl.createBuffer();
	var vertices = [
		-1, 1,
		-1, -1,
		1, -1,
		
		-1,1,
		1,1,
		1,-1
	];
	gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
	
	var vPosAttrib = gl.getAttribLocation(program, 'vPos');
	gl.vertexAttribPointer(
		vPosAttrib,
		2, gl.FLOAT, gl.FALSE,
		2 * Float32Array.BYTES_PER_ELEMENT,
		0
	);
	gl.enableVertexAttribArray(vPosAttrib);
	
    //==================================================
    var thisframetime;
    var lastframetime = performance.now();
    var dt;
    var frames = [];
    var lastPrintTime = performance.now();
    var loop = function(){
    	thisframetime = performance.now();
		dt = thisframetime - lastframetime;
		lastframetime = thisframetime;
		if(lastPrintTime + 750 < thisframetime){
			lastPrintTime = this.frametime;
			var average = 0;
			for(var i= 0; i < frames.length; i++){
				average += frames[i];
			}
			average /= frames.length;
			document.title = 1000/ average + ' fps';
		}
    	
    	
    	gl.clearColor(0.75, 0.85, 0.8, 1.0);
    	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    	
    	gl.uniform2fv(uniforms.viewportDimensions, vpDimensions);
    	gl.uniform1f(uniforms.minI, minI);
    	gl.uniform1f(uniforms.maxI, maxI);
    	gl.uniform1f(uniforms.minR, minR);
    	gl.uniform1f(uniforms.maxR, maxR);
    	

    	//$$$ 텍스쳐
//     	gl.bindTexture(gl.TEXTURE_2D, modelTexture);
//     	gl.activeTexture(gl.TEXTURE0);	//0,1 순서대로 들어간다.
    	
//     	gl.drawElements(gl.TRIANGLES, modelIndices.length, gl.UNSIGNED_SHORT, 0);	//처음엔 없어서 에러..
    	gl.drawArrays(gl.TRIANGLES, 0, 6);	//처음엔 없어서 에러..
// 		gl.viewport(0,0,canvas.width, canvas.height);	//0-1사이의 값이 화면과 대칭되도록 설정.
		
    	requestAnimationFrame(loop);
    }
    requestAnimationFrame(loop);

    OnResizeWindow();

    function OnResizeWindow(){
    	if(!canvas){
    		return;
    	}
    	
//     	canvas.width = window.innerWidth;
//     	canvas.height = window.innerHeight;
    	
		vpDimensions = [canvas.width,canvas.height];
    	
    	var oldRealRange = maxR - minR;
    	maxR = (maxI - minI) * (canvas.width / canvas.height) / 1.4 + minR;
    	var newRealRange = maxR - minR;
    	
    	minR -= (newRealRange - oldRealRange) /2;
    	maxR = (maxI - minI) * (canvas.width / canvas.height) / 1.4 + minR;
    	gl.viewport(0,0,canvas.width, canvas.height);
    }
    
    function OnZoom(e){
    	var imaginaryRange = maxI - minI;
    	var newRange;
    	if(e.deltaY < 0){
    		newRange = imaginaryRange * 0.95;
    	}else{
    		newRange = imaginaryRange * 1.05;
    	}
    	
    	var delta = newRange - imaginaryRange;
    	minI -= delta /2;
    	maxI = minI + newRange;
    	
    	//console.log(delta, minI, maxI);
    	
    	OnResizeWindow();
    	
    }
    
    var last_position = {};
    function onMouseMove(e){
    	if(e.buttons === 1){
    		
    		//ie
    		var movementX = (last_position.x ? e.clientX - last_position.x : 0);
    	    var movementY = (last_position.y ? e.clientY - last_position.y : 0);
    		
    		
    		var iRange = maxI - minI;
    		var rRange = maxR - minR;
    		
    		var iDelta = (movementY / canvas.height) * iRange;
    		var rDelta = (movementX / canvas.width) * rRange;
    		
    		minI += iDelta;
    		maxI += iDelta;
    		minR -= rDelta;
    		maxR -= rDelta;
    	}
    	
    	last_position = {
			x : e.clientX,
			y : e.clientY
		};
    }
}