音视频开发之旅(42) - 光照基础(一)

// Specular
float specularStrength = 0.9;//镜面反射强度
vec3 viewDir = normalize(viewPos - fragPos);//归一化的
vec3 reflectDir = reflect(-lightDir, unitNormal);//光线向量和视图向量(可通过视图矩阵转换)之间的夹角正中的方向。称为半角向量
float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0);
specular = specularStrength * spec * lightColor;

二、 实践

为了更好的展示效果,我们立方体的基础上进行环境光照、漫反射光照、镜面反射光照。下面我们依次进行实践。

  1. 画一个立方体 加上图片纹理
  2. 加上环境光
  3. 加上漫反射光
  4. 加上镜面反射光

2.1 画个立方体并且渲染图片纹理

立方体的绘画我们可以采用画六个面的方式,也可以采用画一个面然后采用投影的方式。本篇我们才有后者实现

先来看下着色器, 比较简单,传入顶点坐标、纹理坐标、MVP矩阵以及纹理

//cube_vertex.glsl
precision mediump float;
attribute vec3 aPosition;
attribute vec2 aTexCoord;

uniform mat4 uMatrix;
varying vec2 v_texCoord;

void main()
{
gl_Position = uMatrix * vec4(aPosition,1.0);
v_texCoord = aTexCoord;
}

//cube_fragment.glsl

precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D uTexture;
void main()
{
gl_FragColor = texture2D(uTexture, v_texCoord);
}

接着可以先画一个面,设置每个面上的顶点坐标和纹理坐标,然后根据透视投影变换投影出每个面上的画面。
关键代码如下:
首先确定每个面的顶点坐标和纹理坐标

val vertexData = floatArrayOf(
//position //texture coord
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,

-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,

-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,

0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,

-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,

-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
)
var vertexArrayBuffer = ByteBuffer
.allocateDirect(vertexData.size * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData)
vertexArrayBuffer.position(0)

下面来看下Render的实现

//在onSurfaceChanged 确定好透视投影矩阵和视图投影矩阵。

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
val whRadio = width / (height * 1.0f)
Matrix.setIdentityM(projectionMatrix, 0)
Matrix.perspectiveM(projectionMatrix, 0, 60f, whRadio, 1f, 100f)

Matrix.setIdentityM(viewMatrix,0);
Matrix.setLookAtM(viewMatrix,0,
2f,0f,3f,
0f,0f,0f,
0f,1f,0f)
}

//绘制
override fun onDrawFrame(gl: GL10?) {
//这里由于用到深度测试需要清除GL_DEPTH_BUFFER_BIT
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)

GLES20.glClearColor(0f, 0f, 0f, 1f)

//必须要加深度测试
GLES20.glEnable(GLES20.GL_DEPTH_TEST)

Matrix.setIdentityM(modeMatrix, 0)

//采用旋转的方式,只能采用旋转的方式,进行实现视角变换,达到移动的效果
Matrix.rotateM(modeMatrix, 0, xRotation, 1f, 0f, 0f)
Matrix.rotateM(modeMatrix, 0, yRotation, 0f, 1f, 0f)

Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modeMatrix, 0)
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0)

GLES20.glUseProgram(mProgram)

//传mvp矩阵数据
GLES20.glUniformMatrix4fv(uMatrixLoc, 1, false, mvpMatrix, 0)
//传纹理数据
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, skyBoxTexture)
GLES20.glUniform1i(uTextureLoc, 0)

GLES20.glEnableVertexAttribArray(aPositionLoc)
cubeLight.vertexArrayBuffer.position(0);
GLES20.glVertexAttribPointer(aPositionLoc, CubeLight.POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, CubeLight.STRIDE, cubeLight.vertexArrayBuffer)

GLES20.glEnableVertexAttribArray(aTextureCoorLoc)
cubeLight.vertexArrayBuffer.position(CubeLight.POSITION_COMPONENT_COUNT);
GLES20.glVertexAttribPointer(aTextureCoorLoc, CubeLight.POSITION_TEXTURE_COUNT, GLES20.GL_FLOAT, false, CubeLight.STRIDE, cubeLight.vertexArrayBuffer)

cubeLight.vertexArrayBuffer.position(0);

GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,36)
}

具体介绍请看代码注释。完整代码已上传至 github github.com/ayyb1988/me…

资料

《OpenGL编程指南》

基础光照
探究OpenGL光照模型的着色器实现
OpenGL_ES-光照(光照基础,漫反射,镜面反射)

最后

我的面试经验分享可能不会去罗列太多的具体题目,因为我依然认为面试经验中最宝贵的不是那一个个具体的题目或者具体的答案,而是结束面试时,那一刻你的感受以及多天之后你的回味~

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值