opengl es写的第一个立方体

记录一下使用opengl es写的第一个立方体

native-lib.cpp代码

#include "GLInit.h"
#include <assert.h>

extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = nullptr;
    if ((vm->GetEnv((void **) &env, JNI_VERSION_1_6)) != JNI_OK) {
        return JNI_FALSE;
    };
    assert(env);
    if (!GLInit::registerNativeMethods(env)) {
        return JNI_FALSE;
    }
    LOGD("JNI_OnLoad finish");
    return JNI_VERSION_1_6;
}

glinit.cpp代码


#include "GLInit.h"
#include "GLUtils.h"
#include "glm/glm.hpp"
#include "glm/ext.hpp"
#include <GLES2/gl2.h>
#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>

GLuint mProgramm;
GLuint vbo, ibo, textureId;
GLint positionLocation, textcoordLocation;
GLint modleLocation, viewLocation, projectLocation, U_MainTextureLocation;

glm::mat4 identifyMatric = glm::mat4(1.0f);//单位矩阵
glm::mat4 projecttionMatric;//投影矩阵
glm::mat4 viewMatric;//视图变换

float vertexs[] = {
        //face
        1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,
        1.0f, -1.0f, 1.0f, 1.0f, 0.0f,
        //right
        1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
        1.0f, -1.0f, 1.0f, 0.0f, 0.0f,
        1.0f, -1.0f, -1.0f, 1.0f, 0.0f,
        //top
        1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, -1.0f, 0.0f, 1.0f,
        -1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
        1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
        //back
        -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, -1.0f, 0.0f, 1.0f,
        1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
        -1.0f, -1.0f, -1.0f, 1.0f, 0.0f,
        //left
        -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, -1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
        -1.0f, -1.0f, 1.0f, 1.0f, 0.0f,
        //bottow
        1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
        -1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, -1.0f, 0.0f, 0.0f,
        1.0f, -1.0f, -1.0f, 1.0f, 0.0f
};

unsigned int indexs[] = {
        0, 1, 2, 0, 2, 3,
        4, 5, 6, 4, 6, 7,
        8, 9, 10, 8, 10, 11,
        12, 13, 14, 12, 14, 15,
        16, 17, 18, 16, 18, 19,
        20, 21, 22, 20, 22, 23
};

void loadTexure();

GLuint creatTexture(unsigned char *bmp, long width, long height);

bool GLInit::registerNativeMethods(JNIEnv *pEnv) {
    jclass jclass1 = nullptr;
    jclass1 = pEnv->FindClass(GL_LOAD_CLASS);
    if (jclass1 == nullptr)
        return JNI_FALSE;
    jint registerNatives = pEnv->RegisterNatives(
            jclass1, jniNativeMethods, sizeof(jniNativeMethods) / sizeof(jniNativeMethods[0]));
    if (registerNatives < 0)
        return JNI_FALSE;
    return JNI_TRUE;
}

void init(JNIEnv *env, jclass type, jobject assets) {
    JavaVM *javaVM;
    env->GetJavaVM(&javaVM);
    AAssetManager *assetManager = AAssetManager_fromJava(env, assets);
    GLUtils::setParameter(env, javaVM, assets, assetManager);
    //loadTexure();
}

void loadTexure() {
    if (!GL_TRUE) {
        textureId = GLUtils::loadTexture("cube.png");
    } else {
        char *content = GLUtils::readFile("wood.bmp");
//        char *content = GLUtils::readFile("earth.bmp");
        long width = 0, height = 0;
        unsigned char *bmp = GLUtils::decodeBMP(content, width, height);
        textureId = creatTexture(bmp, width, height);
        delete content;
    }
}

GLuint creatTexture(unsigned char *bmp, long width, long height) {
    GLuint textureId;
    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    //GLenum target,    GL_TEXURE_2D
    // GLint level,     bitmap level
    // GLint internalformat,    像素格式
    // GLsizei width,       宽度
    // GLsizei height,      高度
    // GLint border,
    // GLenum format,       数据源格式
    // GLenum type,         数据源每一个point类型unsined char 即byte
    // const void *pixels   文理数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, bmp);
    glBindTexture(GL_TEXTURE_2D, 0);
    return textureId;
}

