代码
MySurfaceView.java
package com.Diamond.gl09;
import android.opengl.*;
import android.opengl.GLES32;
import android.opengl.GLSurfaceView;
import android.content.Context;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.egl.EGLConfig;
import android.content.res.AssetManager;
import java.io.IOException;
import android.renderscript.Float3;
import android.renderscript.Float4;
import android.view.MotionEvent;
import android.util.Log;
import java.util.Random;
public class MySurfaceView extends GLSurfaceView {
public class MyRenderer implements GLSurfaceView.Renderer {
public GLES32 gl;
public Program usual;
public Program illumination;
public MyObj[] cubes;
public MyObj sphere;
public Camera camera;
public Axis axis;
public Fog fog;
public Light[] lights;
public float angleX,angleY,distance;
public Texture texture;
public int w,h;
public boolean enableFog;
@Override
public void onSurfaceCreated(GL10 p1, EGLConfig p2) {
usual = new Program(Program.loadFromAssetsFile("usual.vert", getResources()), Program.loadFromAssetsFile("usual.frag", getResources()));
illumination = new Program(Program.loadFromAssetsFile("illumination.vert", getResources()), Program.loadFromAssetsFile("illumination.frag", getResources()));
texture = new Texture(getResources().openRawResource(R.raw.texture), gl.GL_TEXTURE_2D, 0);
Random random = new Random();
random.setSeed(System.currentTimeMillis());
try {
float scale = 0.5f;
AssetManager am = getResources().getAssets();
cubes = new MyObj[1000];
MyObj cube = new MyObj(am.open("cube.obj"), new Float4());
for (int i = 0;i < cubes.length;i++) {
cubes[i] = new MyObj(cube.VAO, cube.vCount);
cubes[i].texture = texture;
cubes[i].enableTexture = true;
cubes[i].color = new Float4(random.nextFloat(), random.nextFloat(), random.nextFloat(), 1);
}
randomCubes();
sphere = new MyObj(am.open("sphere.obj"), new Float4(0, 0, 1, 1));
sphere.setScale(scale).moveX(0.5f);
sphere.texture = texture;
sphere.enableTexture = true;
} catch (IOException e) {
e.printStackTrace();
}
angleX = 0;
angleY = 0;
distance = 10;
camera = new Camera(new Float3(0, 0, 1), new Float3(0, 0, 0), new Float3(0, 1, 0));
updateCamera(0, 0);
updateCameraP();
axis = new Axis();
fog = new Fog(1, 10, new Float4(0.1f, 0.1f, 0.1f, 1.0f));
enableFog = true;
lights = new Light[4];
lights[0] = new Light();
lights[1] = new Light();
lights[1].setPosition(new Float3(0, 0, 0));
lights[2] = new Light();
lights[2].setPosition(new Float3(0, 5, 0));
lights[3] = new Light();
lights[3].setPosition(new Float3(0, -5, 0));
gl.glEnable(gl.GL_DEPTH_TEST);
gl.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
}
@Override
public void onSurfaceChanged(GL10 p1, int p2, int p3) {
updateCameraP();
}
@Override
public void onDrawFrame(GL10 p1) {
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
usual.useProgram();
camera.draw(usual);
fog.enableFog = false;
fog.draw(usual);
axis.draw(usual);
illumination.useProgram();
illumination.setUniform("u_enableColor", true);
illumination.setUniform("u_enableTexture", false);
camera.draw(illumination);
fog.enableFog = enableFog;
fog.draw(illumination);
lights[0].setPosition(camera.getPosition());
for (int i = 0;i < lights.length;i++) {
lights[i].draw(illumination, i);
}
for (int i = 0;i < cubes.length;i++) {
cubes[i].draw(illumination);
}
sphere.draw(illumination);
}
public void updateCamera(float dx, float dy) {
angleX += dx;
angleY += dy;
camera.setOrbit(angleX, angleY, distance);
}
public void updateCameraP() {
w = getMeasuredWidth();
h = getMeasuredHeight();
int a = Math.max(w,h);
int b = Math.min(w,h);
float ratio = a / b;
camera.setPerspective(120.0f,0.5f,0.1f,100.0f);
}
public void randomCubes() {
Random random = new Random();
random.setSeed(System.currentTimeMillis());
for(int i = 0;i < cubes.length;i++) {
cubes[i].setPosition(new Float3(random.nextFloat() * 10 - 5, random.nextFloat() * 10 - 5, random.nextFloat() * 10 - 5));
cubes[i].setRotate(new Float3(random.nextFloat() * 360, random.nextFloat() * 360, 0));
cubes[i].setScale(random.nextFloat() * 0.5f);
}
}
public void regularCubes() {
for(int i = 0;i < cubes.length;i++) {
cubes[i].setRotate(new Float3(0,0,0));
cubes[i].setScale(0.5f);
int x = i / 100;
int y = i / 10 % 10;
int z = i % 10;
cubes[i].setPosition(new Float3(x - 5,y - 5,z - 5));
}
}
}
public MyRenderer renderer;
public float lastX,lastY;
public float speed;
public MySurfaceView(Context context) {
super(context);
this.setEGLContextClientVersion(3);
renderer = new MyRenderer();
this.setRenderer(renderer);
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
speed = 100;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
lastX = event.getX();
lastY = event.getY();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
float nowX = event.getX();
float nowY = event.getY();
float dx = nowX - lastX;
float dy = nowY - lastY;
dx *= speed / 1080;
dy *= speed / 2160;
renderer.updateCamera(-dx, dy);
lastX = nowX;
lastY = nowY;
}
return super.onTouchEvent(event);
}
}
illumination.frag
#version 320 es
precision highp float;
in vec3 v_normal;
in vec3 v_position;
in vec2 v_texCoord;
out vec4 o_color;
uniform vec4 u_color;
uniform bool u_enableColor;
uniform vec3 u_cameraposition;
const int lightnum = 4;
struct Fog
{
float start;
float end;
vec4 color;
bool enable;
};
struct Light
{
vec3 position;
vec4 color;
float intensity;
};
uniform Fog fog;
uniform Light lights[lightnum];
uniform sampler2D texSampler;
uniform bool u_enableTexture;
const float constant = 1.0;
const float linear = 0.045;
const float quadratic = 0.0075;
vec4 cal_light(Light l,vec4 color)
{
vec4 ambient = 0.1f * l.color;
vec3 lightdir = normalize(l.position - v_position);
float diff = max(dot(v_normal,lightdir),0.0f);
vec4 diffuse = diff * l.color;
vec3 cameradir = normalize(u_cameraposition - v_position);
vec3 reflectdir = normalize(reflect(-lightdir,v_normal));
float spec = pow(max(dot(cameradir,reflectdir),0.0f),l.intensity);
vec4 specular = spec * l.color;
float distance = length(l.position - v_position);
float attenuation = 1.0 / (constant + linear * distance + quadratic * (distance * distance));
return (ambient + diffuse + specular) * color * attenuation;
}
float cal_fog(Fog f)
{
float distance = length(u_cameraposition - v_position);
float factor = (f.end - distance) / (f.end - f.start);
factor = max(min(factor,1.0),0.0);
return factor;
}
vec4 get_color()
{
vec4 result;
if(u_enableColor)
{
if(u_enableTexture)
{
result = u_color * texture(texSampler,v_texCoord);
}
else
{
result = u_color;
}
}
else
{
result = texture(texSampler,v_texCoord);
}
return result;
}
void main()
{
vec4 color = get_color();
vec4 lightresult = cal_light(lights[0],color);
for(int i = 1;i < lightnum;i++)
{
lightresult += cal_light(lights[i],color);
}
float factor;
if(fog.enable)
{
factor = cal_fog(fog);
}
else
{
factor = 1.0;
}
if(factor == 0.0)
{
o_color = fog.color;
}
else
{
o_color = lightresult * factor + fog.color * (1.0 - factor);
}
}
提示
1.改了着色器,可以支持多光源了,只要
program.setUniform("lights[" + index + "].position",lights[index].getPosition());
就行了 2.还把颜色分开来了,支持纹理或者纯色或者纹理*颜色作为片段照明前颜色 3.camera.draw()和light.draw()是我偷懒,把提交uniform的都并一块了
效果图
一般就这效果(1000个方块) 如果比较多(10000个方块),就会朝一个轴延伸 MainActivity的代码就不展示了,很简单的
|