初次提交
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>Sample18_6</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,12 @@
|
||||
#Sun Dec 04 13:21:38 CST 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.bn.Sample18_6"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<uses-sdk android:minSdkVersion="8" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name=".MyActivity"
|
||||
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>
|
||||
@@ -0,0 +1,12 @@
|
||||
precision mediump float;
|
||||
varying vec4 vaaColor; //接收从顶点着色器过来的参数
|
||||
varying vec4 vambient;
|
||||
varying vec4 vdiffuse;
|
||||
varying vec4 vspecular;
|
||||
void main()
|
||||
{
|
||||
//将颜色给此片元
|
||||
vec4 finalColor = vaaColor;
|
||||
//给此片元颜色值
|
||||
gl_FragColor = finalColor*vambient+finalColor*vspecular+finalColor*vdiffuse;//给此片元颜色值
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
precision mediump float;
|
||||
uniform sampler2D sTexture;//纹理内容数据
|
||||
varying vec2 vTextureCoord; //接收从顶点着色器过来的参数
|
||||
varying vec4 vambient;
|
||||
varying vec4 vdiffuse;
|
||||
varying vec4 vspecular;
|
||||
void main()
|
||||
{
|
||||
//将计算出的颜色给此片元
|
||||
vec4 finalColor=texture2D(sTexture, vTextureCoord);
|
||||
//给此片元颜色值
|
||||
gl_FragColor = finalColor*vambient+finalColor*vspecular+finalColor*vdiffuse;//给此片元颜色值
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
uniform mat4 uMVPMatrix; //总变换矩阵
|
||||
uniform mat4 uMMatrix; //变换矩阵
|
||||
uniform vec3 uLightLocation; //光源位置
|
||||
uniform vec3 uCamera; //摄像机位置
|
||||
attribute vec3 aPosition; //顶点位置
|
||||
attribute vec3 aNormal; //顶点法向量
|
||||
attribute vec4 aColor; //顶点颜色
|
||||
varying vec4 vaaColor; //用于传递给片元着色器的变量
|
||||
varying vec4 vambient;
|
||||
varying vec4 vdiffuse;
|
||||
varying vec4 vspecular;
|
||||
|
||||
//定位光光照计算的方法
|
||||
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); //根据总变换矩阵计算此次绘制此顶点位置
|
||||
pointLight(normalize(aNormal),vambient,vdiffuse,vspecular,uLightLocation,vec4(0.3,0.3,0.3,1.0),vec4(0.7,0.7,0.7,1.0),vec4(0.3,0.3,0.3,1.0));
|
||||
vaaColor = aColor;//将接收的颜色传递给片元着色器
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
uniform mat4 uMVPMatrix; //总变换矩阵
|
||||
uniform mat4 uMMatrix; //变换矩阵
|
||||
uniform vec3 uLightLocation; //光源位置
|
||||
uniform vec3 uCamera; //摄像机位置
|
||||
attribute vec3 aPosition; //顶点位置
|
||||
attribute vec3 aNormal; //顶点法向量
|
||||
attribute vec2 aTexCoor; //顶点纹理坐标
|
||||
varying vec2 vTextureCoord; //用于传递给片元着色器的变量
|
||||
varying vec4 vambient;
|
||||
varying vec4 vdiffuse;
|
||||
varying vec4 vspecular;
|
||||
|
||||
//定位光光照计算的方法
|
||||
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); //根据总变换矩阵计算此次绘制此顶点位置
|
||||
pointLight(normalize(aNormal),vambient,vdiffuse,vspecular,uLightLocation,vec4(0.3,0.3,0.3,1.0),vec4(0.7,0.7,0.7,1.0),vec4(0.3,0.3,0.3,1.0));
|
||||
vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
|
||||
}
|
||||
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.
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,25 @@
|
||||
/* 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.Sample18_6;
|
||||
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class drawable {
|
||||
public static final int icon=0x7f020000;
|
||||
public static final int tex_floor=0x7f020001;
|
||||
public static final int tex_wall=0x7f020002;
|
||||
}
|
||||
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 |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello World, MyActivity!</string>
|
||||
<string name="app_name">Sample18_6</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import static com.bn.Sample18_6.ShaderUtil.createProgram;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
|
||||
/*
|
||||
* 正二十面体
|
||||
* 基于三个互相垂直的黄金长方形
|
||||
*/
|
||||
public class Ball
|
||||
{
|
||||
int mProgram;//自定义渲染管线着色器程序id
|
||||
int muMVPMatrixHandle;//总变换矩阵引用
|
||||
int maPositionHandle; //顶点位置属性引用
|
||||
int maColorHandle; //顶点颜色属性引用
|
||||
int muMMatrixHandle;
|
||||
|
||||
int maCameraHandle; //摄像机位置属性引用
|
||||
int maNormalHandle; //顶点法向量属性引用
|
||||
int maLightLocationHandle;//光源位置属性引用
|
||||
|
||||
|
||||
String mVertexShader;//顶点着色器
|
||||
String mFragmentShader;//片元着色器
|
||||
|
||||
FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
|
||||
FloatBuffer mColorBuffer; //顶点颜色数据缓冲
|
||||
FloatBuffer mNormalBuffer;//顶点法向量数据缓冲
|
||||
int vCount=0;
|
||||
float xAngle=0;//绕x轴旋转的角度
|
||||
float yAngle=0;//绕y轴旋转的角度
|
||||
float zAngle=0;//绕z轴旋转的角度
|
||||
|
||||
float bHalf=0;//黄金长方形的宽
|
||||
float r=0;//球的半径
|
||||
|
||||
public Ball(MySurfaceView mv,float scale,float aHalf,int n)
|
||||
{
|
||||
//调用初始化顶点数据的initVertexData方法
|
||||
initVertexData(scale,aHalf,n);
|
||||
//调用初始化着色器的intShader方法
|
||||
initShader(mv);
|
||||
}
|
||||
|
||||
//自定义的初始化顶点数据的方法
|
||||
public void initVertexData(float scale, float aHalf, int n) //大小,黄金长方形的长的一半,分段数
|
||||
{
|
||||
aHalf*=scale;
|
||||
//初始化成员变量
|
||||
bHalf=aHalf*0.618034f;
|
||||
r=(float) Math.sqrt(aHalf*aHalf+bHalf*bHalf);
|
||||
vCount=3*20*n*n;//顶点个数,共有20个三角形,每个三角形都有三个顶点
|
||||
//正20面体坐标数据初始化
|
||||
ArrayList<Float> alVertix20=new ArrayList<Float>();//正20面体的顶点列表(未卷绕)
|
||||
ArrayList<Integer> alFaceIndex20=new ArrayList<Integer>();//正20面体组织成面的顶点的索引值列表(按逆时针卷绕)
|
||||
//正20面体顶点
|
||||
alVertix20.add(0f); alVertix20.add(aHalf); alVertix20.add(-bHalf);//顶正棱锥顶点
|
||||
|
||||
alVertix20.add(0f); alVertix20.add(aHalf); alVertix20.add(bHalf);//棱柱上的点
|
||||
alVertix20.add(aHalf); alVertix20.add(bHalf); alVertix20.add(0f);
|
||||
alVertix20.add(bHalf); alVertix20.add(0f); alVertix20.add(-aHalf);
|
||||
alVertix20.add(-bHalf); alVertix20.add(0f); alVertix20.add(-aHalf);
|
||||
alVertix20.add(-aHalf); alVertix20.add(bHalf); alVertix20.add(0f);
|
||||
|
||||
alVertix20.add(-bHalf); alVertix20.add(0f); alVertix20.add(aHalf);
|
||||
alVertix20.add(bHalf); alVertix20.add(0f); alVertix20.add(aHalf);
|
||||
alVertix20.add(aHalf); alVertix20.add(-bHalf); alVertix20.add(0f);
|
||||
alVertix20.add(0f); alVertix20.add(-aHalf); alVertix20.add(-bHalf);
|
||||
alVertix20.add(-aHalf); alVertix20.add(-bHalf); alVertix20.add(0f);
|
||||
|
||||
alVertix20.add(0f); alVertix20.add(-aHalf); alVertix20.add(bHalf);//底棱锥顶点
|
||||
//正20面体索引
|
||||
alFaceIndex20.add(0); alFaceIndex20.add(1); alFaceIndex20.add(2);
|
||||
alFaceIndex20.add(0); alFaceIndex20.add(2); alFaceIndex20.add(3);
|
||||
alFaceIndex20.add(0); alFaceIndex20.add(3); alFaceIndex20.add(4);
|
||||
alFaceIndex20.add(0); alFaceIndex20.add(4); alFaceIndex20.add(5);
|
||||
alFaceIndex20.add(0); alFaceIndex20.add(5); alFaceIndex20.add(1);
|
||||
|
||||
alFaceIndex20.add(1); alFaceIndex20.add(6); alFaceIndex20.add(7);
|
||||
alFaceIndex20.add(1); alFaceIndex20.add(7); alFaceIndex20.add(2);
|
||||
alFaceIndex20.add(2); alFaceIndex20.add(7); alFaceIndex20.add(8);
|
||||
alFaceIndex20.add(2); alFaceIndex20.add(8); alFaceIndex20.add(3);
|
||||
alFaceIndex20.add(3); alFaceIndex20.add(8); alFaceIndex20.add(9);
|
||||
alFaceIndex20.add(3); alFaceIndex20.add(9); alFaceIndex20.add(4);
|
||||
alFaceIndex20.add(4); alFaceIndex20.add(9); alFaceIndex20.add(10);
|
||||
alFaceIndex20.add(4); alFaceIndex20.add(10); alFaceIndex20.add(5);
|
||||
alFaceIndex20.add(5); alFaceIndex20.add(10); alFaceIndex20.add(6);
|
||||
alFaceIndex20.add(5); alFaceIndex20.add(6); alFaceIndex20.add(1);
|
||||
|
||||
alFaceIndex20.add(6); alFaceIndex20.add(11); alFaceIndex20.add(7);
|
||||
alFaceIndex20.add(7); alFaceIndex20.add(11); alFaceIndex20.add(8);
|
||||
alFaceIndex20.add(8); alFaceIndex20.add(11); alFaceIndex20.add(9);
|
||||
alFaceIndex20.add(9); alFaceIndex20.add(11); alFaceIndex20.add(10);
|
||||
alFaceIndex20.add(10); alFaceIndex20.add(11); alFaceIndex20.add(6);
|
||||
//计算卷绕顶点
|
||||
float[] vertices20=VectorUtil.calVertices(alVertix20, alFaceIndex20);//只计算顶点
|
||||
|
||||
//坐标数据初始化
|
||||
ArrayList<Float> alVertix=new ArrayList<Float>();//原顶点列表(未卷绕)
|
||||
ArrayList<Integer> alFaceIndex=new ArrayList<Integer>();//组织成面的顶点的索引值列表(按逆时针卷绕)
|
||||
int vnCount=0;//前i-1行前所有顶点数的和
|
||||
for(int k=0;k<vertices20.length;k+=9)//对正20面体每个大三角形循环
|
||||
{
|
||||
float [] v1=new float[]{vertices20[k+0], vertices20[k+1], vertices20[k+2]};
|
||||
float [] v2=new float[]{vertices20[k+3], vertices20[k+4], vertices20[k+5]};
|
||||
float [] v3=new float[]{vertices20[k+6], vertices20[k+7], vertices20[k+8]};
|
||||
//顶点
|
||||
for(int i=0;i<=n;i++)
|
||||
{
|
||||
float[] viStart=VectorUtil.devideBall(r, v1, v2, n, i);
|
||||
float[] viEnd=VectorUtil.devideBall(r, v1, v3, n, i);
|
||||
for(int j=0;j<=i;j++)
|
||||
{
|
||||
float[] vi=VectorUtil.devideBall(r, viStart, viEnd, i, j);
|
||||
alVertix.add(vi[0]); alVertix.add(vi[1]); alVertix.add(vi[2]);
|
||||
}
|
||||
}
|
||||
//索引
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
if(i==0){//若是第0行,直接加入卷绕后顶点索引012
|
||||
alFaceIndex.add(vnCount+0); alFaceIndex.add(vnCount+1);alFaceIndex.add(vnCount+2);
|
||||
vnCount+=1;
|
||||
if(i==n-1){//如果是每个大三角形的最后一次循环,将下一列的顶点个数也加上
|
||||
vnCount+=2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int iStart=vnCount;//第i行开始的索引
|
||||
int viCount=i+1;//第i行顶点数
|
||||
int iEnd=iStart+viCount-1;//第i行结束索引
|
||||
|
||||
int iStartNext=iStart+viCount;//第i+1行开始的索引
|
||||
int viCountNext=viCount+1;//第i+1行顶点数
|
||||
int iEndNext=iStartNext+viCountNext-1;//第i+1行结束的索引
|
||||
//前面的四边形
|
||||
for(int j=0;j<viCount-1;j++)
|
||||
{
|
||||
int index0=iStart+j;//四边形的四个顶点索引
|
||||
int index1=index0+1;
|
||||
int index2=iStartNext+j;
|
||||
int index3=index2+1;
|
||||
alFaceIndex.add(index0); alFaceIndex.add(index2);alFaceIndex.add(index3);//加入前面的四边形
|
||||
alFaceIndex.add(index0); alFaceIndex.add(index3);alFaceIndex.add(index1);
|
||||
}// j
|
||||
alFaceIndex.add(iEnd); alFaceIndex.add(iEndNext-1);alFaceIndex.add(iEndNext); //最后一个三角形
|
||||
vnCount+=viCount;//第i行前所有顶点数的和
|
||||
if(i==n-1){//如果是每个大三角形的最后一次循环,将下一列的顶点个数也加上
|
||||
vnCount+=viCountNext;
|
||||
}
|
||||
}// i
|
||||
}
|
||||
|
||||
//计算卷绕顶点
|
||||
float[] vertices=VectorUtil.calVertices(alVertix, alFaceIndex);//只计算顶点
|
||||
float[] normals=vertices;//顶点就是法向量
|
||||
|
||||
//顶点坐标数据初始化
|
||||
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);//创建顶点坐标数据缓冲
|
||||
vbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
|
||||
mVertexBuffer = vbb.asFloatBuffer();//转换为float型缓冲
|
||||
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
|
||||
mVertexBuffer.position(0);//设置缓冲区起始位置
|
||||
//法向量数据初始化
|
||||
ByteBuffer nbb = ByteBuffer.allocateDirect(normals.length*4);//创建顶点法向量数据缓冲
|
||||
nbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
|
||||
mNormalBuffer = nbb.asFloatBuffer();//转换为float型缓冲
|
||||
mNormalBuffer.put(normals);//向缓冲区中放入顶点法向量数据
|
||||
mNormalBuffer.position(0);//设置缓冲区起始位置
|
||||
|
||||
float[] colors=new float[vCount*4];//顶点颜色数组
|
||||
int Count=0;
|
||||
for(int i=0;i<vCount;i++)
|
||||
{
|
||||
colors[Count++]=1; //r
|
||||
colors[Count++]=1; //g
|
||||
colors[Count++]=1; //b
|
||||
colors[Count++]=1; //a
|
||||
|
||||
}
|
||||
//创建顶点着色数据缓冲
|
||||
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
|
||||
cbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
|
||||
mColorBuffer = cbb.asFloatBuffer();//转换为Float型缓冲
|
||||
mColorBuffer.put(colors);//向缓冲区中放入顶点着色数据
|
||||
mColorBuffer.position(0);//设置缓冲区起始位置
|
||||
}
|
||||
|
||||
//初始化着色器
|
||||
public void initShader(MySurfaceView mv)
|
||||
{
|
||||
//加载顶点着色器的脚本内容
|
||||
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_color_light.sh", mv.getResources());
|
||||
//加载片元着色器的脚本内容
|
||||
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_color_light.sh", mv.getResources());
|
||||
//基于顶点着色器与片元着色器创建程序
|
||||
mProgram = createProgram(mVertexShader, mFragmentShader);
|
||||
//获取程序中顶点位置属性引用id
|
||||
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
|
||||
//获取程序中顶点颜色属性引用id
|
||||
maColorHandle= GLES20.glGetAttribLocation(mProgram, "aColor");
|
||||
//获取程序中总变换矩阵引用id
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
|
||||
|
||||
//获取程序中顶点法向量属性引用id
|
||||
maNormalHandle= GLES20.glGetAttribLocation(mProgram, "aNormal");
|
||||
//获取程序中摄像机位置引用id
|
||||
maCameraHandle=GLES20.glGetUniformLocation(mProgram, "uCamera");
|
||||
//获取程序中光源位置引用id
|
||||
maLightLocationHandle=GLES20.glGetUniformLocation(mProgram, "uLightLocation");
|
||||
//获取位置、旋转变换矩阵引用id
|
||||
muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void drawSelf()
|
||||
{
|
||||
|
||||
MatrixState.rotate(xAngle, 1, 0, 0);
|
||||
MatrixState.rotate(yAngle, 0, 1, 0);
|
||||
MatrixState.rotate(zAngle, 0, 0, 1);
|
||||
|
||||
//制定使用某套shader程序
|
||||
GLES20.glUseProgram(mProgram);
|
||||
|
||||
//将最终变换矩阵传入shader程序
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
|
||||
|
||||
//将位置、旋转变换矩阵传入shader程序
|
||||
GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0);
|
||||
//将摄像机位置传入shader程序
|
||||
GLES20.glUniform3fv(maCameraHandle, 1, MatrixState.cameraFB);
|
||||
//将光源位置传入shader程序
|
||||
GLES20.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightPositionFB);
|
||||
|
||||
|
||||
//传送顶点位置数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maPositionHandle,
|
||||
3,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mVertexBuffer
|
||||
);
|
||||
//传送顶点颜色数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maColorHandle,
|
||||
4,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
4*4,
|
||||
mColorBuffer
|
||||
);
|
||||
//传送顶点法向量数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maNormalHandle,
|
||||
4,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mNormalBuffer
|
||||
);
|
||||
|
||||
//启用顶点位置数据
|
||||
GLES20.glEnableVertexAttribArray(maPositionHandle);
|
||||
//启用顶点颜色数据
|
||||
GLES20.glEnableVertexAttribArray(maColorHandle);
|
||||
//启用顶点法向量数据
|
||||
GLES20.glEnableVertexAttribArray(maNormalHandle);
|
||||
|
||||
//绘制线条的粗细
|
||||
GLES20.glLineWidth(2);
|
||||
//绘制
|
||||
GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, vCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import static com.bn.Sample18_6.Constant.*;
|
||||
import android.opengl.Matrix;
|
||||
|
||||
//用于控制的球
|
||||
public class BallForControl {
|
||||
MySurfaceView mv;
|
||||
Ball ball;//用于绘制的桌球
|
||||
|
||||
float rotateX; //球的旋转轴
|
||||
float rotateY;
|
||||
float rotateZ;
|
||||
|
||||
float tempX; //球位置的临时变量
|
||||
float tempZ;
|
||||
|
||||
float tempSPANX; //球移动距离的临时变量
|
||||
float tempSPANZ;
|
||||
|
||||
float tempLength; //球前进的距离临时变量
|
||||
|
||||
float tempAngle; //球旋转的角度
|
||||
|
||||
float[] selfRotateMatrix;//自带旋转矩阵
|
||||
|
||||
public BallForControl(MySurfaceView mv,float scale,float aHalf,int n)
|
||||
{
|
||||
this.mv=mv;
|
||||
ball=new Ball(mv,scale,aHalf,n);
|
||||
//初始化自带旋转矩阵
|
||||
selfRotateMatrix=new float[16];
|
||||
//初始时旋转一定的度数
|
||||
Matrix.setRotateM(selfRotateMatrix, 0, 10, 0, 1, 0);
|
||||
}
|
||||
|
||||
public void drawSelf()
|
||||
{
|
||||
MatrixState.pushMatrix();
|
||||
//移动到指定位置
|
||||
MatrixState.translate(Constant.XOFFSET, 1.2f, Constant.ZOFFSET);
|
||||
//加上自带旋转矩阵
|
||||
MatrixState.matrix(selfRotateMatrix);
|
||||
//绘制球
|
||||
ball.drawSelf();
|
||||
MatrixState.popMatrix();
|
||||
}
|
||||
|
||||
//球前进的方法
|
||||
public void go(){
|
||||
tempSPANX=Constant.SPANX; //球移动距离的临时变量赋值
|
||||
tempSPANZ=Constant.SPANZ;
|
||||
|
||||
tempX=Constant.XOFFSET+tempSPANX; //根据传感器,变化当前球的位置
|
||||
tempZ=Constant.ZOFFSET+tempSPANZ;
|
||||
|
||||
|
||||
//如果与上下两条边发生碰撞
|
||||
if( (tempZ<-ZBOUNDARY)||(tempZ>ZBOUNDARY))
|
||||
{
|
||||
tempSPANZ=0;
|
||||
}
|
||||
//如果与左右两条边发生碰撞
|
||||
if((tempX<-XBOUNDARY)|| (tempX>XBOUNDARY))
|
||||
{
|
||||
tempSPANX=0;
|
||||
}
|
||||
|
||||
|
||||
//球当前的位置发生变化
|
||||
Constant.XOFFSET+=tempSPANX;
|
||||
Constant.ZOFFSET+=tempSPANZ;
|
||||
|
||||
|
||||
//*****************旋转 begin************************
|
||||
|
||||
//前进的方向向量为Constant.SPANX Constant.SPANZ,
|
||||
//那么旋转轴为
|
||||
rotateX=tempSPANZ;
|
||||
rotateY=0;
|
||||
rotateZ=-tempSPANX;
|
||||
//前进的距离
|
||||
tempLength=(float) Math.sqrt(tempSPANX*tempSPANX+tempSPANZ*tempSPANZ);
|
||||
//计算前进的角度值
|
||||
tempAngle=(float) Math.toDegrees(tempLength/Constant.BALLR);
|
||||
|
||||
//改变球的旋转矩阵
|
||||
//旋转时要求角度不为0且轴不能全为0
|
||||
if(Math.abs(tempAngle)!=0&&(Math.abs(rotateZ)!=0||Math.abs(rotateX)!=0))
|
||||
{
|
||||
float[] newMatrix=new float[16];
|
||||
Matrix.setRotateM(newMatrix, 0, tempAngle, rotateX, rotateY, rotateZ);
|
||||
float[] resultMatrix=new float[16];
|
||||
Matrix.multiplyMM(resultMatrix, 0, newMatrix, 0, selfRotateMatrix,0);
|
||||
selfRotateMatrix=resultMatrix;
|
||||
}
|
||||
|
||||
//************************旋转 end************************
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.bn.Sample18_6;
|
||||
/*
|
||||
* 控制球运动的线程
|
||||
*/
|
||||
public class BallGoThread extends Thread {
|
||||
BallForControl ballForControl;//声明AllBalls的引用
|
||||
int timeSpan=12;
|
||||
private boolean flag=false;//循环标志位
|
||||
|
||||
public BallGoThread(BallForControl ballForControl)//构造器
|
||||
{
|
||||
this.ballForControl=ballForControl;//成员变量赋值
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()//重写run方法
|
||||
{
|
||||
while(flag)//while循环
|
||||
{
|
||||
ballForControl.go();//调用使所有球运动的方法
|
||||
|
||||
try{
|
||||
Thread.sleep(timeSpan);//一段时间后再运动
|
||||
}
|
||||
catch(Exception e){
|
||||
e.printStackTrace();//打印异常
|
||||
}
|
||||
}
|
||||
}
|
||||
public void setFlag(boolean flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.bn.Sample18_6;
|
||||
//常量类
|
||||
public class Constant
|
||||
{
|
||||
public static final float SCALE=1;
|
||||
|
||||
//黄金长方形长边的一半
|
||||
public static final float AHALF=1;
|
||||
|
||||
//给定木块凹槽的数据
|
||||
public static final float CUBE_LENGTH=18; //矩形平面的长度
|
||||
public static final float CUBE_HEIGHT=1; //墙的高度
|
||||
public static final float CUBE_WIDTH=12; //矩形平面的宽度
|
||||
public static final float WALL_WIDTH=1f; //墙的厚度
|
||||
//----------------------------数据给定结束-----------------------------------------
|
||||
|
||||
public static float D3_CUBE_LENGTH=CUBE_LENGTH*SCALE; //三维空间中底面矩形的真正长度
|
||||
public static float D3_CUBE_WIDTH=CUBE_WIDTH*SCALE; //三维空间中底面矩形的真正宽度
|
||||
public static float D3_WALL_WIDTH=WALL_WIDTH*SCALE; //三维空间中墙的真正厚度
|
||||
public static float BALLR=(float) Math.sqrt(SCALE*AHALF*SCALE*AHALF+SCALE*AHALF*0.618034f*SCALE*AHALF*0.618034f); //球的半径
|
||||
|
||||
//底面凹槽的边界,均为正值
|
||||
public static float XBOUNDARY=D3_CUBE_LENGTH/2-D3_WALL_WIDTH-BALLR; //x方向上的边界
|
||||
public static float ZBOUNDARY=D3_CUBE_WIDTH/2-D3_WALL_WIDTH-BALLR; //z方向上的边界
|
||||
|
||||
|
||||
public static float XOFFSET=0; //球位置坐标
|
||||
public static float ZOFFSET=0;
|
||||
|
||||
public static float SPANX=0; //球的步进
|
||||
public static float SPANZ=0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
public class Cube
|
||||
{
|
||||
MySurfaceView mv;
|
||||
TextureRect[] rect=new TextureRect[6];
|
||||
float xAngle=0;//绕x轴旋转的角度
|
||||
float yAngle=0;//绕y轴旋转的角度
|
||||
float zAngle=0;//绕z轴旋转的角度
|
||||
float a; //立方体的长
|
||||
float b; //立方体的高
|
||||
float c; //立方体的宽(厚度)
|
||||
float size;//尺寸
|
||||
public Cube(MySurfaceView mv,float scale,float[] abc)
|
||||
{
|
||||
a=abc[0];
|
||||
b=abc[1];
|
||||
c=abc[2];
|
||||
rect[0]=new TextureRect(mv,scale,a,b);
|
||||
rect[1]=new TextureRect(mv,scale,a,b);
|
||||
rect[2]=new TextureRect(mv,scale,c,b);
|
||||
rect[3]=new TextureRect(mv,scale,c,b);
|
||||
rect[4]=new TextureRect(mv,scale,a,c);
|
||||
rect[5]=new TextureRect(mv,scale,a,c);
|
||||
// 初始化完成后再改变各量的值
|
||||
size=scale;
|
||||
a*=size;
|
||||
b*=size;
|
||||
c*=size;
|
||||
}
|
||||
public void drawSelf(int ballTexId)
|
||||
{
|
||||
MatrixState.rotate(xAngle, 1, 0, 0);
|
||||
MatrixState.rotate(yAngle, 0, 1, 0);
|
||||
MatrixState.rotate(zAngle, 0, 0, 1);
|
||||
//前面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0, 0, c/2);
|
||||
rect[0].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
//后面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0, 0, -c/2);
|
||||
MatrixState.rotate(180.0f, 0, 1, 0);
|
||||
rect[1].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
//右面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(a/2, 0, 0);
|
||||
MatrixState.rotate(90.0f, 0, 1, 0);
|
||||
rect[2].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
//左面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(-a/2, 0, 0);
|
||||
MatrixState.rotate(-90.0f, 0, 1, 0);
|
||||
rect[3].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
//下面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0, -b/2, 0);
|
||||
MatrixState.rotate(90.0f, 1, 0, 0);
|
||||
rect[4].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
//上面
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0, b/2, 0);
|
||||
MatrixState.rotate(-90.0f, 1, 0, 0);
|
||||
rect[5].drawSelf(ballTexId);
|
||||
MatrixState.popMatrix();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
public class CubeGroup {
|
||||
|
||||
MySurfaceView mv;
|
||||
|
||||
TextureRect textureRect;//底部立方体
|
||||
Cube sideCube1;//左右侧立方体
|
||||
Cube sideCube2;//前后侧立方体
|
||||
float size;//尺寸
|
||||
float a;
|
||||
float b;
|
||||
float c;
|
||||
float width;
|
||||
public CubeGroup(MySurfaceView mv,
|
||||
float scale, //比例
|
||||
float a, //矩形平面长度
|
||||
float b, //墙的高度
|
||||
float c , //矩形平面宽度
|
||||
float width //墙的厚度
|
||||
){
|
||||
//创建各个组成部分的对象
|
||||
textureRect = new TextureRect(mv,scale,a,c);//立方体
|
||||
sideCube1 = new Cube(mv, scale, new float[]{c, b, width});//立方体
|
||||
sideCube2 = new Cube(mv, scale, new float[]{a-2*width, b, width});//立方体
|
||||
// 初始化完成后再改变各量的值
|
||||
size = scale;
|
||||
a *= size;
|
||||
b *= size;
|
||||
c *= size;
|
||||
width *= size;
|
||||
//初始化成员变量的值
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
this.width = width;
|
||||
}
|
||||
public void drawSelf(int floorTexId,int wallTexId){
|
||||
//底部
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.rotate(-90, 1, 0, 0);
|
||||
textureRect.drawSelf(floorTexId);
|
||||
MatrixState.popMatrix();
|
||||
//左右侧
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(-(a - width)/2,b/2, 0);
|
||||
MatrixState.rotate(90, 0, 1, 0);
|
||||
sideCube1.drawSelf(wallTexId);
|
||||
MatrixState.popMatrix();
|
||||
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate((a - width)/2,b/2, 0);
|
||||
MatrixState.rotate(90, 0, 1, 0);
|
||||
sideCube1.drawSelf(wallTexId);
|
||||
MatrixState.popMatrix();
|
||||
//前后侧
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0,b/2, (c - width)/2);
|
||||
sideCube2.drawSelf(wallTexId);
|
||||
MatrixState.popMatrix();
|
||||
|
||||
MatrixState.pushMatrix();
|
||||
MatrixState.translate(0,b/2, -(c - width)/2);
|
||||
sideCube2.drawSelf(wallTexId);
|
||||
MatrixState.popMatrix();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.bn.Sample18_6;
|
||||
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);
|
||||
}
|
||||
//获取具体物体的总变换矩阵
|
||||
static float[] mMVPMatrix=new float[16];
|
||||
public static float[] getFinalMatrix()
|
||||
{
|
||||
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, currMatrix, 0);
|
||||
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
|
||||
return mMVPMatrix;
|
||||
}
|
||||
|
||||
//获取具体物体的变换矩阵
|
||||
public static float[] getMMatrix()
|
||||
{
|
||||
return currMatrix;
|
||||
}
|
||||
|
||||
//获取投影矩阵
|
||||
public static float[] getProjMatrix()
|
||||
{
|
||||
return mProjMatrix;
|
||||
}
|
||||
|
||||
//获取摄像机朝向的矩阵
|
||||
public static float[] getCaMatrix()
|
||||
{
|
||||
return mVMatrix;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//设置灯光位置的方法
|
||||
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,113 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class MyActivity extends Activity {
|
||||
//SensorManager对象引用
|
||||
SensorManager mySensorManager;
|
||||
|
||||
Sensor mySensor; //传感器类型
|
||||
|
||||
MySurfaceView mySurfaceView;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public 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);
|
||||
|
||||
//获得SensorManager对象
|
||||
mySensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
|
||||
//姿态传感器
|
||||
mySensor=mySensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
|
||||
|
||||
|
||||
mySurfaceView = new MySurfaceView(this);
|
||||
this.setContentView(mySurfaceView);
|
||||
//获取焦点
|
||||
mySurfaceView.requestFocus();
|
||||
//设置为可触控
|
||||
mySurfaceView.setFocusableInTouchMode(true);
|
||||
|
||||
}
|
||||
|
||||
private SensorEventListener mySensorListener =
|
||||
new SensorEventListener(){//开发实现了SensorEventListener接口的传感器监听器
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy){}
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event){
|
||||
float []values=event.values;//获取三个轴方向上的值
|
||||
|
||||
float directionDotXYZ[]=RotateUtil.getDirectionDot
|
||||
(
|
||||
new double[]{values[0],values[1],values[2]}
|
||||
);
|
||||
//标准化xy位移量
|
||||
double mLength=directionDotXYZ[0]*directionDotXYZ[0]+
|
||||
directionDotXYZ[1]*directionDotXYZ[1];
|
||||
mLength=Math.sqrt(mLength);
|
||||
|
||||
if(mLength==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if( directionDotXYZ[2]<0)
|
||||
{
|
||||
Constant.SPANX=(float)((directionDotXYZ[1]/mLength)*0.08f);
|
||||
Constant.SPANZ=(float)((directionDotXYZ[0]/mLength)*0.08f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Constant.SPANX=(float)((directionDotXYZ[1]/mLength)*0.08f);
|
||||
Constant.SPANZ=-(float)((directionDotXYZ[0]/mLength)*0.08f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onResume() { //重写onResume方法
|
||||
mySensorManager.registerListener( //注册监听器
|
||||
mySensorListener, //监听器对象
|
||||
mySensor, //传感器类型
|
||||
SensorManager.SENSOR_DELAY_NORMAL //传感器事件传递的频度
|
||||
);
|
||||
|
||||
super.onResume();
|
||||
}
|
||||
@Override
|
||||
protected void onPause() { //重写onPause方法
|
||||
mySensorManager.unregisterListener(mySensorListener); //取消注册监听器
|
||||
super.onPause();
|
||||
}
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode,KeyEvent e)
|
||||
{
|
||||
switch(keyCode)
|
||||
{
|
||||
case 4:
|
||||
System.exit(0);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.bn.Sample18_6;
|
||||
public class MyMathUtil{
|
||||
|
||||
/***
|
||||
*
|
||||
* @param a 增广矩阵
|
||||
* @return 结果数组(一维)
|
||||
*/
|
||||
static double a[][];
|
||||
//通过doolittle分解解n元一次线性方程组的工具方法
|
||||
static double[] doolittle(double a[][]){
|
||||
MyMathUtil.a=a;
|
||||
int rowNum = a.length ;//获得未知数的个数
|
||||
int xnum = a[0].length-rowNum;// 所求解的组数(一)
|
||||
|
||||
double AugMatrix[][]=new double[10][20];//拓展的增广矩阵
|
||||
|
||||
readData(a,rowNum,xnum,AugMatrix);
|
||||
|
||||
for(int i=1;i<=rowNum;i++)
|
||||
{
|
||||
prepareChoose(i,rowNum,AugMatrix);
|
||||
choose(i,rowNum,xnum,AugMatrix);
|
||||
resolve(i,rowNum,xnum,AugMatrix);
|
||||
}
|
||||
|
||||
findX(rowNum,xnum,AugMatrix);
|
||||
|
||||
double[] result=new double[rowNum];
|
||||
for(int i=0;i<rowNum;i++)
|
||||
{
|
||||
result[i]=AugMatrix[i+1][rowNum+1];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void readData(double a[][],int rowNum,int xnum,double AugMatrix[][])
|
||||
{//增广矩阵的拓展
|
||||
for(int i=0;i<=rowNum;i++)
|
||||
{
|
||||
AugMatrix[i][0]=0;
|
||||
}
|
||||
for(int i=0;i<=rowNum+xnum;i++)
|
||||
{
|
||||
AugMatrix[0][i]=0;
|
||||
}
|
||||
for(int i=1;i<=rowNum;i++)
|
||||
for(int j=1;j<=rowNum+xnum;j++)
|
||||
AugMatrix[i][j]=a[i-1][j-1];
|
||||
}
|
||||
|
||||
static void prepareChoose(int times,int rowNum,double AugMatrix[][])
|
||||
{//计算准备选主元
|
||||
for(int i=times;i<=rowNum;i++)
|
||||
{
|
||||
for(int j=times-1;j>=1;j--)
|
||||
{
|
||||
AugMatrix[i][times]=AugMatrix[i][times]-AugMatrix[i][j]*AugMatrix[j][times];
|
||||
}
|
||||
}
|
||||
}
|
||||
static void choose(int times,int rowNum,int xnum,double AugMatrix[][])
|
||||
{//选主元
|
||||
int line=times;
|
||||
for(int i=times+1;i<=rowNum;i++)//选最大行
|
||||
{
|
||||
if(AugMatrix[i][times]*AugMatrix[i][times]>AugMatrix[line][times]*AugMatrix[line][times])
|
||||
line=i;
|
||||
}
|
||||
if(AugMatrix[line][times]==0)//最大数等于零
|
||||
{
|
||||
System.out.println("doolittle fail !!!");
|
||||
|
||||
}
|
||||
if(line!=times)//交换
|
||||
{
|
||||
double temp;
|
||||
for(int i=1;i<=rowNum+xnum;i++)
|
||||
{
|
||||
temp=AugMatrix[times][i];
|
||||
AugMatrix[times][i]=AugMatrix[line][i];
|
||||
AugMatrix[line][i]=temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void resolve(int times,int rowNum,int xnum,double AugMatrix[][])
|
||||
{//分解
|
||||
for(int i=times+1;i<=rowNum;i++)
|
||||
{
|
||||
AugMatrix[i][times]=AugMatrix[i][times]/AugMatrix[times][times];
|
||||
}
|
||||
for(int i=times+1;i<=rowNum+xnum;i++)
|
||||
{
|
||||
for(int j=times-1;j>=1;j--)
|
||||
{
|
||||
AugMatrix[times][i]=AugMatrix[times][i]-AugMatrix[times][j]*AugMatrix[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
static void findX(int rowNum,int xnum,double AugMatrix[][])
|
||||
{//求解
|
||||
for(int k=1;k<=xnum;k++)
|
||||
{
|
||||
AugMatrix[rowNum][rowNum+k]=AugMatrix[rowNum][rowNum+k]/AugMatrix[rowNum][rowNum];
|
||||
for(int i=rowNum-1;i>=1;i--)
|
||||
{
|
||||
for(int j=rowNum;j>i;j--)
|
||||
{
|
||||
AugMatrix[i][rowNum+k]=AugMatrix[i][rowNum+k]-AugMatrix[i][j]*AugMatrix[j][rowNum+k];
|
||||
}
|
||||
AugMatrix[i][rowNum+k]=AugMatrix[i][rowNum+k]/AugMatrix[i][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.GLUtils;
|
||||
import android.opengl.GLES20;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
class MySurfaceView extends GLSurfaceView {
|
||||
|
||||
private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度缩放比例
|
||||
private float mPreviousY;//上次的触控位置Y坐标
|
||||
private float mPreviousX;//上次的触控位置X坐标
|
||||
|
||||
private float cameraX=0;//摄像机的位置
|
||||
private float cameraY=30;
|
||||
private float cameraZ=0;
|
||||
|
||||
private float targetX=0;//看点
|
||||
private float targetY=0;
|
||||
private float targetZ=0;
|
||||
|
||||
private float sightDis=26;//摄像机和目标的距离
|
||||
private float angdegElevation=90;//仰角
|
||||
private float angdegAzimuth=0;//方位角
|
||||
|
||||
private SceneRenderer mRenderer;//场景渲染器
|
||||
int texFloorId; //地板的纹理id
|
||||
int texWallId; //墙面的纹理
|
||||
|
||||
BallGoThread ballGoThread; //球运动的线程
|
||||
|
||||
public MySurfaceView(Context context) {
|
||||
super(context);
|
||||
this.setEGLContextClientVersion(2); //设置使用OPENGL ES2.0
|
||||
mRenderer = new SceneRenderer(); //创建场景渲染器
|
||||
setRenderer(mRenderer); //设置渲染器
|
||||
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染
|
||||
}
|
||||
|
||||
//触摸事件回调方法
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
float y = e.getY();
|
||||
float x = e.getX();
|
||||
switch (e.getAction()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float dy = y - mPreviousY;//计算触控笔Y位移
|
||||
float dx = x - mPreviousX;//计算触控笔X位移
|
||||
|
||||
angdegAzimuth += dx * TOUCH_SCALE_FACTOR;//设置沿y轴旋转角度
|
||||
angdegElevation+= dy * TOUCH_SCALE_FACTOR;//设置沿x轴旋转角度
|
||||
|
||||
//仰角
|
||||
if(angdegElevation>=90){
|
||||
angdegElevation=90;
|
||||
}else if(angdegElevation<=0){
|
||||
angdegElevation=0;
|
||||
}
|
||||
}
|
||||
mPreviousY = y;//记录触控笔位置
|
||||
mPreviousX = x;//记录触控笔位置
|
||||
return true;
|
||||
}
|
||||
|
||||
private class SceneRenderer implements GLSurfaceView.Renderer
|
||||
{
|
||||
CubeGroup cubeGroup;//立方体组
|
||||
BallForControl ballForControl; //球
|
||||
|
||||
public void onDrawFrame(GL10 gl)
|
||||
{
|
||||
//清除深度缓冲与颜色缓冲
|
||||
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
double angradElevation=Math.toRadians(angdegElevation);//仰角(弧度)
|
||||
double angradAzimuth=Math.toRadians(angdegAzimuth);//方位角
|
||||
cameraX=(float) (targetX+sightDis*Math.cos(angradElevation)*Math.sin(angradAzimuth));
|
||||
cameraY=(float) (targetY+sightDis*Math.sin(angradElevation));
|
||||
cameraZ=(float) (targetZ+sightDis*Math.cos(angradElevation)*Math.cos(angradAzimuth));
|
||||
|
||||
MatrixState.setCamera(//设置camera位置
|
||||
cameraX, //人眼位置的X
|
||||
cameraY, //人眼位置的Y
|
||||
cameraZ, //人眼位置的Z
|
||||
|
||||
targetX, //人眼球看的点X
|
||||
targetY, //人眼球看的点Y
|
||||
targetZ, //人眼球看的点Z
|
||||
|
||||
0, //头的朝向
|
||||
1,
|
||||
0
|
||||
);
|
||||
|
||||
//绘制墙面
|
||||
MatrixState.pushMatrix();
|
||||
cubeGroup.drawSelf(texFloorId,texWallId);
|
||||
MatrixState.popMatrix();
|
||||
|
||||
MatrixState.pushMatrix();
|
||||
//绘制球
|
||||
ballForControl.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, 4f, 100);
|
||||
//初始化光源
|
||||
MatrixState.setLightLocation(0 , 12 , 0);
|
||||
//创建线程对象
|
||||
ballGoThread=new BallGoThread(ballForControl);
|
||||
//线程标志位设为true
|
||||
ballGoThread.setFlag(true);
|
||||
//开启线程
|
||||
ballGoThread.start();
|
||||
|
||||
}
|
||||
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
//设置屏幕背景色RGBA
|
||||
GLES20.glClearColor(0.0f,0.0f,0.0f, 1.0f);
|
||||
//启用深度测试
|
||||
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
||||
//设置为打开背面剪裁
|
||||
GLES20.glEnable(GLES20.GL_CULL_FACE);
|
||||
//初始化变换矩阵
|
||||
MatrixState.setInitStack();
|
||||
//地板的纹理id
|
||||
texFloorId=initTexture(R.drawable.tex_floor);
|
||||
//墙面的纹理id
|
||||
texWallId=initTexture(R.drawable.tex_wall);
|
||||
|
||||
//创建各个立方体
|
||||
cubeGroup=new CubeGroup(MySurfaceView.this,Constant.SCALE,
|
||||
Constant.CUBE_LENGTH, Constant.CUBE_HEIGHT, Constant.CUBE_WIDTH ,Constant.WALL_WIDTH);//立方体组
|
||||
|
||||
//创建球的对象
|
||||
ballForControl=new BallForControl(MySurfaceView.this,Constant.SCALE,Constant.AHALF,5);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
//关闭线程
|
||||
ballGoThread.setFlag(false);
|
||||
}
|
||||
|
||||
public int initTexture(int drawableId)//textureId
|
||||
{
|
||||
//生成纹理ID
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures
|
||||
(
|
||||
1, //产生的纹理id的数量
|
||||
textures, //纹理id的数组
|
||||
0 //偏移量
|
||||
);
|
||||
int textureId=textures[0];
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
|
||||
|
||||
//通过输入流加载图片===============begin===================
|
||||
InputStream is = this.getResources().openRawResource(drawableId);
|
||||
Bitmap bitmapTmp;
|
||||
try
|
||||
{
|
||||
bitmapTmp = BitmapFactory.decodeStream(is);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
is.close();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
//通过输入流加载图片===============end=====================
|
||||
|
||||
//实际加载纹理
|
||||
GLUtils.texImage2D
|
||||
(
|
||||
GLES20.GL_TEXTURE_2D, //纹理类型,在OpenGL ES中必须为GL10.GL_TEXTURE_2D
|
||||
0, //纹理的层次,0表示基本图像层,可以理解为直接贴图
|
||||
bitmapTmp, //纹理图像
|
||||
0 //纹理边框尺寸
|
||||
);
|
||||
bitmapTmp.recycle(); //纹理加载成功后释放图片
|
||||
|
||||
return textureId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.bn.Sample18_6;
|
||||
/*
|
||||
* 该类为静态工具类,提供静态方法来计算
|
||||
* 小球应该的运动方向
|
||||
*/
|
||||
public class RotateUtil
|
||||
{
|
||||
//angle为弧度 gVector 为重力向量[x,y,z,1]
|
||||
//返回值为旋转后的向量
|
||||
public static double[] pitchRotate(double angle,double[] gVector)
|
||||
{
|
||||
double[][] matrix=//绕x轴旋转变换矩阵
|
||||
{
|
||||
{1,0,0,0},
|
||||
{0,Math.cos(angle),Math.sin(angle),0},
|
||||
{0,-Math.sin(angle),Math.cos(angle),0}, //原来为:{0,-Math.sin(angle),Math.cos(angle),0},
|
||||
{0,0,0,1}
|
||||
};
|
||||
|
||||
double[] tempDot={gVector[0],gVector[1],gVector[2],gVector[3]};
|
||||
for(int j=0;j<4;j++)
|
||||
{
|
||||
gVector[j]=(tempDot[0]*matrix[0][j]+tempDot[1]*matrix[1][j]+
|
||||
tempDot[2]*matrix[2][j]+tempDot[3]*matrix[3][j]);
|
||||
}
|
||||
|
||||
return gVector;
|
||||
}
|
||||
|
||||
//angle为弧度 gVector 为重力向量[x,y,z,1]
|
||||
//返回值为旋转后的向量
|
||||
public static double[] rollRotate(double angle,double[] gVector)
|
||||
{
|
||||
double[][] matrix=//绕y轴旋转变换矩阵
|
||||
{
|
||||
{Math.cos(angle),0,-Math.sin(angle),0},
|
||||
{0,1,0,0},
|
||||
{Math.sin(angle),0,Math.cos(angle),0},
|
||||
{0,0,0,1}
|
||||
};
|
||||
|
||||
double[] tempDot={gVector[0],gVector[1],gVector[2],gVector[3]};
|
||||
for(int j=0;j<4;j++)
|
||||
{
|
||||
gVector[j]=(tempDot[0]*matrix[0][j]+tempDot[1]*matrix[1][j]+
|
||||
tempDot[2]*matrix[2][j]+tempDot[3]*matrix[3][j]);
|
||||
}
|
||||
|
||||
return gVector;
|
||||
}
|
||||
|
||||
//angle为弧度 gVector 为重力向量[x,y,z,1]
|
||||
//返回值为旋转后的向量
|
||||
public static double[] yawRotate(double angle,double[] gVector)
|
||||
{
|
||||
double[][] matrix=//绕z轴旋转变换矩阵
|
||||
{
|
||||
{Math.cos(angle),Math.sin(angle),0,0},
|
||||
{-Math.sin(angle),Math.cos(angle),0,0},
|
||||
{0,0,1,0},
|
||||
{0,0,0,1}
|
||||
};
|
||||
|
||||
double[] tempDot={gVector[0],gVector[1],gVector[2],gVector[3]};
|
||||
for(int j=0;j<4;j++)
|
||||
{
|
||||
gVector[j]=(tempDot[0]*matrix[0][j]+tempDot[1]*matrix[1][j]+
|
||||
tempDot[2]*matrix[2][j]+tempDot[3]*matrix[3][j]);
|
||||
}
|
||||
|
||||
return gVector;
|
||||
}
|
||||
|
||||
|
||||
public static float[] getDirectionDot(double[] values)
|
||||
{
|
||||
double yawAngle=-Math.toRadians(values[0]);//获取Yaw轴旋转角度弧度
|
||||
double pitchAngle=-Math.toRadians(values[1]);//获取Pitch轴旋转角度弧度
|
||||
double rollAngle=-Math.toRadians(values[2]);//获取Roll轴旋转角度弧度
|
||||
|
||||
//虚拟一个重力向量
|
||||
double[] gVector={0,0,-100,1};
|
||||
|
||||
//yaw轴恢复
|
||||
gVector=RotateUtil.yawRotate(yawAngle,gVector);
|
||||
|
||||
//pitch轴恢复
|
||||
gVector=RotateUtil.pitchRotate(pitchAngle,gVector);
|
||||
|
||||
//roll轴恢复
|
||||
gVector=RotateUtil.rollRotate(rollAngle,gVector);
|
||||
|
||||
double mapX=gVector[0];
|
||||
double mapY=gVector[1];
|
||||
double mapZ=gVector[2];
|
||||
|
||||
float[] result={(float) mapX,(float) mapY,(float) mapZ};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import static com.bn.Sample18_6.ShaderUtil.createProgram;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
//矩形平面
|
||||
public class TextureRect
|
||||
{
|
||||
int mProgram;//自定义渲染管线着色器程序id
|
||||
int muMVPMatrixHandle;//总变换矩阵引用
|
||||
int maPositionHandle; //顶点位置属性引用
|
||||
int maTexCoorHandle; //顶点纹理坐标属性引用
|
||||
|
||||
int muMMatrixHandle;//位置、旋转、缩放变换矩阵
|
||||
int maCameraHandle; //摄像机位置属性引用
|
||||
int maNormalHandle; //顶点法向量属性引用
|
||||
int maLightLocationHandle;//光源位置属性引用
|
||||
|
||||
|
||||
String mVertexShader;//顶点着色器代码脚本
|
||||
String mFragmentShader;//片元着色器代码脚本
|
||||
|
||||
FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
|
||||
FloatBuffer mTexCoorBuffer;//顶点纹理坐标数据缓冲
|
||||
FloatBuffer mNormalBuffer;//顶点法向量数据缓冲
|
||||
int vCount=0;
|
||||
float xAngle=0;//绕x轴旋转的角度
|
||||
float yAngle=0;//绕y轴旋转的角度
|
||||
float zAngle=0;//绕z轴旋转的角度
|
||||
|
||||
public TextureRect(MySurfaceView mv,float scale,float a,float b)
|
||||
{
|
||||
//调用初始化顶点数据的initVertexData方法
|
||||
initVertexData(scale,a,b);
|
||||
//调用初始化着色器的intShader方法
|
||||
initShader(mv);
|
||||
}
|
||||
|
||||
//自定义初始化顶点坐标数据的方法
|
||||
public void initVertexData(float scale,float a, float b) {
|
||||
|
||||
a*=scale;
|
||||
b*=scale;
|
||||
float xOffset=a/2;
|
||||
float yOffset=b/2;
|
||||
vCount=6;
|
||||
//坐标数据初始化
|
||||
float[] vertices=new float[]{
|
||||
-xOffset,-yOffset,0,
|
||||
xOffset,yOffset,0,
|
||||
-xOffset,yOffset,0,
|
||||
|
||||
-xOffset,-yOffset,0,
|
||||
xOffset,-yOffset,0,
|
||||
xOffset,yOffset,0
|
||||
};
|
||||
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);//创建顶点坐标数据缓冲
|
||||
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
mVertexBuffer = vbb.asFloatBuffer();//转换为float型缓冲
|
||||
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
|
||||
mVertexBuffer.position(0);//设置缓冲区起始位置
|
||||
//法向量数据初始化
|
||||
float[] normals=new float[]{
|
||||
0,0,1,
|
||||
0,0,1,
|
||||
0,0,1,
|
||||
|
||||
0,0,1,
|
||||
0,0,1,
|
||||
0,0,1,
|
||||
};//法向量数组
|
||||
ByteBuffer nbb = ByteBuffer.allocateDirect(normals.length*4);//创建顶点法向量数据缓冲
|
||||
nbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
mNormalBuffer = nbb.asFloatBuffer();//转换为float型缓冲
|
||||
mNormalBuffer.put(normals);//向缓冲区中放入顶点法向量数据
|
||||
mNormalBuffer.position(0);//设置缓冲区起始位置
|
||||
//纹理数据的初始化
|
||||
float[] textures=new float[]{//顶点纹理S、T坐标值数组
|
||||
0,1,
|
||||
1,0,
|
||||
0,0,
|
||||
|
||||
0,1,
|
||||
1,1,
|
||||
1,0,
|
||||
};
|
||||
ByteBuffer cbb = ByteBuffer.allocateDirect(textures.length*4);//创建顶点纹理数据缓冲
|
||||
cbb.order(ByteOrder.nativeOrder());//设置字节顺序
|
||||
mTexCoorBuffer = cbb.asFloatBuffer();//转换为float型缓冲
|
||||
mTexCoorBuffer.put(textures);//向缓冲区中放入顶点纹理数据
|
||||
mTexCoorBuffer.position(0);//设置缓冲区起始位置
|
||||
}
|
||||
|
||||
//自定义初始化着色器的initShader方法
|
||||
public void initShader(MySurfaceView mv)
|
||||
{
|
||||
//加载顶点着色器的脚本内容
|
||||
mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_tex_light.sh", mv.getResources());
|
||||
//加载片元着色器的脚本内容
|
||||
mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_tex_light.sh", mv.getResources());
|
||||
//基于顶点着色器与片元着色器创建程序
|
||||
mProgram = createProgram(mVertexShader, mFragmentShader);
|
||||
//获取程序中顶点位置属性引用id
|
||||
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
|
||||
//获取程序中顶点纹理坐标属性引用id
|
||||
maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor");
|
||||
//获取程序中总变换矩阵引用id
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
|
||||
//获取程序中顶点法向量属性引用id
|
||||
maNormalHandle= GLES20.glGetAttribLocation(mProgram, "aNormal");
|
||||
//获取程序中摄像机位置引用id
|
||||
maCameraHandle=GLES20.glGetUniformLocation(mProgram, "uCamera");
|
||||
//获取程序中光源位置引用id
|
||||
maLightLocationHandle=GLES20.glGetUniformLocation(mProgram, "uLightLocation");
|
||||
//获取位置、旋转变换矩阵引用id
|
||||
muMMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMMatrix");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void drawSelf(int texId)
|
||||
{
|
||||
//制定使用某套shader程序
|
||||
GLES20.glUseProgram(mProgram);
|
||||
//将最终变换矩阵传入shader程序
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);
|
||||
//将位置、旋转变换矩阵传入shader程序
|
||||
GLES20.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0);
|
||||
//将摄像机位置传入shader程序
|
||||
GLES20.glUniform3fv(maCameraHandle, 1, MatrixState.cameraFB);
|
||||
//将光源位置传入shader程序
|
||||
GLES20.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightPositionFB);
|
||||
|
||||
//传送顶点位置数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maPositionHandle,
|
||||
3,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mVertexBuffer
|
||||
);
|
||||
//传送顶点纹理坐标数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maTexCoorHandle,
|
||||
2,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
2*4,
|
||||
mTexCoorBuffer
|
||||
);
|
||||
//传送顶点法向量数据
|
||||
GLES20.glVertexAttribPointer
|
||||
(
|
||||
maNormalHandle,
|
||||
4,
|
||||
GLES20.GL_FLOAT,
|
||||
false,
|
||||
3*4,
|
||||
mNormalBuffer
|
||||
);
|
||||
|
||||
//启用顶点位置数据
|
||||
GLES20.glEnableVertexAttribArray(maPositionHandle);
|
||||
//启用顶点纹理数据
|
||||
GLES20.glEnableVertexAttribArray(maTexCoorHandle);
|
||||
//启用顶点法向量数据
|
||||
GLES20.glEnableVertexAttribArray(maNormalHandle);
|
||||
//绑定纹理
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
|
||||
|
||||
//绘制纹理矩形
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.bn.Sample18_6;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
//计算三角形法向量的工具类
|
||||
public class VectorUtil {
|
||||
//向量规格化的方法
|
||||
public static float[] normalizeVector(float [] vec){
|
||||
float mod=module(vec);
|
||||
return new float[]{vec[0]/mod, vec[1]/mod, vec[2]/mod};//返回规格化后的向量
|
||||
}
|
||||
//求向量的模的方法
|
||||
public static float module(float [] vec){
|
||||
return (float) Math.sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
|
||||
}
|
||||
//两个向量叉乘的方法
|
||||
public static float[] crossTwoVectors(float[] a, float[] b)
|
||||
{
|
||||
float x=a[1]*b[2]-a[2]*b[1];
|
||||
float y=a[2]*b[0]-a[0]*b[2];
|
||||
float z=a[0]*b[1]-a[1]*b[0];
|
||||
return new float[]{x, y, z};//返回叉乘结果
|
||||
}
|
||||
//两个向量点乘的方法
|
||||
public static float dotTwoVectors(float[] a, float[] b)
|
||||
{
|
||||
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];//返回点乘结果
|
||||
}
|
||||
|
||||
//根据原纹理坐标和索引,计算卷绕后的纹理的方法
|
||||
public static float[] calTextures(
|
||||
ArrayList<Float> alST,//原纹理坐标列表(未卷绕)
|
||||
ArrayList<Integer> alTexIndex//组织成面的纹理坐标的索引值列表(按逆时针卷绕)
|
||||
)
|
||||
{
|
||||
float[] textures=new float[alTexIndex.size()*2];
|
||||
//生成顶点的数组
|
||||
int stCount=0;
|
||||
for(int i:alTexIndex){
|
||||
textures[stCount++]=alST.get(2*i);
|
||||
textures[stCount++]=alST.get(2*i+1);
|
||||
}
|
||||
return textures;
|
||||
}
|
||||
public static float[] calVertices(
|
||||
ArrayList<Float> alv,//原顶点列表(未卷绕)
|
||||
ArrayList<Integer> alFaceIndex//组织成面的顶点的索引值列表(按逆时针卷绕)
|
||||
)
|
||||
{
|
||||
float[] vertices=new float[alFaceIndex.size()*3];
|
||||
//生成顶点的数组
|
||||
int vCount=0;
|
||||
for(int i:alFaceIndex){
|
||||
vertices[vCount++]=alv.get(3*i);
|
||||
vertices[vCount++]=alv.get(3*i+1);
|
||||
vertices[vCount++]=alv.get(3*i+2);
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
//计算圆弧的n等分点坐标的方法
|
||||
public static float[] devideBall(
|
||||
float r, //球的半径
|
||||
float[] start, //指向圆弧起点的向量
|
||||
float[] end, //指向圆弧终点的向量
|
||||
int n, //圆弧分的份数
|
||||
int i //求第i份在圆弧上的坐标(i为0和n时分别代表起点和终点坐标)
|
||||
)
|
||||
{
|
||||
/*
|
||||
* 先求出所求向量的规格化向量,再乘以半径r即可
|
||||
* s0*x+s1*y+s2*z=cos(angle1)//根据所求向量和起点向量夹角为angle1---1式
|
||||
* e0*x+e1*y+e2*z=cos(angle2)//根据所求向量和终点向量夹角为angle2---2式
|
||||
* x*x+y*y+z*z=1//所球向量的规格化向量模为1---3式
|
||||
* x*n0+y*n1+z*n2=0//所球向量与法向量垂直---4式
|
||||
* 算法为:将1、2两式用换元法得出x=a1+b1*z,y=a2+b2*z的形式,
|
||||
* 将其代入4式求出z,再求出x、y,最后将向量(x,y,z)乘以r即为所求坐标。
|
||||
* 1式和2式是将3式代入得到的,因此已经用上了。
|
||||
* 由于叉乘的结果做了分母,因此起点、终点、球心三点不能共线
|
||||
* 注意结果是将劣弧等分
|
||||
*/
|
||||
//先将指向起点和终点的向量规格化
|
||||
float[] s=VectorUtil.normalizeVector(start);
|
||||
float[] e=VectorUtil.normalizeVector(end);
|
||||
if(n==0){//如果n为零,返回起点坐标
|
||||
return new float[]{s[0]*r, s[1]*r, s[2]*r};
|
||||
}
|
||||
//求两个向量的夹角
|
||||
double angrad=Math.acos(VectorUtil.dotTwoVectors(s, e));//起点终点向量夹角
|
||||
double angrad1=angrad*i/n;//所球向量和起点向量的夹角
|
||||
double angrad2=angrad-angrad1;//所球向量和终点向量的夹角
|
||||
//求法向量normal
|
||||
float[] normal=VectorUtil.crossTwoVectors(s, e);
|
||||
//用doolittle分解算法解n元一次线性方程组
|
||||
double matrix[][]={//增广矩阵
|
||||
{s[0],s[1],s[2],Math.cos(angrad1)},
|
||||
{e[0],e[1],e[2],Math.cos(angrad2)},
|
||||
{normal[0],normal[1],normal[2],0}
|
||||
};
|
||||
double result[]=MyMathUtil.doolittle(matrix);//解
|
||||
//求规格化向量xyz的值
|
||||
float x=(float) result[0];
|
||||
float y=(float) result[1];
|
||||
float z=(float) result[2];
|
||||
//返回圆弧的n等分点坐标
|
||||
return new float[]{x*r, y*r, z*r};
|
||||
}
|
||||
//计算线段的n等分点坐标的方法
|
||||
public static float[] devideLine(
|
||||
float[] start, //线段起点坐标
|
||||
float[] end, //线段终点坐标
|
||||
int n, //线段分的份数
|
||||
int i //求第i份在线段上的坐标(i为0和n时分别代表起点和终点坐标)
|
||||
)
|
||||
{
|
||||
if(n==0){//如果n为零,返回起点坐标
|
||||
return start;
|
||||
}
|
||||
//求起点到终点的向量
|
||||
float[] ab=new float[]{end[0]-start[0], end[1]-start[1], end[2]-start[2]};
|
||||
//求向量比例
|
||||
float vecRatio=i/(float)n;
|
||||
//求起点到所求点的向量
|
||||
float[] ac=new float[]{ab[0]*vecRatio, ab[1]*vecRatio, ab[2]*vecRatio};
|
||||
//所求坐标
|
||||
float x=start[0]+ac[0];
|
||||
float y=start[1]+ac[1];
|
||||
float z=start[2]+ac[2];
|
||||
//返回线段的n等分点坐标
|
||||
return new float[]{x, y, z};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user