add ModelRender class

This commit is contained in:
wyq 2023-03-07 17:00:21 +08:00
parent 376df7f35d
commit 5c84f06d89
6 changed files with 363 additions and 39 deletions

View File

@ -8137,6 +8137,49 @@ public class GraphicFactory {
return meshGraphic;
}
/**
* Create model graphic
*
* @param faceIndices Vertex indices array
* @param x X coordinates array
* @param y Y coordinates array
* @param z Z coordinates array
* @param ls Legend scheme
* @return
*/
public static Model model(Array faceIndices, Array x, Array y,
Array z, LegendScheme ls) {
Model model = new Model();
model.setTriangles(faceIndices, x, y, z);
model.setLegendScheme(ls);
return model;
}
/**
* Create model graphic
*
* @param faceIndices Vertex indices array
* @param x X coordinates array
* @param y Y coordinates array
* @param z Z coordinates array
* @param normal Normal array
* @param ls Legend scheme
* @return
*/
public static Model model(Array faceIndices, Array x, Array y,
Array z, Array normal, LegendScheme ls) {
if (normal == null) {
return model(faceIndices, x, y, z, ls);
}
Model model = new Model();
model.setTriangles(faceIndices, x, y, z, normal);
model.setLegendScheme(ls);
return model;
}
/**
* Create volume graphics
*

View File

@ -1,7 +1,13 @@
package org.meteoinfo.chart.graphic;
public class Model {
protected TriMeshGraphic triMeshGraphic;
import org.joml.Vector3f;
import java.util.List;
public class Model extends TriMeshGraphic {
protected Vector3f angle = new Vector3f();
protected float scale = 1;
/**
* Constructor
@ -11,28 +17,43 @@ public class Model {
}
/**
* Constructor
*
* @param triMeshGraphic Triangle mesh graphic
* Get angle
* @return The angle
*/
public Model(TriMeshGraphic triMeshGraphic) {
this.triMeshGraphic = triMeshGraphic;
public Vector3f getAngle() {
return angle;
}
/**
* Get triangle mesh graphic
* @return Triangle mesh graphic
* Set angle
* @param value Then angle
*/
public TriMeshGraphic getTriMeshGraphic() {
return this.triMeshGraphic;
public void setAngle(Vector3f value) {
angle = value;
}
/**
* Set triangle mesh graphic
* @param value Triangle mesh graphic
* Set angle
* @param value The angle
*/
public void setTriMeshGraphic(TriMeshGraphic value) {
this.triMeshGraphic = value;
public void setAngle(List<Float> value) {
angle = new Vector3f(value.get(0), value.get(1), value.get(2));
}
/**
* Get scale
* @return The scale
*/
public float getScale() {
return scale;
}
/**
* Set value
* @param value The value
*/
public void setScale(float value) {
scale = value;
}
/**

View File

@ -20,16 +20,16 @@ import java.util.logging.Logger;
public class TriMeshGraphic extends GraphicCollection3D {
private Logger logger = Logger.getLogger("TriMeshGraphic");
private float[] vertexPosition;
private float[] vertexValue;
private float[] vertexColor;
private float[] vertexNormal;
private int[] vertexIndices;
protected float[] vertexPosition;
protected float[] vertexValue;
protected float[] vertexColor;
protected float[] vertexNormal;
protected int[] vertexIndices;
//private LinkedHashMap<Integer, List<Integer>> triangleMap;
private boolean faceInterp;
private boolean edgeInterp;
private boolean mesh;
private boolean normalLoaded = false;
protected boolean faceInterp;
protected boolean edgeInterp;
protected boolean mesh;
protected boolean normalLoaded = false;
/**
* Constructor

View File

@ -9,7 +9,7 @@ import org.meteoinfo.chart.graphic.TriMeshGraphic;
import java.util.ArrayList;
import java.util.List;
public class Cylinder extends Model {
public class Cylinder {
private float baseRadius;
private float topRadius;
private float height;
@ -64,9 +64,9 @@ public class Cylinder extends Model {
}
}
@Override
protected void buildTriMeshGraphic() {
this.triMeshGraphic = new TriMeshGraphic();
protected TriMeshGraphic buildTriMeshGraphic() {
TriMeshGraphic triMeshGraphic = new TriMeshGraphic();
int n = this.vertices.size();
float[] vertexPosition = new float[n * 3];
float[] vertexNormal = new float[n * 3];
@ -82,9 +82,11 @@ public class Cylinder extends Model {
vertexNormal[j + 2] = v.z;
}
int[] vertexIndices = this.indices.stream().mapToInt(Integer::intValue).toArray();
this.triMeshGraphic.setVertexPosition(vertexPosition);
this.triMeshGraphic.setVertexNormal(vertexNormal);
this.triMeshGraphic.setVertexIndices(vertexIndices);
triMeshGraphic.setVertexPosition(vertexPosition);
triMeshGraphic.setVertexNormal(vertexNormal);
triMeshGraphic.setVertexIndices(vertexIndices);
return triMeshGraphic;
}
/**

View File

@ -2518,6 +2518,18 @@ public class GLPlot extends Plot {
pointRender.updateMatrix();
pointRender.draw();
} else if (graphic instanceof TriMeshGraphic) {
if (graphic instanceof Model) {
if (!this.renderMap.containsKey(graphic)) {
renderMap.put(graphic, new ModelRender(gl, (Model) graphic));
}
ModelRender modelRender = (ModelRender) renderMap.get(graphic);
modelRender.setTransform(this.transform, this.alwaysUpdateBuffers);
modelRender.setOrthographic(this.orthographic);
modelRender.setLighting(this.lighting);
modelRender.updateMatrix();
modelRender.setRotateModelView(this.modelViewMatrixR);
modelRender.draw();
} else {
if (!this.renderMap.containsKey(graphic)) {
renderMap.put(graphic, new TriMeshRender(gl, (TriMeshGraphic) graphic));
}
@ -2527,6 +2539,7 @@ public class GLPlot extends Plot {
triMeshRender.setLighting(this.lighting);
triMeshRender.updateMatrix();
triMeshRender.draw();
}
} else if (graphic instanceof VolumeGraphic) {
try {
if (this.clipPlane)

View File

@ -0,0 +1,245 @@
package org.meteoinfo.chart.render.jogl;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.util.GLBuffers;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.meteoinfo.chart.graphic.Model;
import org.meteoinfo.chart.graphic.TriMeshGraphic;
import org.meteoinfo.chart.jogl.Program;
import org.meteoinfo.chart.jogl.Transform;
import org.meteoinfo.chart.jogl.Utils;
import org.meteoinfo.geometry.legend.PolygonBreak;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class ModelRender extends JOGLGraphicRender {
private Model model;
private IntBuffer vbo;
//private IntBuffer vboNormal;
private Program program;
private float[] vertexPosition;
private int sizePosition;
private int sizeNormal;
private int sizeColor;
/**
* Constructor
*
* @param gl The JOGL GL2 object
*/
public ModelRender(GL2 gl) {
super(gl);
useShader = false;
if (useShader) {
try {
this.compileShaders();
} catch (Exception e) {
e.printStackTrace();
}
}
initVertexBuffer();
}
/**
* Constructor
*
* @param gl The opengl pipeline
* @param model The model
*/
public ModelRender(GL2 gl, Model model) {
this(gl);
this.model = model;
this.setBufferData();
}
private void initVertexBuffer() {
vbo = GLBuffers.newDirectIntBuffer(2);
}
private void setBufferData() {
if (vertexPosition == null) {
vertexPosition = model.getVertexPosition();
}
FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexPosition);
if (model.getVertexNormal() == null) {
model.calculateNormalVectors(vertexPosition);
}
FloatBuffer normalBuffer = GLBuffers.newDirectFloatBuffer(model.getVertexNormal());
FloatBuffer colorBuffer = GLBuffers.newDirectFloatBuffer(model.getVertexColor());
sizePosition = vertexBuffer.capacity() * Float.BYTES;
sizeNormal = normalBuffer.capacity() * Float.BYTES;
sizeColor = colorBuffer.capacity() * Float.BYTES;
gl.glGenBuffers(2, vbo);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo.get(0));
gl.glBufferData(GL.GL_ARRAY_BUFFER, sizePosition + sizeNormal + sizeColor, null, GL.GL_STATIC_DRAW);
gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, sizePosition, vertexBuffer);
gl.glBufferSubData(GL.GL_ARRAY_BUFFER, sizePosition, sizeNormal, normalBuffer);
gl.glBufferSubData(GL.GL_ARRAY_BUFFER, sizePosition + sizeNormal, sizeColor, colorBuffer);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
IntBuffer indexBuffer = GLBuffers.newDirectIntBuffer(model.getVertexIndices());
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vbo.get(1));
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Integer.BYTES, indexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
}
@Override
public void setTransform(Transform transform, boolean alwaysUpdateBuffers) {
boolean updateBuffer = true;
if (!alwaysUpdateBuffers && this.transform != null && this.transform.equals(transform))
updateBuffer = false;
super.setTransform((Transform) transform.clone());
if (alwaysUpdateBuffers) {
setBufferData();
}
}
void compileShaders() throws Exception {
String vertexShaderCode = Utils.loadResource("/shaders/mesh/vertex.vert");
String fragmentShaderCode = Utils.loadResource("/shaders/mesh/mesh.frag");
program = new Program("mesh", vertexShaderCode, fragmentShaderCode);
}
/**
* Update shaders
*/
public void updateShaders() {
if (program == null) {
try {
compileShaders();
} catch (Exception e) {
e.printStackTrace();
}
}
}
void setUniforms() {
program.allocateUniform(gl, "matrixModelViewProjection", (gl2, loc) -> {
gl2.glUniformMatrix4fv(loc, 1, false, this.viewProjMatrix.get(Buffers.newDirectFloatBuffer(16)));
});
program.allocateUniform(gl, "matrixModelView", (gl2, loc) -> {
gl2.glUniformMatrix4fv(loc, 1, false, toMatrix(this.mvmatrix).get(Buffers.newDirectFloatBuffer(16)));
});
Matrix4f matrixNormal = toMatrix(this.mvmatrix);
matrixNormal.setColumn(3, new Vector4f(0,0,0,1));
program.allocateUniform(gl, "matrixNormal", (gl2, loc) -> {
gl2.glUniformMatrix4fv(loc, 1, false, matrixNormal.get(Buffers.newDirectFloatBuffer(16)));
});
float[] rgba = model.getColor().getRGBComponents(null);
program.allocateUniform(gl, "color", (gl2, loc) -> {
gl2.glUniform4fv(loc, 1, rgba, 0);
});
program.allocateUniform(gl, "lightPosition", (gl2, loc) -> {
gl2.glUniform4fv(loc, 1, lighting.getPosition(), 0);
});
program.allocateUniform(gl, "lightAmbient", (gl2, loc) -> {
gl2.glUniform4fv(loc, 1, lighting.getAmbient(), 0);
});
program.allocateUniform(gl, "lightDiffuse", (gl2, loc) -> {
gl2.glUniform4fv(loc, 1, lighting.getDiffuse(), 0);
});
program.allocateUniform(gl, "lightSpecular", (gl2, loc) -> {
gl2.glUniform4fv(loc, 1, lighting.getSpecular(), 0);
});
program.setUniforms(gl);
}
@Override
public void draw() {
gl.glPushMatrix();
FloatBuffer fb = Buffers.newDirectFloatBuffer(16);
Matrix4f modelView = new Matrix4f(this.modelViewMatrixR);
modelView.scale(this.model.getScale());
modelView.rotateXYZ(model.getAngle());
gl.glLoadMatrixf(modelView.get(fb));
if (useShader) {
program.use(gl);
setUniforms();
int attribVertexPosition = gl.glGetAttribLocation(program.getProgramId(), "vertexPosition");
int attribVertexNormal = gl.glGetAttribLocation(program.getProgramId(), "vertexNormal");
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo.get(0));
gl.glEnableVertexAttribArray(attribVertexPosition);
gl.glEnableVertexAttribArray(attribVertexNormal);
gl.glVertexAttribPointer(attribVertexPosition, 3, GL.GL_FLOAT, false, 0, 0);
gl.glVertexAttribPointer(attribVertexNormal, 3, GL.GL_FLOAT, false, 0, vertexPosition.length * Float.BYTES);
gl.glDrawArrays(GL.GL_TRIANGLES, 0, model.getVertexNumber());
gl.glDisableVertexAttribArray(attribVertexPosition);
gl.glDisableVertexAttribArray(attribVertexNormal);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glUseProgram(0);
} else {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo.get(0));
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, vbo.get(1));
// enable vertex arrays
gl.glEnableClientState(GL2.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glNormalPointer(GL.GL_FLOAT, 0, sizePosition);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl.glColorPointer(4, GL.GL_FLOAT, 0, sizePosition + sizeNormal);
PolygonBreak pb = (PolygonBreak) model.getLegendScheme().getLegendBreak(0);
if (pb.isDrawFill()) {
gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
gl.glPolygonOffset(1.0f, 1.0f);
if (model.isFaceInterp()) {
gl.glDrawElements(GL2.GL_TRIANGLES, model.getVertexIndices().length, GL.GL_UNSIGNED_INT, 0);
} else {
gl.glShadeModel(GL2.GL_FLAT);
gl.glDrawElements(GL2.GL_TRIANGLES, model.getVertexIndices().length, GL.GL_UNSIGNED_INT, 0);
gl.glShadeModel(GL2.GL_SMOOTH);
}
}
if (pb.isDrawOutline()) {
boolean lightEnabled = this.lighting.isEnable();
if (lightEnabled) {
this.lighting.stop(gl);
}
gl.glLineWidth(pb.getOutlineSize() * this.dpiScale);
if (!model.isMesh()) {
gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
float[] rgba = pb.getOutlineColor().getRGBComponents(null);
gl.glColor4fv(rgba, 0);
}
gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE);
//gl.glDrawArrays(GL.GL_TRIANGLES, 0, meshGraphic.getVertexNumber());
gl.glDrawElements(GL.GL_TRIANGLES, model.getVertexIndices().length, GL.GL_UNSIGNED_INT, 0);
gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL);
if (lightEnabled) {
this.lighting.start(gl);
}
}
gl.glDisableClientState(GL2.GL_NORMAL_ARRAY);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
}
gl.glPopMatrix();
}
}