ShaderToy & Matlab & OpenGL实现流动Love

0. 效果图

该文章基于https://www.shadertoy.com/view/7l3GDS
嗯,自己稍微把理论推导了下,并在Matlab和OpenGL上实现
先看下现象吧。
基于Matlab
在这里插入图片描述
Matlab上无法做动态的,因为for循环很耗时间,只能做个静态的。

基于OpenGL

动态爱心

1. 数学理论

相关知识:贝塞尔曲线(二次),卡尔丹公式,范盛金公式,欧拉公式
先来看看爱心的公式吧
网址:https://mathworld.wolfram.com/HeartCurve.html
我使用的是
在这里插入图片描述
也即
在这里插入图片描述
是用参数方程来表示的,完整的爱心如图所示
在这里插入图片描述
这里采取的是30个点,t的个数是30个,可以画出完整的爱心,但是为了显示流动的爱心,只能取部分,代码中我取了8个,和shadertoy上保持一致,此时的图像为:
在这里插入图片描述
是不是有了像shadertoy上的雏形了。
OpenGL绘制爱心的原理:求出窗口上每一个像素点位置到爱心的交点(这是最重要的),求出交点后,就可以用它来显示了(经过色调,Gamma校正等等,这些都很简单的)。
现在问题来了,怎么求出像素点位置到爱心的交点;可知,像素点位置到爱心的交点是有无数个的,因为可以基于像素点作无数条射线到爱心,所以,采取获取最近的交点;既然是最近的交点,那么就会想到高中所学----点到直线的距离,垂直最短,但距离公式不适用于本文章(因为本文是贝塞尔曲线,而不是直线)
在这里插入图片描述
如图所示,对于曲线MP,要求点A到MP的最短距离和交点,利用高中的距离公式求出距离和交点不适用。
而上面说过,我们取爱心中的8个点连接成线段,分别求出像素点位置到这7个线段(8个点,7个线段)的距离,但是可以看出,这8个点连接成的爱心棱角分明,没有那么圆滑,所以利用二次贝塞尔曲线获取圆滑的点,就可以使得爱心也圆滑;同时也可以求出最近的交点。
二次贝塞尔曲线:嗯,这个大家网上自己搜,资料很多的。
我这里就直接写它的方程
在这里插入图片描述
现令窗口上任意一像素点位置为M,求出点M到贝塞尔曲线方程P(t)的交点。
方法:对P(t)求导,曲线的导数表示它的切线,对于屏幕上任意位置的点M来说,M到曲线上最近的点是该点的垂线,可用点乘为0的性质求交点,如图所示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上是推导的全部过程,附带卡尔丹公式盛金公式的资料链接
https://www.zhihu.com/question/300431578/answer/523083159

2. Matlab仿真

嗯,就是在Matlab上稍微写点代码,要知道在shadertoy或者glsl中,都内置了相关函数,比如clamp,fract,smoothstep函数等等,但是在Matlab上就没有,也就是说这需要我们自己在matlab写。(嗯,因为没有Matlab的代码块,我就用C++的),以下是Matlab绘制动态爱心所用的所有.m文件。至于函数的作用是什么,学了一丢丢Matlab和glsl语法的都知道,我这里不多解释,就把重要的写了注释。
clamp.m

function [result] = clamp(input, minvalue, maxvalue)
    result = min(max(input, minvalue), maxvalue);
end

fract.m

function [result] = fract(input)
    result = input - floor(input);
end

smoothstep.m

function [result] = smoothstep(edge0, edge1, input)
    temp = clamp((input - edge0) / (edge1 - edge0), 0.0, 1.0);
%     result = temp .* temp .* (3.0 - 2 .* temp);
    result = temp;
end

GetGlow.m

function [result] = GetGlow(dist, radius, intensity)
    result = power(dist * radius, intensity);
end

getHeartPosition.m

function [x, y] = getHeartPosition(i, t, offset, len, speed)
    input = offset + i * len + fract(speed * t) * 6.28;
    x = 16 * sin(input) .* sin(input) .* sin(input);
    y = 13 * cos(input) - 5 * cos(2 * input) - 2 * cos(3 * input) - cos(4 * input);
end

