Implement simple Scene3d drawing: #183

This commit is contained in:
Vadim Lopatin 2016-03-31 10:54:54 +03:00
parent d882a203c0
commit 92a348974f
10 changed files with 176 additions and 82 deletions

View File

@ -280,9 +280,11 @@
<Compile Include="src\dlangui\graphics\images.d" />
<Compile Include="src\dlangui\graphics\resources.d" />
<Compile Include="src\dlangui\graphics\scene\camera.d" />
<Compile Include="src\dlangui\graphics\scene\drawableobject.d" />
<Compile Include="src\dlangui\graphics\scene\effect.d" />
<Compile Include="src\dlangui\graphics\scene\material.d" />
<Compile Include="src\dlangui\graphics\scene\mesh.d" />
<Compile Include="src\dlangui\graphics\scene\model.d" />
<Compile Include="src\dlangui\graphics\scene\node.d" />
<Compile Include="src\dlangui\graphics\scene\scene3d.d" />
<Compile Include="src\dlangui\graphics\scene\transform.d" />

View File

@ -139,9 +139,11 @@
<Compile Include="src\dlangui\graphics\images.d" />
<Compile Include="src\dlangui\graphics\resources.d" />
<Compile Include="src\dlangui\graphics\scene\camera.d" />
<Compile Include="src\dlangui\graphics\scene\drawableobject.d" />
<Compile Include="src\dlangui\graphics\scene\effect.d" />
<Compile Include="src\dlangui\graphics\scene\material.d" />
<Compile Include="src\dlangui\graphics\scene\mesh.d" />
<Compile Include="src\dlangui\graphics\scene\model.d" />
<Compile Include="src\dlangui\graphics\scene\node.d" />
<Compile Include="src\dlangui\graphics\scene\scene3d.d" />
<Compile Include="src\dlangui\graphics\scene\transform.d" />

View File

@ -771,9 +771,11 @@
<Folder name="graphics">
<Folder name="scene">
<File path="src\dlangui\graphics\scene\camera.d" />
<File path="src\dlangui\graphics\scene\drawableobject.d" />
<File path="src\dlangui\graphics\scene\effect.d" />
<File path="src\dlangui\graphics\scene\material.d" />
<File path="src\dlangui\graphics\scene\mesh.d" />
<File path="src\dlangui\graphics\scene\model.d" />
<File path="src\dlangui\graphics\scene\node.d" />
<File path="src\dlangui\graphics\scene\scene3d.d" />
<File path="src\dlangui\graphics\scene\transform.d" />

View File

@ -6,6 +6,8 @@ import dlangui.graphics.scene.camera;
import dlangui.graphics.scene.mesh;
import dlangui.graphics.scene.material;
import dlangui.graphics.scene.effect;
import dlangui.graphics.scene.model;
import dlangui.graphics.scene.node;
import dlangui.graphics.glsupport;
import dlangui.graphics.gldrawbuf;
import derelict.opengl3.gl3;
@ -114,7 +116,7 @@ class UiWidget : VerticalLayout, CellVisitor {
int y0 = 0;
int z0 = 0;
_mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
Mesh _mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
for (int i = 0; i < 10; i++) {
_mesh.addCubeMesh(vec3(x0+ 0, y0+0, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1, 1, 1));
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
@ -126,6 +128,11 @@ class UiWidget : VerticalLayout, CellVisitor {
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+-i * 2 + 1.0f, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1 - i / 12, i / 12, 1));
_mesh.addCubeMesh(vec3(x0+ -i * 2 - 1.0f, y0+-i * 2 - 1.0f, z0+ -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1));
}
Material cubeMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "crate");
Model cubeDrawable = new Model(cubeMaterial, _mesh);
Node3d cubeNode = new Node3d("cubes", cubeDrawable);
_scene.addChild(cubeNode);
_minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
_world = new World();
@ -146,6 +153,12 @@ class UiWidget : VerticalLayout, CellVisitor {
_world.camPosition = Position(Vector3d(0, 3, 0), Vector3d(0, 0, 1));
updateMinerMesh();
Material minerMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "blocks");
Model minerDrawable = new Model(minerMaterial, _minerMesh);
Node3d minerNode = new Node3d("miner", minerDrawable);
_scene.addChild(minerNode);
//CellVisitor visitor = new TestVisitor();
//Log.d("Testing cell visitor");
//long ts = currentTimeMillis;
@ -229,28 +242,13 @@ class UiWidget : VerticalLayout, CellVisitor {
}
float angle = 0;
EffectRef _program;
Scene3d _scene;
Scene3dRef _scene;
Camera _cam;
Mesh _mesh;
Mesh _minerMesh;
GLTexture _tx;
GLTexture _blockstx;
/// this is OpenGLDrawableDelegate implementation
private void doDraw(Rect windowRect, Rect rc) {
if (_program.isNull) {
_program = EffectCache.instance.get("textured.vert", "textured.frag");
}
if (!_tx)
_tx = new GLTexture("crate");
if (!_blockstx)
_blockstx = new GLTexture("blocks");
if (!_tx.isValid || !_blockstx.isValid) {
Log.e("Invalid texture");
return;
}
_cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
_cam.setIdentity();
//_cam.translate(vec3(
@ -329,33 +327,13 @@ class UiWidget : VerticalLayout, CellVisitor {
checkgl!glEnable(GL_DEPTH_TEST);
checkgl!glCullFace(GL_BACK);
_program.bind();
_program.setUniform("matrix", projectionViewModelMatrix);
_tx.texture.setup();
_tx.texture.setSamplerParams(true);
_scene.drawScene(false);
_program.draw(_mesh);
_tx.texture.unbind();
_blockstx.texture.setup();
_blockstx.texture.setSamplerParams(false);
_program.draw(_minerMesh);
_blockstx.texture.unbind();
_program.unbind();
checkgl!glDisable(GL_DEPTH_TEST);
checkgl!glDisable(GL_CULL_FACE);
}
~this() {
destroy(_scene);
if (_program)
destroy(_program);
if (_tx)
destroy(_tx);
destroy(_world);
}
}

