利用OpenGL实现线性规划寻找目标函数极值可视化

利用OpenGL实现线性规划寻找目标函数极值可视化

简介

最近一段时间学完了简单的线性规划,今天放假闲着于是就花了一点时间把之前用OpenGL实现的函数图像绘制修改成了线性规划的绘图,并且能实现目标函数极值寻找的可视化。
利用OpenGL实现线性规划寻找目标函数极值可视化
如图这是实现了寻找 z = x^2 + y^2 的最大值的效果

利用OpenGL实现线性规划寻找目标函数极值可视化
这是实现了寻找 z = 2x + y 的最大值。

利用OpenGL实现线性规划寻找目标函数极值可视化
当然,非线性的规划也是很容易的,这是寻找 z = x^3 + y^2 的最大值。

说明

Func函数定义你要绘制的二元不等式组,Target函数定义你要寻找极值的目标函数,Color函数一般不用修改,具体我没时间细说了。

代码

#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif

uniform vec2 resolution;
uniform vec3 pointers[10];
uniform int pointerCount;
uniform float time;

float pi = atan(1.0) * 4.0;

//Implicit / f(x) plotter thing.

//Line thickness (in pixels).
#define LINE_SIZE 2.0

//Grid line & axis thickness (in pixels).
#define GRID_LINE_SIZE 1.0
#define GRID_AXIS_SIZE 2.5

//Number of grid lines per unit.
#define GRID_LINES 1.0

const vec2 GRAD_OFFS = vec2(0.005, 0.0);

#define GRAD(f, p) (vec2(f(p) - f(p + GRAD_OFFS.xy), f(p) - f(p + GRAD_OFFS.yx)) / GRAD_OFFS.xx)

//PLOT(Function, Color, Destination, Screen Position)
#define PLOT(f, c, d, p) d = mix(c(d, p), d, smoothstep(0.0, (LINE_SIZE / resolution.y * zoom), abs(f(p) / length(GRAD(f,p)))))

//XY range of the display.
float zoom = 20.0;
vec2 move = vec2(0.0);

float Func(vec2 p)
{
	return float(!(
		(p.x > 0.2) &&
		(p.x + 2.0 * p.y < 10.0) &&
		(2.0 * p.x - p.y < 10.0)
	));
}

float Target(vec2 p)
{
	return p.x * p.x + p.y * p.y;
}

vec3 Color(vec3 d, vec2 p)
{
	return d * 0.8 * (atan(10.0 + -abs(tan(time))
		* Target(p)) / pi + 0.5) + vec3(1, 0, 1);
}

float grid(vec2 p)
{
	vec2 uv = mod(p,1.0 / GRID_LINES);

	float halfScale = 1.0 / GRID_LINES / 2.0;

	float gridRad = (GRID_LINE_SIZE / resolution.y) * zoom;
	float grid = halfScale - max(abs(uv.x - halfScale), abs(uv.y - halfScale));
	grid = smoothstep(0.0, gridRad, grid);

	float axisRad = (GRID_AXIS_SIZE / resolution.y) * zoom;
	float axis = min(abs(p.x), abs(p.y));
	axis = smoothstep(axisRad - 0.05, axisRad, axis);

	return min(grid, axis);
}


void main(void)
{
	vec2 aspect = resolution.xy
		/ resolution.y / 2.0;

	if (pointerCount < 1) {
		move = resolution.y * aspect;
	} else if (pointerCount == 1) {
		move = pointers[0].xy;
	} else if (pointerCount > 1) {
		zoom *= resolution.y / 4.0 /
			distance(pointers[0], pointers[1]);
		for (int n = 0; n < pointerCount; ++n) {
			move += pointers[n].xy;
		}
		move = move / float(pointerCount);
	}

	vec2 uv = ( (gl_FragCoord.xy - move)
		/ resolution.y );
	uv *= zoom;

	vec3 col = vec3(grid(uv) * 0.25 + 0.75);

    PLOT(Func, Color, col, uv);

	gl_FragColor = vec4(vec3(col), 1.0 );
}