GetDistance.m

function [result] = GetDistance(p0, p1)
    result = sqrt(sum((p0 - p1) .* (p0 - p1)));
end

GetMinIndex.m

function [result] = GetMinIndex(input)
    result = 1;
    [row, col] = size(input);
    len = row * col;
    dis = zeros(1, len);
    for i = 1:1:len
        data = input{i, 1};
        dis(1, i) = sqrt(sum(data .* data));
    end
    [~, result] = find(dis == min(min(dis)));
    
end

sdBesizer.m,这是最核心的,所写的代码和上述的推导一致,有兴趣的可以推导看看。

function [Realresult, ptResult, beta] = sdBezier(M, P0, P1, P2)
    Realresult = 0.0;
    ptResult = zeros(1, 2);
    % M = pos
    A = P1 - P0;
    B = P0 - 2.*P1 + P2;
    P0MinusM = P0 - M;
    
    a = dot(B, B);
    b = 3 * dot(A, B);
    c = 2 * dot(A, A) + dot(P0MinusM, B);
    d = dot(A, P0MinusM);
    
    d3 = 1 / 3;
    d27 = 1 / 27;
    bDiva = b / a;
    cDiva = c / a;
    dDiva = d / a;
    
    p = cDiva - bDiva * bDiva * d3;
    q = 2 * bDiva * bDiva * bDiva * d27 - bDiva * cDiva * d3 + dDiva;
    
    delta = q * q + 4 * p * p * p * d27;
    result = 0.0;
    beta = 0;
    if(delta >= 0.0)
%         disp('>=0');
        beta = 1;
        h = sqrt(delta);             % h > 0
        x = [h - q, -h - q] ./ 2;
        uv = sign(x) .* power(abs(x), [d3, d3]);
        t = uv(1, 1) + uv(1, 2) - b / (3 * a);
        t = clamp(t, 0.0, 1.0);
        
        pt = t .* t .* B + 2 .* A .* t + P0;
        result = sqrt(sum((M - pt) .* (M - pt)));
        ptResult = pt;
        
    else
%         disp('<0');
        beta = -1;
        PI = 3.1415926;
        sqrtP = sqrt(-p / 3);
        insideL = acos(3 * q / (2 * p) / sqrtP) / 3;
        t = [cos(insideL), cos(insideL - 2 * PI / 3), cos(insideL - 4 * PI / 3)] .* 2 .* sqrtP - b / (3 * a);
        t = clamp(t, 0.0, 1.0);
        
        pt = t(1, 1) .* t(1, 1) .* B + 2 .* A .* t(1, 1) + P0;
        temp = sqrt(sum((M - pt) .* (M - pt)));
        
        dist = temp;
        pt = t(1, 2) .* t(1, 2) .* B + 2 .* A .* t(1, 2) + P0;
        temp = sqrt(sum((M - pt) .* (M - pt)));
        dist = min(dist, temp);
        
        pt = t(1, 3) .* t(1, 3) .* B + 2 .* A .* t(1, 3) + P0;
        temp = sqrt(sum((M - pt) .* (M - pt)));
        dist = min(dist, temp);
        
        result = dist;
        A = {t(1, 1) .* t(1, 1) .* B + 2 .* A .* t(1, 1) + P0,
             t(1, 2) .* t(1, 2) .* B + 2 .* A .* t(1, 2) + P0,
             t(1, 3) .* t(1, 3) .* B + 2 .* A .* t(1, 3) + P0};
        ptIndex = GetMinIndex(A);
        ptResult = A{ptIndex, 1};
    end
    temp = [0.0, result];
    Realresult = max(temp);
end

TestLightDistance.m 运行的脚本文件


speed = -0.5;
len = 0.25;
point_count = 8;
scale = 0.012;      % 缩放系数
thickness = 0.0035;
eps = 1e-10;
light = 0.0;
intensity = 1.3;
radius = 0.012; %0.015;

iWidth = 50;
iHeight = 50;
WH = 50;
lightLocationMatrix = cell(iWidth, iHeight);
lightMatrix = zeros(iWidth, iHeight);