View File

@ -15,7 +15,8 @@ class Camera : Node3d {
protected bool _enabled;
this() {
this(string ID = null) {
super(ID);
_enabled = true;
setPerspective(4.0f, 3.0f, 45.0f, 0.1f, 100.0f);
}
@ -30,6 +31,11 @@ class Camera : Node3d {
_enabled = v;
}
/// returns true if some changes occured in projection or view matrix since last matrix getter call
@property bool viewChanged() {
return _dirtyTransform || _dirtyViewProjection || _dirtyView;
}
/// get projection matrix
@property ref const(mat4) projectionMatrix() {
return _projectionMatrix;

View File

@ -12,40 +12,6 @@ import dlangui.graphics.scene.mesh;
/// Reference counted Effect object
alias EffectRef = Ref!Effect;
/// Effect ID
struct EffectId {
string vertexShaderName;
string fragmentShaderName;
string definitions;
this(string vertexShader, string fragmentShader, string defs) {
vertexShaderName = vertexShader;
fragmentShaderName = fragmentShader;
definitions = defs;
}
size_t toHash() const @safe pure nothrow
{
size_t hash;
foreach (char c; vertexShaderName)
hash = (hash * 9) + c;
hash = (hash * 31) + 198237283;
foreach (char c; fragmentShaderName)
hash = (hash * 9) + c;
hash = (hash * 31) + 84574112;
foreach (char c; definitions)
hash = (hash * 9) + c;
return hash;
}
bool opEquals(ref const EffectId s) const @safe pure nothrow
{
return
std.string.cmp(this.vertexShaderName, s.vertexShaderName) == 0 &&
std.string.cmp(this.fragmentShaderName, s.fragmentShaderName) == 0 &&
std.string.cmp(this.definitions, s.definitions) == 0;
}
}
/// Effect (aka OpenGL program)
class Effect : GLProgram {
EffectId _id;
@ -181,3 +147,43 @@ class EffectCache {
}
}
/// Effect ID
struct EffectId {
string vertexShaderName;
string fragmentShaderName;
string definitions;
this(string vertexShader, string fragmentShader, string defs) {
vertexShaderName = vertexShader;
fragmentShaderName = fragmentShader;
definitions = defs;
}
/// returns true if ID is not assigned
@property bool empty() {
return !vertexShaderName.length || !vertexShaderName.length;
}
size_t toHash() const @safe pure nothrow
{
size_t hash;
foreach (char c; vertexShaderName)
hash = (hash * 9) + c;
hash = (hash * 31) + 198237283;
foreach (char c; fragmentShaderName)
hash = (hash * 9) + c;
hash = (hash * 31) + 84574112;
foreach (char c; definitions)
hash = (hash * 9) + c;
return hash;
}
bool opEquals(ref const EffectId s) const @safe pure nothrow
{
return
std.string.cmp(this.vertexShaderName, s.vertexShaderName) == 0 &&
std.string.cmp(this.fragmentShaderName, s.fragmentShaderName) == 0 &&
std.string.cmp(this.definitions, s.definitions) == 0;
}
}

View File

@ -7,16 +7,32 @@ import dlangui.core.logger;
import dlangui.graphics.glsupport;
import dlangui.graphics.gldrawbuf;
import dlangui.graphics.scene.effect;
import dlangui.graphics.scene.node;
import dlangui.graphics.scene.mesh;
/// Reference counted Material object
alias MaterialRef = Ref!Material;
class Material : RefCountedObject {
protected EffectRef _effect;
protected EffectId _effectId;
protected TextureRef _texture;
protected string _textureId;
// TODO: more material properties
@property EffectRef effect() { return _effect; }
this() {
}
this(EffectId effectId, string textureId) {
_effectId = effectId;
_textureId = textureId;
}
@property EffectRef effect() {
if (_effect.isNull && !_effectId.empty)
_effect = EffectCache.instance.get(_effectId);
return _effect;
}
/// set as effect instance
@property Material effect(EffectRef e) {
_effect = e;
@ -24,11 +40,19 @@ class Material : RefCountedObject {
}
/// set as effect id
@property Material effect(EffectId effectId) {
_effect = EffectCache.instance.get(effectId);
if (_effectId == effectId)
return this; // no change
_effectId = effectId;
_effect.clear();
return this;
}
@property TextureRef texture() { return _texture; }
@property TextureRef texture() {
if (_texture.isNull && _textureId.length) {
_texture = GLTextureCache.instance.get(_textureId);
}
return _texture;
}
/// set texture
@property Material texture(TextureRef e) {
_texture = e;
@ -36,7 +60,32 @@ class Material : RefCountedObject {
}
/// set texture from resourceId
@property Material texture(string resourceId) {
_texture = GLTextureCache.instance.get(resourceId);
if (_textureId == resourceId)
return this; // no change
_texture.clear();
_textureId = resourceId;
return this;
}
void bind(Node3d node) {
assert(!effect.isNull);
effect.bind();
if (!texture.isNull) {
texture.texture.setup();
texture.texture.setSamplerParams(true);
}
// TODO: more uniforms
_effect.setUniform("matrix", node.projectionViewModelMatrix);
}
void drawMesh(Mesh mesh) {
effect.draw(mesh);
}
void unbind() {
if (!texture.isNull) {
texture.texture.unbind();
}
effect.unbind();
}
}

View File

@ -5,21 +5,33 @@ import dlangui.core.math3d;
import dlangui.graphics.scene.transform;
import dlangui.core.collections;
import dlangui.graphics.scene.scene3d;
import dlangui.graphics.scene.drawableobject;
/// 3D scene node
class Node3d : Transform {
protected Node3d _parent;
protected Scene3d _scene;
protected string _id;
protected DrawableObjectRef _drawable;
protected mat4 _worldMatrix;
protected ObjectList!Node3d _children;
this() {
this(string id = null) {
super();
_id = id;
}
this(string id, DrawableObject drawable) {
super();
_id = id;
_drawable = drawable;
}
/// drawable attached to node
@property ref DrawableObjectRef drawable() { return _drawable; }
/// returns scene for node
@property Scene3d scene() {
if (_scene)
@ -41,11 +53,12 @@ class Node3d : Transform {
return _children[index];
}
/// add child node
void addChild(Node3d node) {
/// add child node, return current node
Node3d addChild(Node3d node) {
_children.add(node);
node.parent = this;
node.scene = scene;
return this;
}
/// removes and destroys child node by index
@ -53,6 +66,8 @@ class Node3d : Transform {
destroy(_children.remove(index));
}
@property ref ObjectList!Node3d children() { return _children; }
/// parent node
@property Node3d parent() {
return _parent;
@ -60,6 +75,7 @@ class Node3d : Transform {
@property Node3d parent(Node3d v) {
_parent = v;
_scene = v.scene;
return this;
}
/// id of node
@ -71,4 +87,9 @@ class Node3d : Transform {
_id = v;
return this;
}
/// returns projectionMatrix * viewMatrix * modelMatrix
@property mat4 projectionViewModelMatrix() {
return _scene.projectionViewMatrix * matrix;
}
}

View File

@ -1,10 +1,14 @@
module dlangui.graphics.scene.scene3d;
import dlangui.core.types;
import dlangui.graphics.scene.node;
import dlangui.graphics.scene.camera;
public import dlangui.core.math3d;
/// Reference counted Scene3d object
alias Scene3dRef = Ref!Scene3d;
/// 3D scene
class Scene3d : Node3d {
@ -47,6 +51,29 @@ class Scene3d : Node3d {
static mat4 dummyIdentityMatrix;
return dummyIdentityMatrix;
}
protected bool _wireframe;
void drawScene(bool wireframe) {
_wireframe = wireframe;
visit(this, &sceneDrawVisitor);
}
protected bool sceneDrawVisitor(Node3d node) {
if (!node.drawable.isNull)
node.drawable.draw(node, _wireframe);
return false;
}
}
/// depth-first recursive node traversion, stops if visitor returns true
bool visit(Node3d node, bool delegate(Node3d node) visitor) {
bool res = visitor(node);
if (res)
return true;
foreach(child; node.children) {
bool res = visit(child, visitor);
if (res)
return true;
}
return false;
}

View File

@ -1,9 +1,10 @@
module dlangui.graphics.scene.transform;
import dlangui.core.math3d;
import dlangui.core.types;
/// 3d transform: scale + translation + rotation
class Transform {
class Transform : RefCountedObject {
// transform flags
protected bool _dirtyTransform = true;
protected bool _hasScale = false;