效果如图(里面的方体):
注意:化学元素围成的圈,后面的透过方体也能看到!!!。
贴图图片:
第一步:shader的编写
顶点着色器:
uniform mat4 uMVPMatrix; //总变换矩阵 uniform mat4 uMMatrix; //变换矩阵 uniform vec3 uLightLocation; //光源位置 uniform vec3 uCamera; //摄像机位置 attribute vec3 aPosition; //顶点位置 attribute vec3 aNormal; //顶点法向量 attribute vec2 aTexCoor; //顶点纹理坐标 //用于传递给片元着色器的变量 varying vec4 vAmbient; varying vec4 vDiffuse; varying vec4 vSpecular; varying vec2 vTextureCoord; //定位光光照计算的方法 void pointLight( //定位光光照计算的方法 in vec3 normal, //法向量 inout vec4 ambient, //环境光最终强度 inout vec4 diffuse, //散射光最终强度 inout vec4 specular, //镜面光最终强度 in vec3 lightLocation, //光源位置 in vec4 lightAmbient, //环境光强度 in vec4 lightDiffuse, //散射光强度 in vec4 lightSpecular //镜面光强度 ){ ambient=lightAmbient; //直接得出环境光的最终强度 vec3 normalTarget=aPosition+normal; //计算变换后的法向量 vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz-(uMMatrix*vec4(aPosition,1)).xyz; newNormal=normalize(newNormal); //对法向量规格化 //计算从表面点到摄像机的向量 vec3 eye= normalize(uCamera-(uMMatrix*vec4(aPosition,1)).xyz); //计算从表面点到光源位置的向量vp vec3 vp= normalize(lightLocation-(uMMatrix*vec4(aPosition,1)).xyz); vp=normalize(vp);//格式化vp vec3 halfVector=normalize(vp+eye); //求视线与光线的半向量 float shininess=50.0; //粗糙度,越小越光滑 float nDotViewPosition=max(0.0,dot(newNormal,vp)); //求法向量与vp的点积与0的最大值 diffuse=lightDiffuse*nDotViewPosition; //计算散射光的最终强度 float nDotViewHalfVector=dot(newNormal,halfVector); //法线与半向量的点积 float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess)); //镜面反射光强度因子 specular=lightSpecular*powerFactor; //计算镜面光的最终强度 } void main() { gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置 vec4 ambientTemp, diffuseTemp, specularTemp; //存放环境光、散射光、镜面反射光的临时变量 pointLight(normalize(aNormal),ambientTemp,diffuseTemp,specularTemp,uLightLocation, vec4(1.0,1.0,1.0,1.0),vec4(1.0,1.0,1.0,1.0),vec4(1.0,1.0,1.0,1.0)); vAmbient=ambientTemp; vDiffuse=diffuseTemp; vSpecular=specularTemp; vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器 }
片元着色器:
precision mediump float; uniform sampler2D sTexture;//纹理内容数据 //接收从顶点着色器过来的参数 varying vec4 vAmbient; varying vec4 vDiffuse; varying vec4 vSpecular; varying vec2 vTextureCoord; void main() { vec4 finalColor=texture2D(sTexture, vTextureCoord); <span style="color:#cc0000;"> finalColor.a=(finalColor.r+finalColor.g+finalColor.b)/3.0;//核心语句!!!!!!!!!!!</span> gl_FragColor = finalColor*vAmbient+finalColor*vSpecular+finalColor*vDiffuse; }
package com.gzdxid.utils; import android.opengl.GLES20; public class DrawCubeTextureLight { private DrawRectTextureLight frontRect = null; private DrawRectTextureLight leftRect = null; private DrawRectTextureLight bottomRect = null; private int flag; private float halfWidth; private float halfHeight; private float halfLength; final float tzz = 0.1f; final float tzs=0.0f; // flag==0:法线朝里;flag==1:法线朝外; public DrawCubeTextureLight(float width,float height,float length,int mProgram, int flag) { frontRect = new DrawRectTextureLight(width, height,mProgram); leftRect=new DrawRectTextureLight(height, length, mProgram); bottomRect=new DrawRectTextureLight(width, length, mProgram); this.flag = flag; this.halfWidth=width/2; this.halfHeight=height/2; this.halfLength=length/2; } // textureId:up-down-left-right-front-back public void drawSelf(int[] textureId) { <span style="color:#ff0000;">GLES20.glDisable(GLES20.GL_DEPTH_TEST);//一定要关闭,不然方体后面的元素看不到</span> switch (flag) { case 0: drawCube0(textureId); break; case 1: drawCube1(textureId); break; } <span style="color:#cc0000;">GLES20.glEnable(GLES20.GL_DEPTH_TEST);</span> } private void drawCube0(int[] textureId) { // TODO Auto-generated method stub // up MatrixState.pushMatrix(); MatrixState.translate(0, halfHeight - tzz, 0); MatrixState.rotate(90, 1, 0, 0); bottomRect.drawSelf(textureId[0]); MatrixState.popMatrix(); // down MatrixState.pushMatrix(); MatrixState.translate(0, -halfHeight + tzz, 0); MatrixState.rotate(-90, 1, 0, 0); bottomRect.drawSelf(textureId[1]); MatrixState.popMatrix(); // left MatrixState.pushMatrix(); MatrixState.translate(-halfWidth + tzz, 0, 0); MatrixState.rotate(90, 0, 1, 0); leftRect.drawSelf(textureId[2]); MatrixState.popMatrix(); // right MatrixState.pushMatrix(); MatrixState.translate(halfWidth - tzz, 0, 0); MatrixState.rotate(-90, 0, 1, 0); leftRect.drawSelf(textureId[3]); MatrixState.popMatrix(); // front MatrixState.pushMatrix(); MatrixState.translate(0, 0, halfLength - tzz); MatrixState.rotate(180, 0, 1, 0); frontRect.drawSelf(textureId[4]); MatrixState.popMatrix(); // back MatrixState.pushMatrix(); MatrixState.translate(0, 0, -halfLength + tzz); frontRect.drawSelf(textureId[5]); MatrixState.popMatrix(); } private void drawCube1(int[] textureId) { // up MatrixState.pushMatrix(); MatrixState.translate(0, halfHeight - tzs, 0); MatrixState.rotate(-90, 1, 0, 0); bottomRect.drawSelf(textureId[0]); MatrixState.popMatrix(); // down MatrixState.pushMatrix(); MatrixState.translate(0, -halfHeight + tzs, 0); MatrixState.rotate(90, 1, 0, 0); bottomRect.drawSelf(textureId[1]); MatrixState.popMatrix(); // left MatrixState.pushMatrix(); MatrixState.translate(-halfWidth + tzs, 0, 0); MatrixState.rotate(-90, 0, 1, 0); leftRect.drawSelf(textureId[3]); MatrixState.popMatrix(); // right MatrixState.pushMatrix(); MatrixState.translate(halfWidth - tzs, 0, 0); MatrixState.rotate(90, 0, 1, 0); leftRect.drawSelf(textureId[2]); MatrixState.popMatrix(); // front MatrixState.pushMatrix(); MatrixState.translate(0, 0, halfLength - tzs); frontRect.drawSelf(textureId[4]); MatrixState.popMatrix(); // back MatrixState.pushMatrix(); MatrixState.translate(0, 0, -halfLength + tzs); MatrixState.rotate(180, 0, 1, 0); frontRect.drawSelf(textureId[5]); MatrixState.popMatrix(); } }
补:画平面代码:
package com.gzdxid.utils; import java.nio.FloatBuffer; import android.opengl.GLES20; //纹理矩形 public class DrawRectTextureLight { int mProgram;//自定义渲染管线着色器程序id int muMVPMatrixHandle;//总变换矩阵引用 int maPositionHandle; //顶点位置属性引用 int maTexCoorHandle; //顶点纹理坐标属性引用 String mVertexShader;//顶点着色器 String mFragmentShader;//片元着色器 FloatBuffer mVertexBuffer;//顶点坐标数据缓冲 FloatBuffer mTexCoorBuffer;//顶点纹理坐标数据缓冲 int vCount=0; public DrawRectTextureLight(float width, float height, int mProgram) { initVertexData(width, height); intShader(mProgram); } //初始化顶点坐标与着色数据的方法 public void initVertexData(float width, float height) { vCount = 6; float w = width / 2; float h = height / 2; float vertices[] = new float[] { -w, h, 0, -w, -h, 0, w, -h, 0, w, -h, 0, w, h, 0, -w, h, 0, }; mVertexBuffer=UtilBufferTransfer.getFloatBuffer(vertices); float texCoor[] = new float[] { 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; mTexCoorBuffer=UtilBufferTransfer.getFloatBuffer(texCoor); } //初始化shader public void intShader(int mProgam) { this.mProgram = mProgam; muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor"); } public void drawSelf(int texId) { GLES20.glUseProgram(mProgram); GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0); GLES20.glVertexAttribPointer ( maPositionHandle, 3, GLES20.GL_FLOAT, false, 3*4, mVertexBuffer ); GLES20.glVertexAttribPointer ( maTexCoorHandle, 2, GLES20.GL_FLOAT, false, 2*4, mTexCoorBuffer ); GLES20.glEnableVertexAttribArray(maPositionHandle); GLES20.glEnableVertexAttribArray(maTexCoorHandle); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount); } }
第三步:应用
<span style="color:#ff0000;"> GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);</span> MatrixState.pushMatrix(); MatrixState.translate(0, 0, offsetZ); MatrixState.rotate(angleRotateCube, 0, 1, 0); MatrixState.rotate(-angleRotateZ, 0, 0, 1); centerCube.drawSelf(cubeId); MatrixState.popMatrix(); <span style="color:#ff0000;">GLES20.glDisable(GLES20.GL_BLEND);</span>