function buildSceneShader(){
	var scene_distance_function =
		"float scene_distance(vec3 x, out int mat){" +
		"	float dist = 1e32;" +
		"	mat = -1;" +
		"	float d = 0.0;" +
		"	int m = -1;";
	for (var i = 0; i < scene.length; ++i){
		scene_distance_function += scene[i].distance("x", "d", "m");
		scene_distance_function += "dist = min(d, dist); mat = dist == d ? m : mat;";
	}
	scene_distance_function += "return dist;}";

	scene_distance_function +=
		"float scene_distance(vec3 x){" +
		"	float dist = 1e32;" +
		"	float d = 0.0;";
	for (var i = 0; i < scene.length; ++i){
		scene_distance_function += scene[i].distance("x", "d");
		scene_distance_function += "dist = min(d, dist);";
	}
	scene_distance_function += "return dist;}";

	var sample_lights_function =
		"vec3 sample_illumination(vec3 p, vec3 w_o, int mat){" +
		"	vec3 illum = vec3(0);" +
		"	vec3 li = vec3(0);" +
		"	vec3 w_i = vec3(0);";
	for (var i = 0; i < lights.length; ++i){
		sample_lights_function += lights[i].sample("p", "li", "w_i");
		sample_lights_function +=
		"	if (!shadow_test(w_i, p)){" +
		"		vec3 normal = normalize(gradient(p));" +
		"		vec3 tan = vec3(0);" +
		"		vec3 bitan = vec3(0);" +
		"		coordinate_system(normal, tan, bitan);" +
		"		vec3 w_is = vec3(0);" +
		"		vec3 w_os = vec3(0);" +
				transform_to_shading_glsl("normal", "tan", "bitan", "w_i", "w_is") +
				transform_to_shading_glsl("normal", "tan", "bitan", "w_o", "w_os") +
		"		illum += shade_material(mat, -w_is, w_os) * li * abs(dot(w_i, normal));" +
		"	}";
	}
	sample_lights_function +=
		"	illum.r = clamp(illum.r, 0.0, 1.0);" +
		"	illum.g = clamp(illum.g, 0.0, 1.0);" +
		"	illum.b = clamp(illum.b, 0.0, 1.0);" +
		"	return illum;}";

	var shade_materials_function =
		"vec3 shade_material(int mat, vec3 w_i, vec3 w_o){" +
		"	vec3 f = vec3(0);";
	for (var i = 0; i < materials.length; ++i){
		shade_materials_function += "if (mat == " + i + "){"
			+ materials[i].shade("f", "w_i", "w_o") + "return f;}";
	}
	shade_materials_function += "return f;}";

	var ray_fs_src =
		constants +
		"precision highp float;" +
		"uniform float sample;" +
		"uniform vec3 eye;" +
		"uniform sampler2D prev_tex;" +
		"uniform vec2 canvas_dim;" +
		"varying vec3 px_ray;" +
		POINT_LIGHT_SAMPLE_GLSL +
		DIRECT_LIGHT_SAMPLE_GLSL +
		SPHERE_DISTANCE_GLSL +
		TORUS_DISTANCE_GLSL +
		MATERIAL_FUNCTIONS_GLSL +
		LAMBERTIAN_MATERIAL_GLSL +
		OREN_NAYAR_MATERIAL_GLSL +
		shade_materials_function +
		scene_distance_function +
		"vec3 gradient(vec3 p){" +
		"	float h = 0.5 * 0.00001;" +
		"	float den = 1.0 / (2.0 * h);" +
		"	float dx = den * (scene_distance(p + vec3(h, 0, 0)) - scene_distance(p - vec3(h, 0, 0)));" +
		"	float dy = den * (scene_distance(p + vec3(0, h, 0)) - scene_distance(p - vec3(0, h, 0)));" +
		"	float dz = den * (scene_distance(p + vec3(0, 0, h)) - scene_distance(p - vec3(0, 0, h)));" +
		"	return vec3(dx, dy, dz);" +
		"}" +
		"bool shadow_test(vec3 ray_dir, vec3 ray_orig){" +
		"	const float max_dist = 1.0e10;" +
		"	const int max_iter = 20;" +
		"	float t = 0.001;" +
		"	int mat = -1;" +
		"	for (int i = 0; i < max_iter; ++i){" +
		"		vec3 p = ray_orig + ray_dir * t;" +
		"		float dt = scene_distance(p);" +
		"		t += dt;" +
		"		if (dt <= 1.0e-4){" +
		"			return true;" +
		"		}" +
		"	}" +
		"	return false;" +
		"}" +
		sample_lights_function +
		"vec3 intersect_scene(vec3 ray_dir, vec3 ray_orig){" +
		"	const float max_dist = 1.0e10;" +
		"	const int max_iter = 35;" +
		"	float t = 0.0;" +
		"	vec3 pass_color = vec3(0);" +
		"	int mat = -1;" +
		"	for (int i = 0; i < max_iter; ++i){" +
		"		vec3 p = ray_orig + ray_dir * t;" +
		"		float dt = scene_distance(p, mat);" +
		"		t += dt;" +
		"		if (dt <= 5.0e-6){" +
		"			pass_color = sample_illumination(p, -ray_dir, mat);" +
		"			break;" +
		"		}" +
		"	}" +
		"	return pass_color;" +
		"}" +
		"void main(void){" +
		"	vec3 ray_dir = normalize(px_ray);" +
		"	vec3 pass_color = intersect_scene(ray_dir, eye);" +
		"	vec3 prev_pass = texture2D(prev_tex, gl_FragCoord.xy / canvas_dim).rgb;" +
		"	gl_FragColor = vec4(prev_pass + (pass_color - prev_pass) / (sample + 1.0), 1.0);" +
		"}";
	var raytrace = compileShader(ray_vs_src, ray_fs_src);
	pos_attrib = gl.getAttribLocation(raytrace, "pos");
	sample_unif = gl.getUniformLocation(raytrace, "sample");
	eye_unif = gl.getUniformLocation(raytrace, "eye");
	var canvas_dim_unif = gl.getUniformLocation(raytrace, "canvas_dim");
	ray_unifs = [];
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray00"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray10"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray01"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray11"));
	gl.useProgram(raytrace);
	gl.uniform2f(canvas_dim_unif, WIDTH, HEIGHT);
	eye_pos = new Vec3f(0, 0, 2);
	var rays = perspectiveCamera(eye_pos, new Vec3f(0, 0, 0), new Vec3f(0, 1, 0), 60.0, WIDTH / HEIGHT);
	for (var i = 0; i < 4; ++i){
		var vals = rays[i].flatten();
		gl.uniform3fv(ray_unifs[i], rays[i].flatten());
	}
	gl.uniform3fv(eye_unif, eye_pos.flatten());
	return raytrace;
}
// Rebuild scene shader based on the updated scene
Rebuild scene shader based on the updated scene
Rebuild scene shader based on the updated scene
function buildSceneShader(){
	var scene_distance_function =
		"float scene_distance(vec3 x, out int mat){" +
		"	float dist = 1e32;" +
		"	mat = -1;" +
		"	float d = 0.0;" +
		"	int m = -1;";
	for (var i = 0; i < scene.length; ++i){
		scene_distance_function += scene[i].distance("x", "d", "m");
		scene_distance_function += "dist = min(d, dist); mat = dist == d ? m : mat;";
	}
	scene_distance_function += "return dist;}";
	scene_distance_function +=
		"float scene_distance(vec3 x){" +
		"	float dist = 1e32;" +
		"	float d = 0.0;";
	for (var i = 0; i < scene.length; ++i){
		scene_distance_function += scene[i].distance("x", "d");
		scene_distance_function += "dist = min(d, dist);";
	}
	scene_distance_function += "return dist;}";
	var sample_lights_function =
		"vec3 sample_illumination(vec3 p, vec3 w_o, int mat){" +
		"	vec3 illum = vec3(0);" +
		"	vec3 li = vec3(0);" +
		"	vec3 w_i = vec3(0);";
	for (var i = 0; i < lights.length; ++i){
		sample_lights_function += lights[i].sample("p", "li", "w_i");
		sample_lights_function +=
		"	if (!shadow_test(w_i, p)){" +
		"		vec3 normal = normalize(gradient(p));" +
		"		vec3 tan = vec3(0);" +
		"		vec3 bitan = vec3(0);" +
		"		coordinate_system(normal, tan, bitan);" +
		"		vec3 w_is = vec3(0);" +
		"		vec3 w_os = vec3(0);" +
				transform_to_shading_glsl("normal", "tan", "bitan", "w_i", "w_is") +
				transform_to_shading_glsl("normal", "tan", "bitan", "w_o", "w_os") +
		"		illum += shade_material(mat, -w_is, w_os) * li * abs(dot(w_i, normal));" +
		"	}";
	}
	sample_lights_function +=
		"	illum.r = clamp(illum.r, 0.0, 1.0);" +
		"	illum.g = clamp(illum.g, 0.0, 1.0);" +
		"	illum.b = clamp(illum.b, 0.0, 1.0);" +
		"	return illum;}";
	var shade_materials_function =
		"vec3 shade_material(int mat, vec3 w_i, vec3 w_o){" +
		"	vec3 f = vec3(0);";
	for (var i = 0; i < materials.length; ++i){
		shade_materials_function += "if (mat == " + i + "){"
			+ materials[i].shade("f", "w_i", "w_o") + "return f;}";
	}
	shade_materials_function += "return f;}";
	var ray_fs_src =
		constants +
		"precision highp float;" +
		"uniform float sample;" +
		"uniform vec3 eye;" +
		"uniform sampler2D prev_tex;" +
		"uniform vec2 canvas_dim;" +
		"varying vec3 px_ray;" +
		POINT_LIGHT_SAMPLE_GLSL +
		DIRECT_LIGHT_SAMPLE_GLSL +
		SPHERE_DISTANCE_GLSL +
		TORUS_DISTANCE_GLSL +
		MATERIAL_FUNCTIONS_GLSL +
		LAMBERTIAN_MATERIAL_GLSL +
		OREN_NAYAR_MATERIAL_GLSL +
		shade_materials_function +
		scene_distance_function +
		"vec3 gradient(vec3 p){" +
		"	float h = 0.5 * 0.00001;" +
		"	float den = 1.0 / (2.0 * h);" +
		"	float dx = den * (scene_distance(p + vec3(h, 0, 0)) - scene_distance(p - vec3(h, 0, 0)));" +
		"	float dy = den * (scene_distance(p + vec3(0, h, 0)) - scene_distance(p - vec3(0, h, 0)));" +
		"	float dz = den * (scene_distance(p + vec3(0, 0, h)) - scene_distance(p - vec3(0, 0, h)));" +
		"	return vec3(dx, dy, dz);" +
		"}" +
		"bool shadow_test(vec3 ray_dir, vec3 ray_orig){" +
		"	const float max_dist = 1.0e10;" +
		"	const int max_iter = 20;" +
		"	float t = 0.001;" +
		"	int mat = -1;" +
		"	for (int i = 0; i < max_iter; ++i){" +
		"		vec3 p = ray_orig + ray_dir * t;" +
		"		float dt = scene_distance(p);" +
		"		t += dt;" +
		"		if (dt <= 1.0e-4){" +
		"			return true;" +
		"		}" +
		"	}" +
		"	return false;" +
		"}" +
		sample_lights_function +
		"vec3 intersect_scene(vec3 ray_dir, vec3 ray_orig){" +
		"	const float max_dist = 1.0e10;" +
		"	const int max_iter = 35;" +
		"	float t = 0.0;" +
		"	vec3 pass_color = vec3(0);" +
		"	int mat = -1;" +
		"	for (int i = 0; i < max_iter; ++i){" +
		"		vec3 p = ray_orig + ray_dir * t;" +
		"		float dt = scene_distance(p, mat);" +
		"		t += dt;" +
		"		if (dt <= 5.0e-6){" +
		"			pass_color = sample_illumination(p, -ray_dir, mat);" +
		"			break;" +
		"		}" +
		"	}" +
		"	return pass_color;" +
		"}" +
		"void main(void){" +
		"	vec3 ray_dir = normalize(px_ray);" +
		"	vec3 pass_color = intersect_scene(ray_dir, eye);" +
		"	vec3 prev_pass = texture2D(prev_tex, gl_FragCoord.xy / canvas_dim).rgb;" +
		"	gl_FragColor = vec4(prev_pass + (pass_color - prev_pass) / (sample + 1.0), 1.0);" +
		"}";
	var raytrace = compileShader(ray_vs_src, ray_fs_src);
	pos_attrib = gl.getAttribLocation(raytrace, "pos");
	sample_unif = gl.getUniformLocation(raytrace, "sample");
	eye_unif = gl.getUniformLocation(raytrace, "eye");
	var canvas_dim_unif = gl.getUniformLocation(raytrace, "canvas_dim");
	ray_unifs = [];
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray00"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray10"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray01"));
	ray_unifs.push(gl.getUniformLocation(raytrace, "ray11"));
	gl.useProgram(raytrace);
	gl.uniform2f(canvas_dim_unif, WIDTH, HEIGHT);
	eye_pos = new Vec3f(0, 0, 2);
	var rays = perspectiveCamera(eye_pos, new Vec3f(0, 0, 0), new Vec3f(0, 1, 0), 60.0, WIDTH / HEIGHT);
	for (var i = 0; i < 4; ++i){
		var vals = rays[i].flatten();
		gl.uniform3fv(ray_unifs[i], rays[i].flatten());
	}
	gl.uniform3fv(eye_unif, eye_pos.flatten());
	return raytrace;
}
function buildSceneShader ( ) { var scene_distance_function = "float scene_distance(vec3 x, out int mat){" + "	float dist = 1e32;" + "	mat = -1;" + "	float d = 0.0;" + "	int m = -1;" ; for ( var i = 0 ; i < scene . length ; ++ i ) { scene_distance_function += scene [ i ] . distance ( "x" , "d" , "m" ) ; scene_distance_function += "dist = min(d, dist); mat = dist == d ? m : mat;" ; } scene_distance_function += "return dist;}" ; scene_distance_function += "float scene_distance(vec3 x){" + "	float dist = 1e32;" + "	float d = 0.0;" ; for ( var i = 0 ; i < scene . length ; ++ i ) { scene_distance_function += scene [ i ] . distance ( "x" , "d" ) ; scene_distance_function += "dist = min(d, dist);" ; } scene_distance_function += "return dist;}" ; var sample_lights_function = "vec3 sample_illumination(vec3 p, vec3 w_o, int mat){" + "	vec3 illum = vec3(0);" + "	vec3 li = vec3(0);" + "	vec3 w_i = vec3(0);" ; for ( var i = 0 ; i < lights . length ; ++ i ) { sample_lights_function += lights [ i ] . sample ( "p" , "li" , "w_i" ) ; sample_lights_function += "	if (!shadow_test(w_i, p)){" + "		vec3 normal = normalize(gradient(p));" + "		vec3 tan = vec3(0);" + "		vec3 bitan = vec3(0);" + "		coordinate_system(normal, tan, bitan);" + "		vec3 w_is = vec3(0);" + "		vec3 w_os = vec3(0);" + transform_to_shading_glsl ( "normal" , "tan" , "bitan" , "w_i" , "w_is" ) + transform_to_shading_glsl ( "normal" , "tan" , "bitan" , "w_o" , "w_os" ) + "		illum += shade_material(mat, -w_is, w_os) * li * abs(dot(w_i, normal));" + "	}" ; } sample_lights_function += "	illum.r = clamp(illum.r, 0.0, 1.0);" + "	illum.g = clamp(illum.g, 0.0, 1.0);" + "	illum.b = clamp(illum.b, 0.0, 1.0);" + "	return illum;}" ; var shade_materials_function = "vec3 shade_material(int mat, vec3 w_i, vec3 w_o){" + "	vec3 f = vec3(0);" ; for ( var i = 0 ; i < materials . length ; ++ i ) { shade_materials_function += "if (mat == " + i + "){" + materials [ i ] . shade ( "f" , "w_i" , "w_o" ) + "return f;}" ; } shade_materials_function += "return f;}" ; var ray_fs_src = constants + "precision highp float;" + "uniform float sample;" + "uniform vec3 eye;" + "uniform sampler2D prev_tex;" + "uniform vec2 canvas_dim;" + "varying vec3 px_ray;" + POINT_LIGHT_SAMPLE_GLSL + DIRECT_LIGHT_SAMPLE_GLSL + SPHERE_DISTANCE_GLSL + TORUS_DISTANCE_GLSL + MATERIAL_FUNCTIONS_GLSL + LAMBERTIAN_MATERIAL_GLSL + OREN_NAYAR_MATERIAL_GLSL + shade_materials_function + scene_distance_function + "vec3 gradient(vec3 p){" + "	float h = 0.5 * 0.00001;" + "	float den = 1.0 / (2.0 * h);" + "	float dx = den * (scene_distance(p + vec3(h, 0, 0)) - scene_distance(p - vec3(h, 0, 0)));" + "	float dy = den * (scene_distance(p + vec3(0, h, 0)) - scene_distance(p - vec3(0, h, 0)));" + "	float dz = den * (scene_distance(p + vec3(0, 0, h)) - scene_distance(p - vec3(0, 0, h)));" + "	return vec3(dx, dy, dz);" + "}" + "bool shadow_test(vec3 ray_dir, vec3 ray_orig){" + "	const float max_dist = 1.0e10;" + "	const int max_iter = 20;" + "	float t = 0.001;" + "	int mat = -1;" + "	for (int i = 0; i < max_iter; ++i){" + "		vec3 p = ray_orig + ray_dir * t;" + "		float dt = scene_distance(p);" + "		t += dt;" + "		if (dt <= 1.0e-4){" + "			return true;" + "		}" + "	}" + "	return false;" + "}" + sample_lights_function + "vec3 intersect_scene(vec3 ray_dir, vec3 ray_orig){" + "	const float max_dist = 1.0e10;" + "	const int max_iter = 35;" + "	float t = 0.0;" + "	vec3 pass_color = vec3(0);" + "	int mat = -1;" + "	for (int i = 0; i < max_iter; ++i){" + "		vec3 p = ray_orig + ray_dir * t;" + "		float dt = scene_distance(p, mat);" + "		t += dt;" + "		if (dt <= 5.0e-6){" + "			pass_color = sample_illumination(p, -ray_dir, mat);" + "			break;" + "		}" + "	}" + "	return pass_color;" + "}" + "void main(void){" + "	vec3 ray_dir = normalize(px_ray);" + "	vec3 pass_color = intersect_scene(ray_dir, eye);" + "	vec3 prev_pass = texture2D(prev_tex, gl_FragCoord.xy / canvas_dim).rgb;" + "	gl_FragColor = vec4(prev_pass + (pass_color - prev_pass) / (sample + 1.0), 1.0);" + "}" ; var raytrace = compileShader ( ray_vs_src , ray_fs_src ) ; pos_attrib = gl . getAttribLocation ( raytrace , "pos" ) ; sample_unif = gl . getUniformLocation ( raytrace , "sample" ) ; eye_unif = gl . getUniformLocation ( raytrace , "eye" ) ; var canvas_dim_unif = gl . getUniformLocation ( raytrace , "canvas_dim" ) ; ray_unifs = [ ] ; ray_unifs . push ( gl . getUniformLocation ( raytrace , "ray00" ) ) ; ray_unifs . push ( gl . getUniformLocation ( raytrace , "ray10" ) ) ; ray_unifs . push ( gl . getUniformLocation ( raytrace , "ray01" ) ) ; ray_unifs . push ( gl . getUniformLocation ( raytrace , "ray11" ) ) ; gl . useProgram ( raytrace ) ; gl . uniform2f ( canvas_dim_unif , WIDTH , HEIGHT ) ; eye_pos = new Vec3f ( 0 , 0 , 2 ) ; var rays = perspectiveCamera ( eye_pos , new Vec3f ( 0 , 0 , 0 ) , new Vec3f ( 0 , 1 , 0 ) , 60.0 , WIDTH / HEIGHT ) ; for ( var i = 0 ; i < 4 ; ++ i ) { var vals = rays [ i ] . flatten ( ) ; gl . uniform3fv ( ray_unifs [ i ] , rays [ i ] . flatten ( ) ) ; } gl . uniform3fv ( eye_unif , eye_pos . flatten ( ) ) ; return raytrace ; }
Rebuild scene shader based on the updated scene
Rebuild scene shader based on the updated scene