for i = 1:1:iHeight
    for j = 1:1:iWidth
        x = (j - 1 - iWidth / 2);
        y = (iHeight / 2 - i + 1);
        lightLocationMatrix{i, j} = [x, y] / WH;
    end
end

% 静态爱心
x = zeros(1, point_count);
y = zeros(1, point_count);
outputX = zeros(1, iWidth * iHeight * (point_count - 1));
outputY = zeros(1, iWidth * iHeight * (point_count - 1));

x_1 = zeros(1, point_count);
y_1 = zeros(1, point_count);
outputX_1 = zeros(1, iWidth * iHeight * (point_count - 1));
outputY_1 = zeros(1, iWidth * iHeight * (point_count - 1));

for i = 1:1:point_count
    [output_x, output_y] = getHeartPosition(i, 0, 0.7, len, -0.25);
    x(1, i) = output_x;
    y(1, i) = output_y;
end

c = ([x(1, 1), y(1, 1)] + [x(1, 2), y(1, 2)]) ./ 2;
originalpoint = [0, 0];

% 从左到右 从上到下
for row = 1:1:iHeight
    for col = 1:1:iWidth
        light = 0.0;
        d = 0.0;
        c = ([x(1, 1), y(1, 1)] + [x(1, 2), y(1, 2)]) ./ 2;
        for i = 1:1:(point_count - 1)
            c_prev = c;
            c = ([x(1, i), y(1, i)] + [x(1, i + 1), y(1, i + 1)]) ./ 2;

            P0 = scale .* c_prev;
            P1 = scale .* [x(1, i), y(1, i)];
            P2 = scale .* c;

            [d, pt, ~]= sdBezier(lightLocationMatrix{row, col}, P0, P1, P2);
%             [d, pt]= sdBezier(originalpoint, P0, P1, P2);

            index = (col - 1) * (point_count - 1) + i + (point_count - 1) * iHeight * (row - 1);
            outputX(1, index) = pt(1, 1);
            outputY(1, index) = pt(1, 2);
            
            e = 0.0;
            if(i > 1)
                e = GetDistance(lightLocationMatrix{row, col}, P0);
            else
                e = 1000.0;
            end
            light = light +  1 / max(d - thickness, eps);
            light = light - 1 / max(e - thickness, eps);
        end
        glow = GetGlow(light, radius, intensity);
        lightMatrix(row, col) = glow;
    end
end

q14_X = outputX(1, 1:357);
q14_Y = outputY(1, 1:357);
qiuYu7_X = zeros(1, 2500);
qiuYu7_Y = zeros(1, 2500);
qiuYu7Index = 0;
for i = 1:1:size(outputX, 2)
    if(mod(i, 7) == 1)
        qiuYu7Index = qiuYu7Index + 1;
        qiuYu7_X(1, qiuYu7Index) = outputX(1, i);
        qiuYu7_Y(1, qiuYu7Index) = outputY(1, i);
    end
end

figure(1);
imshow(lightMatrix);

% figure(2);
% imshow(TempMatrix, []);

figure(3);
plot( x ,y, 'r') %绘图
xlim([-50, 50]);
ylim([-50, 50]);
set(gca, 'XGrid', 'on');
set(gca, 'YGrid', 'on');

figure(4);
scatter(outputX, outputY,'g');
xlim([-0.5, 0.5]);
ylim([-0.5, 0.5]);
set(gca, 'XGrid', 'on');
set(gca, 'YGrid', 'on');


% figure(5);
% scatter(q14_X, q14_Y,'g');
% xlim([-0.5, 0.5]);
% ylim([-0.5, 0.5]);
% set(gca, 'XGrid', 'on');
% set(gca, 'YGrid', 'on');

运行TestLightDistance.m效果展示图为:
交点图:这就是爱心的由来
在这里插入图片描述
爱心折线图:
在这里插入图片描述
图像:
在这里插入图片描述
不得不说,C++用的多,写Matlab的时候就会觉得很奇怪,懂的都懂。
把位移改下,再把两个图相加就可以得到
在这里插入图片描述

3. GLSL(OpenGL)仿真

1.frag 片段着色器 嗯,其实就是把Shadertoy上的抄过来而已

#version 330 core

