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那里,这个看看就行。
总结
嗯,还可以。本人菜鸡一个,如有错误可指出。