Page 1 of 1

Problem with normal mapping

Posted: Wed Apr 27, 2016 8:26 am
by Luke100000
Hello,
I am trying to write a shader for normal mapping. It works fine (more or less), but the shape of the light does strange things. Since some parts of the code is copy/paste I am not sure where the problem could be.

Next problem: how can I draw two images at once? I need the diffuse and the normal one at the same time, do I?

I took this as inspiration: viewtopic.php?t=11076

my code takes an image, calculate a hightmap first and then calculates a normalmap. Not professional, but it should work.
use the mouse to move lightning at the first image.

Code: Select all

canvas = {300, 300}

light_canvas = love.graphics.newCanvas(canvas[1], canvas[2])
diffuse_canvas = love.graphics.newCanvas(canvas[1], canvas[2])
heightmap_canvas = love.graphics.newCanvas(canvas[1], canvas[2], "r8")
normal_canvas = love.graphics.newCanvas(canvas[1], canvas[2])

img_diffuse = love.graphics.newImage("diffuse.jpg")

screen = {w = 1200, h = 400}
love.window.setMode(screen.w, screen.h)

function love.load()
	local s = math.max(canvas[1]/img_diffuse:getWidth(), canvas[2]/img_diffuse:getHeight())
	love.graphics.setCanvas(diffuse_canvas)
	love.graphics.draw(img_diffuse, 0, 0, 0, s)
	
	--render heightmmap
	love.graphics.setCanvas(heightmap_canvas)
	love.graphics.setShader(generate_heightmap_shader)
	love.graphics.draw(diffuse_canvas)
	love.graphics.setShader()
	love.graphics.setCanvas()
	
	--render normalmap
	generate_normal_shader:send("size", canvas[1])
	love.graphics.setCanvas(normal_canvas)
	love.graphics.setShader(generate_normal_shader)
	love.graphics.draw(heightmap_canvas)
	love.graphics.setShader()
	love.graphics.setCanvas()
end

function love.draw()
	bumb:send("light_vec", {love.mouse.getX(), love.mouse.getY(), 5})
	local s = (screen.w / 3) / canvas[1]
	
	love.graphics.setShader(bumb)
	love.graphics.setCanvas(light_canvas)
	love.graphics.clear()
	love.graphics.draw(normal_canvas)
	love.graphics.setCanvas()
	love.graphics.setShader()
	
	love.graphics.draw(diffuse_canvas, 0, 0, 0, s)
	love.graphics.setColor(200, 160, 160)
	--love.graphics.rectangle("fill", 0, 0, 400, 400)
	love.graphics.setColor(255, 255, 255)
	love.graphics.draw(light_canvas, 0, 0, 0, s)
	
	love.graphics.setShader(draw_heightmap_shader)
	love.graphics.draw(heightmap_canvas, 300*s, 0, 0, s)
	
	love.graphics.setShader(draw_normal_shader)
	love.graphics.draw(normal_canvas, 600*s, 0, 0, s)
	love.graphics.setShader()
end

generate_heightmap_shader = love.graphics.newShader[[
	vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
	{
		vec4 c = Texel(texture, tc);
		float b = (c[0]+c[1]+c[2]+c[3])/4;
		return vec4(b, 0, 0, 1);
	}
]]

generate_normal_shader = love.graphics.newShader[[
	extern float size;
	vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
	{
		float c1 = Texel(texture, tc + vec2(-1, 0)/size).r;
		float c2 = Texel(texture, tc + vec2(1, 0)/size).r;
		float c3 = Texel(texture, tc + vec2(0, -1)/size).r;
		float c4 = Texel(texture, tc + vec2(0, 1)/size).r;
		
		vec3 x = {2, 0, c2-c1};
		vec3 y = {0, 2, c4-c3};
		return vec4(cross(x, y)*5, 1);
	}
]]

draw_heightmap_shader = love.graphics.newShader[[
	vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
	{
		float c = Texel(texture, tc).r;
		return vec4(c, c, c, 1);
	}
]]