precision highp float;
layout(location = 0) out vec4 outColor;
uniform float u_time;
uniform vec2 u_screenSize;

const int POINT_COUNT = 8;
const float speed = -0.5;
const float len = 0.25;
const float scale = 0.012;
float intensity = 1.3;
float radius = 0.012; //0.015;

float thickness = .0035;

float BezierSDF(vec2 M,vec2 P0,vec2 P1,vec2 P2)
{
    vec2 A = P1-P0;
    vec2 B = P2-P1-A;
    vec2 Mp = P0-M;
    float a = dot(B,B);
    float b = 3.*dot(A,B);
    float c = 2.*dot(A,A)+dot(Mp,B);
    float d = dot(A,Mp);
    float d3 = 1./3.;
    float d27 = 1./27.;
    float bda = b/a;
    float cda = c/a;
    float p = cda-bda*bda*d3;
    float q = 2.*bda*bda*bda*d27-d3*bda*cda+d/a;
    float h = q*q+4.*p*p*p*d27;
    float dist = 0.;

    if(h >= 0.)
    {
        h = sqrt(h);
        vec2 x = (vec2(h,-h)-q)/2.;
        vec2 uv = sign(x)*pow(abs(x),vec2(1./3.));
        float t = uv.x+uv.y-b/(3.*a);
        t = clamp(t,0.,1.);
        vec2 pt = t*t*B+2.*A*t+P0;
        dist = length(M-pt);
    }
    else
    {
        float PI = 3.1415926;
        float sqrtP = sqrt(p/-3.);
        float insideL = acos(3.*q/(2.*p)/sqrtP)/3.;
        vec3 t = vec3(cos(insideL),cos(insideL-2.*PI/3.),cos(insideL-4.*PI/3.))*2.*sqrtP-b/(3.*a);
        t = clamp(t,0.,1.);
        vec2 pt = t.x*t.x*B+2.*A*t.x+P0;
        float temp = length(M-pt);
        dist = temp;
        pt = t.y*t.y*B+2.*A*t.y+P0;
        temp = length(M-pt);
        dist = min(dist,temp);
        pt = t.z*t.z*B+2.*A*t.z+P0;
        temp = length(M-pt);
        dist = min(dist,temp);
    }
    return dist;
}

vec2 getHeartPosition(float t)
{
    return vec2(16.0 * sin(t) * sin(t) * sin(t),
                -(13.0 * cos(t) - 5.0 * cos(2.0*t)
                - 2.0 * cos(3.0*t) - cos(4.0*t)));
}

float getGlow(float dist, float radius, float intensity)
{
    return pow(radius*dist, intensity);
}

float getSegment(float t, vec2 pos, float offset)
{
    vec2 points[POINT_COUNT];
	for(int i = 0; i < POINT_COUNT; i++)
    {
        points[i] = getHeartPosition(offset + float(i)*len + fract(speed * t) * 6.28);
    }
    
    vec2 c = (points[0] + points[1]) / 2.0;
    vec2 c_prev;
	float light = 0.;
    const float eps = 1e-10;
    
    for(int i = 0; i < POINT_COUNT-1; i++)
    {
        c_prev = c;
        c = (points[i] + points[i+1]) / 2.0;
        // Distance from bezier segment
        float d = BezierSDF(pos, scale * c_prev, scale * points[i], scale * c);
        // Distance from endpoint (except from first point)
        float e = i > 0 ? distance(pos, scale * c_prev) : 1000.;
        // Convert the distance to light and accumulate
        light += 1. / max(d - thickness, eps);
        // Convert the endpoint as well and subtract
        light -= 1. / max(e - thickness, eps);
    }
    
    return max(0.0, light);
}

void main()
{
    vec2 fragCoord = gl_FragCoord.xy;
    vec2 uv = fragCoord / u_screenSize;
    float widthHeightRatio = u_screenSize.x / u_screenSize.y;

    vec2 center = vec2(0.5, 0.5);
    vec2 pos = center - uv;
    pos.y /= widthHeightRatio;
    pos.y += 0.03;

    float t = u_time;

    float dist_0 = getSegment(t, pos, 0.0);
    float glow_0 = getGlow(dist_0, radius, intensity);
    vec3 col_0 = vec3(0.0);
    col_0 += glow_0 * vec3(1.0,0.05,0.3);

    float dist_1 = getSegment(t, pos, 3.4);
    float glow_1 = getGlow(dist_1, radius, intensity);
    vec3 col_1 = vec3(0.0);
    col_1 += glow_1 * vec3(0.1,0.4,1.0);

    vec3 col = col_0 + col_1;
    col = 1.0 - exp(-col);
    col = pow(col, vec3(0.4545));
    outColor = vec4(col, 1.0);
}