void onSurfaceCreated() {
    mProgramm = GLUtils::CreatProgramm();
    if (mProgramm == 0) {
        LOGD("creat programm failed");
        return;
    }
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);//指定剔出操作的多边形面 本函数可以禁用多边形正面或背面上的光照、阴影和颜色计算及操作,消除不必要的渲染计算是因为无论对象如何进行旋转或变换
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

    positionLocation = glGetAttribLocation(mProgramm, "position");
    textcoordLocation = glGetAttribLocation(mProgramm, "textcoord");
    modleLocation = glGetUniformLocation(mProgramm, "M");
    viewLocation = glGetUniformLocation(mProgramm, "V");
    projectLocation = glGetUniformLocation(mProgramm, "P");
    U_MainTextureLocation = glGetUniformLocation(mProgramm, "U_MainTexture");

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    size_t verlength = sizeof(vertexs) / sizeof(vertexs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * verlength, vertexs, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    size_t fralength = sizeof(indexs) / sizeof(indexs[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * fralength, indexs, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    loadTexure();
}

void onSurfaceChanged(JNIEnv *env, jclass type, jfloat width, jfloat height) {
    LOGD("onSurfaceChanged");
    glViewport(0, 0, width, height);
    projecttionMatric = glm::perspective(90.0f, width / height, 0.1f, 10.0f);

    glm::vec3 vec(0.0f, 0.0f, -3.0f);
    glm::vec3 vec2(1.0f, 1.0f, 0.0f);
    viewMatric = glm::translate(identifyMatric, vec) * glm::rotate(identifyMatric, 45.0f, vec2);
    identifyMatric = glm::mat4(1.0f);
}

void onDrawFrame() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUseProgram(mProgramm);

    glUniformMatrix4fv(modleLocation, 1, GL_FALSE, glm::value_ptr(identifyMatric));
    glUniformMatrix4fv(viewLocation, 1, GL_FALSE, glm::value_ptr(viewMatric));
    glUniformMatrix4fv(projectLocation, 1, GL_FALSE, glm::value_ptr(projecttionMatric));
    //纹理
    glBindTexture(GL_TEXTURE_2D, textureId);
    glUniform1i(U_MainTextureLocation, 0);
    //顶点坐标
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray(positionLocation);
    //  哪个      第一个参数指定顶点属性位置,与顶点着色器中layout(location=0)对应。
    //  坐标由xyz组成        第二个参数指定顶点属性大小。
    //  浮点数             第三个参数指定数据类型。
    // 是否归一化            第四个参数定义是否希望数据被标准化。
    // 数据间隔     (stride 步幅;大步,阔步;进展;一跨) 每个点的数据间隔        第五个参数是步长(Stride),指定在连续的顶点属性之间的间隔。
    //从哪个位置开始           第六个参数表示我们的位置数据在缓冲区起始位置的偏移量。
    glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
    //纹理坐标
    glEnableVertexAttribArray(textcoordLocation);
    glVertexAttribPointer(textcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5,
                          (void *) (sizeof(float) * 3));
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //第一个参数表示绘制的类型,有三种取值:
    //GL_TRIANGLES:每三个顶之间绘制三角形,之间不连接;
    //GL_TRIANGLE_FAN:以V0V1V2,V0V2V3,V0V3V4,……的形式绘制三角形;
    //GL_TRIANGLE_STRIP:顺序在每三个顶点之间均绘制三角形。这个方法可以保证从相同的方向上所有三角形均被绘制。以V0V1V2,V1V2V3,V2V3V4……的形式绘制三角形;
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    //第二个参数是我们打算绘制顶点的个数
    size_t length = sizeof(indexs) / sizeof(indexs[0]);
    glDrawElements(GL_TRIANGLES, length, GL_UNSIGNED_INT, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glUseProgram(0);

}

glinit.h 头文件


#include <jni.h>
#include <android/log.h>

#define TAG "TAG" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型

#ifndef SECONDTRIANGLE_GLINIT_H
#define SECONDTRIANGLE_GLINIT_H
#define GL_LOAD_CLASS "com/vivo/secondtriangle/GLNativeUtils"

 void init(JNIEnv *env, jclass type, jobject assets);

 void onSurfaceCreated();

 void onSurfaceChanged(JNIEnv *env, jclass type, jfloat width, jfloat height);

 void onDrawFrame();

static JNINativeMethod jniNativeMethods[] = {
        {"init",             "(Landroid/content/res/AssetManager;)V", (void *) init},
        {"onSurfaceCreated", "()V",                                    (void *) onSurfaceCreated},
        {"onSurfaceChanged", "(FF)V",                                  (void *) onSurfaceChanged},
        {"onDrawFrame",      "()V",                                    (void *) onDrawFrame}
};

class GLInit {

public:

    static bool registerNativeMethods(JNIEnv *pEnv);

};


#endif //SECONDTRIANGLE_GLINIT_H

glutils 创建programming所用


#include <android/asset_manager_jni.h>
#include "GLUtils.h"

_JNIEnv *env = nullptr;
AAssetManager *assetManager = nullptr;
JavaVM *javaVM = nullptr;
static jobject assets = nullptr;

/**
 * 设置全局参数
 * @param pEnv
 * @param pManager
 */
void GLUtils::setParameter(JNIEnv *pEnv, JavaVM *pVM, jobject asset, AAssetManager *pManager) {
    env = pEnv;
    assets = asset;
    assetManager = pManager;
    javaVM = pVM;
}

/**
 * creat gles programm
 * @return
 */
GLuint GLUtils::CreatProgramm() {
    if (assetManager == nullptr) {
        return GL_FALSE;
    }
    GLuint vertexShader = creatShader(GL_VERTEX_SHADER, cubeVertexShader);
    if (vertexShader == GL_FALSE) {
        return 0;
    }
    GLuint fragmentShader = creatShader(GL_FRAGMENT_SHADER, cubeFragmentShader);
    if (fragmentShader == GL_FALSE) {
        return 0;
    }

    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    glDetachShader(program, vertexShader);
    glDetachShader(program, fragmentShader);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    GLint linkedStatus;
    glGetProgramiv(program, GL_LINK_STATUS, &linkedStatus);
    if (linkedStatus == GL_FALSE) {
        char chars[1024];
        int lenght;
        glGetProgramInfoLog(program, 1024, &lenght, chars);
        LOGD("error create programm:%s", chars);
        glDeleteProgram(program);
        return 0;
    }
    return program;
}


/**
 * 读取assert文件
 * @param pManager
 * @param shaderPath
 * @return
 */
char *GLUtils::readFile(const char *shaderPath) {
    AAsset *aAsset = AAssetManager_open(assetManager, shaderPath, AASSET_MODE_UNKNOWN);
    if (aAsset == nullptr) {
        LOGD("aAsset == nullptr");
        return nullptr;
    }
    off_t length = AAsset_getLength(aAsset);
    char *chars = new char[length + 1];
    AAsset_read(aAsset, chars, length);
    chars[length] = '\0';
    AAsset_close(aAsset);
//    LOGD("%s", chars);
    return chars;
}

/**
 * 创建shader
 * @param shadeType
 * @param shaderPath
 * @param pManager
 * @return
 */
GLuint GLUtils::creatShader(int shadeType, const char *shaderPath) {
    const char *vertexShaderChars = readFile(shaderPath);
    if (vertexShaderChars == nullptr) {
        LOGD("vertexShaderChars == nullptr");
        return GL_FALSE;
    }
    GLuint shader = glCreateShader(shadeType);
    glShaderSource(shader, 1, &vertexShaderChars, nullptr);
    glCompileShader(shader);
    delete vertexShaderChars;

    GLint complite = -1;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &complite);
    if (complite == GL_FALSE) {
        char chars[1024];
        GLint length;
        //shader
        //緩衝區
        //讀到的長度 真實的日志大小
        //日志放哪
        glGetShaderInfoLog(shader, 1024, &length, chars);
        //打印
        LOGD("error creat shader:%s", chars);
        glDeleteShader(shader);
        return 0;
    }
    LOGD("creat shader success:%d", shader);
    return shader;
}

/**
 * java 层获取textureID 并返回  不用解码图片,java用bitmap
 * @param filePath
 * @return
 */
GLuint GLUtils::loadTexture(const char *filePath) {
    if (javaVM->AttachCurrentThread(&env, NULL) != JNI_OK) {
        return GL_FALSE;
    }
    jclass pJclass = env->FindClass(java_utils_path);
    if (pJclass == NULL) {
        LOGD("can't find class");
        return GL_FALSE;
    }
    //第三个参数为  方法参数类型以及返回值
    jmethodID pJmethodID = env->GetStaticMethodID(pJclass, "loadTexture",
                                                  "(Landroid/content/res/AssetManager;Ljava/lang/String;)I");
    if (pJmethodID == NULL) {
        LOGD("can't find methodId");
        return GL_FALSE;
    }
    jstring pJstring = env->NewStringUTF(filePath);
    LOGD("env:%p,assets:%p", env, assets);
    GLuint textureId = env->CallStaticIntMethod(pJclass, pJmethodID,
                                                assets, pJstring);
    env->DeleteLocalRef(pJstring);
    LOGD("loadTexture finish");
    return textureId;
}

/**
 * 解码bmp
 * @param bmpData
 * @param width
 * @param height
 * @return
 */
unsigned char *GLUtils::decodeBMP(char *bmpData, long &width, long &height) {
    //要读四个字节  如果是八个字节要转为int
    LOGD("long size:%ld,unsigned long size:%ld", sizeof(long), sizeof(unsigned long));
    //0x4D42 bmp标准   offset 0 :bmptype :unsigned short
    if (0x4D42 == (*(unsigned short *) bmpData)) {
        //offset 10:bmptype:unsined long    ->imagedate offset
        unsigned long imageStartLengh = *(unsigned long *) (bmpData + 10);
        //offset 18 :width long -> image width
        width = *(long *) (bmpData + 18);
        //offset 22 :height long -> image width
        height = *(long *) (bmpData + 22);
        LOGD("decodeBMP size:%ld,width:%ld,height:%ld", imageStartLengh, width, height);
        unsigned char *imageData = (unsigned char *) (bmpData + imageStartLengh);
        for (int i = 0; i < width * height * 3; i += 3) {
            //BRG 转为 RGB
            unsigned char temp = imageData[i];
            imageData[i] = imageData[i + 2];
            imageData[i + 2] = temp;
        }
        return imageData;
    } else {
        LOGD("不是bmp格式");
        return nullptr;
    }
}

在里面还是用到了jni条用java方法 创建纹理并返回纹理坐标。这样就不用解码图片,java直接用的bitmap

package com.vivo.secondtriangle;

import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;

/**
 * date:2018/12/20:11:25
 * describe:
 */
public class GLESUtils {

    public static int loadTexture(AssetManager manager, String path) {
        InputStream in = null;
        try {
            in = manager.open(path);
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
        BitmapFactory.Options op = new BitmapFactory.Options();
        op.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap bmp = BitmapFactory.decodeStream(in, null, op);

        // generate textureID
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        int textureID = textures[0];

        // create texture
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
        GLES20.glTexParameteri(
                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(
                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
                GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
                GLES20.GL_CLAMP_TO_EDGE);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        // clean up
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            bmp.recycle();
        }
        return textureID;
    }

}

fragmentshader

varying vec2 V_Textcoord;
uniform sampler2D U_MainTexture;

void main() {
       gl_FragColor = texture2D(U_MainTexture,V_Textcoord);
}

vertexshader

uniform mat4 M;
uniform mat4 V;
uniform mat4 P;

attribute vec3 position;
attribute vec2 textcoord;
varying vec2 V_Textcoord;

void main() {
    V_Textcoord = textcoord;
    gl_Position = P*V*M*vec4(position,1.0);
}

 

 

 

glsl 查找的一些api资料

GLSL中只可以使用一维的数组。

修饰符	描述
const	常量值必须在声明是初始化。它是只读的不可修改的。
attribute	表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体
uniform	一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
varying	顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
centorid varying	在没有多重采样的情况下,与varying是一样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。
invariant	(不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。
in	用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符
out	用在函数的参数中,表示该参数是输出参数,值是会改变的。
inout	用在函数的参数,表示这个参数即是输入参数也是输出参数。

内置变量(内置变量可以与固定函数功能进行交互。在使用前不需要声明)

顶点着色器可用的内置变量如下表:
名称	类型	描述
gl_Color	vec4	输入属性-表示顶点的主颜色
gl_SecondaryColor	vec4	输入属性-表示顶点的辅助颜色
gl_Normal	vec3	输入属性-表示顶点的法线值
gl_Vertex	vec4	输入属性-表示物体空间的顶点位置
gl_MultiTexCoordn	vec4	输入属性-表示顶点的第n个纹理的坐标
gl_FogCoord	float	输入属性-表示顶点的雾坐标
gl_Position	vec4	输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
gl_ClipVertex	vec4	输出坐标,用于用户裁剪平面的裁剪
gl_PointSize	float	点的大小
gl_FrontColor	vec4	正面的主颜色的varying输出
gl_BackColor	vec4	背面主颜色的varying输出
gl_FrontSecondaryColor	vec4	正面的辅助颜色的varying输出
gl_BackSecondaryColor	vec4	背面的辅助颜色的varying输出
gl_TexCoord[]	vec4	纹理坐标的数组varying输出
gl_FogFragCoord	float	雾坐标的varying输出

片段着色器的内置变量如下表:
名称	类型	描述
gl_Color	vec4	包含主颜色的插值只读输入
gl_SecondaryColor	vec4	包含辅助颜色的插值只读输入
gl_TexCoord[]	vec4	包含纹理坐标数组的插值只读输入
gl_FogFragCoord	float	包含雾坐标的插值只读输入
gl_FragCoord	vec4	只读输入,窗口的x,y,z和1/w
gl_FrontFacing	bool	只读输入,如果是窗口正面图元的一部分,则这个值为true
gl_PointCoord	vec2	点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。
gl_FragData[]	vec4	使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。
gl_FragColor	vec4	输出的颜色用于随后的像素操作
gl_FragDepth	float	输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替

向量中单独的成分可以通过{x,y,z,w},{r,g,b,a}或者{s,t,p,q}的记法来表示。
这些不同的记法用于顶点,颜色,纹理坐标。在成分选择中,你不可以混合使用这些记法。其中{s,t,p,q}中的p替换了纹理的r坐标,因为与颜色r重复了

函数
在每个shader中必须有一个main函数。main函数中的void参数是可选的,但返回值是void时必须的。
GLSL中的函数,必须是在全局范围定义和声明的。不能在函数定义中声明或定义函数。函数必须有返回类型,参数是可选的。参数的修饰符(in, out, inout, const等)是可选的。
结构体和数组也可以作为函数的参数。如果是数组作为函数的参数,则必须制定其大小。在调用传参时,只传数组名就可以了。
GLSL中函数递归是不被允许的。其行为是未定义的。

内建函数
三角函数
下标用anyFloat来表示float、vec2、vec3和vec4中的一种:

三角函数
函数	描述
anyFloat radians(anyFloat degrees)	将角度值转化为弧度值
anyFloat degrees(anyFloat radians)	将弧度值转化为角度值
anyFloat sin(anyFloat angle)	三角正弦
anyFloat cos(anyFLoat angle)	三角余弦
anyFloat tan(anyFLoat angle)	三角正切
anyFloat asin(anyFloat x)	反正弦
anyFloat acos(anyFloat x)	反余弦
anyFloat atan(anyFloat y,anyFloat x)	y/x的反正切
anyFloat sinh(anyFloat x)	双曲正弦
anyFloat cosh(anyFloat x)	双曲余弦
anyFloat tanh(anyFloat x)	双曲正切
anyFloat asinh(anyFloat x)	反双曲正弦
anyFloat acosh(anyFloat x)	反双曲余弦
anyFloat atanh(anyFloat x)	反双曲正切

指数函数
函数	描述
anyFloat pow(anyFLoat x,anyFloat y)	x的y次方
anyFloat exp(anyFLoat x)	x的自然指数
anyFloat log(anyFloat x)	x的自然对数
anyFloat exp2(anyFloat x)	2的x次方
anyFloat log2(anyFLoat angle)	以2为底的x的自然对数
anyFloat sqrt(anyFloat x)	x的平方根
anyFloat inversesqrt(anyFloat x)

几何函数
函数	描述
float length(vec2/vec3/vec4 x)	返回x向量的长度
float distance(vec p0,vec p1)	返回p0和p1之间的距离
float dot(vec x,vec y)	返回x和y的点乘结果
vec3 cross(vec3 x,vec3 y)	返回x和y的叉乘结果
vec normalize(vec x)	返回和x方向相同的单位长度向量
vec faceforward(vec N,vec I,vec nRef)	如果dot(Nref,l)<0则返回N,否则返回-N
vec reflect(vec l,vec N)	返回入社向量l的反射方向和表面方向N
vec refract(vec vec N,float eta)	返回入射向量l的反射方向、表面方向N和折射指数比eta

矩阵函数
许多矩阵操作都是使用常规数学运算符进行的,不过还有一些有用的矩阵函数:
矩阵函数

函数	描述
mat matrixCompMult(mat x,mat y)	逐个分量地将两个矩阵相乘。这与线性代数的矩阵乘法不同
mat2 outerProduct(vec2 c,vec2 r)	返回一个矩阵,这个矩阵是指定的两个向量的外积(叉乘积)
mat3 outerProduct(vec3 c,vec3 r)
mat4 outerProduct(vec4 c,vec4 r)
mat2X3 outerProduct(vec3 c,vec2 r)
mat3X2 outerProduct(vec2 c,vec3 r)
mat2X4 outerProduct(vec4 c,vec2 r)
mat4X2 outerProduct(vec2 c,vec4 r)
mat3X4 outerProduct(vec4 c,vec3 r)
mat4X3 outerProduct(vec3 c,vec4 r)
mat2 transpose(mat2 m)	返回一个矩阵,这个矩阵是指定就很的转置矩阵
mat3 transpose(mat3 m)
mat4 transpose(mat4 m)
mat2X3 transpose(mat3X2 m)
mat3X2 transpose(mat2X3 m)
mat2X4 transpose(mat4X2 m)
mat4X2 transpose(mat2X4 m)
mat3X4 transpose(mat4X3 m)
mat4X3 transpose(mat3X4 m)
float determinant(mat2 m)	返回一个矩阵,这个矩阵是指定矩阵的行列式
float determinant(mat3 m)
float determinant(mat4 m)
mat2 inverse(mat2 m)	返回一个矩阵,这个矩阵是指定矩阵的逆矩阵
mat3 inverse(mat3 m)
mat4 inverse(mat4 m)

向量相关函数
向量之间的比较,要使用下标列出的这些函数:
向量相关函数

函数	描述
bvec lessThan(vec x,vec y)	逐个分量地返回x
bvec lessThan(ivec x,ivec y)
bvec lessThan(uvec x,uvec y)
bvec lessThanEqual(vec x,vec y)	逐个分量地返回x<=y的结果
bvec lessThanEquea(ivec x,ivec y)
bvec lessThanEqual(uvec x,uvec y)
bvec greaterThan(vec x,vec y)	逐个分量地返回x>y的结果
bvec greaterThan(ivec x,ivec y)
bvec greaterThan(uvec x,uvec y)
bvec greaterThanEqual(vec x,vec y)	逐个分量地返回x>=y的结果
bvec greaterThanEqual (ivec x,ivec y)
bvec greaterThanEqual (uvec x,uvec y)
bvec equal(vec x,vec y)	逐个分量地返回x==y的结果
bvec equal(ivec x,ivec y)
bvec equal(uvec x,uvec y)
bvec notEqual(vec x,vec y)	逐个分量地返回x!=y的结果
bvec notEqual (ivec x,ivec y)
bvec notEqual (uvec x,uvec y)
bool any(bvec x)	如果x的任意分量为真,则返回真
bool all(bvec x)	如果x的所有分量都为真,则返回真
bvec not(bvec x)	返回x的逐个分量的补集

常用函数
所有这些函数都能用于标量和向量数据类型的运算,并且也返回标量和向量数据类型:
矩阵函数 通用函数

函数	描述
anyFloat abs(anyFLoat x)	返回x的绝对值
anyInt abs(anyInt x)
anyFLoat sign(anyFloat x)	返回1.0或-1.0,取决于x
anyInt sign(anyInt x)
anyFloat floor(anyFLoat x)	返回不大于x的最小整数
anyFloat trunc(anyFloat x)	返回不大于x的最接近的整数
anyFloat round(anyFloat x)	返回最接近x的整数的值。如果是小数部分为0.5则可能取任意一个方向的整数(根据具体实现而定)
anyFloat roundEven(anyFloat x)	返回最接近x的整数的值。如果是小数部分为0.5则取最接近的偶数
anyFloat ceil(anyFloat x)	返回大于x的最接近它的整数值
anyFloat fract(anyFloat x)	返回x的小数部分
anyFloat mod(anyFloat x,float y)	返回x对y取余得到的模数
anyFloat mod(anyFloat x,anyFloat y)
anyFloat mod(anyFloat x,out anyFloat l)	返回x的小数部分,并将l设为余下的整数部分的值
anyFloat min(anyFloat x,anyFloat y)	返回x和y中较小的一个
anyFloat min(anyFloat x,anyInt y)
anyInt min(anyInt x,anyInt y)
anyInt min(anyInt x,int y)
anyUInt min(anyUInt x,anyUInt y)
anyUint min(anyUInt x,uint y)
anyFloat max(anyFloat x,anyFloat y)	返回x和y中较大的一个
anyFloat max (anyFloat x,anyInt y)
anyInt max (anyInt x,anyInt y)
anyInt max (anyInt x,int y)
anyUInt max (anyUInt x,anyUInt y)
anyUint max (anyUInt x,uint y)
anyFLoat clamp(anyFLoat x,anyFLoat minVal,anyFLoat maxVal)	返回缩放到minVal到maxVal范围内的x
anyFLoat clamp(anyFLoat x,float minVal,float maxVal)
anyFLoat clamp(anyInt x,anyInt minVal, anyInt maxVal)
anyFLoat clamp(anyInt x,int minVal, int maxVal)
anyFLoat clamp(anyUint x, anyUint minVal, anyUint maxVal)
anyFLoat clamp(anyUint x, uint minVal, uint maxVal)
anyFLoat mix(anyFLoat x,anyFloat y,anyFloat a)	返回x和y的线性混合,a从0到1变化
anyFLoat mix(anyFLoat x,anyFloat y,float a)
anyFloat mix(anyFloat x,anyFLoat y,anyBool a)	在a为假时返回x的各个分量,而在a为真时返回y的各个分量
anyFLoat step(anyFloat edge,anyFloat x)	如果x小于edge则返回0.0或1.0,否则返回1.0
anyFloat step(float edge,anyFloat x)
anyFloat smoothstep(anyFloat edge0,anyFLoat edge1,anyFloat x)	如果x<=edge0则返回0.0,如果x>=edge1则返回1.0,如果在两者之间则在0.0和1.0之间取一个平滑的Hermite插值
anyFloat smoothstep(anyFloat edge0,fLoat edge1,anyFloat x)
anyBool isnan(anyFLoat x)	Returns true ifxis Nan
anyBool isinf(anyFloat x)	如果x为正无穷大或负无穷大,则返回真
anyInt floatBitsToInt(anyFLoat x)	将一个浮点值转换成整数值
anyUint floatBitsToUint(anyFloat x)
anyFLoat intBitsToFloat(anyInt x)	将一个整数值转换成浮点值
anyFLoat uintBitsToFloat(anyUint x)
顶点数组对象:Vertex Array Object,VAO
顶点缓冲对象:Vertex Buffer Object,VBO
索引缓冲对象:Element Buffer Object,EBO或Index Buffer Object,IBO

标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间

GL_STATIC_DRAW :数据不会或几乎不会改变。
GL_DYNAMIC_DRAW:数据会被改变很多。
GL_STREAM_DRAW :数据每次绘制时都会改变。

在GLSL中一个向量有最多4个分量,每个分量值都代表空间中的一个坐标,它们可以通过vec.x、vec.y、vec.z和vec.w来获取。
注意vec.w分量不是用作表达空间中的位置的(我们处理的是3D不是4D),而是用在所谓透视除法(Perspective Division)上。

如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误,记住这点!

纹理坐标的范围通常是从(0, 0)到(1, 1)
环绕方式	描述
GL_REPEAT	对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEAT	和GL_REPEAT一样,但每次重复图片是镜像放置的。
GL_CLAMP_TO_EDGE	纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
GL_CLAMP_TO_BORDER	超出的坐标为用户指定的边缘颜色。


过滤方式	描述
GL_NEAREST_MIPMAP_NEAREST	使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST	使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR	在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR	在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样

一个纹理的位置值通常称为一个纹理单元(Texture Unit)。一个纹理的默认纹理单元是0,它是默认的激活纹理单元,所以教程前面部分我们没有分配一个位置值。
纹理单元GL_TEXTURE0默认总是被激活,所以我们在前面的例子里当我们使用glBindTexture的时候,无需激活任何纹理单元

OpenGL可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值