draw_normal_shader = love.graphics.newShader[[
	vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
	{
		vec4 c = Texel(texture, tc);
		return c;
	}
]]

bumb = love.graphics.newShader[[
	extern vec3 light_vec;

	vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
		vec3 light_direction = light_vec - vec3(pixel_coords, 0);
		float distance = length(light_direction);
		light_direction = normalize(light_direction);
		
		vec3 normal = Texel(texture, texture_coords).xyz;
		//normal = normalize(mix(vec3(-1), vec3(1), normal));
		
		float attenuation = 500/pow(distance, 1.2);
		
		float diffuse_term = clamp(attenuation * dot(normal, light_direction), 0.0, 1.0);
		
		vec3 dark_color = vec3(0.0, 0.0, 1);
		vec3 light_color = vec3(0.8, 0.8, 0.0);
		vec3 ambient = mix(dark_color, light_color, diffuse_term) * 0.20;
		
		float cel_diffuse_term = smoothstep(0.49, 0.52, diffuse_term)/2 + 0.5;
		
		vec3 l = cel_diffuse_term * vec3(0.8,0.5,0.6) + ambient;
		return vec4(cel_diffuse_term + ambient, length(cel_diffuse_term));
	}
]]

Re: Problem with normal mapping

Posted: Wed Apr 27, 2016 10:19 am
by cval
Couldn't get your love file to work, it says
err.png
err.png (23.91 KiB) Viewed 3403 times
However, i think you dont really need to draw anything simultaneously. If i get things correctly, you calculate your diffuse in your shader and then draw it as final image.

Here is my old code with normal mapping experiments, hope it helps. You can use arrows to move light around and pgup and pgdown to increase or decrease its height.
shader.love
(1.9 MiB) Downloaded 126 times

Re: Problem with normal mapping

Posted: Wed Apr 27, 2016 10:43 am
by s-ol
You pass one image into the shader with Shader:send and an "extern image" in the shader code.

Re: Problem with normal mapping

Posted: Wed Apr 27, 2016 11:28 am
by Luke100000
cval wrote:Couldn't get your love file to work, it says
err.png
However, i think you dont really need to draw anything simultaneously. If i get things correctly, you calculate your diffuse in your shader and then draw it as final image.

Here is my old code with normal mapping experiments, hope it helps. You can use arrows to move light around and pgup and pgdown to increase or decrease its height.
shader.love
Thanks, it really helped!
s-ol wrote:You pass one image into the shader with Shader:send and an "extern image" in the shader code.
How fast is this? I want to redraw the image every second.

Re: Problem with normal mapping

Posted: Wed Apr 27, 2016 8:40 pm
by s-ol
Luke100000 wrote:
s-ol wrote:You pass one image into the shader with Shader:send and an "extern image" in the shader code.
How fast is this? I want to redraw the image every second.
so? just do. it's not very performance intensive. You should still sort the stuff you draw by texture anyway though (draw everything with texture and normal map A first, then B, then C....)

Re: Problem with normal mapping

Posted: Thu Apr 28, 2016 11:57 am
by Luke100000
Next problem: My shader starts flickering at certain pixels when using the length() function.

Code: Select all

	extern vec3 l;
	
	vec4 effect(vec4 colour, Image tex, vec2 tc, vec2 pixCoord) {
		vec4 norm_txl = Texel(tex,tc);
		vec3 normal = normalize(norm_txl.rgb*2.0-1.0);
		vec3 light_vec = normalize(l-pixCoord);
		float attenuation = min(2/pow(length(l-pixCoord)/32, 2), 2);
		float diffuse = max(dot(normal, light_vec)*attenuation, 0.0);
		
		if (tc.x < 0.5) {
			return vec4(1,1,1,1);
		} else {
			return vec4(diffuse, diffuse, diffuse, 1);
		}
	}

Re: Problem with normal mapping

Posted: Mon Jun 06, 2016 10:18 am
by 4aiman
Sadly,
Снимок экрана_2016-06-06_10-49-56.png
Снимок экрана_2016-06-06_10-49-56.png (23.35 KiB) Viewed 3163 times
:(