|
1 | 1 |
|
2 | | -Stuck, again. I need a good way to access vertex data. The current system has some flaws: |
3 | | - |
4 | | - 1. Processes must assume the format and number of components of an attribute. |
5 | | - This is especially concerning. |
6 | | - 2. Data cannot be accessed as struct buffers. This not a huge issue. |
7 | | - 3. Attributes are accessed by a string identifier. |
8 | | - |
9 | | -I want to have a more concrete way to work with attributes. Something along these lines: |
10 | | - |
11 | | -public interface PositionAttribute { |
12 | | - void setPosition(int vertex, Vector3f position); |
13 | | - Vector3f getPosition(int vertex); |
14 | | - void setPositionAccess(DataAccess access); |
15 | | -} |
16 | | - |
17 | | -The problem is that a single attribute can get fairly bloated if you also add nice things like bulk setters and getters. Multiply that by every attribute you want, and it can get quite unwieldy. It also has that odd access setter on each attribute, which for whatever reason really annoys me. |
18 | | - |
19 | | -What would actually be ideal is if everything could be represented by a simple "Vertex" struct. |
20 | | - |
21 | | -struct Vertex { |
22 | | - Vector3f position; |
23 | | - Vector2f texCoord; |
24 | | - Vector3f normal; |
25 | | -} |
26 | | - |
27 | | -(of course, in Java struct declaration is more complicated). The advantage is that all the vertex buffers can be very simply mapped as buffers of Vertex. It would also translate fairly well to instances. |
28 | | - |
29 | | -struct Instance { |
30 | | - Matrix4f worldViewProjection; |
31 | | - Vector4f color; |
32 | | -} |
33 | | - |
34 | | -The problem is what to do with vertex data split across multiple buffers, which could very well be done if multiple shaders want to access the vertex positions, but not everything wants the texCoord and normal data. In which case it'd be represented as so: |
35 | | - |
36 | | -struct VertexPart1 { |
37 | | - Vector3f position; |
38 | | -} |
39 | | -struct VertexPart2 { |
40 | | - Vector2f texCoord; |
41 | | - Vector3f normal; |
42 | | -} |
43 | | - |
44 | | -User-side, this wouldn't be much of a problem. He should know what type of vertex he's working with. But the engine utilities don't necessarily know that. The vertex struct would have to implement an interface (possibly for each attribute, as discussed above), and the utility would have to cast each individual vertex to the desired type. |
45 | | - |
46 | | -for (Vertex v : mesh.getVertices()) { |
47 | | - ((Position)v).setPosition(Vector3f.ZERO); |
48 | | -} |
49 | | - |
50 | | -It's messy and a pain to work with. It also doesn't properly address the dual vertex buffer situation. A possible solution to this is custom iterators which will automatically verify that an entire batch of vertices already meets the requirements. It would work something like this: |
51 | | - |
52 | | -for (Position p : mesh.getVertices(Position.class)) { |
53 | | - p.setPosition(Vector3f.ZERO); |
54 | | -} |
55 | | -for (TexCoord t : mesh.getVertices(TexCoord.class)) { |
56 | | - t.setTexCoord(Vector2f.ZERO); |
57 | | -} |
58 | | -mesh.unmap(); // unmap all used buffers |
59 | | - |
60 | | -getVertices() implementation may look something like this: |
61 | | - |
62 | | -public class Mesh { |
63 | | - private final Collection<VertexBuffer<?>> buffers = new ArrayList<>(); |
64 | | - private final Map<Class<? extends VertexAttribute>, VertexBuffer<?>> bufferLookup = new HashMap<>(); |
65 | | - public <T extends VertexAttribute> Iterable<T> getVertices(Class<T> type) { |
66 | | - VertexBuffer<?> buf = bufferLookup.get(type); |
67 | | - if (buf != null) { |
68 | | - return buf.getVertices(type); |
69 | | - } |
70 | | - for (VertexBuffer<?> buffer : buffers) { |
71 | | - if (type.isAssignableFrom(buffer.getVertexType())) { |
72 | | - bufferLookup.put(type, buffer); |
73 | | - return buffer.getVertices(type); |
74 | | - } |
75 | | - } |
76 | | - throw new IllegalArgumentException("Mesh does not contain " + type); |
77 | | - } |
78 | | -} |
79 | | -public class VertexBuffer <V extends Vertex> { |
80 | | - private final Class<V> vertexType; |
81 | | - private final GpuBuffer buffer; |
82 | | - public <T extends VertexAttribute> Iterable<T> getVertices(Class<T> type) { |
83 | | - if (!type.isAssignableFrom(vertexType)) { |
84 | | - throw new ClassCastException("Vertex data is not " + type); |
85 | | - } |
86 | | - return (Iterable<T>)map(); |
87 | | - } |
88 | | - public Iterable<V> map() { |
89 | | - return buffer.map((Long address, Integer size) -> V.Buffer.create(address, size)); |
90 | | - } |
91 | | - public Class<V> getVertexType() { |
92 | | - return vertexType; |
93 | | - } |
94 | | -} |
95 | | - |
96 | | -Unfortunately, this doesn't make accessing two different attributes at once very do-able. You'd have to do an awkward multi-iterator loop, which is just a pain to do. It would be better to have to do this: |
97 | | - |
98 | | -List<Position> pos = mesh.getVertices(Position.class); |
99 | | -List<TexCoord> tex = mesh.getVertices(TexCoord.class); |
100 | | -pos.get(12).setPosition(tex.get(11).toVector3f()); |
101 | | - |
102 | | -How about this: |
103 | | - |
104 | | -Position pos = mesh.getAttribute(Position.class); |
105 | | -TexCoord tex = mesh.getAttribute(TexCoord.class); |
106 | | -pos.set(12, 0f, 0f, 0f); |
107 | | -Vector3f v = pos.get(11); |
108 | | -for (Vector3f v : pos) { |
109 | | - |
110 | | -} |
111 | | -for (int i : Attributes.iterate(pos, tex)) { |
112 | | - |
113 | | -} |
114 | | - |
115 | | -public interface Attribute <T> extends Iterable<T> { |
116 | | - |
117 | | - Attribute<T> map(); |
118 | | - |
119 | | - void set(int element, T value); |
120 | | - |
121 | | - T get(int element); |
122 | | - |
123 | | - int size(); |
124 | | - |
125 | | - // optional |
126 | | - default T get(int element, T store) { |
127 | | - return get(element); |
128 | | - } |
129 | | - |
130 | | - @Override |
131 | | - default Iterator<T> iterator() { |
132 | | - return new IteratorImpl<>(null); |
133 | | - } |
134 | | - |
135 | | - default IteratorImpl<T> iterator(T store) { |
136 | | - return new IteratorImpl<>(store); |
137 | | - } |
138 | | - |
139 | | - class IteratorImpl <T> implements Iterator<T>, Iterable<T> { |
140 | | - |
141 | | - private final Attribute<T> attr; |
142 | | - private final T store; |
143 | | - private int index = 0; |
144 | | - |
145 | | - public IteratorImpl(Attribute<T> attr, T store) { |
146 | | - this.attr = attr; |
147 | | - this.store = store; |
148 | | - } |
149 | | - |
150 | | - public boolean hasNext() { |
151 | | - return index < attr.size(); |
152 | | - } |
153 | | - |
154 | | - public T next() { |
155 | | - return attr.get(index++, store); |
156 | | - } |
157 | | - |
158 | | - public Iterator<T> iterator() { |
159 | | - this.index = 0; |
160 | | - return this; |
161 | | - } |
162 | | - |
163 | | - } |
164 | | - |
165 | | -} |
166 | | -public abstract class AbstractAttribute <T> implements Attribute<T> { |
167 | | - |
168 | | - protected final VertexBuffer vertexBuffer; |
169 | | - protected final int stride, offset, size; |
170 | | - protected ByteBuffer buffer; |
171 | | - |
172 | | - public AbstractAttribute(VertexBuffer vertexBuffer, int stride, int offset, int size) { |
173 | | - this.vertexBuffer = vertexBuffer; |
174 | | - } |
175 | | - |
176 | | -} |
177 | | -public class Position implements Attribute<Vector3f> { |
178 | | - |
179 | | - private VertexBuffer buffer; |
180 | | - private int stride, offset; |
181 | | - |
182 | | - @Override |
183 | | - public void set(int element, Vector3f value) { |
184 | | - set(element, value.x, value.y, value.z); |
185 | | - } |
186 | | - |
187 | | - @Override |
188 | | - public Vector3f get(int element) { |
189 | | - Vector3f store = new Vector3f(); |
190 | | - ByteBuffer buf = buffer.map().position(element * stride + offset); |
191 | | - store.x = buf.getFloat(); |
192 | | - store.y = buf.getFloat(); |
193 | | - store.z = buf.getFloat(); |
194 | | - return store; |
195 | | - } |
196 | | - |
197 | | - public void set(int element, float x, float y, float z) { |
198 | | - buffer.map() |
199 | | - .position(element * stride + offset) |
200 | | - .putFloat(x).putFloat(y).putFloat(z); |
201 | | - } |
202 | | - |
203 | | -} |
204 | | - |
205 | | -If mappings are frequent -> streaming buffer |
206 | | -If mappings are less frequent -> dynamic buffer |
207 | | -If only one mapping occurs OR a mapping hasn't occured in a very long time -> static buffer |
208 | | - |
209 | | -Static AND dynamic |
210 | | - Build |
211 | | - 1. Create GPU buffer (device local) |
212 | | - 2. Create CPU buffer (nio) |
213 | | - CPU -> GPU |
214 | | - 1. Acquire staging buffer (host visible and coherent) |
215 | | - 2. Map staging buffer |
216 | | - 3. Copy CPU buffer -> staging buffer |
217 | | - 4. Record copy staging buffer -> GPU buffer |
218 | | - 5. Unmap staging buffer |
219 | | - --- wait for copy to complete |
220 | | - 6. Release staging buffer |
221 | | - GPU -> CPU |
222 | | - 1. Acquire staging buffer (host visible and coherent) |
223 | | - 2. Copy GPU buffer -> staging buffer |
224 | | - --- wait for copy to complete |
225 | | - 3. Map staging buffer |
226 | | - 4. Copy staging buffer -> CPU buffer |
227 | | - OR read directly from staging buffer |
228 | | - (depends on the nature of the read op) |
229 | | - 5. Unmap staging buffer |
230 | | - 6. Release staging buffer |
231 | | -Streaming |
232 | | - Build |
233 | | - 1. Create GPU buffers per frame (host visible and coherent) |
234 | | - 2. Create CPU buffer (nio) |
235 | | - CPU -> GPU |
236 | | - 1. Map frame GPU buffer (if not already mapped) |
237 | | - 2. Copy CPU buffer -> frame GPU buffer |
238 | | - 3. Unmap frame GPU buffer (if necessary) |
239 | | - GPU -> CPU |
240 | | - 1. Map a GPU buffer (if not already mapped) |
241 | | - 2. Copy GPU buffer -> CPU buffer |
242 | | - 3. Unmap GPU buffer (if necessary) |
| 2 | +Material should be split into two different classes: |
243 | 3 |
|
| 4 | +1. Associate values with uniform names. This is what NewMaterial is doing. |
| 5 | +2. Associate uniform names with descriptor bindings. Previously, this role would've been filled by MaterialDef. |
0 commit comments