初次提交
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Sample19_3</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" package="com.bn.Sample19_3">
|
||||
<uses-sdk android:minSdkVersion="8" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name="com.bn.Sample19_3.Sample19_3Activity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
precision mediump float;
|
||||
//接收从顶点着色器过来的参数
|
||||
varying vec4 ambient;
|
||||
varying vec4 diffuse;
|
||||
varying vec4 specular;
|
||||
uniform vec4 aColor;
|
||||
void main()
|
||||
{
|
||||
//将计算出的颜色给此片元
|
||||
//vec4 finalColor=vec4(0.9,0.9,0.9,1.0);
|
||||
gl_FragColor = aColor*ambient+aColor*specular+aColor*diffuse;//给此片元颜色值
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Max2Obj Version 4.0 Mar 10th, 2001
|
||||
#
|
||||
# object (null) to come ...
|
||||
#
|
||||
v -30.000000 -0.000002 30.000000
|
||||
v 30.000000 -0.000002 30.000000
|
||||
v -30.000000 0.000002 -30.000000
|
||||
v 30.000000 0.000002 -30.000000
|
||||
# 4 vertices
|
||||
|
||||
g (null)
|
||||
f 3 1 4
|
||||
f 2 4 1
|
||||
# 2 faces
|
||||
|
||||
g
|
||||
@@ -0,0 +1,51 @@
|
||||
uniform mat4 uMVPMatrix; //总变换矩阵
|
||||
uniform mat4 uMMatrix; //变换矩阵
|
||||
uniform vec3 uLightLocation; //光源位置
|
||||
uniform vec3 uCamera; //摄像机位置
|
||||
attribute vec3 aPosition; //顶点位置
|
||||
attribute vec3 aNormal; //顶点法向量
|
||||
//用于传递给片元着色器的变量
|
||||
varying vec4 ambient;
|
||||
varying vec4 diffuse;
|
||||
varying vec4 specular;
|
||||
|
||||
//定位光光照计算的方法
|
||||
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(0.1,0.1,0.1,1.0),vec4(0.7,0.7,0.7,1.0),vec4(0.3,0.3,0.3,1.0));
|
||||
|
||||
ambient=ambientTemp;
|
||||
diffuse=diffuseTemp;
|
||||
specular=specularTemp;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-8
|
||||
@@ -0,0 +1,19 @@
|
||||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f030000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||
*
|
||||
* This class was automatically generated by the
|
||||
* aapt tool from the resource data it found. It
|
||||
* should not be modified by hand.
|
||||
*/
|
||||
|
||||
package com.bn.Sample19_5;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
}
|
||||
public static final class layout {
|
||||
public static final int main=0x7f030000;
|
||||
}
|
||||
public static final class string {
|
||||
public static final int app_name=0x7f040001;
|
||||
public static final int hello=0x7f040000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Sample19_3</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
//用于记录触控点坐标、及绘制触控点的类
|
||||
public class BNPoint
|
||||
{
|
||||
//触控点X、Y坐标
|
||||
float x;
|
||||
float y;
|
||||
public BNPoint(float x,float y)
|
||||
{
|
||||
this.x=x;
|
||||
this.y=y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import static com.bn.Sample19_3.MySurfaceView.*;
|
||||
import static com.bn.Sample19_3.Sample19_3Activity.*;
|
||||
|
||||
public class KeyThread extends Thread
|
||||
{
|
||||
//键盘状态 1-up 2-down 4-left 8-right
|
||||
int keyState=0;
|
||||
boolean flag=true;
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
while(flag)
|
||||
{
|
||||
if((keyState&0x1)!=0)
|
||||
{//按下向前运动的键
|
||||
xOffset-=0.3f;
|
||||
}
|
||||
else if((keyState&0x2)!=0)
|
||||
{//按下向后运动的键
|
||||
xOffset+=0.3f;
|
||||
}
|
||||
if((keyState&0x4)!=0)
|
||||
{//按下向左运动的键
|
||||
yAngle+=2.5f;
|
||||
}
|
||||
else if((keyState&0x8)!=0)
|
||||
{//按下向右运动的键
|
||||
yAngle-=2.5f;
|
||||
}
|
||||
if(yAngle>=360||yAngle<=-360)
|
||||
{
|
||||
yAngle=0;
|
||||
}
|
||||
try
|
||||
{
|
||||
Thread.sleep(30);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
//检测按键,更改比特位
|
||||
public void keyPress(float x,float y)
|
||||
{
|
||||
if(x>=0&&x<screenWidth/2&&y>=0&&y<screenHeight/2)
|
||||
{//向前
|
||||
keyState=keyState|0x1;
|
||||
}
|
||||
else if(x>=screenWidth/2&&x<screenWidth&&y>=0&&y<screenHeight/2)
|
||||
{//向后
|
||||
keyState=keyState|0x2;
|
||||
}
|
||||
else if(x>=0&&x<screenWidth/2&&y>=screenHeight/2&&y<screenHeight)
|
||||
{//向左
|
||||
keyState=keyState|0x4;
|
||||
}
|
||||
else if(x>=screenWidth/2&&x<=screenWidth&&y>=screenHeight/2&&y<=screenHeight)
|
||||
{//向右
|
||||
keyState=keyState|0x8;
|
||||
}
|
||||
}
|
||||
//抬起按键时调用的方法
|
||||
public void keyUp(float x,float y)
|
||||
{
|
||||
if(x>=0&&x<screenWidth/2&&y>=0&&y<screenHeight/2)
|
||||
{//向前
|
||||
keyState=keyState&0xE;
|
||||
}
|
||||
else if(x>=screenWidth/2&&x<screenWidth&&y>=0&&y<screenHeight/2)
|
||||
{//向后
|
||||
keyState=keyState&0xD;
|
||||
}
|
||||
else if(x>=0&&x<screenWidth/2&&y>=screenHeight/2&&y<screenHeight)
|
||||
{//向左
|
||||
keyState=keyState&0xB;
|
||||
}
|
||||
else if(x>=screenWidth/2&&x<=screenWidth&&y>=screenHeight/2&&y<=screenHeight)
|
||||
{//向右
|
||||
keyState=keyState&0x7;
|
||||
}
|
||||
}
|
||||
//所有触控点均抬起时调用的方法,即将keyState值赋值为0
|
||||
public void clearKeyState()
|
||||
{
|
||||
keyState=keyState&0x0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
|
||||
public class LoadUtil
|
||||
{
|
||||
//求两个向量的叉积
|
||||
public static float[] getCrossProduct(float x1,float y1,float z1,float x2,float y2,float z2)
|
||||
{
|
||||
//求出两个矢量叉积矢量在XYZ轴的分量ABC
|
||||
float A=y1*z2-y2*z1;
|
||||
float B=z1*x2-z2*x1;
|
||||
float C=x1*y2-x2*y1;
|
||||
|
||||
return new float[]{A,B,C};
|
||||
}
|
||||
|
||||
//向量规格化
|
||||
public static float[] vectorNormal(float[] vector)
|
||||
{
|
||||
//求向量的模
|
||||
float module=(float)Math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]);
|
||||
return new float[]{vector[0]/module,vector[1]/module,vector[2]/module};
|
||||
}
|
||||
|
||||
//从obj文件中加载携带顶点信息的物体,并自动计算每个顶点的平均法向量
|
||||
public static LoadedObjectVertexNormal loadFromFile(String fname, Resources r,MySurfaceView mv)
|
||||
{
|
||||
//加载后物体的引用
|
||||
LoadedObjectVertexNormal lo=null;
|
||||
//原始顶点坐标列表--直接从obj文件中加载
|
||||
ArrayList<Float> alv=new ArrayList<Float>();
|
||||
//顶点组装面索引列表--根据面的信息从文件中加载
|
||||
ArrayList<Integer> alFaceIndex=new ArrayList<Integer>();
|
||||
//结果顶点坐标列表--按面组织好
|
||||
ArrayList<Float> alvResult=new ArrayList<Float>();
|
||||
//平均前各个索引对应的点的法向量集合Map
|
||||
//此HashMap的key为点的索引, value为点所在的各个面的法向量的集合
|
||||
HashMap<Integer,HashSet<Normal>> hmn=new HashMap<Integer,HashSet<Normal>>();
|
||||
|
||||
try
|
||||
{
|
||||
InputStream in=r.getAssets().open(fname);
|
||||
InputStreamReader isr=new InputStreamReader(in);
|
||||
BufferedReader br=new BufferedReader(isr);
|
||||
String temps=null;
|
||||
|
||||
//扫面文件,根据行类型的不同执行不同的处理逻辑
|
||||
while((temps=br.readLine())!=null)
|
||||
{
|
||||
//用空格分割行中的各个组成部分
|
||||
String[] tempsa=temps.split("[ ]+");
|
||||
if(tempsa[0].trim().equals("v"))
|
||||
{//此行为顶点坐标
|
||||
//若为顶点坐标行则提取出此顶点的XYZ坐标添加到原始顶点坐标列表中
|
||||
alv.add(Float.parseFloat(tempsa[1]));
|
||||
alv.add(Float.parseFloat(tempsa[2]));
|
||||
alv.add(Float.parseFloat(tempsa[3]));
|
||||
}
|
||||
else if(tempsa[0].trim().equals("f"))
|
||||
{//此行为三角形面
|
||||
/*
|
||||
*若为三角形面行则根据 组成面的顶点的索引从原始顶点坐标列表中
|
||||
*提取相应的顶点坐标值添加到结果顶点坐标列表中,同时根据三个
|
||||
*顶点的坐标计算出此面的法向量并添加到平均前各个索引对应的点
|
||||
*的法向量集合组成的Map中
|
||||
*/
|
||||
|
||||
int[] index=new int[3];//三个顶点索引值的数组
|
||||
|
||||
//计算第0个顶点的索引,并获取此顶点的XYZ三个坐标
|
||||
index[0]=Integer.parseInt(tempsa[1].split("/")[0])-1;
|
||||
float x0=alv.get(3*index[0]);
|
||||
float y0=alv.get(3*index[0]+1);
|
||||
float z0=alv.get(3*index[0]+2);
|
||||
alvResult.add(x0);
|
||||
alvResult.add(y0);
|
||||
alvResult.add(z0);
|
||||
|
||||
//计算第1个顶点的索引,并获取此顶点的XYZ三个坐标
|
||||
index[1]=Integer.parseInt(tempsa[2].split("/")[0])-1;
|
||||
float x1=alv.get(3*index[1]);
|
||||
float y1=alv.get(3*index[1]+1);
|
||||
float z1=alv.get(3*index[1]+2);
|
||||
alvResult.add(x1);
|
||||
alvResult.add(y1);
|
||||
alvResult.add(z1);
|
||||
|
||||
//计算第2个顶点的索引,并获取此顶点的XYZ三个坐标
|
||||
index[2]=Integer.parseInt(tempsa[3].split("/")[0])-1;
|
||||
float x2=alv.get(3*index[2]);
|
||||
float y2=alv.get(3*index[2]+1);
|
||||
float z2=alv.get(3*index[2]+2);
|
||||
alvResult.add(x2);
|
||||
alvResult.add(y2);
|
||||
alvResult.add(z2);
|
||||
|
||||
//记录此面的顶点索引
|
||||
alFaceIndex.add(index[0]);
|
||||
alFaceIndex.add(index[1]);
|
||||
alFaceIndex.add(index[2]);
|
||||
|
||||
//通过三角形面两个边向量0-1,0-2求叉积得到此面的法向量
|
||||
//求0号点到1号点的向量
|
||||
float vxa=x1-x0;
|
||||
float vya=y1-y0;
|
||||
float vza=z1-z0;
|
||||
//求0号点到2号点的向量
|
||||
float vxb=x2-x0;
|
||||
float vyb=y2-y0;
|
||||
float vzb=z2-z0;
|
||||
//通过求两个向量的叉积计算法向量
|
||||
float[] vNormal=vectorNormal(getCrossProduct
|
||||
(
|
||||
vxa,vya,vza,vxb,vyb,vzb
|
||||
));
|
||||
|
||||
for(int tempInxex:index)
|
||||
{//记录每个索引点的法向量到平均前各个索引对应的点的法向量集合组成的Map中
|
||||
//获取当前索引对应点的法向量集合
|
||||
HashSet<Normal> hsn=hmn.get(tempInxex);
|
||||
if(hsn==null)
|
||||
{//若集合不存在则创建
|
||||
hsn=new HashSet<Normal>();
|
||||
}
|
||||
//将此点的法向量添加到集合中
|
||||
//由于Normal类重写了equals方法,因此同样的法向量不会重复出现在此点
|
||||
//对应的法向量集合中
|
||||
hsn.add(new Normal(vNormal[0],vNormal[1],vNormal[2]));
|
||||
//将集合放进HsahMap中
|
||||
hmn.put(tempInxex, hsn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//生成顶点数组
|
||||
int size=alvResult.size();
|
||||
float[] vXYZ=new float[size];
|
||||
for(int i=0;i<size;i++)
|
||||
{
|
||||
vXYZ[i]=alvResult.get(i);
|
||||
}
|
||||
|
||||
//生成法向量数组
|
||||
float[] nXYZ=new float[alFaceIndex.size()*3];
|
||||
int c=0;
|
||||
for(Integer i:alFaceIndex)
|
||||
{
|
||||
//根据当前点的索引从Map中取出一个法向量的集合
|
||||
HashSet<Normal> hsn=hmn.get(i);
|
||||
//求出平均法向量
|
||||
float[] tn=Normal.getAverage(hsn);
|
||||
//将计算出的平均法向量存放到法向量数组中
|
||||
nXYZ[c++]=tn[0];
|
||||
nXYZ[c++]=tn[1];
|
||||
nXYZ[c++]=tn[2];
|
||||
}
|
||||
//创建3D物体对象
|
||||
lo=new LoadedObjectVertexNormal(mv,vXYZ,nXYZ);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.d("load error", "load error");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.bn.Sample19_3;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
//加载后的物体——携带顶点信息,自动计算面平均法向量
|
||||
public class LoadedObjectVertexNormal
|
||||
{
|
||||
int mProgram;//自定义渲染管线着色器程序id
|
||||
int muMVPMatrixHandle;//总变换矩阵引用
|
||||
int muMMatrixHandle;//位置、旋转变换矩阵
|
||||
int muColorHandle;//顶点颜色
|
||||
int maPositionHandle; //顶点位置属性引用
|
||||
int maNormalHandle; //顶点法向量属性引用
|
||||
int maLightLocationHandle;//光源位置属性引用
|
||||
int maCameraHandle; //摄像机位置属性引用
|
||||
|
||||
String mVertexShader;//顶点着色器代码脚本
|
||||
String mFragmentShader;//片元着色器代码脚本
|
||||
|
||||
FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
|
||||
FloatBuffer mNormalBuffer;//顶点法向量数据缓冲
|
||||
int vCount=0;
|
||||
float vertices[];
|
||||
float minX;//x轴最小位置
|
||||
float maxX;//x轴最大位置
|
||||
float minY;//y轴最小位置
|
||||
float maxY;//y轴最大位置
|
||||
float minZ;//z轴最小位置
|
||||
float maxZ;//z轴最大位置
|
||||
float midX;//中心点坐标
|
||||
float midY;
|
||||
float midZ;
|
||||
//顶点颜色
|
||||
float[] color=new float[]
|
||||
{
|
||||
1,1,1,1
|
||||
};
|
||||
|
||||
public LoadedObjectVertexNormal(MySurfaceView mv,float[] vertices,float[] normals)
|
||||
{
|
||||
//初始化顶点坐标与着色数据
|
||||
initVertexData(vertices,normals);
|
||||
//初始化shader
|
||||
initShader(mv);
|
||||
}
|
||||
|
||||
//初始化顶点坐标与着色数据的方法
|
||||
public void initVertexData(float[] vertices,float[] normals)
|
||||
{
|
||||
//顶点坐标数据的初始化================begin============================
|
||||
vCount=vertices.length/3;
|
||||
this.vertices=new float[vertices.length];
|
||||
this.vertices=vertices;
|
||||
//创建顶点坐标数据缓冲
|
||||
//vertices.length*4是因为一个整数四个字节
|
||||
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
|
||||
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
mVertexBuffer = vbb.asFloatBuffer();//转换为Float型缓冲
|
||||
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
|
||||
mVertexBuffer.position(0);//设置缓冲区起始位置
|
||||
|
||||
//顶点法向量数据的初始化================begin============================
|
||||
ByteBuffer cbb = ByteBuffer.allocateDirect(normals.length*4);
|
||||
cbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
mNormalBuffer = cbb.asFloatBuffer();//转换为Float型缓冲
|
||||
mNormalBuffer.put(normals);//向缓冲区中放入顶点法向量数据
|
||||
mNormalBuffer.position(0);//设置缓冲区起始位置
|
||||
//特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
|
||||
//转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
|
||||
//顶点着色数据的初始化================end============================
|
||||
}
|
||||
|
||||
//初始化shader
|
||||
public void initShader(MySurfaceView mv)
|
||||
{
|
||||
//加载顶点着色器的脚本内容
|
||||
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
|
||||
//加载片元着色器的脚本内容
|
||||
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
|
||||
//基于顶点着色器与片元着色器创建程序
|
||||
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
|
||||
//获取程序中顶点位置属性引用
|
||||
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
|
||||
//获取程序中顶点法向量属性引用
|
||||
maNormalHandle= GLES20.glGetAttribLocation(mProgram, "aNormal");
|
||||
//获取程序中总变换矩阵引用
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
//获取位置、旋转变换矩阵引用
|
||||
muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");
|
||||
//获取程序中光源位置引用
|
||||
maLightLocationHandle=GLES20.glGetUniformLocation(mProgram, "uLightLocation");
|
||||
//获取程序中摄像机位置引用
|
||||
maCameraHandle=GLES20.glGetUniformLocation(mProgram, "uCamera");
|
||||
muColorHandle=GLES20.glGetUniformLocation(mProgram, "aColor");
|
||||
}
|
||||
|
||||
public void drawSelf()
|
||||
{
|
||||
//制定使用某套着色器程序
|
||||
GLES20.glUseProgram(mProgram);
|
||||
//将最终变换矩阵传入着色器程序
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
|
||||
//将位置、旋转变换矩阵传入着色器程序
|
||||
GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0);
|
||||
//将光源位置传入着色器程序
|
||||
GLES20.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightPositionFB);
|
||||
//将摄像机位置传入着色器程序
|
||||
GLES20.glUniform3fv(maCameraHandle, 1, MatrixState.cameraFB);
|
||||
//传入顶点颜色数据
|
||||
GLES20.glUniform4fv(muColorHandle, 1, color, 0);
|
||||
//将顶点位置数据传入渲染管线
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maPositionHandle,
|
||||
3,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mVertexBuffer
|
||||
);
|
||||
//将顶点法向量数据传入渲染管线
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maNormalHandle,
|
||||
3,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mNormalBuffer
|
||||
);
|
||||
//启用顶点位置、法向量数据
|
||||
GLES20.glEnableVertexAttribArray(maPositionHandle);
|
||||
GLES20.glEnableVertexAttribArray(maNormalHandle);
|
||||
//绘制加载的物体
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
|
||||
}
|
||||
//获取物体包围盒的长、宽以及高
|
||||
public float[] findMinMax()
|
||||
{
|
||||
for(int i=0;i<vertices.length/3;i++)
|
||||
{
|
||||
//判断X轴的最小和最大位置
|
||||
if(vertices[i*3]<minX)
|
||||
{
|
||||
minX=vertices[i*3];
|
||||
}
|
||||
if(vertices[i*3]>maxX)
|
||||
{
|
||||
maxX=vertices[i*3];
|
||||
}
|
||||
//判断Y轴的最小和最大位置
|
||||
if(vertices[i*3+1]<minY)
|
||||
{
|
||||
minY=vertices[i*3+1];
|
||||
}
|
||||
if(vertices[i*3+1]>maxY)
|
||||
{
|
||||
maxY=vertices[i*3+1];
|
||||
}
|
||||
//判断Z轴的最小和最大位置
|
||||
if(vertices[i*3+2]<minZ)
|
||||
{
|
||||
minZ=vertices[i*3+2];
|
||||
}
|
||||
if(vertices[i*3+2]>maxZ)
|
||||
{
|
||||
maxZ=vertices[i*3+2];
|
||||
}
|
||||
}
|
||||
float[] length={maxX-minX,maxZ-minZ,maxY-minY};
|
||||
return length;
|
||||
}
|
||||
//获取物体的中心点坐标
|
||||
public float[] findMid(float xOffset,float yOffset,float zOffset)
|
||||
{
|
||||
midX=(minX+maxX)/2+xOffset;
|
||||
midY=(minY+maxY)/2+yOffset;
|
||||
midZ=(minZ+maxZ)/2+zOffset;
|
||||
float[] mid={midX,midY,midZ};
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.bn.Sample19_3;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import android.opengl.Matrix;
|
||||
|
||||
//存储系统矩阵状态的类
|
||||
public class MatrixState
|
||||
{
|
||||
private static float[] mProjMatrix = new float[16];//4x4矩阵 投影用
|
||||
private static float[] mVMatrix = new float[16];//摄像机位置朝向9参数矩阵
|
||||
private static float[] currMatrix;//当前变换矩阵
|
||||
public static float[] lightLocation=new float[]{0,0,0};//定位光光源位置
|
||||
public static FloatBuffer cameraFB;
|
||||
public static FloatBuffer lightPositionFB;
|
||||
|
||||
//保护变换矩阵的栈
|
||||
static float[][] mStack=new float[10][16];
|
||||
static int stackTop=-1;
|
||||
|
||||
public static void setInitStack()//获取不变换初始矩阵
|
||||
{
|
||||
currMatrix=new float[16];
|
||||
Matrix.setRotateM(currMatrix, 0, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
public static void pushMatrix()//保护变换矩阵
|
||||
{
|
||||
stackTop++;
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
mStack[stackTop][i]=currMatrix[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static void popMatrix()//恢复变换矩阵
|
||||
{
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
currMatrix[i]=mStack[stackTop][i];
|
||||
}
|
||||
stackTop--;
|
||||
}
|
||||
|
||||
public static void translate(float x,float y,float z)//设置沿xyz轴移动
|
||||
{
|
||||
Matrix.translateM(currMatrix, 0, x, y, z);
|
||||
}
|
||||
|
||||
public static void rotate(float angle,float x,float y,float z)//设置绕xyz轴移动
|
||||
{
|
||||
Matrix.rotateM(currMatrix,0,angle,x,y,z);
|
||||
}
|
||||
|
||||
public static void scale(float x,float y,float z)
|
||||
{
|
||||
Matrix.scaleM(currMatrix,0, x, y, z);
|
||||
}
|
||||
|
||||
//插入自带矩阵
|
||||
public static void matrix(float[] self)
|
||||
{
|
||||
float[] result=new float[16];
|
||||
Matrix.multiplyMM(result,0,currMatrix,0,self,0);
|
||||
currMatrix=result;
|
||||
}
|
||||
|
||||
|
||||
//设置摄像机
|
||||
static ByteBuffer llbb= ByteBuffer.allocateDirect(3*4);
|
||||
static float[] cameraLocation=new float[3];//摄像机位置
|
||||
public static void setCamera
|
||||
(
|
||||
float cx, //摄像机位置x
|
||||
float cy, //摄像机位置y
|
||||
float cz, //摄像机位置z
|
||||
float tx, //摄像机目标点x
|
||||
float ty, //摄像机目标点y
|
||||
float tz, //摄像机目标点z
|
||||
float upx, //摄像机UP向量X分量
|
||||
float upy, //摄像机UP向量Y分量
|
||||
float upz //摄像机UP向量Z分量
|
||||
)
|
||||
{
|
||||
Matrix.setLookAtM
|
||||
(
|
||||
mVMatrix,
|
||||
0,
|
||||
cx,
|
||||
cy,
|
||||
cz,
|
||||
tx,
|
||||
ty,
|
||||
tz,
|
||||
upx,
|
||||
upy,
|
||||
upz
|
||||
);
|
||||
|
||||
cameraLocation[0]=cx;
|
||||
cameraLocation[1]=cy;
|
||||
cameraLocation[2]=cz;
|
||||
|
||||
llbb.clear();
|
||||
llbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
cameraFB=llbb.asFloatBuffer();
|
||||
cameraFB.put(cameraLocation);
|
||||
cameraFB.position(0);
|
||||
}
|
||||
|
||||
//设置透视投影参数
|
||||
public static void setProjectFrustum
|
||||
(
|
||||
float left, //near面的left
|
||||
float right, //near面的right
|
||||
float bottom, //near面的bottom
|
||||
float top, //near面的top
|
||||
float near, //near面距离
|
||||
float far //far面距离
|
||||
)
|
||||
{
|
||||
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
|
||||
}
|
||||
|
||||
//设置正交投影参数
|
||||
public static void setProjectOrtho
|
||||
(
|
||||
float left, //near面的left
|
||||
float right, //near面的right
|
||||
float bottom, //near面的bottom
|
||||
float top, //near面的top
|
||||
float near, //near面距离
|
||||
float far //far面距离
|
||||
)
|
||||
{
|
||||
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
|
||||
}
|
||||
|
||||
//用于一帧内的摄像机矩阵
|
||||
private static float[] mVMatrixForSpecFrame = new float[16];//摄像机位置朝向9参数矩阵
|
||||
public static void copyMVMatrix()
|
||||
{
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
mVMatrixForSpecFrame[i]=mVMatrix[i];
|
||||
}
|
||||
}
|
||||
|
||||
//获取具体物体的总变换矩阵
|
||||
static float[] mMVPMatrix=new float[16];
|
||||
public static float[] getFinalMatrix()
|
||||
{
|
||||
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrixForSpecFrame, 0, currMatrix, 0);
|
||||
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
|
||||
return mMVPMatrix;
|
||||
}
|
||||
|
||||
//获取具体物体的变换矩阵
|
||||
public static float[] getMMatrix()
|
||||
{
|
||||
return currMatrix;
|
||||
}
|
||||
|
||||
//设置灯光位置的方法
|
||||
static ByteBuffer llbbL = ByteBuffer.allocateDirect(3*4);
|
||||
public static void setLightLocation(float x,float y,float z)
|
||||
{
|
||||
llbbL.clear();
|
||||
|
||||
lightLocation[0]=x;
|
||||
lightLocation[1]=y;
|
||||
lightLocation[2]=z;
|
||||
|
||||
llbbL.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
lightPositionFB=llbbL.asFloatBuffer();
|
||||
lightPositionFB.put(lightLocation);
|
||||
lightPositionFB.position(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import java.util.HashMap;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.GLES20;
|
||||
import android.view.MotionEvent;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import android.content.Context;
|
||||
|
||||
public class MySurfaceView extends GLSurfaceView
|
||||
{
|
||||
private SceneRenderer mRenderer;//场景渲染器
|
||||
//茶壶的偏移量
|
||||
static float xOffset=0;
|
||||
//茶壶转动的角度
|
||||
static float yAngle=0;
|
||||
HashMap<Integer,BNPoint> hm=new HashMap<Integer,BNPoint>();
|
||||
//模拟键盘监听线程
|
||||
KeyThread kt;
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event)
|
||||
{
|
||||
//获取触控的动作编号
|
||||
int action=event.getAction()&MotionEvent.ACTION_MASK;
|
||||
//获取主、辅点id(down时主辅点id皆正确,up时辅点id正确,主点id要查询Map中剩下的一个点的id)
|
||||
int id=(event.getAction()&MotionEvent.ACTION_POINTER_ID_MASK)>>>MotionEvent.ACTION_POINTER_ID_SHIFT;
|
||||
switch(action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN: //主点down
|
||||
case MotionEvent.ACTION_POINTER_DOWN: //辅点down
|
||||
hm.put(id, new BNPoint(event.getX(id),event.getY(id)));
|
||||
kt.keyPress(event.getX(id), event.getY(id));
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
float x=hm.get(id).x;
|
||||
float y=hm.get(id).y;
|
||||
hm.remove(id);
|
||||
kt.keyUp(x, y);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
hm.clear();
|
||||
kt.clearKeyState();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public MySurfaceView(Context context)
|
||||
{
|
||||
super(context);
|
||||
this.setEGLContextClientVersion(2); //设置使用OPENGL ES2.0
|
||||
mRenderer = new SceneRenderer(); //创建场景渲染器
|
||||
setRenderer(mRenderer); //设置渲染器
|
||||
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染
|
||||
}
|
||||
|
||||
private class SceneRenderer implements GLSurfaceView.Renderer
|
||||
{
|
||||
//从指定的obj文件中加载对象
|
||||
LoadedObjectVertexNormal ch;
|
||||
LoadedObjectVertexNormal pm;
|
||||
|
||||
public void onDrawFrame(GL10 gl)
|
||||
{
|
||||
//清除深度缓冲与颜色缓冲
|
||||
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
|
||||
MatrixState.copyMVMatrix();
|
||||
MatrixState.pushMatrix();//保护现场
|
||||
//若加载的物体不为空则绘制物体
|
||||
if(pm!=null)
|
||||
{
|
||||
pm.drawSelf();
|
||||
}
|
||||
MatrixState.popMatrix();
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(xOffset, 0, 0);
|
||||
MatrixState.rotate(yAngle, 0, 1, 0);
|
||||
if(ch!=null)
|
||||
{
|
||||
ch.drawSelf();
|
||||
}
|
||||
MatrixState.popMatrix();
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
//设置视窗大小及位置
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
//计算GLSurfaceView的宽高比
|
||||
float ratio = (float) width / height;
|
||||
//调用此方法计算产生透视投影矩阵
|
||||
MatrixState.setProjectFrustum(-ratio, ratio, -1, 1, 2, 100);
|
||||
MatrixState.setCamera(0,5,25,0,0,0,0,1,0);
|
||||
//初始化光源位置
|
||||
MatrixState.setLightLocation(70, 30, 70);
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
//设置屏幕背景色RGBA
|
||||
GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);
|
||||
//打开深度检测
|
||||
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
||||
//打开背面剪裁
|
||||
GLES20.glEnable(GLES20.GL_CULL_FACE);
|
||||
//初始化变换矩阵
|
||||
MatrixState.setInitStack();
|
||||
//加载要绘制的物体
|
||||
ch=LoadUtil.loadFromFile("ch.obj", MySurfaceView.this.getResources(),MySurfaceView.this);
|
||||
pm=LoadUtil.loadFromFile("pm.obj", MySurfaceView.this.getResources(),MySurfaceView.this);
|
||||
kt=new KeyThread();
|
||||
kt.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import java.util.Set;
|
||||
//表示法向量的类,此类的一个对象表示一个法向量
|
||||
public class Normal
|
||||
{
|
||||
public static final float DIFF=0.0000001f;//判断两个法向量是否相同的阈值
|
||||
//法向量在XYZ轴上的分量
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
|
||||
public Normal(float nx,float ny,float nz)
|
||||
{
|
||||
this.nx=nx;
|
||||
this.ny=ny;
|
||||
this.nz=nz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if(o instanceof Normal)
|
||||
{//若两个法向量XYZ三个分量的差都小于指定的阈值则认为这两个法向量相等
|
||||
Normal tn=(Normal)o;
|
||||
if(Math.abs(nx-tn.nx)<DIFF&&
|
||||
Math.abs(ny-tn.ny)<DIFF&&
|
||||
Math.abs(ny-tn.ny)<DIFF
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//由于要用到HashSet,因此一定要重写hashCode方法
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//求法向量平均值的工具方法
|
||||
public static float[] getAverage(Set<Normal> sn)
|
||||
{
|
||||
//存放法向量和的数组
|
||||
float[] result=new float[3];
|
||||
//把集合中所有的法向量求和
|
||||
for(Normal n:sn)
|
||||
{
|
||||
result[0]+=n.nx;
|
||||
result[1]+=n.ny;
|
||||
result[2]+=n.nz;
|
||||
}
|
||||
//将求和后的法向量规格化
|
||||
return LoadUtil.vectorNormal(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class Sample19_3Activity extends Activity
|
||||
{
|
||||
private MySurfaceView mGLSurfaceView;
|
||||
static float screenWidth;//屏幕宽度
|
||||
static float screenHeight;//屏幕高度
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
//设置为全屏
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
//设置为横屏模式
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
DisplayMetrics dm=new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(dm);
|
||||
screenWidth=dm.widthPixels; //dm.widthPixels 获取屏幕横向分辨率
|
||||
screenHeight=dm.heightPixels; //dm.heightPixels 获取屏幕竖向分辨率
|
||||
//初始化GLSurfaceView
|
||||
mGLSurfaceView = new MySurfaceView(this);
|
||||
setContentView(mGLSurfaceView);
|
||||
mGLSurfaceView.requestFocus();//获取焦点
|
||||
mGLSurfaceView.setFocusableInTouchMode(true);//设置为可触控
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
mGLSurfaceView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
mGLSurfaceView.onPause();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.bn.Sample19_3;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.opengl.GLES20;
|
||||
import android.util.Log;
|
||||
|
||||
//加载顶点Shader与片元Shader的工具类
|
||||
public class ShaderUtil
|
||||
{
|
||||
//加载制定shader的方法
|
||||
public static int loadShader
|
||||
(
|
||||
int shaderType, //shader的类型 GLES20.GL_VERTEX_SHADER GLES20.GL_FRAGMENT_SHADER
|
||||
String source //shader的脚本字符串
|
||||
)
|
||||
{
|
||||
//创建一个新shader
|
||||
int shader = GLES20.glCreateShader(shaderType);
|
||||
//若创建成功则加载shader
|
||||
if (shader != 0)
|
||||
{
|
||||
//加载shader的源代码
|
||||
GLES20.glShaderSource(shader, source);
|
||||
//编译shader
|
||||
GLES20.glCompileShader(shader);
|
||||
//存放编译成功shader数量的数组
|
||||
int[] compiled = new int[1];
|
||||
//获取Shader的编译情况
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0)
|
||||
{//若编译失败则显示错误日志并删除此shader
|
||||
Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");
|
||||
Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));
|
||||
GLES20.glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
//创建shader程序的方法
|
||||
public static int createProgram(String vertexSource, String fragmentSource)
|
||||
{
|
||||
//加载顶点着色器
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
||||
if (vertexShader == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//加载片元着色器
|
||||
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
||||
if (pixelShader == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//创建程序
|
||||
int program = GLES20.glCreateProgram();
|
||||
//若程序创建成功则向程序中加入顶点着色器与片元着色器
|
||||
if (program != 0)
|
||||
{
|
||||
//向程序中加入顶点着色器
|
||||
GLES20.glAttachShader(program, vertexShader);
|
||||
checkGlError("glAttachShader");
|
||||
//向程序中加入片元着色器
|
||||
GLES20.glAttachShader(program, pixelShader);
|
||||
checkGlError("glAttachShader");
|
||||
//链接程序
|
||||
GLES20.glLinkProgram(program);
|
||||
//存放链接成功program数量的数组
|
||||
int[] linkStatus = new int[1];
|
||||
//获取program的链接情况
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
||||
//若链接失败则报错并删除程序
|
||||
if (linkStatus[0] != GLES20.GL_TRUE)
|
||||
{
|
||||
Log.e("ES20_ERROR", "Could not link program: ");
|
||||
Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));
|
||||
GLES20.glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
//检查每一步操作是否有错误的方法
|
||||
public static void checkGlError(String op)
|
||||
{
|
||||
int error;
|
||||
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
|
||||
{
|
||||
Log.e("ES20_ERROR", op + ": glError " + error);
|
||||
throw new RuntimeException(op + ": glError " + error);
|
||||
}
|
||||
}
|
||||
|
||||
//从sh脚本中加载shader内容的方法
|
||||
public static String loadFromAssetsFile(String fname,Resources r)
|
||||
{
|
||||
String result=null;
|
||||
try
|
||||
{
|
||||
InputStream in=r.getAssets().open(fname);
|
||||
int ch=0;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
while((ch=in.read())!=-1)
|
||||
{
|
||||
baos.write(ch);
|
||||
}
|
||||
byte[] buff=baos.toByteArray();
|
||||
baos.close();
|
||||
in.close();
|
||||
result=new String(buff,"UTF-8");
|
||||
result=result.replaceAll("\\r\\n","\n");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user