1.vert 顶点着色器

#version 330 core

layout(location = 0) in vec4 a_position;
uniform mat4 u_MVPMatrix;

//out vec3 ourColor;

void main()
{
    gl_Position = a_position;
//    ourColor = aColor;
}

main.cpp 写的比较潦草,能看懂就行

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Shader_Cus.h"
#include <iostream>
#include <math.h>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <sys/timeb.h>
#include <time.h>
#include <sys/timeb.h>
#include <Windows.h>

#define MATH_PI 3.1415926535897932384626433832802

const unsigned int screen_width = 600;
const unsigned int screen_height = 600;


typedef unsigned int uint;

//void UpdateMVPMatrix(glm::mat4& mvpMatrix, int angleX, int angleY, float ratio);

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


	// glfw window creation
	// --------------------
	GLFWwindow* window = glfwCreateWindow(screen_width, screen_height, "LearnOpenGL", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	//glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	// glad: load all OpenGL function pointers
	// ---------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	Shader ourShader("1.vert", "1.frag");

	GLint m_SamplerLoc = GL_NONE;
	GLint m_MVPMatLoc = GL_NONE;
	GLint m_TimeLoc = GL_NONE;
	GLint m_SizeLoc = GL_NONE;

	//m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
	//m_MVPMatLoc = glGetUniformLocation(ourShader.ID, "u_MVPMatrix");
	m_SizeLoc = glGetUniformLocation(ourShader.ID, "u_screenSize");
	m_TimeLoc = glGetUniformLocation(ourShader.ID, "u_time");


	GLfloat verticesCoords[] = {
			-1.0f,  1.0f, 0.0f,  // Position 0
			-1.0f, -1.0f, 0.0f,  // Position 1
			1.0f,  -1.0f, 0.0f,  // Position 2
			1.0f,   1.0f, 0.0f,  // Position 3
	};

	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

	glm::mat4 m_MVPMatrix;
	int m_AngleX = 0;
	int m_AngleY = 0;
	float m_ScaleX = 1.0f;
	float m_ScaleY = 1.0f;

	GLuint m_VaoId, m_VboIds[3];
	// Generate VBO Ids and load the VBOs with data
	glGenBuffers(3, m_VboIds);
	glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(verticesCoords), verticesCoords, GL_STATIC_DRAW);


	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	// Generate VAO Id
	glGenVertexArrays(1, &m_VaoId);
	glBindVertexArray(m_VaoId);

	glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (const void*)0);
	glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);

	//	glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
	//	glEnableVertexAttribArray(1);
	//	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (const void *)0);
	//	glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);

	glBindVertexArray(GL_NONE);

	while (!glfwWindowShouldClose(window))
	{
		//UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, (float)screen_width / screen_height);

		glUseProgram(ourShader.ID);

		glBindVertexArray(m_VaoId);

		//glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
		float fTime = static_cast<float>(fmod(GetTickCount(), 2000) / 2000);
		float fTime1 = static_cast<float>(glfwGetTime());

		//std::cout << "fTime1: " << fTime1 << std::endl;

		glUniform1f(m_TimeLoc, fTime1);
		glUniform2f(m_SizeLoc, screen_width, screen_height);

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void*)0);
		//交换缓冲并且检查是否有触发事件(比如键盘输入、鼠标移动)
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glDeleteProgram(ourShader.ID);
	glDeleteBuffers(3, m_VboIds);
	glDeleteVertexArrays(1, &m_VaoId);

	glfwTerminate();
	return 0;
}

Shader_Cus.h OpenGL相关

#pragma once

#ifndef SHADER_H
#define SHADER_H

