OpenGL系列之九:glsl着色器语言
2022-11-29 本文已影响0人
itfitness
目录
相关文章
OpenGL系列之一:OpenGL第一个程序
OpenGL系列之二:绘制三角形
OpenGL系列之三:三角形顶点增加颜色
OpenGL系列之四:绘制四边形
OpenGL系列之五:绘制点和线
OpenGL系列之六:绘制立方体
OpenGL系列之七:纹理贴图
OpenGL系列之八:立方体纹理贴图
实现效果
实现步骤
1.编写glsl文件
glsl是着色器语言,分为顶点着色器和片元着色器,具体的话我这也不过多介绍了,因为目前我也初学,可以参考以下连接:
https://gitcode.net/mirrors/wshxbqq/GLSL-Card?utm_source=csdn_github_accelerator
https://thebookofshaders.com/?lan=ch
http://www.tastones.com/stackoverflow/glsl/getting-started-with-glsl/first_ogl_4.0_glsl_shader_program/
这里我编写的比较简单,如下所示:
顶点着色器vertex.vert
#version 300 es //指定OpenglES 版本
//需要C代码传入的两个变量
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec4 a_color;
//需要C代码传入的矩阵
uniform mat4 u_mat;
//输出的变量(给片元着色器使用)
out vec4 o_color;
void main(void)
{
//可以通过这里修改颜色值来改变颜色
o_color = vec4(a_color.r,a_color.g,a_color.b,a_color.a);
gl_Position = u_mat * a_position;
}
片元着色器fragment.frag
#version 300 es //指定OpenglES 版本
//指定精度
precision mediump float;
//顶点着色器输出的,变量名需要相同
in vec4 o_color;
//片元着色器输出的,在本案例里就是渲染的颜色
out vec4 fragColor;
void main(void)
{
fragColor = o_color;
}
2.加载glsl文件
这里进行了封装,基本都是固定的,基本就是加载、连接、设置变量等等,以后也可以直接使用,所以就不过多解释了。
CCOpenGLShader.h
#ifndef CCOPENGLES_CCOPENGLSHADER_H
#define CCOPENGLES_CCOPENGLSHADER_H
#include "CCGLPrimitivesDef.h"
class CCOpenGLShader {
public:
CCOpenGLShader();
~CCOpenGLShader();
void Bind();
void Release();
void InitShadersFromFile(AAssetManager* pManager, const char* vShader,const char* fshader);
void DisableAttributeArray(const char *name);
void EnableAttributeArray(const char *name);
void SetAttributeBuffer(const char* name,GLenum type, const void *values, int tupleSize, int stride = 0);
void SetUniformValue(const char* name, int iValue);
void SetUniformValue(const char* name, GLfloat fValue);
void SetUniformValue(const char* name, glm::vec3 vecValue);
void SetUniformValue(const char* name, glm::mat4 matValue);
private:
int compileShader(AAssetManager* m_pAssetManager,const char* sPath, GLint sType);
private:
GLuint m_shaderProgram;
};
#endif //CCOPENGLES_CCOPENGLSHADER_H
CCOpenGLShader.cpp
#include "CCOpenGLShader.h"
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
CCOpenGLShader::CCOpenGLShader()
{
m_shaderProgram = 0;
}
CCOpenGLShader::~CCOpenGLShader()
{
}
void CCOpenGLShader::InitShadersFromFile(AAssetManager* pManager,const char* vPath, const char* fPath)
{
GLuint vertexId = 0;
GLuint fragId = 0;
vertexId = compileShader(pManager,vPath ,GL_VERTEX_SHADER);
fragId = compileShader(pManager,fPath ,GL_FRAGMENT_SHADER);
char message[512];
int status = 0;
m_shaderProgram = glCreateProgram();
if (vertexId != -1)
{
glAttachShader(m_shaderProgram, vertexId);
}
if (fragId != -1)
{
glAttachShader(m_shaderProgram, fragId);
}
glLinkProgram(m_shaderProgram);
glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &status);
if (!status)
{
glGetProgramInfoLog(m_shaderProgram, 512, NULL, message);
LOGE("Get shaderProgram failed: %s",message);
}
glDeleteShader(vertexId);
glDeleteShader(fragId);
}
int CCOpenGLShader::compileShader(AAssetManager* pManager,const char* fName, GLint sType)
{
AAsset* file = AAssetManager_open(pManager,fName, AASSET_MODE_BUFFER);
size_t shaderSize = AAsset_getLength(file);
char* sContentBuff = (char*)malloc(shaderSize);
AAsset_read(file, sContentBuff, shaderSize);
LOGD("SHADERS: %s",sContentBuff);
unsigned int shaderID = 0;
char message[512]={0};
int status = 0;
shaderID = glCreateShader(sType);
glShaderSource(shaderID, 1, &sContentBuff, (const GLint *)&shaderSize);
glCompileShader(shaderID);
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &status);
if (!status)
{
glGetShaderInfoLog(shaderID, 512, NULL, message);
LOGF("Compile Shader Status failed: %s",message);
}
if(sContentBuff != NULL){
free(sContentBuff);
sContentBuff = NULL;
}
AAsset_close(file);
return shaderID;
}
void CCOpenGLShader::Bind()
{
glUseProgram(m_shaderProgram);
}
void CCOpenGLShader::Release()
{
glUseProgram(0);
}
void CCOpenGLShader::SetUniformValue(const char* name, int iValue)
{
glUniform1i(glGetUniformLocation(m_shaderProgram, name), iValue);
}
void CCOpenGLShader::SetUniformValue(const char* name, GLfloat fValue)
{
glUniform1f(glGetUniformLocation(m_shaderProgram, name), fValue);
}
void CCOpenGLShader::SetUniformValue(const char* name, glm::vec3 vec3Value)
{
glUniform3fv(glGetUniformLocation(m_shaderProgram, name), 1, glm::value_ptr(vec3Value));
}
void CCOpenGLShader::SetUniformValue(const char* name, glm::mat4 matValue)
{
glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, name) , 1 , GL_FALSE , glm::value_ptr(matValue));
}
void CCOpenGLShader::EnableAttributeArray(const char *name)
{
GLuint location = glGetAttribLocation(m_shaderProgram, name);
glEnableVertexAttribArray(location);
}
void CCOpenGLShader::DisableAttributeArray(const char *name)
{
GLuint location = glGetAttribLocation(m_shaderProgram, name);
glDisableVertexAttribArray(location);
}
void CCOpenGLShader::SetAttributeBuffer(const char* name,GLenum type, const void *values, int tupleSize, int stride)
{
GLuint location = glGetAttribLocation(m_shaderProgram, name);
glVertexAttribPointer(location,tupleSize,type,GL_FALSE,stride,values);
}
加载的话是根据文件名,获取到Assets文件夹中的文件
extern "C"
JNIEXPORT void JNICALL
Java_com_itfitness_opengldemo_GLRender_ndkInitGL(JNIEnv *env, jobject thiz, jobject assets) {
ccRender.initGL();
AAssetManager *astManager = AAssetManager_fromJava (env, assets);
ccRender.ccOpenGlShader.InitShadersFromFile(astManager,"vertex.vert","fragment.frag");
}
使用的话基本都是固定的步骤,这里就不贴全部代码了,如下绘制函数所示:
/**
* 画三角
*/
void CCRender::drawTriangle() {
CCFloat7 triangleVert[] ={
{0, 0.5, -3, 1, 0, 0,1.0},
{-0.5, -0.5, -3, 0, 1, 0,1.0},
{0.5, -0.5, -3, 0, 0, 1,1.0},
};
m_angle += 0.03f;
glm::mat4x4 cubeMat;
glm::mat4x4 cubeTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3));
glm::mat4x4 cubeRotMat = glm::rotate(glm::mat4(1.0f),m_angle,glm::vec3(0.0f, 0.0f, -3.0) );
glm::mat4x4 cubeScaleMat = glm::scale(glm::mat4(1.0f),glm::vec3(0.3f, 0.2f, 0.3) );
//透视投影矩阵,跟之前的glOrthof(-1,1,-1,1,0.1,1000);差不多意思,3.0glOrthof这个API没有了
glm::mat4 projMat = glm::perspective(glm::radians(60.0f), (float)9/(float)18, 0.0f, 1000.0f);
cubeMat = projMat * cubeRotMat;
ccOpenGlShader.Bind();
//这里的变量名与glsl中的一样
//传递矩阵数据
ccOpenGlShader.SetUniformValue("u_mat",cubeMat);
//启动顶点变量
ccOpenGlShader.EnableAttributeArray("a_position");
//启动着色变量
ccOpenGlShader.EnableAttributeArray("a_color");
//为变量设置数据
ccOpenGlShader.SetAttributeBuffer("a_position",GL_FLOAT,triangleVert,3,sizeof(CCFloat7));
ccOpenGlShader.SetAttributeBuffer("a_color",GL_FLOAT,&triangleVert[0].r,4,sizeof(CCFloat7));
glDrawArrays(GL_TRIANGLES,0,3);
//关闭顶点变量
ccOpenGlShader.DisableAttributeArray("a_position");
//关闭着色变量
ccOpenGlShader.DisableAttributeArray("a_color");
ccOpenGlShader.Release();
}
3.注意事项
这里与之前的程序不同,使用了opengl es 3.0,其中有些API不能用了与之前程序相比删除了一些API的使用,然后在创建GLSurfaceView的时候也需要指定opengl es 的版本号
val glSurfaceView = GLSurfaceView(this)
glSurfaceView.setEGLContextClientVersion(3)
glSurfaceView.setRenderer(GLRender(this))