#include <glad/glad.h>
#include <glm/glm.hpp>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

class Shader
{
public:
    unsigned int ID;
    // constructor generates the shader on the fly
    // ------------------------------------------------------------------------
    Shader(const char* vertexPath, const char* fragmentPath)
    {
        // 1. retrieve the vertex/fragment source code from filePath
        std::string vertexCode;
        std::string fragmentCode;
        std::ifstream vShaderFile;
        std::ifstream fShaderFile;
        // ensure ifstream objects can throw exceptions:
        vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        try
        {
            // open files
            vShaderFile.open(vertexPath);
            fShaderFile.open(fragmentPath);
            std::stringstream vShaderStream, fShaderStream;
            // read file's buffer contents into streams
            vShaderStream << vShaderFile.rdbuf();
            fShaderStream << fShaderFile.rdbuf();
            // close file handlers
            vShaderFile.close();
            fShaderFile.close();
            // convert stream into string
            vertexCode = vShaderStream.str();
            fragmentCode = fShaderStream.str();
        }
        catch (std::ifstream::failure& e)
        {
            std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl;
        }
        const char* vShaderCode = vertexCode.c_str();
        const char* fShaderCode = fragmentCode.c_str();
        // 2. compile shaders
        unsigned int vertex, fragment;
        // vertex shader
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, NULL);
        glCompileShader(vertex);
        checkCompileErrors(vertex, "VERTEX");
        // fragment Shader
        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, NULL);
        glCompileShader(fragment);
        checkCompileErrors(fragment, "FRAGMENT");
        // shader Program
        ID = glCreateProgram();
        glAttachShader(ID, vertex);
        glAttachShader(ID, fragment);
        glLinkProgram(ID);
        checkCompileErrors(ID, "PROGRAM");
        // delete the shaders as they're linked into our program now and no longer necessary
        glDeleteShader(vertex);
        glDeleteShader(fragment);
    }
    // activate the shader
    // ------------------------------------------------------------------------
    void use()
    {
        glUseProgram(ID);
    }
    // utility uniform functions
    // ------------------------------------------------------------------------
    void setBool(const std::string& name, bool value) const
    {
        glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
    }
    // ------------------------------------------------------------------------
    void setInt(const std::string& name, int value) const
    {
        glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
    }
    // ------------------------------------------------------------------------
    void setFloat(const std::string& name, float value) const
    {
        glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
    }
    // ------------------------------------------------------------------------
    void setVec2(const std::string& name, const glm::vec2& value) const
    {
        glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec2(const std::string& name, float x, float y) const
    {
        glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
    }
    // ------------------------------------------------------------------------
    void setVec3(const std::string& name, const glm::vec3& value) const
    {
        glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec3(const std::string& name, float x, float y, float z) const
    {
        glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
    }
    // ------------------------------------------------------------------------
    void setVec4(const std::string& name, const glm::vec4& value) const
    {
        glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
    }
    void setVec4(const std::string& name, float x, float y, float z, float w) const
    {
        glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
    }
    // ------------------------------------------------------------------------
    void setMat2(const std::string& name, const glm::mat2& mat) const
    {
        glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }
    // ------------------------------------------------------------------------
    void setMat3(const std::string& name, const glm::mat3& mat) const
    {
        glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }
    // ------------------------------------------------------------------------
    void setMat4(const std::string& name, const glm::mat4& mat) const
    {
        glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
    }

private:
    // utility function for checking shader compilation/linking errors.
    // ------------------------------------------------------------------------
    void checkCompileErrors(unsigned int shader, std::string type)
    {
        int success;
        char infoLog[1024];
        if (type != "PROGRAM")
        {
            glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
            }
        }
        else
        {
            glGetProgramiv(shader, GL_LINK_STATUS, &success);
            if (!success)
            {
                glGetProgramInfoLog(shader, 1024, NULL, infoLog);
                std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
            }
        }
    }
};
#endif

大概就是这样了,效果图就是最上面的;因为环境不一样,若把代码直接粘贴运行,不一定可以运行出来。精髓都在Matlab那里,这个看看就行。

总结

嗯,还可以。本人菜鸡一个,如有错误可指出。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值